From d091f426b54788ed47f6ed071f39a658d64afbaa Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Mon, 2 Jul 2012 12:18:51 +0200 Subject: [PATCH] Sunstone: comment code, very small code fixes and improvements (cherry picked from commit dfd2a227c09a04e44b3b740b646ad9e401a05fa5) --- src/sunstone/public/js/monitoring.js | 124 ++++++++++++++++-- src/sunstone/public/js/plugins/acls-tab.js | 9 +- .../public/js/plugins/clusters-tab.js | 79 ++++++----- src/sunstone/public/js/plugins/config-tab.js | 11 +- .../public/js/plugins/dashboard-tab.js | 2 + .../public/js/plugins/dashboard-users-tab.js | 2 + .../public/js/plugins/datastores-tab.js | 8 +- src/sunstone/public/js/plugins/groups-tab.js | 1 + src/sunstone/public/js/plugins/hosts-tab.js | 56 +++++--- src/sunstone/public/js/plugins/images-tab.js | 13 ++ .../public/js/plugins/marketplace-tab.js | 1 + .../public/js/plugins/templates-tab.js | 7 +- src/sunstone/public/js/plugins/users-tab.js | 10 ++ src/sunstone/public/js/plugins/vnets-tab.js | 16 ++- src/sunstone/public/js/sunstone-util.js | 25 +++- 15 files changed, 287 insertions(+), 77 deletions(-) diff --git a/src/sunstone/public/js/monitoring.js b/src/sunstone/public/js/monitoring.js index 5b31bc1fd6..e2efa88563 100644 --- a/src/sunstone/public/js/monitoring.js +++ b/src/sunstone/public/js/monitoring.js @@ -15,26 +15,82 @@ /* -------------------------------------------------------------------------- */ +/* This files act as helper to manage gathering and plotting of data + in dashboards. */ + +// Monitoring configuration is composed of diferent configurations that can +// be added anytime. According to its values, data is gathered and processed +// for resources. Example: +/* +SunstoneMonitoringConfig['HOST'] = { + plot: function(monitoring){ + // receives monitoring data object, with monitoring series + // information for this resource. monitoring object contains one key per monitoring value below. Normally you can call SunstoneMonitoring.plot() directly + // with each of the series + }, + monitor : { + //This object defines what data is collected and how. i.e. + "statePie" : { + // must be an element of resource object. If its a second level + // key, then write as ['TEMPLATE','MAX_CPU'] + partitionPath: "STATE", //Will create a partition looking at... + + // A function that receives the list of elements and returns + // a set of series with the relevant information ready + // ready to be plotted + operation: SunstoneMonitoring.ops.partition //processing function + + // "pie" or "bars", according to this the series will be + // formatted in different ways. + dataType: "pie", //In what format data is collected (for what plot) + colorize: function(state){ //how to color the series. + // ie. pie sectors depending on host state + } + }, + plotOptions : { + //jquery flot plot options. See host plugin directly. This options + //are passed to flot on SunstoneMonitoring.plot(). + } + }, + "cpuPerCluster" : { + path: ["HOST_SHARE","CPU_USAGE"], //second level data + partitionPath: "CLUSTER_ID", //partition data according to... + operation: SunstoneMonitoring.ops.partition, //processing + dataType: "bars", + plotOptions: { + } + } + ... + +See sunstone plugins for more info and examples +*/ + + var SunstoneMonitoringConfig = {} var SunstoneMonitoring = { monitor : function(resource, list){ - + // Runs the monitoring operation for each monitor object option + // on the list of resources that comes as parameter. + // Forms the monitoring object with the results and calls + // the plotting function (defined in config). if (!SunstoneMonitoringConfig[resource]) return false var monConfigs = SunstoneMonitoringConfig[resource].monitor var monitoring = {} - for (conf in monConfigs){ + for (conf in monConfigs){ //for each of the things we want to monitor var conf_obj = monConfigs[conf] var plotID = conf var series = conf_obj.operation(resource, list, conf_obj) monitoring[plotID]=series } - //Call back after monitorization is done SunstoneMonitoringConfig[resource].plot(monitoring) }, plot : function(resource,plotID,container,series){ + // Calls the jQuery flot library plot() + // with the plotOptions from the configuration for the resource. + // If series (monitoring info) is empty, put message instead. var config = SunstoneMonitoringConfig[resource].monitor[plotID] var options = config.plotOptions @@ -47,31 +103,56 @@ var SunstoneMonitoring = { } }, ops : { + // Functions to process data contained in a list of resources in a + // specific way. The result is a series array containing the + // information, in the format jQuery flot expects it to plot. partition : function(resource,list,config){ + // Partitions data according to partitionPath. + // That is, it groups resources according to the value of + // partitionPath (for example, by CLUSTER), and counts + // how many of them are in each group (so it can be plotted). + // If path is provided (for example MEMORY), + // then it sums the value of path, instead + // of counting. + + // We use this for state pies, memory/cpu by cluster graphs, + // users per group graphs... + var path = config.path var partitionPath = config.partitionPath - var dataType = config.dataType + var dataType = config.dataType //which way the series should look like for flot + var partitions = {} + + // for each element (for example HOST) in the list for (var i=0; i< list.length; i++){ var elem = list[i][resource] var value = path ? parseInt(explore_path(elem,path),10) : 1 var partition = explore_path(elem, partitionPath) - //Things on cluster none + // Things on cluster none hack if ((partitionPath == "CLUSTER" && !partition.length) || (partitionPath == "CLUSTER_ID" && partition == "-1")) partition = "none" + // If the partition group is not there, we create it if (!partitions[partition]) partitions[partition] = value + // Otherwise we sum the value to it. else partitions[partition] += value } + // Now we have to format the data in the partitions according + // to what flot expects. + // Note that for bars the values of our x axis are fixed to + // [0, 1, 2...] this values are later not shown or alternatively + // the ticks are renamed with the axis_labels names. + var series = [] var axis_labels = [] var i = 0; - for (partition in partitions) { + for (partition in partitions) { //for each partition var value = partitions[partition] var data; switch (dataType){ @@ -84,15 +165,21 @@ var SunstoneMonitoring = { default: data = value; } + // prepare labels for the axis ticks + // for example CLUSTER names axis_labels.push([i,partition]) + + // set color of this bar/pie sector var color = config.colorize ? config.colorize(partition) : null + + // push the data in the series series.push({ label: partition, data: data, color: color }) i++ } - + // Modify configuration with custom labels. if (config.plotOptions.xaxis && config.plotOptions.xaxis.customLabels == true){ config.plotOptions.xaxis.ticks = axis_labels @@ -102,6 +189,8 @@ var SunstoneMonitoring = { return series }, hostCpuUsagePartition : function(resource,list,config){ + // Work as function above, except that partition is pre-defined + // and hosts are divided into them according to cpu usage. var partitions = { "Idle" : 0, "Ok" : 0, @@ -139,25 +228,38 @@ var SunstoneMonitoring = { return series }, totalize : function(resource,list,config){ + // just count how many items are in the list return list.length }, singleBar : function(resource,list,config){ - var paths = config.paths + // Paint data series on a single horizontal bar + // For example used_memory together with memory_usage and max_memory + // or net_tx vs. net_rx + // For each data object in the series, a total sum is calculated + var paths = config.paths // array of paths + // each path can be an array too if it is >= 2nd level path + + // initialize sums var totals = new Array(paths.length) for (var i=0; i< totals.length; i++) totals[i] = 0 var series = [] + // for each item (i.e. HOST), add the value of each of the paths + // to the respective totals for (var i=0; i< list.length; i++){ var elem = list[i][resource] for (var j=0; j< paths.length; j++) totals[j] += parseInt(explore_path(elem,paths[j]),10) } + // The totals have the sum of all items (for example of max_memory) + // Now for each total we push it to the series object. for (var i=0; i< totals.length; i++){ series.push({ - data: [[totals[i],0]], + data: [[totals[i],0]], //we paint on 0 value of y axis + // y axis labels will be hidden label: paths[i], color: config.colorize? config.colorize(paths[i]) : null, }) @@ -167,6 +269,10 @@ var SunstoneMonitoring = { } } + +// This function explores a path in an element and returns the value. +// For example, if path = 'STATE' it will return elem.STATE. But if +// path = ['TEMPLATE','MAX_CPU'] it will return elem.TEMPLATE.MAX_CPU function explore_path(elem,path){ if (!$.isArray(path)) //base case - non array return elem[path] diff --git a/src/sunstone/public/js/plugins/acls-tab.js b/src/sunstone/public/js/plugins/acls-tab.js index 9fdebd324c..2189989d69 100644 --- a/src/sunstone/public/js/plugins/acls-tab.js +++ b/src/sunstone/public/js/plugins/acls-tab.js @@ -183,7 +183,7 @@ var acls_tab = { parentTab: 'system_tab' } - +//Monitoring for ACLs - just count how many SunstoneMonitoringConfig['ACL'] = { plot: function(monitoring){ //$('#totalAcls', $dashboard).text(monitoring['totalAcls']) @@ -358,12 +358,14 @@ function setupCreateAclDialog(){ height: height }); + //Default selected options $('#res_subgroup_all',dialog).attr('checked','checked'); $('#res_id',dialog).attr('disabled','disabled'); $('#belonging_to',dialog).attr('disabled','disabled'); $('button',dialog).button(); + //Resource subset radio buttons $('.res_subgroup',dialog).click(function(){ var value = $(this).val(); var context = $(this).parent(); @@ -383,6 +385,7 @@ function setupCreateAclDialog(){ }; }); + //trigger ACL string preview on keyup $('input#res_id',dialog).keyup(function(){ $(this).trigger("change"); }); @@ -480,12 +483,12 @@ function setupCreateAclDialog(){ // required: we have to put the right options in the // selects. function popUpCreateAclDialog(){ - var users = $(''); + var users = $(''); $('.empty_value',users).remove(); $('option',users).addClass("user"); users.prepend(''); - var groups = $(''); + var groups = $(''); $('.empty_value',groups).remove(); $('option',groups).addClass("group"); groups.prepend(''); diff --git a/src/sunstone/public/js/plugins/clusters-tab.js b/src/sunstone/public/js/plugins/clusters-tab.js index a8c2087cde..3b365ea362 100644 --- a/src/sunstone/public/js/plugins/clusters-tab.js +++ b/src/sunstone/public/js/plugins/clusters-tab.js @@ -219,8 +219,14 @@ var clusters_tab = { parentTab: "infra_tab", }; + +// Cluster monitoring configuration. This config controls the monitoring +// which is plotted in the cluster dashboards. +// It operations are run for every cluster and are related to hosts in that +// cluster SunstoneMonitoringConfig['CLUSTER_HOST'] = { plot: function(monitoring){ + //plot the series calculated for the hosts in a specific cluster var cluster_id = SunstoneMonitoringConfig.CLUSTER_HOST.cluster_id if (cluster_id == '-1') cluster_id = '-'; @@ -232,6 +238,9 @@ SunstoneMonitoringConfig['CLUSTER_HOST'] = { monitoring[plotID]); }; }, + // Monitor configuration are the same those in the HOST + // configuration (except for cluster partitions) + // the difference is that these are plotted somewhere else. monitor : { "statePie" : { partitionPath: "STATE", @@ -325,7 +334,7 @@ Sunstone.addActions(cluster_actions); Sunstone.addMainTab('clusters_tab',clusters_tab); //Sunstone.addInfoPanel("host_info_panel",host_info_panel); - +//return lists of selected elements in cluster list function clusterElements(){ return getSelectedNodes(dataTable_clusters); } @@ -341,25 +350,8 @@ function clusterElementArray(element_json){ ]; } -/* -//Listen to clicks on the tds of the tables and shows the info dialogs. -function hostInfoListener(){ - $('#tbodyhosts tr',dataTable_hosts).live("click",function(e){ - //do nothing if we are clicking a checkbox! - if ($(e.target).is('input')) {return true;} - var aData = dataTable_hosts.fnGetData(this); - var id = $(aData[0]).val(); - if (!id) return true; - - popDialogLoading(); - Sunstone.runAction("Host.showinfo",id); - return false; - }); -} -*/ - -//updates the host select by refreshing the options in it +//updates the cluster select by refreshing the options in it function updateClusterSelect(){ clusters_select = ''; clusters_select += makeSelectOptions(dataTable_clusters, @@ -371,7 +363,7 @@ function updateClusterSelect(){ ); } -//callback for an action affecting a host element +//callback for an action affecting a cluster element function updateClusterElement(request, element_json){ var id = element_json.CLUSTER.ID; var element = clusterElementArray(element_json); @@ -379,14 +371,14 @@ function updateClusterElement(request, element_json){ updateClusterSelect(); } -//callback for actions deleting a host element +//callback for actions deleting a cluster element function deleteClusterElement(req){ deleteElement(dataTable_clusters,'#cluster_'+req.request.data); $('div#cluster_tab_'+req.request.data,main_tabs_context).remove(); updateClusterSelect(); } -//call back for actions creating a host element +//call back for actions creating a cluster element function addClusterElement(request,element_json){ var id = element_json.CLUSTER.ID; var element = clusterElementArray(element_json); @@ -394,31 +386,34 @@ function addClusterElement(request,element_json){ updateClusterSelect(); } -//callback to update the list of hosts. +//callback to update the list of clusters. function updateClustersView (request,list){ var list_array = []; $.each(list,function(){ - //Grab table data from the host_list + //Grab table data from the list list_array.push(clusterElementArray(this)); }); + //Remove the menus as we recreate them again. removeClusterMenus(); + newClusterMenu(list); updateView(list_array,dataTable_clusters); updateClusterSelect(); - //dependency with the dashboard plugin + //dependency with the infraestructure dashboard plugin updateInfraDashboard("clusters",list); - newClusterMenu(list); }; - +//generates the HTML for the dashboard of a specific cluster function clusterTabContent(cluster_json) { var cluster = cluster_json.CLUSTER; var hosts_n = 0; var dss_n = 0; var vnets_n = 0; + + // Count resources in cluster if (cluster.DATASTORES.ID && cluster.DATASTORES.ID.constructor == Array){ dss_n = cluster.DATASTORES.ID.length; @@ -496,8 +491,8 @@ function clusterTabContent(cluster_json) { ' + tr("Hosts CPU Usage") + '\ \ \ -
\ -
\ +
'+tr("No monitoring information available")+'
\ +
'+tr("No monitoring information available")+'
\ \ \ \ @@ -506,7 +501,7 @@ function clusterTabContent(cluster_json) { \ \ \ -
\ +
'+tr("No monitoring information available")+'
\ \ \ \ @@ -516,7 +511,7 @@ function clusterTabContent(cluster_json) { \ \ \ -
\ +
'+tr("No monitoring information available")+'
\ \ \ \ @@ -613,7 +608,7 @@ function clusterTabContent(cluster_json) { \ \ \ -
\ +
'+tr("No monitoring information available")+'
\ \ \ \ @@ -623,7 +618,7 @@ function clusterTabContent(cluster_json) { \ \ \ -
\ +
'+tr("No monitoring information available")+'
\ \ \ \ @@ -690,6 +685,7 @@ function clusterTabContent(cluster_json) { return html_code; }; +//Removes the clusters from the submenu function removeClusterMenus(){ var data = dataTable_clusters.fnGetData(); @@ -707,7 +703,8 @@ function removeClusterMenus(){ }; }; - +// Creates new cluster submenus +// insert cluster none manually function newClusterMenu(list){ var cluster_none = { 'CLUSTER' : { @@ -728,11 +725,15 @@ function newClusterMenu(list){ $('div#menu li#li_clusters_tab span').addClass('ui-icon-circle-plus'); }; +// Create new cluster menu function newClusterMenuElement(element){ var cluster = element.CLUSTER; + + //trim long cluster names var menu_name = cluster.NAME.length > 10 ? cluster.NAME.substring(0,9)+'...' : cluster.NAME; + // Menu object var menu_cluster = { title: menu_name + ' (id ' + cluster.ID + ')', content: clusterTabContent(element), @@ -762,6 +763,7 @@ function newClusterMenuElement(element){ parentTab: "cluster_tab_" + cluster.ID }; */ + // Add to sunstone Sunstone.addMainTab('cluster_tab_'+cluster.ID,menu_cluster,true); // Sunstone.addMainTab('cluster_hosts_tab_'+cluster.ID,submenu_hosts,true); @@ -769,6 +771,8 @@ function newClusterMenuElement(element){ // Sunstone.addMainTab('cluster_vnets_tab_'+cluster.ID,submenu_vnets,true); }; +// Basicly, we show the hosts/datastore/vnets tab, but before we set +// a filter on the cluster column, so it only shows the cluster we want. function clusterResourceViewListeners(){ //hack the menu selection $('.show_tab_button').live('click',function(){ @@ -860,6 +864,11 @@ function popUpCreateClusterDialog(){ return false; } + +// Receives the list of hosts, divides them into clusters. +// For each cluster, it calls the monitoring action for the hosts +// on that cluster. The monitoring is then plotted in the cluster dashboard. +// This is called from hosts plugin. function monitorClusters(list){ var clustered_hosts = { "-" : []} @@ -933,7 +942,7 @@ $(document).ready(function(){ addElement([ spinner, '','',''],dataTable_clusters); - Sunstone.runAction("Cluster.list"); +// Sunstone.runAction("Cluster.list"); setupCreateClusterDialog(); diff --git a/src/sunstone/public/js/plugins/config-tab.js b/src/sunstone/public/js/plugins/config-tab.js index 7907a523c6..32b14d16f8 100644 --- a/src/sunstone/public/js/plugins/config-tab.js +++ b/src/sunstone/public/js/plugins/config-tab.js @@ -79,7 +79,7 @@ var config_tab = { Sunstone.addActions(config_actions); Sunstone.addMainTab('config_tab',config_tab); - +// Callback when configuration list is received function updateConfig(request,response){ var config = response['user_config']; @@ -89,6 +89,13 @@ function updateConfig(request,response){ }; }; +// Update secure websockets configuration +// First we perform a User.show(). In the callback we update the user template +// to include this parameter. +// Then we post to the server configuration so that it is saved for the session +// Note: the session is originally initialized to the user VNC_WSS if present +// otherwise it is set according to sunstone configuration +// TO DO improve this, server side should take care function updateWss(){ var user_info_req = { data : { @@ -125,7 +132,7 @@ $(document).ready(function(){ if (lang) $('table#config_table #lang_sel option[value="'+lang+'"]').attr('selected','selected'); - //Listener to change language + //Listener to change language. setLang in locale.js $('table#config_table #lang_sel').change(function(){ setLang($(this).val()); }); diff --git a/src/sunstone/public/js/plugins/dashboard-tab.js b/src/sunstone/public/js/plugins/dashboard-tab.js index a9f0a1f65b..0c83095251 100644 --- a/src/sunstone/public/js/plugins/dashboard-tab.js +++ b/src/sunstone/public/js/plugins/dashboard-tab.js @@ -188,6 +188,8 @@ Sunstone.addMainTab('dashboard_tab',dashboard_tab); var $dashboard; +// All monitoring calls and config are called from the Sunstone plugins. + $(document).ready(function(){ $dashboard = $('#dashboard_tab', main_tabs_context); }); \ No newline at end of file diff --git a/src/sunstone/public/js/plugins/dashboard-users-tab.js b/src/sunstone/public/js/plugins/dashboard-users-tab.js index 1a51f7047a..d3ad15a86f 100644 --- a/src/sunstone/public/js/plugins/dashboard-users-tab.js +++ b/src/sunstone/public/js/plugins/dashboard-users-tab.js @@ -128,6 +128,8 @@ Sunstone.addMainTab('dashboard_tab',dashboard_tab); var $dashboard; +// Monitoring calls and config in Sunstone plugins + $(document).ready(function(){ $dashboard = $('#dashboard_tab', main_tabs_context); }); \ No newline at end of file diff --git a/src/sunstone/public/js/plugins/datastores-tab.js b/src/sunstone/public/js/plugins/datastores-tab.js index 364e2aeb30..554c6c1ab2 100644 --- a/src/sunstone/public/js/plugins/datastores-tab.js +++ b/src/sunstone/public/js/plugins/datastores-tab.js @@ -508,8 +508,7 @@ function updateDatastoreInfo(request,ds){ Sunstone.popUpInfoPanel("datastore_info_panel"); } -// Sets up the create-template dialog and all the processing associated to it, -// which is a lot. +// Set up the create datastore dialog function setupCreateDatastoreDialog(){ dialogs_context.append('
'); @@ -624,6 +623,9 @@ function setupDatastoreTemplateUpdateDialog(){ }); }; +// Standard template edition dialog +// If one element is selected auto fecth template +// otherwise let user select function popUpDatastoreTemplateUpdateDialog(){ var select = makeSelectOptions(dataTable_datastores, 1,//id_col @@ -711,6 +713,8 @@ $(document).ready(function(){ tableCheckboxesListener(dataTable_datastores); infoListener(dataTable_datastores,'Datastore.showinfo'); + // Reset filter in case the view was filtered because it was accessed + // from a single cluster. $('div#menu li#li_datastores_tab').live('click',function(){ dataTable_datastores.fnFilter('',5); }); diff --git a/src/sunstone/public/js/plugins/groups-tab.js b/src/sunstone/public/js/plugins/groups-tab.js index 4968358b6d..ea4319232d 100644 --- a/src/sunstone/public/js/plugins/groups-tab.js +++ b/src/sunstone/public/js/plugins/groups-tab.js @@ -388,6 +388,7 @@ function popUpCreateGroupDialog(){ return false; } +// Add groups quotas dialog and calls common setup() in sunstone utils. function setupGroupQuotasDialog(){ dialogs_context.append('
'); $group_quotas_dialog = $('#group_quotas_dialog',dialogs_context); diff --git a/src/sunstone/public/js/plugins/hosts-tab.js b/src/sunstone/public/js/plugins/hosts-tab.js index 0fdcc0fe44..f6ff4b2625 100644 --- a/src/sunstone/public/js/plugins/hosts-tab.js +++ b/src/sunstone/public/js/plugins/hosts-tab.js @@ -17,6 +17,7 @@ /*Host tab plugin*/ /* HOST_HISTORY_LENGTH is ignored by server */ var HOST_HISTORY_LENGTH = 40; +// Configuration object for historical graphs of individual hosts var host_graphs = [ { title : tr("CPU Monitoring information"), @@ -363,29 +364,34 @@ var hosts_tab = { showOnTopMenu: false, }; + +// Configuration object for plots related to hosts in the dashboard SunstoneMonitoringConfig['HOST'] = { plot: function(monitoring){ + // Write the total hosts and discard this value $('#totalHosts', $dashboard).text(monitoring['totalHosts']) delete monitoring['totalHosts'] //if (!$dashboard.is(':visible')) return; + //Plot each of the monitored series for (plotID in monitoring){ var container = $('div#'+plotID,$dashboard); if (!container.length) continue; SunstoneMonitoring.plot("HOST", plotID, container, - monitoring[plotID]); + monitoring[plotID]); //serie }; }, monitor : { + // Config to extract data to make state pie "statePie" : { - partitionPath: "STATE", + partitionPath: "STATE", //we partition hosts acc. to STATE operation: SunstoneMonitoring.ops.partition, - dataType: "pie", + dataType: "pie", //we want to paint a pie colorize: function(state){ - switch (state) { + switch (state) { //This is how we color each pie sector case '0': return "rgb(239,201,86)" //yellow case '1': return "rgb(175,216,248)" //blue case '2': return "rgb(108,183,108)" //green @@ -394,7 +400,7 @@ SunstoneMonitoringConfig['HOST'] = { case '5': return "rgb(160,160,160)" //light gray } }, - plotOptions : { + plotOptions : { //jquery.flot plotting options series: { pie: { show: true } }, legend : { labelFormatter: function(label, series){ @@ -405,13 +411,16 @@ SunstoneMonitoringConfig['HOST'] = { } } }, - "cpuPerCluster" : { - path: ["HOST_SHARE","CPU_USAGE"], - partitionPath: "CLUSTER_ID", + "cpuPerCluster" : { //cpu used in each cluster + path: ["HOST_SHARE","CPU_USAGE"], //totalize cpu + partitionPath: "CLUSTER_ID", //in each cluster operation: SunstoneMonitoring.ops.partition, - dataType: "bars", + dataType: "bars", //we want to paint vertical bars plotOptions: { series: { bars: {show: true, barWidth: 0.5, align: 'center' }}, + //customLabels is a custom option, means a ticks array will + //be added to this configuration with the labels (cluster + //names) when it is ready. xaxis: { show: true, customLabels: true }, yaxis: { min: 0 }, legend : { @@ -424,7 +433,7 @@ SunstoneMonitoringConfig['HOST'] = { } } }, - "memoryPerCluster" : { + "memoryPerCluster" : { //memory used in each cluster. same as above. path: ["HOST_SHARE","MEM_USAGE"], partitionPath: "CLUSTER_ID", operation: SunstoneMonitoring.ops.partition, @@ -448,7 +457,7 @@ SunstoneMonitoringConfig['HOST'] = { } } }, - "globalCpuUsage" : { + "globalCpuUsage" : { //pie according to cpu usage. partitionPath: ["HOST_SHARE", "USED_CPU"], dataType: "pie", operation: SunstoneMonitoring.ops.hostCpuUsagePartition, @@ -456,10 +465,11 @@ SunstoneMonitoringConfig['HOST'] = { series: { pie: { show: true } }, } }, - "totalHosts" : { + "totalHosts" : { //count number of hosts operation: SunstoneMonitoring.ops.totalize }, - "cpuUsageBar" : { + "cpuUsageBar" : { //horizontal bar with cpu usage + // we want the following values to be totalized in the same bar paths: [ ["HOST_SHARE","MAX_CPU"], ["HOST_SHARE","USED_CPU"], @@ -482,7 +492,7 @@ SunstoneMonitoringConfig['HOST'] = { } } }, - "memoryUsageBar" : { + "memoryUsageBar" : { //same as above paths: [ ["HOST_SHARE","MAX_MEM"], ["HOST_SHARE","USED_MEM"], @@ -518,7 +528,7 @@ Sunstone.addActions(host_actions); Sunstone.addMainTab('hosts_tab',hosts_tab); Sunstone.addInfoPanel("host_info_panel",host_info_panel); - +// return selected elements from hosts datatable function hostElements(){ return getSelectedNodes(dataTable_hosts); } @@ -624,7 +634,11 @@ function updateHostsView (request,host_list){ }); SunstoneMonitoring.monitor('HOST', host_list) - if (typeof(monitorClusters) != 'undefined') monitorClusters(host_list) + + //if clusters_sel is there, it means the clusters have arrived. + //Otherwise do not attempt to monitor them. + if (typeof(monitorClusters) != 'undefined' && clusters_sel()) + monitorClusters(host_list) updateView(host_list_array,dataTable_hosts); updateHostSelect(); //dependency with the dashboard plugin @@ -755,6 +769,8 @@ function setupCreateHostDialog(){ $('button',dialog).button(); + + // Show custom driver input only when custom is selected in selects $('input[name="custom_vmm_mad"],'+ 'input[name="custom_im_mad"],'+ 'input[name="custom_vnm_mad"]',dialog).parent().hide(); @@ -834,6 +850,7 @@ function setHostAutorefresh() { },INTERVAL+someTime()); } +// Call back when individual host history monitoring fails function hostMonitorError(req,error_json){ var message = error_json.error.message; var info = req.request.data[0].monitor; @@ -853,7 +870,7 @@ $(document).ready(function(){ "bJQueryUI": true, "bSortClasses": false, "sDom" : '<"H"lfrC>t<"F"ip>', - "oColVis": { + "oColVis": { //exclude checkbox column "aiExclude": [ 0 ] }, "bAutoWidth":false, @@ -887,9 +904,14 @@ $(document).ready(function(){ tableCheckboxesListener(dataTable_hosts); infoListener(dataTable_hosts, "Host.showinfo"); + // This listener removes any filter on hosts table when its menu item is + // selected. The cluster plugins will filter hosts when the hosts + // in a cluster are shown. So we have to make sure no filter has been + // left in place when we want to see all hosts. $('div#menu li#li_hosts_tab').live('click',function(){ dataTable_hosts.fnFilter('',3); }); + // Hide help $('div#hosts_tab div.legend_div',main_tabs_context).hide(); }); diff --git a/src/sunstone/public/js/plugins/images-tab.js b/src/sunstone/public/js/plugins/images-tab.js index 1fea3e7433..f81cbdb151 100644 --- a/src/sunstone/public/js/plugins/images-tab.js +++ b/src/sunstone/public/js/plugins/images-tab.js @@ -557,6 +557,7 @@ function imageElementArray(image_json){ var value = OpenNebula.Helper.image_type(image.TYPE); $('option[value="'+value+'"]',type).replaceWith(''); + //add also persistent/non-persistent selects, type select. return [ '', image.ID, @@ -813,6 +814,7 @@ function setupCreateImageDialog(){ var img_obj; + // Upload is handled by FileUploader vendor plugin var uploader = new qq.FileUploaderBasic({ button: $('#file-uploader',$create_image_dialog)[0], action: 'upload', @@ -823,10 +825,14 @@ function setupCreateImageDialog(){ //notifyMessage(message); }, onSubmit: function(id, fileName){ + //set url params + //since the body is the upload, we need the pass + //the image info here uploader.setParams({ img : JSON.stringify(img_obj), file: fileName }); + //we pop up an upload progress dialog var pos_top = $(window).height() - 120; var pos_left = 190; var pb_dialog = $('
1){ for (var i=0; i< sel_elems.length; i++) + //If we are cloning several images we + //use the name as prefix Sunstone.runAction('Image.clone', sel_elems[i], name+getImageName(sel_elems[i])); diff --git a/src/sunstone/public/js/plugins/marketplace-tab.js b/src/sunstone/public/js/plugins/marketplace-tab.js index 30ff3b6aff..5223e9837b 100644 --- a/src/sunstone/public/js/plugins/marketplace-tab.js +++ b/src/sunstone/public/js/plugins/marketplace-tab.js @@ -245,6 +245,7 @@ $(document).ready(function(){ "aoColumns": [ { "bSortable": false, "fnRender": function ( o, val ) { + //we render 1st column as a checkbox directly return '
'); @@ -2160,6 +2158,7 @@ function setupTemplateCloneDialog(){ notifyError('A name or prefix is needed!'); if (sel_elems.length > 1){ for (var i=0; i< sel_elems.length; i++) + //use name as prefix if several items selected Sunstone.runAction('Template.clone', sel_elems[i], name+getTemplateName(sel_elems[i])); diff --git a/src/sunstone/public/js/plugins/users-tab.js b/src/sunstone/public/js/plugins/users-tab.js index 93e634e809..0fe79025c2 100644 --- a/src/sunstone/public/js/plugins/users-tab.js +++ b/src/sunstone/public/js/plugins/users-tab.js @@ -325,6 +325,9 @@ var user_actions = { type: "single", call: OpenNebula.User.show, callback: function (request,response) { + // when we receive quotas we parse them and create an + // quota objects with html code (
  • ) that can be inserted + // in the dialog var parsed = parseQuotas(response.USER); $('ul#quotas_ul_vm',$user_quotas_dialog).html(parsed.VM) $('ul#quotas_ul_datastore',$user_quotas_dialog).html(parsed.DATASTORE) @@ -391,6 +394,7 @@ var user_buttons = { "User.chauth" : { type: "confirm_with_select", text: tr("Change authentication"), + //We insert our custom select there. select: function() { return '\ \ @@ -447,10 +451,12 @@ var users_tab = { SunstoneMonitoringConfig['USER'] = { plot: function(monitoring){ + //plot the number of total users $('#totalUsers', $dashboard).text(monitoring['totalUsers']) //if (!$dashboard.is(':visible')) return; + //plot users per group var container = $('div#usersPerGroup',$dashboard); SunstoneMonitoring.plot('USER', 'usersPerGroup', @@ -459,6 +465,7 @@ SunstoneMonitoringConfig['USER'] = { }, monitor: { "usersPerGroup" : { + //we want to monitor users divided by GNAME to paint bars. partitionPath: "GNAME", operation: SunstoneMonitoring.ops.partition, dataType: "bars", @@ -636,6 +643,7 @@ function setupCreateUserDialog(){ $('input[name="custom_auth"]',dialog).parent().hide(); }); + $('#create_user_form',dialog).submit(function(){ var user_name=$('#username',this).val(); var user_password=$('#pass',this).val(); @@ -689,6 +697,8 @@ function setupUpdatePasswordDialog(){ }); }; + +//add a setup quota dialog and call the sunstone-util.js initialization function setupUserQuotasDialog(){ dialogs_context.append('
    '); $user_quotas_dialog = $('#user_quotas_dialog',dialogs_context); diff --git a/src/sunstone/public/js/plugins/vnets-tab.js b/src/sunstone/public/js/plugins/vnets-tab.js index 5854d780bf..bc61c3236d 100644 --- a/src/sunstone/public/js/plugins/vnets-tab.js +++ b/src/sunstone/public/js/plugins/vnets-tab.js @@ -488,7 +488,7 @@ Sunstone.addActions(vnet_actions); Sunstone.addMainTab('vnets_tab',vnets_tab); Sunstone.addInfoPanel('vnet_info_panel',vnet_info_panel); - +// return list of selected elements in list function vnElements(){ return getSelectedNodes(dataTable_vNetworks); } @@ -634,6 +634,9 @@ function updateVNetworkInfo(request,vn){ } +// Prints the lis of leases depending on the Vnet TYPE +// It adds the "add lease", "hold lease" fields, and each lease comes with +// hold, release buttons etc. Listeners in setupLeasesOps() function printLeases(vn_info){ var html ='
    \ \ @@ -881,6 +884,8 @@ function setupCreateVNetDialog() { var vlan = $('#vlan',this).val(); var vlan_id = $('#vlan_id',this).val(); + //Depending on network mode we include certain params in the + //template switch (network_mode) { case "default": if (!bridge && !phydev){ @@ -1066,6 +1071,9 @@ function setupVNetTemplateUpdateDialog(){ }); }; + +// When 1 elem in the list is selected then fetch template automaticly +// Otherwise include selected elements in the select and let user choose function popUpVNetTemplateUpdateDialog(){ var select = makeSelectOptions(dataTable_vNetworks, 1,//id_col @@ -1103,6 +1111,8 @@ function popUpVNetTemplateUpdateDialog(){ } +// Listeners to the add, hold, release, delete leases operations in the +// extended information panel. function setupLeasesOps(){ $('button#panel_add_lease_button').live("click",function(){ var lease = $(this).prev().val(); @@ -1115,6 +1125,7 @@ function setupLeasesOps(){ return false; }); + //ranged networks hold lease $('button#panel_hold_lease_button').live("click",function(){ var lease = $(this).prev().val(); //var mac = $(this).previous().val(); @@ -1136,6 +1147,7 @@ function setupLeasesOps(){ return false; }); + //fixed networks hold lease $('a.hold_lease').live("click",function(){ var lease = $(this).parents('tr').attr('ip'); var id = $(this).parents('form').attr('vnid'); @@ -1209,6 +1221,8 @@ $(document).ready(function(){ tableCheckboxesListener(dataTable_vNetworks); infoListener(dataTable_vNetworks,'Network.showinfo'); + // Reset list filter in case it was set because we were lookin + // at a single cluster view $('div#menu li#li_vnets_tab').live('click',function(){ dataTable_vNetworks.fnFilter('',5); }); diff --git a/src/sunstone/public/js/sunstone-util.js b/src/sunstone/public/js/sunstone-util.js index f00c9e06c8..bb808fab4e 100644 --- a/src/sunstone/public/js/sunstone-util.js +++ b/src/sunstone/public/js/sunstone-util.js @@ -18,7 +18,7 @@ /* Some useful functions for Sunstone default plugins */ var INTERVAL=60000; //milisecs -function someTime(){ +function someTime(){ //some time under 30secs return Math.floor(Math.random()*30000); } @@ -46,6 +46,7 @@ function pretty_time(time_seconds) return hour + ":" + mins +":" + secs + " " + month + "/" + day + "/" + year; } +// Format time for plot axis function pretty_time_axis(time){ var d = new Date(); d.setTime(time*1000); @@ -412,6 +413,10 @@ function waitingNodes(dataTable){ $('tr input.check_item:visible',dataTable).replaceWith(spinner); } + +//The following functions extract the value of a specific column +//in a dataTable. If the order of datatable columns is changed this +//should be the only place to adjust. function getUserName(uid){ if (typeof(dataTable_users) != "undefined"){ return getName(uid,dataTable_users,2); @@ -468,6 +473,8 @@ function getTemplateName(id){ return id; }; +// Returns the value of the column with the resource of specified +// id in the dataTable. function getName(id,dataTable,name_col){ var name = id; if (typeof(dataTable) == "undefined") { @@ -484,8 +491,9 @@ function getName(id,dataTable,name_col){ return name; }; -//Search a datatable record matching the filter_str in the filter_col. Returns -//the value of that record in the desired value column. +// A more general version of the above. +// Search a datatable record matching the filter_str in the filter_col. Returns +// the value of that record in the desired value column. function getValue(filter_str,filter_col,value_col,dataTable){ var value=""; if (typeof(dataTable) == "undefined") return value; @@ -806,6 +814,8 @@ function infoListener(dataTable, info_action){ var count = $('tbody .check_item:checked', dataTable).length; + //If ctrl is hold down or there is already some item selected + //then just select. if (info_action){ if (e.ctrlKey || count >= 1) $('.check_item',this).trigger('click'); @@ -845,7 +855,7 @@ function datastores_sel() { return datastores_select; } - +/* Below functions to easier permission management */ function ownerUse(resource){ return parseInt(resource.PERMISSIONS.OWNER_U); @@ -923,6 +933,7 @@ function setPermissionsTable(resource,context){ $('.other_a',context).attr('checked','checked'); }; +//Returns an octet given a permission table with checkboxes function buildOctet(permTable){ var owner=0; var group=0; @@ -952,6 +963,9 @@ function buildOctet(permTable){ return ""+owner+group+other; }; + +// Sets up a dialog to edit and update user and group quotas +// Called from user/group plugins function setupQuotasDialog(dialog){ var height = Math.floor($(window).height()*0.8); //set height to a percentage of the window @@ -1035,6 +1049,8 @@ function popUpQuotasDialog(dialog, resource, sel_elems){ dialog.dialog('open'); } + +//Action to be performed when an edit quota icon is clicked. function setupQuotaIcons(){ $('.quota_edit_icon').live('click',function(){ var dialog = $(this).parents('form'); @@ -1066,6 +1082,7 @@ function setupQuotaIcons(){ }); } +// Returns an object with quota information in form of list items function parseQuotas(elem){ var quotas = []; var results = {