1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-21 14:50:08 +03:00

Bug #1314: Small sunstone fixes

* Remove hosts view for non-admin users.
 * Update users main dashboard with user quota information.
 * Enable users and group plugin for normal users, disabling the administrator operations.
 * Fix non-working quota edit buttons in Chrome/Safari. Minor dialog improvements.
 * Add group extended information tab when clicking on a group.
 * Small fixes regarding disk hotplugging and added labels.
 * Fix net units in VM monitoring
 * Fix UNAME not being set correctly when adding images or vnets to templates
 * Format marketplace images size and add url link to website.
 * Small corrections here and there..
(cherry picked from commit 2b3019a2e9aa7cfd033c20c67f85bf196c2127c9)
This commit is contained in:
Hector Sanjuan 2012-07-03 18:46:10 +02:00 committed by Ruben S. Montero
parent ec8d459589
commit c1a1cc5813
14 changed files with 345 additions and 123 deletions

View File

@ -19,15 +19,13 @@
:group:
oneadmin: true
- plugins/users-tab.js:
:ALL: false
:ALL: true
:user:
:group:
oneadmin: true
- plugins/groups-tab.js:
:ALL: false
:ALL: true
:user:
:group:
oneadmin: true
- plugins/acls-tab.js:
:ALL: false
:user:
@ -59,9 +57,10 @@
:group:
oneadmin: true
- plugins/hosts-tab.js:
:ALL: true
:ALL: false
:user:
:group:
oneadmin: true
- plugins/datastores-tab.js:
:ALL: true
:user:

View File

