diff --git a/install.sh b/install.sh index b0801db3c6..48e5d7ef44 100755 --- a/install.sh +++ b/install.sh @@ -896,6 +896,7 @@ SUNSTONE_MODELS_JSON_FILES="src/sunstone/models/OpenNebulaJSON/HostJSON.rb \ src/sunstone/models/OpenNebulaJSON/UserJSON.rb \ src/sunstone/models/OpenNebulaJSON/VirtualMachineJSON.rb \ src/sunstone/models/OpenNebulaJSON/TemplateJSON.rb \ + src/sunstone/models/OpenNebulaJSON/AclJSON.rb \ src/sunstone/models/OpenNebulaJSON/VirtualNetworkJSON.rb" SUNSTONE_TEMPLATE_FILES="src/sunstone/templates/login.html" @@ -917,6 +918,7 @@ SUNSTONE_PUBLIC_JS_PLUGINS_FILES="\ src/sunstone/public/js/plugins/templates-tab.js \ src/sunstone/public/js/plugins/users-tab.js \ src/sunstone/public/js/plugins/vms-tab.js \ + src/sunstone/public/js/plugins/acls-tab.js \ src/sunstone/public/js/plugins/vnets-tab.js" SUNSTONE_PUBLIC_CSS_FILES="src/sunstone/public/css/application.css \ diff --git a/src/ozones/Server/public/js/ozones-util.js b/src/ozones/Server/public/js/ozones-util.js index fabbc5d9b2..c6cae737f2 100644 --- a/src/ozones/Server/public/js/ozones-util.js +++ b/src/ozones/Server/public/js/ozones-util.js @@ -33,6 +33,16 @@ function updateVMsList(req,list,tag,zone_id,zone_name){ $.each(list,function(){ var vm = this.VM; var state = oZones.Helper.resource_state("vm",vm.STATE); + var hostname = "--"; + + if (state == "ACTIVE" || state == "SUSPENDED"){ + if (vm.HISTORY_RECORDS.HISTORY.constructor == Array){ + hostname = vm.HISTORY_RECORDS.HISTORY[vm.HISTORY_RECORDS.HISTORY.length-1].HOSTNAME; + } else { + hostname = vm.HISTORY_RECORDS.HISTORY.HOSTNAME; + }; + }; + if (state == "ACTIVE") { state = oZones.Helper.resource_state("vm_lcm",vm.LCM_STATE); } @@ -42,25 +52,25 @@ function updateVMsList(req,list,tag,zone_id,zone_name){ zone_id, zone_name, vm.ID, - vm.UID, - vm.GID, + vm.UNAME, + vm.GNAME, vm.NAME, state, vm.CPU, humanize_size(vm.MEMORY), - vm.HISTORY ? vm.HISTORY.HOSTNAME : "--", + hostname, pretty_time(vm.STIME) ]); } else { vms_array.push([ vm.ID, - vm.UID, - vm.GID, + vm.UNAME, + vm.GNAME, vm.NAME, state, vm.CPU, humanize_size(vm.MEMORY), - vm.HISTORY ? vm.HISTORY.HOSTNAME : "--", + vm.HISTORY_RECORDS ? vm.HISTORY_RECORDS.HISTORY.HOSTNAME : "--", pretty_time(vm.STIME) ]); }; @@ -88,8 +98,8 @@ function updateVNsList(req,list,tag,zone_id,zone_name){ zone_id, zone_name, network.ID, - network.UID, - network.GID, + network.UNAME, + network.GNAME, network.NAME, parseInt(network.TYPE) ? "FIXED" : "RANGED", network.BRIDGE, @@ -99,8 +109,8 @@ function updateVNsList(req,list,tag,zone_id,zone_name){ } else { vn_array.push([ network.ID, - network.UID, - network.GID, + network.UNAME, + network.GNAME, network.NAME, parseInt(network.TYPE) ? "FIXED" : "RANGED", network.BRIDGE, @@ -124,8 +134,8 @@ function updateTemplatesList(req,list,tag,zone_id,zone_name){ zone_id, zone_name, template.ID, - template.UID, - template.GID, + template.UNAME, + template.GNAME, template.NAME, pretty_time(template.REGTIME), parseInt(template.PUBLIC) ? "yes" : "no" @@ -133,8 +143,8 @@ function updateTemplatesList(req,list,tag,zone_id,zone_name){ } else { template_array.push([ template.ID, - template.UID, - template.GID, + template.UNAME, + template.GNAME, template.NAME, pretty_time(template.REGTIME), parseInt(template.PUBLIC) ? "yes" : "no" @@ -191,8 +201,8 @@ function updateImagesList(req,list,tag,zone_id,zone_name){ zone_id, zone_name, image.ID, - image.UID, - image.GID, + image.UNAME, + image.GNAME, image.NAME, oZones.Helper.image_type(image.TYPE), pretty_time(image.REGTIME), @@ -204,8 +214,8 @@ function updateImagesList(req,list,tag,zone_id,zone_name){ } else { image_array.push([ image.ID, - image.UID, - image.GID, + image.UNAME, + image.GNAME, image.NAME, oZones.Helper.image_type(image.TYPE), pretty_time(image.REGTIME), diff --git a/src/ozones/Server/public/js/ozones.js b/src/ozones/Server/public/js/ozones.js index b77601bca3..a825b391b0 100644 --- a/src/ozones/Server/public/js/ozones.js +++ b/src/ozones/Server/public/js/ozones.js @@ -21,7 +21,12 @@ var oZones = { var error = {}; if (resp.responseText) { - error = JSON.parse(resp.responseText); + try { + error = JSON.parse(resp.responseText); + } + catch (e) { + error.error = {message: "It appears there was a server exception. Please check server's log."}; + }; } else { diff --git a/src/ozones/Server/public/js/plugins/aggregated-tab.js b/src/ozones/Server/public/js/plugins/aggregated-tab.js index 3f7f83db4c..710e5fa53b 100644 --- a/src/ozones/Server/public/js/plugins/aggregated-tab.js +++ b/src/ozones/Server/public/js/plugins/aggregated-tab.js @@ -186,7 +186,6 @@ var agg_actions = { waitingNodes(dataTable_agg_hosts); Sunstone.runAction("ZoneHosts.list"); }, - callback: Empty, error: onError, notify: false }, @@ -207,7 +206,6 @@ var agg_actions = { waitingNodes(dataTable_agg_vms); Sunstone.runAction("ZoneVMs.list"); }, - callback: Empty, error: onError, notify: false }, @@ -228,7 +226,6 @@ var agg_actions = { waitingNodes(dataTable_agg_vns); Sunstone.runAction("ZoneVNs.list"); }, - callback: Empty, error: onError, notify: false }, @@ -249,7 +246,6 @@ var agg_actions = { waitingNodes(dataTable_agg_images); Sunstone.runAction("ZoneImages.list"); }, - callback: Empty, error: onError, notify: false }, @@ -270,7 +266,6 @@ var agg_actions = { waitingNodes(dataTable_agg_users); Sunstone.runAction("ZoneUsers.list"); }, - callback: Empty, error: onError, notify: false }, @@ -291,7 +286,6 @@ var agg_actions = { waitingNodes(dataTable_agg_templates); Sunstone.runAction("ZoneTemplates.list"); }, - callback: Empty, error: onError, notify: false }, diff --git a/src/ozones/Server/public/js/plugins/dashboard-tab.js b/src/ozones/Server/public/js/plugins/dashboard-tab.js index 20761d59b3..34553f45ab 100644 --- a/src/ozones/Server/public/js/plugins/dashboard-tab.js +++ b/src/ozones/Server/public/js/plugins/dashboard-tab.js @@ -177,8 +177,7 @@ var dashboard_tab_content = var dashboard_tab = { title: 'Dashboard', - content: dashboard_tab_content, - condition : True + content: dashboard_tab_content } Sunstone.addMainTab('dashboard_tab',dashboard_tab); diff --git a/src/ozones/Server/public/js/plugins/vdcs-tab.js b/src/ozones/Server/public/js/plugins/vdcs-tab.js index 9c113c1da7..c995495f43 100644 --- a/src/ozones/Server/public/js/plugins/vdcs-tab.js +++ b/src/ozones/Server/public/js/plugins/vdcs-tab.js @@ -94,7 +94,6 @@ var vdc_actions = { waitingNodes(dataTable_vdcs); Sunstone.runAction("Zone.list"); }, - callback: Empty, error: onError }, diff --git a/src/ozones/Server/public/js/plugins/zones-tab.js b/src/ozones/Server/public/js/plugins/zones-tab.js index 1006d523b8..920d024609 100644 --- a/src/ozones/Server/public/js/plugins/zones-tab.js +++ b/src/ozones/Server/public/js/plugins/zones-tab.js @@ -91,7 +91,6 @@ var zone_actions = { waitingNodes(dataTable_zones); Sunstone.runAction("Zone.list"); }, - callback: Empty, error: onError, notify: false }, diff --git a/src/sunstone/etc/sunstone-plugins.yaml b/src/sunstone/etc/sunstone-plugins.yaml index 3b4c997c4d..38228d404e 100644 --- a/src/sunstone/etc/sunstone-plugins.yaml +++ b/src/sunstone/etc/sunstone-plugins.yaml @@ -40,3 +40,8 @@ :user: :group: oneadmin: true +- plugins/acls-tab.js: + :ALL: false + :user: + :group: + oneadmin: true diff --git a/src/sunstone/models/OpenNebulaJSON.rb b/src/sunstone/models/OpenNebulaJSON.rb index 44685c68f9..0eb98bd37c 100644 --- a/src/sunstone/models/OpenNebulaJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON.rb @@ -26,6 +26,7 @@ require 'OpenNebulaJSON/PoolJSON' require 'OpenNebulaJSON/UserJSON' require 'OpenNebulaJSON/VirtualMachineJSON' require 'OpenNebulaJSON/VirtualNetworkJSON' +require 'OpenNebulaJSON/AclJSON' module OpenNebula class Error diff --git a/src/sunstone/models/OpenNebulaJSON/AclJSON.rb b/src/sunstone/models/OpenNebulaJSON/AclJSON.rb new file mode 100644 index 0000000000..0db8a68ac1 --- /dev/null +++ b/src/sunstone/models/OpenNebulaJSON/AclJSON.rb @@ -0,0 +1,51 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org) # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#--------------------------------------------------------------------------- # + +require 'OpenNebulaJSON/JSONUtils' + +module OpenNebulaJSON + class AclJSON < OpenNebula::Acl + include JSONUtils + + def create(template_json) + acl_string = parse_json(template_json, 'acl') + acl_rule = Acl.parse_rule(acl_string) + if OpenNebula.is_error?(acl_rule) + return acl_rule + end + self.allocate(acl_rule[0],acl_rule[1],acl_rule[2]) + end + + def perform_action(template_json) + action_hash = parse_json(template_json, 'action') + if OpenNebula.is_error?(action_hash) + return action_hash + end + + error_msg = "#{action_hash['perform']} action not " << + " available for this resource" + OpenNebula::Error.new(error_msg) + + # rc = case action_hash['perform'] + # #no actions! + # else + # error_msg = "#{action_hash['perform']} action not " << + # " available for this resource" + # OpenNebula::Error.new(error_msg) + # end + end + end +end diff --git a/src/sunstone/models/OpenNebulaJSON/PoolJSON.rb b/src/sunstone/models/OpenNebulaJSON/PoolJSON.rb index 150956bdf6..a59db50c73 100644 --- a/src/sunstone/models/OpenNebulaJSON/PoolJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/PoolJSON.rb @@ -24,4 +24,5 @@ module OpenNebulaJSON class TemplatePoolJSON < OpenNebula::TemplatePool; include JSONUtils; end class GroupPoolJSON < OpenNebula::GroupPool; include JSONUtils; end class UserPoolJSON < OpenNebula::UserPool; include JSONUtils; end + class AclPoolJSON < OpenNebula::AclPool; include JSONUtils; end end diff --git a/src/sunstone/models/SunstoneServer.rb b/src/sunstone/models/SunstoneServer.rb index fc553b3559..18e98cc371 100644 --- a/src/sunstone/models/SunstoneServer.rb +++ b/src/sunstone/models/SunstoneServer.rb @@ -74,6 +74,7 @@ class SunstoneServer when "vm" then VirtualMachinePoolJSON.new(@client, user_flag) when "vnet" then VirtualNetworkPoolJSON.new(@client, user_flag) when "user" then UserPoolJSON.new(@client) + when "acl" then AclPoolJSON.new(@client) else error = Error.new("Error: #{kind} resource not supported") return [404, error.to_json] @@ -125,6 +126,7 @@ class SunstoneServer when "vm" then VirtualMachineJSON.new(VirtualMachine.build_xml,@client) when "vnet" then VirtualNetworkJSON.new(VirtualNetwork.build_xml, @client) when "user" then UserJSON.new(User.build_xml, @client) + when "acl" then AclJSON.new(Acl.build_xml, @client) else error = Error.new("Error: #{kind} resource not supported") return [404, error.to_json] @@ -249,15 +251,14 @@ class SunstoneServer end # The VM host and its VNC port - host = resource['HISTORY/HOSTNAME'] + host = resource['/VM/HISTORY_RECORDS/HISTORY[last()]/HOSTNAME'] vnc_port = resource['TEMPLATE/GRAPHICS/PORT'] # The noVNC proxy_port proxy_port = config[:vnc_proxy_base_port].to_i + vnc_port.to_i begin - novnc_cmd = "#{config[:novnc_path]}/utils/launch.sh" - pipe = IO.popen("#{novnc_cmd} --listen #{proxy_port} \ - --vnc #{host}:#{vnc_port}") + novnc_cmd = "#{config[:novnc_path]}/utils/wsproxy.py" + pipe = IO.popen("#{novnc_cmd} #{proxy_port} #{host}:#{vnc_port}") rescue Exception => e error = Error.new(e.message) return [500, error.to_json] @@ -344,6 +345,7 @@ class SunstoneServer when "vm" then VirtualMachineJSON.new_with_id(id, @client) when "vnet" then VirtualNetworkJSON.new_with_id(id, @client) when "user" then UserJSON.new_with_id(id, @client) + when "acl" then AclJSON.new_with_id(id, @client) else error = Error.new("Error: #{kind} resource not supported") return error diff --git a/src/sunstone/public/js/opennebula.js b/src/sunstone/public/js/opennebula.js index 769bffab40..276672778c 100644 --- a/src/sunstone/public/js/opennebula.js +++ b/src/sunstone/public/js/opennebula.js @@ -21,7 +21,12 @@ var OpenNebula = { var error = {}; if (resp.responseText) { - error = JSON.parse(resp.responseText); + try { + error = JSON.parse(resp.responseText); + } + catch (e) { + error.error = {message: "It appears there was a server exception. Please check server's log."}; + }; } else { @@ -2589,5 +2594,95 @@ var OpenNebula = { "chgrp" : function(params){ OpenNebula.Helper.chgrp(params,OpenNebula.Template.resource,"template"); } + }, + + "Acl" : { + "resource" : "ACL", + "create" : function(params){ + var callback = params.success; + var callback_error = params.error; + var data = params.data; + var resource = OpenNebula.Acl.resource; + + var request = OpenNebula.Helper.request(resource,"create",data); + + $.ajax({ + url: "acl", + type: "POST", + dataType: "json", + data: JSON.stringify(data), + success: function(response) + { + if (callback) + { + callback(request, response); + } + }, + error: function(response) + { + if (callback_error) + { + callback_error(request, OpenNebula.Error(response)); + } + } + }); + }, + "list" : function(params){ + var callback = params.success; + var callback_error = params.error; + var timeout = params.timeout || false; + + var resource = OpenNebula.Acl.resource; + var request = OpenNebula.Helper.request(resource,"list"); + + $.ajax({ + url: "acl", + type: "GET", + dataType: "json", + data: {timeout: timeout}, + success: function(response) + { + if (callback) + { + var acl_pool = OpenNebula.Helper.pool(resource,response); + callback(request, acl_pool); + } + }, + error: function(response) + { + if (callback_error) + { + callback_error(request, OpenNebula.Error(response)); + } + } + }); + }, + "delete" : function(params){ + var callback = params.success; + var callback_error = params.error; + var id = params.data.id; + var resource = OpenNebula.Acl.resource; + + var request = OpenNebula.Helper.request(resource,"delete", id); + + $.ajax({ + url: "acl/" + id, + type: "DELETE", + success: function() + { + if (callback) + { + callback(request); + } + }, + error: function(response) + { + if (callback_error) + { + callback_error(request, OpenNebula.Error(response)); + } + } + }); + } } } diff --git a/src/sunstone/public/js/plugins/acls-tab.js b/src/sunstone/public/js/plugins/acls-tab.js new file mode 100644 index 0000000000..d25e45dc49 --- /dev/null +++ b/src/sunstone/public/js/plugins/acls-tab.js @@ -0,0 +1,498 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org) */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); you may */ +/* not use this file except in compliance with the License. You may obtain */ +/* a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ +/* See the License for the specific language governing permissions and */ +/* limitations under the License. */ +/* -------------------------------------------------------------------------- */ + +/*ACLs tab plugin*/ +var dataTable_acls; +var $create_acl_dialog; + +var acls_tab_content = +'
'; + +var create_acl_tmpl = +''; + +var acl_actions = { + "Acl.create" : { + type: "create", + call: OpenNebula.Acl.create, + callback: function(){ + Sunstone.runAction("Acl.list"); + }, + error: onError, + notify: true + }, + + "Acl.create_dialog" : { + type: "custom", + call: popUpCreateAclDialog + }, + + "Acl.list" : { + type: "list", + call: OpenNebula.Acl.list, + callback: updateAclsView, + error: onError + }, + + "Acl.refresh" : { + type: "custom", + call: function () { + waitingNodes(dataTable_acls); + Sunstone.runAction("Acl.list"); + } + }, + + "Acl.autorefresh" : { + type: "custom", + call: function(){ + OpenNebula.Acl.list({ + timeout: true, + success: updateAclsView, + error: onError + }); + } + }, + + "Acl.delete" : { + type: "multiple", + call: OpenNebula.Acl.delete, + callback: deleteAclElement, + elements: aclElements, + error: onError, + notify: true + }, +} + +var acl_buttons = { + "Acl.refresh" : { + type: "image", + text: "Refresh list", + img: "images/Refresh-icon.png" + }, + "Acl.create_dialog" : { + type: "create_dialog", + text: "+ New" + }, + "Acl.delete" : { + type: "action", + text: "Delete" + } +} + +var acls_tab = { + title: "ACLs", + content: acls_tab_content, + buttons: acl_buttons +} + +Sunstone.addActions(acl_actions); +Sunstone.addMainTab('acls_tab',acls_tab); + +//Returns selected elements on the acl datatable +function aclElements(){ + return getSelectedNodes(dataTable_acls); +} + +//Receives a segment of an ACL and translates: +// * -> All +// @1 -> Group 1 (tries to translate "1" into group name) +// #1 -> User 1 (tries to translate "1" into username) +//Translation of usernames and groupnames depends on +//group and user plugins tables. +function parseUserAcl(user){ + var user_str=""; + if (user[0] == '*'){ + user_str = "All"; + } else { + if (user[0] == '#'){ + user_str="User "; + user_str+= getUserName(user.substring(1)); + } + else if (user[0] == '@'){ + user_str="Group "; + user_str+= getGroupName(user.substring(1)); + }; + }; + return user_str; +} + +//Similar to above, but #1 means resource with "ID 1" +function parseResourceAcl(user){ + var user_str=""; + if (user[0] == '*'){ + user_str = "All"; + } else { + if (user[0] == '#'){ + user_str="ID "; + user_str+= user.substring(1); + } + else if (user[0] == '@'){ + user_str="Group "; + user_str+= getGroupName(user.substring(1)); + }; + }; + return user_str; +} + +//Parses a full ACL string, and translates it into +//a legible array +//to be put in the datatable fields. +function parseAclString(string) { + var space_split = string.split(' '); + var user = space_split[0]; + var resources = space_split[1]; + var rights = space_split[2]; + + //User + var user_str=parseUserAcl(user); + + + //Resources + var resources_str=""; + var resources_array = resources.split('/'); + var belonging_to = parseResourceAcl(resources_array[1]); + resources_array = resources_array[0].split('+'); + for (var i=0; i