@ -684,4 +684,12 @@ ul.action_list li a:hover{
div.current_quotas ul{
list-style: none;
}
.padding1 {
padding-left: 30px!important;
}
.padding2 {
padding-left: 55px!important;
}

View File

@ -128,7 +128,7 @@ $(document).ready(function () {
applyDefaultStyles: false
, center__paneSelector: ".outer-center"
, west__paneSelector: ".outer-west"
, west__size: 181
, west__size: 200
, north__size: 26
, south__size: 26
, spacing_open: 0 // ALL panes

View File

@ -61,7 +61,10 @@ var cluster_actions = {
"Cluster.create" : {
type: "create",
call : OpenNebula.Cluster.create,
callback : addClusterElement,
callback : function(){
//addClusterElement,
Sunstone.runAction('Cluster.list');
},
error : onError,
notify: true
},
@ -911,7 +914,7 @@ function setupCreateClusterDialog(){
}
};
//Create the OpenNebula.Host.
//Create the OpenNebula.Cluster.
//If it is successfull we refresh the list.
Sunstone.runAction("Cluster.create",cluster_json);
$create_cluster_dialog.dialog('close');

View File

@ -14,6 +14,7 @@
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
var config_response;
var config_tab_content =
'<form>\
<table id="config_table" style="width:100%">\
@ -81,10 +82,10 @@ Sunstone.addMainTab('config_tab',config_tab);
// Callback when configuration list is received
function updateConfig(request,response){
var config = response['user_config'];
config_response = response
//Set wss checkbox to correct value
if (config["wss"] == "yes"){
if (config_response['user_config']["wss"] == "yes"){
$('table#config_table input#wss_checkbox').attr('checked','checked');
};
};

View File

@ -190,6 +190,8 @@ var $dashboard;
// All monitoring calls and config are called from the Sunstone plugins.
function dashboardQuotasHTML(){}
$(document).ready(function(){
$dashboard = $('#dashboard_tab', main_tabs_context);
});

View File

@ -22,46 +22,10 @@ var dashboard_tab_content =
<tr>\
<td>\
<div class="panel">\
<h3>' + tr("Hosts") + '<i class="icon-refresh action_button" value="Host.refresh" style="float:right;cursor:pointer"></i></h3>\
<h3>' + tr("User information") + '</h3>\
<div class="panel_info">\
<table class="info_table">\
<table id="dashboard_user_info" class="info_table">\
\
<tr>\
<td class="key_td">' + tr("Total Hosts") + '</td>\
<td class="key_td">' + tr("State") + '</td>\
</tr>\
<tr>\
<td colspan="2"><div id="totalHosts" class="big_text" style="float:left;width:50%;padding-top:12px;"></div>\
<div id="statePie" style="float:right;width:50%;height:100px;"></div></td>\
</tr>\
\
<tr>\
<td class="key_td">' + tr("Global CPU Usage") + '</td>\
<td></td>\
</tr>\
<tr>\
<td colspan="2"><div id="globalCpuUsage" style="width:100%;height:100px;"></div></td>\
</tr>\
\
<tr>\
<td class="key_td">' + tr("Used vs. Max CPU") + '</td>\
<td><div id="cpuUsageBar_legend"></div></td>\
</tr>\
<tr>\
<td colspan="2">\
<div id="cpuUsageBar" style="width:95%;height:50px"></div>\
</td>\
</tr>\
\
<tr>\
<td class="key_td">' + tr("Used vs. Max Memory") + '</td>\
<td><div id="memoryUsageBar_legend"></div></td>\
</tr>\
<tr>\
<td colspan="2">\
<div id="memoryUsageBar" style="width:95%;height:50px"></div>\
</td>\
</tr>\
\
</table>\
\
@ -128,8 +92,98 @@ Sunstone.addMainTab('dashboard_tab',dashboard_tab);
var $dashboard;
// Monitoring calls and config in Sunstone plugins
function dashboardQuotaRow(quota_json){
var row = '';
switch (quota_json.TYPE){
case "VM":
row += '<tr><td class="padding1">'+tr("VMS")+'</td>';
row += '<td class="value_td">'+quota_json.VMS_USED+' / '+quota_json.VMS+'</td></tr>';
row += '<tr><td class="padding1">'+tr("Memory")+'</td>';
row += '<td class="value_td">'+quota_json.MEMORY_USED+' / '+quota_json.MEMORY+'</td></tr>';
row += '<tr><td class="padding1">'+tr("CPU")+'</td>';
row += '<td class="value_td">'+quota_json.CPU_USED+' / '+quota_json.CPU+'</td></tr>';
break;
case "DATASTORE":
row += '<tr><td class="padding1">'+tr("Datastore")+' id '+quota_json.ID+':</td><td></td></tr>';
row += '<tr><td class="padding2">'+tr("Size")+'</td>';
row += '<td class="value_td">'+quota_json.SIZE_USED+' / '+quota_json.SIZE+'</td>';
row += '<tr><td class="padding2">'+tr("Images")+'</td>';
row += '<td class="value_td">'+quota_json.IMAGES_USED+' / '+quota_json.IMAGES+'</td>';
break;
case "IMAGE":
row += '<tr><td class="padding1">'+tr("Image")+' id '+quota_json.ID+':</td><td></td></tr>';
row += '<tr><td class="padding2">'+tr("RVMs")+'</td>';
row += '<td class="value_td">'+quota_json.RVMS_USED+' / '+quota_json.RVMS+'</td>';
break;
case "NETWORK":
row += '<tr><td class="padding1">'+tr("Network")+' id '+quota_json.ID+':</td><td></td></tr>';
row += '<tr><td class="padding2">'+tr("Leases")+'</td>';
row += '<td class="value_td">'+quota_json.RVMS_USED+' / '+quota_json.RVMS+'</td>';
break;
}
return row
}
function dashboardQuotasHTML(user){
var html = '<tr>\
<td class="key_td">' + tr("Resource quotas") + '</td>\
<td class="value_td">' + tr("Used&nbsp;/&nbsp;Allowed") + '</td>\
</tr>\
<tr>\
<td class="key_td"></td><td class="value_td"></td>\
</tr>';
var results = parseQuotas(user, dashboardQuotaRow);
html += '<tr><td class="key_td">'+tr("VM quota")+':</td>\
<td class="value_td">'+
(results.VM.length ? "" : tr("None"))+'</td></tr>'
html += results.VM;
html += '<tr>\
<td class="key_td"></td><td class="value_td"></td>\
</tr>';
html += '<tr><td class="key_td">'+tr("Datastore quotas")+':</td>\
<td class="value_td">'+
(results.DATASTORE.length ? "" : tr("None"))+'</td></tr>'
html += results.DATASTORE;
html += '<tr>\
<td class="key_td"></td><td class="value_td"></td>\
</tr>';
html += '<tr><td class="key_td">'+tr("Image quotas")+':</td>\
<td class="value_td">'+
(results.IMAGE.length ? "" : tr("None"))+'</td></tr>'
html += results.IMAGE;
html += '<tr>\
<td class="key_td"></td><td class="value_td"></td>\
</tr>';
html += '<tr><td class="key_td">'+tr("Network quotas")+':</td>\
<td class="value_td">'+
(results.NETWORK.length ? "" : tr("None"))+'</td></tr>'
html += results.NETWORK;
html += '<tr>\
<td class="key_td"></td><td class="value_td"></td>\
</tr>';
$('#dashboard_user_info', $dashboard).html(html);
}
$(document).ready(function(){
$dashboard = $('#dashboard_tab', main_tabs_context);
$dashboard = $('#dashboard_tab', main_tabs_context);
});

View File

@ -32,8 +32,8 @@ var groups_tab_content = '\
<th>'+tr("Name")+'</th>\
<th>'+tr("Users")+'</th>\
<th>'+tr("VMs")+'</th>\
<th>'+tr("Memory used")+'</th>\
<th>'+tr("CPU used")+'</th>\
<th>'+tr("Used memory")+'</th>\
<th>'+tr("Used CPU")+'</th>\
</tr>\
</thead>\
<tbody id="tbodygroups">\
@ -142,10 +142,19 @@ var group_actions = {
error: onError,
},
// "Group.showinfo" : {
// type: "custom",
// call: updateGroupInfo
// },
"Group.show" : {
type: "single",
call: OpenNebula.Group.show,
callback: updateGroupElement,
error: onError
},
"Group.showinfo" : {
type: "single",
call: OpenNebula.Group.show,
callback: updateGroupInfo,
error: onError
},
"Group.autorefresh" : {
type: "custom",
@ -185,7 +194,7 @@ var group_actions = {
type: "single",
call: OpenNebula.Group.show,
callback: function (request,response) {
var parsed = parseQuotas(response.GROUP);
var parsed = parseQuotas(response.GROUP,quotaListItem);
$('.current_quotas table tbody',$group_quotas_dialog).append(parsed.VM);
$('.current_quotas table tbody',$group_quotas_dialog).append(parsed.DATASTORE);
$('.current_quotas table tbody',$group_quotas_dialog).append(parsed.IMAGE);
@ -225,7 +234,8 @@ var group_buttons = {
},
"Group.create_dialog" : {
type: "create_dialog",
text: tr("+ New Group")
text: tr("+ New Group"),
condition: mustBeAdmin
},
// "Group.chown" : {
// type: "confirm_with_select",
@ -236,11 +246,13 @@ var group_buttons = {
// },
"Group.quotas_dialog" : {
type : "action",
text : tr("Update quotas")
text : tr("Update quotas"),
condition: mustBeAdmin,
},
"Group.delete" : {
type: "confirm",
text: tr("Delete")
text: tr("Delete"),
condition: mustBeAdmin
},
"Group.help" : {
type: "action",
@ -249,17 +261,35 @@ var group_buttons = {
}
};
var group_info_panel = {
"group_info_tab" : {
title: tr("Group information"),
content:""
},
};
var groups_tab = {
title: tr("Groups"),
content: groups_tab_content,
buttons: group_buttons,
tabClass: 'subTab',
parentTab: 'system_tab'
parentTab: 'system_tab',
condition: mustBeAdmin
};
var groups_tab_non_admin = {
title: tr("Group info"),
content: groups_tab_content,
buttons: group_buttons,
tabClass: 'subTab',
parentTab: 'dashboard_tab',
condition: mustNotBeAdmin
}
SunstoneMonitoringConfig['GROUP'] = {
plot: function(monitoring){
if (!mustBeAdmin()) return;
$('#totalGroups', $dashboard).text(monitoring['totalGroups'])
},
monitor: {
@ -271,6 +301,8 @@ SunstoneMonitoringConfig['GROUP'] = {
Sunstone.addActions(group_actions);
Sunstone.addMainTab('groups_tab',groups_tab);
Sunstone.addMainTab('groups_tab_non_admin',groups_tab_non_admin);
Sunstone.addInfoPanel("group_info_panel",group_info_panel);
function groupElements(){
return getSelectedNodes(dataTable_groups);
@ -350,9 +382,63 @@ function updateGroupsView(request, group_list){
updateView(group_list_array,dataTable_groups);
updateGroupSelect(group_list);
SunstoneMonitoring.monitor('GROUP', group_list)
updateSystemDashboard("groups",group_list);
if (mustBeAdmin())
updateSystemDashboard("groups",group_list);
}
function updateGroupInfo(request,group){
var info = group.GROUP;
var info_tab_html = '\
<table id="info_group_table" class="info_table" style="width:80%">\
<thead>\
<tr><th colspan="2">' + tr("Group information") + ' - '+info.NAME+'</th></tr>\
</thead>\
<tbody>\
<tr>\
<td class="key_td">' + tr("ID") + '</td>\
<td class="value_td">'+info.ID+'</td>\
</tr>\
</tbody>\
</table>\
<table class="info_table" style="width:80%;margin-top:0;margin-bottom:0;">\
<thead>\
<tr><th colspan="2">' + tr("Quota information") +'</th></tr>\
</thead>\
<tbody><tr><td class="key_td"></td><td class="value_td"></td></tr></tbody>\
</table>';
if (!$.isEmptyObject(info.VM_QUOTA))
info_tab_html += '<table class="info_table" style="width:70%;margin-top:0;margin-left:40px;">\
<tbody>'+prettyPrintJSON(info.VM_QUOTA)+'</tbody>\
</table>'
if (!$.isEmptyObject(info.DATASTORE_QUOTA))
info_tab_html += '<table class="info_table" style="width:70%;margin-top:0;margin-left:40px;%">\
<tbody>'+prettyPrintJSON(info.DATASTORE_QUOTA)+'</tbody>\
</table>'
if (!$.isEmptyObject(info.IMAGE_QUOTA))
info_tab_html += '<table class="info_table" style="width:70%;margin-top:0;margin-left:40px;">\
<tbody>'+prettyPrintJSON(info.IMAGE_QUOTA)+'</tbody>\
</table>';
if (!$.isEmptyObject(info.NETWORK_QUOTA))
info_tab_html += '<table class="info_table" style="width:70%;margin-top:0;margin-left:40px;">\
<tbody>'+prettyPrintJSON(info.NETWORK_QUOTA)+'</tbody>\
</table>';
var info_tab = {
title : tr("Group information"),
content : info_tab_html
};
Sunstone.updateInfoPanelTab("group_info_panel","group_info_tab",info_tab);
Sunstone.popUpInfoPanel("group_info_panel");
}
//Prepares the dialog to create
function setupCreateGroupDialog(){
dialogs_context.append('<div title=\"'+tr("Create group")+'\" id="create_group_dialog"></div>');
@ -437,7 +523,8 @@ $(document).ready(function(){
initCheckAllBoxes(dataTable_groups);
tableCheckboxesListener(dataTable_groups);
infoListener(dataTable_groups);
infoListener(dataTable_groups, 'Group.showinfo');
$('div#groups_tab div.legend_div').hide();
$('div#groups_tab_non_admin div.legend_div').hide();
})

View File

@ -152,6 +152,10 @@ function updateMarketInfo(request,app){
<td class="key_td">' + tr("ID") + '</td>\
<td class="value_td">'+app['_id']["$oid"]+'</td>\
</tr>\
<tr>\
<td class="key_td">' + tr("URL") + '</td>\
<td class="value_td"><a href="'+config_response.system_config.marketplace_url+'/'+app['_id']["$oid"]+'" target="_blank">'+config_response.system_config.marketplace_url+'/'+app['_id']["$oid"]+'</a></td>\
</tr>\
<tr>\
<td class="key_td">' + tr("Publisher") + '</td>\
<td class="value_td">'+app['publisher']+'</td>\
@ -170,7 +174,7 @@ function updateMarketInfo(request,app){
</tr>\
<tr>\
<td class="key_td">' + tr("Size") + '</td>\
<td class="value_td">'+app['files'][0]['size']+'</td>\
<td class="value_td">'+humanize_size(app['files'][0]['size'],true)+'</td>\
</tr>\
<tr>\
<td class="key_td">' + tr("Hypervisor") + '</td>\

View File

@ -1391,9 +1391,10 @@ function setupCreateTemplateDialog(){
//Auto-set IMAGE_UNAME hidden field value
$('#IMAGE', section_disks).change(function(){
var uname = getValue($(this).val(),4,2,dataTable_images);
var option = $('option:selected',this);
var uname = getValue(option.attr('elem_id'),1,2,dataTable_images);
$('input#IMAGE_UNAME',section_disks).val(uname);
var target = getValue($(this).val(),4,12,dataTable_images);
var target = getValue(option.attr('elem_id'),1,12,dataTable_images);
if (target && target != "--")
$('input#TARGET',section_disks).val(target);
else
@ -1555,7 +1556,8 @@ function setupCreateTemplateDialog(){
//Auto-set IMAGE_UNAME hidden field value
$('#NETWORK', section_networks).change(function(){
var uname = getValue($(this).val(),4,2,dataTable_vNetworks);
var option = $('option:selected',this);
var uname = getValue(option.attr('elem_id'),1,2,dataTable_vNetworks);
$('input#NETWORK_UNAME',section_networks).val(uname);
});

View File

@ -35,8 +35,8 @@ var users_tab_content = '\
<th>'+tr("Group")+'</th>\
<th>'+tr("Authentication driver")+'</th>\
<th>'+tr("VMs")+'</th>\
<th>'+tr("Memory used")+'</th>\
<th>'+tr("CPU used")+'</th>\
<th>'+tr("Used memory")+'</th>\
<th>'+tr("Used CPU")+'</th>\
<th>'+tr("Group ID")+'</th>\
</tr>\
</thead>\
@ -323,7 +323,7 @@ var user_actions = {
// when we receive quotas we parse them and create an
// quota objects with html code (<li>) that can be inserted
// in the dialog
var parsed = parseQuotas(response.USER);
var parsed = parseQuotas(response.USER,quotaListItem);
$('.current_quotas table tbody',$user_quotas_dialog).append(parsed.VM);
$('.current_quotas table tbody',$user_quotas_dialog).append(parsed.DATASTORE);
$('.current_quotas table tbody',$user_quotas_dialog).append(parsed.IMAGE);
@ -365,7 +365,8 @@ var user_buttons = {
},
"User.create_dialog" : {
type: "create_dialog",
text: tr("+ New")
text: tr("+ New"),
condition: mustBeAdmin
},
"User.update_dialog" : {
type: "action",
@ -378,13 +379,15 @@ var user_buttons = {
},
"User.quotas_dialog" : {
type : "action",
text : tr("Update quotas")
text : tr("Update quotas"),
condition: mustBeAdmin
},
"User.chgrp" : {
type: "confirm_with_select",
text: tr("Change group"),
select: groups_sel,
tip: tr("This will change the main group of the selected users. Select the new group")+":"
tip: tr("This will change the main group of the selected users. Select the new group")+":",
condition: mustBeAdmin
},
"User.chauth" : {
type: "confirm_with_select",
@ -396,7 +399,8 @@ var user_buttons = {
<option value="x509">'+tr("x509")+'</option>\
<option value="public">'+tr("Public")+'</option>'
},
tip: tr("Please choose the new type of authentication for the selected users")+":"
tip: tr("Please choose the new type of authentication for the selected users")+":",
condition: mustBeAdmin
},
// "User.addgroup" : {
// type: "confirm_with_select",
@ -414,7 +418,8 @@ var user_buttons = {
// },
"User.delete" : {
type: "confirm",
text: tr("Delete")
text: tr("Delete"),
condition: mustBeAdmin
},
"User.help" : {
type: "action",
@ -440,12 +445,25 @@ var users_tab = {
content: users_tab_content,
buttons: user_buttons,
tabClass: 'subTab',
parentTab: 'system_tab'
parentTab: 'system_tab',
condition: mustBeAdmin,
};
var users_tab_non_admin = {
title: tr("User info"),
content: users_tab_content,
buttons: user_buttons,
tabClass: 'subTab',
parentTab: 'dashboard_tab',
condition: mustNotBeAdmin,
}
SunstoneMonitoringConfig['USER'] = {
plot: function(monitoring){
//plot only when i am admin
if (!mustBeAdmin()) return;
//plot the number of total users
$('#totalUsers', $dashboard).text(monitoring['totalUsers'])
@ -484,6 +502,7 @@ SunstoneMonitoringConfig['USER'] = {
Sunstone.addActions(user_actions);
Sunstone.addMainTab('users_tab',users_tab);
Sunstone.addMainTab('users_tab_non_admin',users_tab_non_admin);
Sunstone.addInfoPanel("user_info_panel",user_info_panel);
function userElements(){
@ -553,11 +572,14 @@ function updateUsersView(request,users_list){
var user_list_array = [];
$.each(users_list,function(){
if (this.USER.ID == uid)
dashboardQuotasHTML(this.USER);
user_list_array.push(userElementArray(this));
});
updateView(user_list_array,dataTable_users);
SunstoneMonitoring.monitor('USER', users_list)
updateSystemDashboard("users",users_list);
if (mustBeAdmin())
updateSystemDashboard("users",users_list);
updateUserSelect();
};
@ -573,7 +595,7 @@ function updateUserInfo(request,user){
</thead>\
<tbody>\
<tr>\
<td class="key_td">' + tr("id") + '</td>\
<td class="key_td">' + tr("ID") + '</td>\
<td class="value_td">'+user_info.ID+'</td>\
</tr>\
<tr>\
@ -786,4 +808,5 @@ $(document).ready(function(){
infoListener(dataTable_users,'User.showinfo');
$('div#users_tab div.legend_div').hide();
$('div#users_tab_non_admin div.legend_div').hide();
});

View File

@ -38,11 +38,13 @@ var vm_graphs = [
{ title : tr("Network transmission"),
monitor_resources : "NET_TX",
humanize_figures : true,
convert_from_bytes : true,
history_length : VM_HISTORY_LENGTH
},
{ title : tr("Network reception"),
monitor_resources : "NET_RX",
humanize_figures : true,
convert_from_bytes : true,
history_length : VM_HISTORY_LENGTH
}
];
@ -668,10 +670,10 @@ SunstoneMonitoringConfig['VM'] = {
var t = ((new Date().getTime()) - netUsage.time) / 1000 //in secs
var bandwidth_up = monitoring['netUsageBar'][1].data[0][0] - netUsage.up
bandwidth_up /= t
var bandwidth_up_str = humanize_size(bandwidth_up) + "b/s" //bytes /sec
var bandwidth_up_str = humanize_size(bandwidth_up,true) + "B/s" //bytes /sec
var bandwidth_down = monitoring['netUsageBar'][0].data[0][0] - netUsage.down
bandwidth_down /= t
var bandwidth_down_str = humanize_size(bandwidth_down) + "b/s" //bytes /sec
var bandwidth_down_str = humanize_size(bandwidth_down,true) + "B/s" //bytes /sec
if (bandwidth_up >= 0)
$('#bandwidth_up', $dashboard).text(bandwidth_up_str)
@ -742,14 +744,14 @@ SunstoneMonitoringConfig['VM'] = {
xaxis: {
min: 0,
tickFormatter : function(val,axis) {
return humanize_size(val);
return humanize_size(val,true);
},
},
legend: {
noColumns: 3,
container: '#netUsageBar_legend',
labelFormatter: function(label, series){
return label + " - " + humanize_size(series.data[0][0])
return label + " - " + humanize_size(series.data[0][0],true)
}
}
}
@ -1114,27 +1116,28 @@ function printDisks(vm_info){
html += '<tr id="no_disks_tr"><td class="key_td">\
'+tr("No disks to show")+'\
</td><td class="value_td"></td></tr>';
html += '</tbody></table></form>';
return html;
}
else {
for (var i = 0; i < disks.length; i++){
var disk = disks[i];
html += '<tr disk_id="'+(disk.DISK_ID)+'"><td class="key_td">';
html += disk.DISK_ID + ' - ' +
(disk.IMAGE ? disk.IMAGE : "Volatile") + '</td>';
html += '<td class="value_td">\
for (var i = 0; i < disks.length; i++){
var disk = disks[i];
html += '<tr disk_id="'+(disk.DISK_ID)+'"><td class="key_td">';
html += disk.DISK_ID + ' - ' +
(disk.IMAGE ? disk.IMAGE : "Volatile") + '</td>';
html += '<td class="value_td">\
'+(vm_info.STATE == "3" ? '\
<button value="VM.detachdisk" class="detachdisk" style="float:right;color:#555555;height:26px;"><i class="icon-trash icon-large"></i></button>\
<button value="VM.detachdisk" class="detachdisk" style="float:right;color:#555555;height:26px;">'+tr("Detach")+' <i class="icon-remove icon-large"></i></button>\
' : '')+'\
<button value="VM.saveas" class="saveas" style="float:right;margin-right:10px;color:#555555;height:26px;"><i class="icon-download icon-large"></i></button>\
<input style="float:right;width:9em;margin-right:10px;margin-top:3px;" type="text" value="saveas_'+vm_info.ID+'_'+disk.DISK_ID+'" name="saveas_name"></input>'
+'\
</td>';
<button value="VM.saveas" class="saveas" style="float:right;margin-right:10px;color:#555555;height:26px;">'+tr("Save")+' <i class="icon-download icon-large"></i></button>\
<input style="float:right;width:9em;margin-right:10px;margin-top:3px;" type="text" value="saveas_'+vm_info.ID+'_'+disk.DISK_ID+'" name="saveas_name"></input>\
<label style="float:right;margin-top:4px;">'+tr("Save_as name")+':</label>'
+'\
</td>';
}
}
html += '</tbody>\
</table>';
</table>';
// If VM is not RUNNING, then we forget about the attach disk form.
if (vm_info.STATE != "3"){
@ -1163,7 +1166,7 @@ function printDisks(vm_info){
</select>\
</td>\
</tr>\
<tr class="at_volatile"><td class="key_td"><label>'+tr("Size")+':</label></td>\
<tr class="at_volatile"><td class="key_td"><label>'+tr("Size")+' (MB):</label></td>\
<td class="value_td">\
<input type="text" name="SIZE" style="width:8em;"></input>\
</td>\
@ -1186,6 +1189,7 @@ function printDisks(vm_info){
<input type="text" name="DEV_PREFIX" value="sd" style="width:8em;"></input>\
</td>\
</tr>\
<!--\
<tr class="at_volatile"><td class="key_td"><label>'+tr("Readonly")+':</label></td>\
<td class="value_td">\
<select name="READONLY" style="width:12em;">\
@ -1202,6 +1206,7 @@ function printDisks(vm_info){
</select>\
</td>\
</tr>\
-->\
<tr><td class="key_td"></td>\
<td class="value_td">\
<button type="submit" value="VM.attachdisk">Attach</button>\
@ -1282,8 +1287,8 @@ function hotpluggingOps(){
disk_obj.FORMAT = $('input[name="FORMAT"]',this).val();
disk_obj.TYPE = $('select[name="TYPE"]',this).val();
disk_obj.DEV_PREFIX = $('input[name="DEV_PREFIX"]',this).val();
disk_obj.READONLY = $('select[name="READONLY"]',this).val();
disk_obj.SAVE = $('save[name="SAVE"]',this).val();
// disk_obj.READONLY = $('select[name="READONLY"]',this).val();
// disk_obj.SAVE = $('save[name="SAVE"]',this).val();
break;
}

View File

@ -76,11 +76,13 @@ function pretty_time_runtime(time){
}
//returns a human readable size in Kilo, Mega, Giga or Tera bytes
function humanize_size(value) {
//if no from_bytes, assumes value comes in Ks
function humanize_size(value,from_bytes) {
if (typeof(value) === "undefined") {
value = 0;
}
var binarySufix = ["K", "M", "G", "T" ];
var binarySufix = from_bytes ?
["", "K", "M", "G", "T" ] : ["K", "M", "G", "T" ];
var i=0;
while (value > 1024 && i < 3){
value = value / 1024;
@ -561,12 +563,18 @@ function getSelectedNodes(dataTable){
return selected_nodes;
}
//returns a HTML string with a select input code generated from
//a dataTable. Allows filtering elements.
//returns a HTML string with options for
//a select input code generated from a dataTable.
//Allows filtering elements specifing status columns
//and bad status (if the values of the columns match the bad status)
//then this elem is skipped.
//no_empty_obj allows to skip adding a Please Select option
function makeSelectOptions(dataTable,
id_col,name_col,
option_value_col,
option_name_col,
status_cols,
bad_status_values,no_empty_opt){
bad_status_values,
no_empty_opt){
var nodes = dataTable.fnGetData();
var select = "";
if (!no_empty_opt)
@ -574,8 +582,12 @@ function makeSelectOptions(dataTable,
var array;
for (var j=0; j<nodes.length;j++){
var elem = nodes[j];
var id = elem[id_col];
var name = elem[name_col];
var value = elem[option_value_col];
//ASSUMPTION: elem id in column 1
var id = elem[1];
var name = elem[option_name_col];
var status, bad_status;
var ok=true;
for (var i=0;i<status_cols.length;i++){
@ -589,7 +601,7 @@ function makeSelectOptions(dataTable,
};
};
if (ok){
select +='<option value="'+id+'">'+name+'</option>';
select +='<option elem_id="'+id+'" value="'+value+'">'+name+' (id:'+id+')</option>';
};
};
return select;
@ -607,9 +619,9 @@ function escapeDoubleQuotes(string){
//of plotting comes, we can put the data in the right place.
function generateMonitoringDivs(graphs, id_prefix){
var str = "";
//43% of the width of the screen minus
//40% of the width of the screen minus
//181px (left menu size)
var width = ($(window).width()-181)*40/100;
var width = ($(window).width()-200)*39/100;
var id_suffix="";
var label="";
var id="";
@ -640,6 +652,7 @@ 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 convert_from_bytes = info.convert_from_bytes;
var id_suffix = labels.replace(/,/g,'_');
id_suffix = id_suffix.replace(/\//g,'_');
var labels_array = labels.split(',');
@ -652,7 +665,8 @@ function plot_graph(data,context,id_prefix,info){
//labels array.
for (var i=0; i<labels_array.length; i++) {
serie = {
label: labels_array[i],
//Turns label TEMPLATE/BLABLA into BLABLA
label: labels_array[i].split('/').pop(),
data: monitoring[labels_array[i]]
};
series.push(serie);
@ -664,7 +678,7 @@ function plot_graph(data,context,id_prefix,info){
// * Axis options: print time and sizes correctly
var options = {
legend : { show : true,
noColumns: mon_count++,
noColumns: mon_count+1,
container: $('#legend_'+id_suffix)
},
xaxis : {
@ -674,7 +688,7 @@ function plot_graph(data,context,id_prefix,info){
},
yaxis : { labelWidth: 40,
tickFormatter: function(val, axis) {
return humanize(val);
return humanize(val, convert_from_bytes);
},
min: 0
}
@ -835,6 +849,10 @@ function mustBeAdmin(){
return gid == 0;
}
function mustNotBeAdmin(){
return !mustBeAdmin();
}
function users_sel(){
return users_select;
}
@ -1008,6 +1026,13 @@ function setupQuotasDialog(dialog){
json['TYPE'] = sel.toUpperCase();
if (json['TYPE'] == "VM" &&
$('.current_quotas table tbody tr.vm_quota', dialog).length){
notifyError("Only 1 VM quota is allowed")
return false;
}
var tr = quotaListItem(json)
$('.current_quotas table tbody',dialog).append($(tr).hide().fadeIn());
return false;
@ -1081,7 +1106,7 @@ function setupQuotaIcons(){
}
// Returns an object with quota information in form of list items
function parseQuotas(elem){
function parseQuotas(elem, formatter_f){
var quotas = [];
var results = {
VM : "",
@ -1132,7 +1157,7 @@ function parseQuotas(elem){
}
for (var i = 0; i < quotas.length; i++){
var tr = quotaListItem(quotas[i]);
var tr = formatter_f(quotas[i]);
results[quotas[i].TYPE] += tr;
}
return results;
@ -1141,29 +1166,34 @@ function parseQuotas(elem){
//Receives a quota json object. Returns a nice string out of it.
function quotaListItem(quota_json){
var value = JSON.stringify(quota_json)
var str = '<tr quota=\''+value+'\'><td>'+
var str = '<tr quota=\''+value+'\' ';
if (quota_json.TYPE == "VM")
str += ' class="vm_quota" ';
str += '><td>'+
quota_json.TYPE+
'</td><td style="width:100%;"><pre style="margin:0;">';
switch(quota_json.TYPE){
case "VM":
str += 'VMs: ' + quota_json.VMS + (quota_json.VMS_USED ? ' (' + quota_json.VMS_USED + '). ' : ". ") +
'Memory: ' + quota_json.MEMORY + (quota_json.MEMORY_USED ? ' (' + quota_json.MEMORY_USED + '). ' : ". ") +
'Memory: ' + quota_json.MEMORY + (quota_json.MEMORY_USED ? 'MB (' + quota_json.MEMORY_USED + 'MB). ' : ". ") +
'CPU: ' + quota_json.CPU + (quota_json.CPU_USED ? ' (' + quota_json.CPU_USED + '). ' : ". ");
break;
case "DATASTORE":
str += 'ID: ' + getDatastoreName(quota_json.ID) + '. ' +
'Size: ' + quota_json.SIZE + (quota_json.SIZE_USED ? ' (' + quota_json.SIZE_USED + '). ' : ". ") +
str += 'ID/Name: ' + getDatastoreName(quota_json.ID) + '. ' +
'Size: ' + quota_json.SIZE + (quota_json.SIZE_USED ? 'MB (' + quota_json.SIZE_USED + 'MB). ' : ". ") +
'Images: ' + quota_json.IMAGES + (quota_json.IMAGES_USED ? ' (' + quota_json.IMAGES_USED + '). ' : ".");
break;
case "IMAGE":
str += 'ID: ' + getImageName(quota_json.ID) + '. ' +
str += 'ID/Name: ' + getImageName(quota_json.ID) + '. ' +
'RVMs: ' + quota_json.RVMS + (quota_json.RVMS_USED ? ' (' + quota_json.RVMS_USED + '). ' : ". ");
break;
case "NETWORK":
str += 'ID: ' + getVNetName(quota_json.ID) + '. ' +
str += 'ID/Name: ' + getVNetName(quota_json.ID) + '. ' +
'Leases: ' + quota_json.LEASES + (quota_json.LEASES_USED ? ' (' + quota_json.LEASES_USED + '). ': ". ");
break;
}
str += '</td><td><i class="quota_edit_icon icon-pencil"></i></pre></td></tr>';
str += '</td><td><button class="quota_edit_icon"><i class="icon-pencil"></i></button></pre></td></tr>';
return str;
}

View File

@ -255,7 +255,11 @@ get '/config' do
uconf = {
:user_config => {
:lang => session[:lang],
:wss => session[:wss]
:wss => session[:wss],
:marketplace_url => settings.config[:marketplace_url]
},
:system_config => {
:marketplace_url => settings.config[:marketplace_url]
}
}