From e20851f044ba1edf9d5a292b595039851523ecfb Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Thu, 6 Oct 2011 14:43:48 +0200 Subject: [PATCH 01/27] Feature #789: Small improvements to OZonesClient and cli helpers The client's default template attribute to put_resource() and post_resource() is now a JSON string. post/put_resource_str() converts a ONE template into json (method to_body) and then calls put/post_resource() post_resource_file() reads the ONE template from file, then calls post_resource_str() cli helpers have been accordingly updated. FORCE attribute handling has been remove from delhost action. --- src/ozones/Client/bin/onevdc | 2 +- src/ozones/Client/lib/OZonesClient.rb | 22 ++++++++++++------- src/ozones/Client/lib/cli/ozones_helper.rb | 2 +- .../lib/cli/ozones_helper/vdc_helper.rb | 8 ++----- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/ozones/Client/bin/onevdc b/src/ozones/Client/bin/onevdc index 0ad2e6c85b..246487f312 100755 --- a/src/ozones/Client/bin/onevdc +++ b/src/ozones/Client/bin/onevdc @@ -64,7 +64,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do end command :delhost, 'Deletes the set of hosts from the VDC', - :vdcid, :range, :options=>[FORCE] do + :vdcid, :range do helper.delhost(args[0], args[1], options) end end diff --git a/src/ozones/Client/lib/OZonesClient.rb b/src/ozones/Client/lib/OZonesClient.rb index bb015b6f63..f139b0a3ad 100644 --- a/src/ozones/Client/lib/OZonesClient.rb +++ b/src/ozones/Client/lib/OZonesClient.rb @@ -89,18 +89,21 @@ EOT # Post a new Resource to the relevant OZones Pool # :zonetemplate ###################################################################### - def post_resource(kind, template) + def post_resource_file(kind, template) tmpl_str = File.read(template) post_resource_str(kind, tmpl_str) end def post_resource_str(kind, tmpl_str) - body_str = OZonesClient::to_body(kind, tmpl_str) - + tmpl_json = OZonesClient::tobody(tmpl_str) + post_resource(kind, tmpl_json) + end + + def post_resource(kind, tmpl_json) url = URI.parse("#{@endpoint}/#{kind}") req = Net::HTTP::Post.new(url.path) - req.body=body_str + req.body=tmpl_json req.basic_auth @ozonesauth[0], @ozonesauth[1] @@ -111,13 +114,16 @@ EOT return OZonesClient::parse_error(res, kind) end - def put_resource(kind, id, tmpl_str) - body_str = OZonesClient::to_body(kind, tmpl_str) - + def put_resource_str(kind, id, tmpl_str) + tmpl_json = OZonesClient::to_body(kind, tmpl_str) + put_resource(kind, id, tmpl_json) + end + + def put_resource(kind, id, tmpl_json) url = URI.parse("#{@endpoint}/#{kind}/#{id}") req = Net::HTTP::Put.new(url.path) - req.body=body_str + req.body=tmpl_json req.basic_auth @ozonesauth[0], @ozonesauth[1] diff --git a/src/ozones/Client/lib/cli/ozones_helper.rb b/src/ozones/Client/lib/cli/ozones_helper.rb index 6363e1f7fb..70115f8832 100644 --- a/src/ozones/Client/lib/cli/ozones_helper.rb +++ b/src/ozones/Client/lib/cli/ozones_helper.rb @@ -29,7 +29,7 @@ module OZonesHelper end def create_resource(kind, template) - rc = @client.post_resource(kind, template) + rc = @client.post_resource_file(kind, template) if OZonesClient::is_error?(rc) [-1, rc.message] diff --git a/src/ozones/Client/lib/cli/ozones_helper/vdc_helper.rb b/src/ozones/Client/lib/cli/ozones_helper/vdc_helper.rb index b3d56bdd2c..6ddb48e412 100644 --- a/src/ozones/Client/lib/cli/ozones_helper/vdc_helper.rb +++ b/src/ozones/Client/lib/cli/ozones_helper/vdc_helper.rb @@ -72,7 +72,7 @@ class VDCHelper < OZonesHelper::OZHelper template << "FORCE=YES\n" end - rc = @client.put_resource(@vdc_str, id, template) + rc = @client.put_resource_str(@vdc_str, id, template) if OZonesClient::is_error?(rc) return [-1, rc.message] @@ -95,11 +95,7 @@ class VDCHelper < OZonesHelper::OZHelper new_host = (hosts - host_array).join(',') template = "ID=#{id}\nHOSTS=#{new_host}\n" - if options[:force] - template << "FORCE=YES\n" - end - - rc = @client.put_resource(@vdc_str, id, template) + rc = @client.put_resource_str(@vdc_str, id, template) if OZonesClient::is_error?(rc) return [-1, rc.message] From 067879d770d32ca97551fe20f3517285a3d90ccc Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Tue, 11 Oct 2011 15:21:49 +0200 Subject: [PATCH 02/27] Feature #789: First version of ozones api Slightly tested. Uncommented. To be extended with some utils (like printing helpers). --- src/ozones/Client/lib/api/zona.rb | 33 +++++++ .../Client/lib/api/zona/OZonesElement.rb | 79 +++++++++++++++++ src/ozones/Client/lib/api/zona/OZonesJSON.rb | 63 ++++++++++++++ src/ozones/Client/lib/api/zona/OZonesPool.rb | 54 ++++++++++++ src/ozones/Client/lib/api/zona/VDCElement.rb | 87 +++++++++++++++++++ src/ozones/Client/lib/api/zona/VDCPool.rb | 34 ++++++++ src/ozones/Client/lib/api/zona/ZoneElement.rb | 52 +++++++++++ src/ozones/Client/lib/api/zona/ZonePool.rb | 36 ++++++++ 8 files changed, 438 insertions(+) create mode 100644 src/ozones/Client/lib/api/zona.rb create mode 100644 src/ozones/Client/lib/api/zona/OZonesElement.rb create mode 100644 src/ozones/Client/lib/api/zona/OZonesJSON.rb create mode 100644 src/ozones/Client/lib/api/zona/OZonesPool.rb create mode 100644 src/ozones/Client/lib/api/zona/VDCElement.rb create mode 100644 src/ozones/Client/lib/api/zona/VDCPool.rb create mode 100644 src/ozones/Client/lib/api/zona/ZoneElement.rb create mode 100644 src/ozones/Client/lib/api/zona/ZonePool.rb diff --git a/src/ozones/Client/lib/api/zona.rb b/src/ozones/Client/lib/api/zona.rb new file mode 100644 index 0000000000..bdb392371e --- /dev/null +++ b/src/ozones/Client/lib/api/zona.rb @@ -0,0 +1,33 @@ +# -------------------------------------------------------------------------- # +# 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 'rubygems' +require 'OZonesClient.rb' + +require 'zona/OZonesJSON' + +require 'zona/OZonesPool' +require 'zona/OZonesElement' + +require 'zona/ZonePool' +require 'zona/ZoneElement' + +require 'zona/VDCPool' +require 'zona/VDCElement' + +module Zona + +end diff --git a/src/ozones/Client/lib/api/zona/OZonesElement.rb b/src/ozones/Client/lib/api/zona/OZonesElement.rb new file mode 100644 index 0000000000..c375875bdc --- /dev/null +++ b/src/ozones/Client/lib/api/zona/OZonesElement.rb @@ -0,0 +1,79 @@ +# -------------------------------------------------------------------------- # +# 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. # +#--------------------------------------------------------------------------- # + +module Zona + + class OZonesElement < JSONElement + + protected + + def initialize(hash, client) + @client = client + @json_hash = hash + + @pe_id = self["id"] ? self["id"].to_i : nil + @name = self["name"] ? self["name"] : nil + end + + def info(kind, root_element) + return Error.new('ID not defined') if !@pe_id + + rc = @client.get_resource(kind,@pe_id) + if !OZonesClient.is_error?(rc) + initialize_json(rc.body,root_element) + + rc = nil + + @pe_id = self["id"] ? self["id"].to_i : nil + @name = self["name"] ? self["name"] : nil + + end + rc + end + + def allocate_hash(kind, tmpl_hash) + allocate(kind, tmpl_hash.to_json) + end + + def allocate(kind, tmpl_json) + rc = @client.post_resource(kind, tmpl_json) + + if !OZonesClient.is_error?(rc) + initialize_json(rc.body,kind.upcase) + @pe_id = self["id"].to_i + rc = nil + end + rc + end + + def delete(kind) + return Error.new('ID not defined') if !@pe_id + + rc = @client.delete_resource(kind,@pe_id) + return rc if OZonesClient.is_error?(rc) + nil + end + + public + + attr_reader :pe_id, :name + + def self.new_with_id(id, client=nil) + self.new(self.build_json(id),client) + end + + end +end diff --git a/src/ozones/Client/lib/api/zona/OZonesJSON.rb b/src/ozones/Client/lib/api/zona/OZonesJSON.rb new file mode 100644 index 0000000000..0cfd1fbd17 --- /dev/null +++ b/src/ozones/Client/lib/api/zona/OZonesJSON.rb @@ -0,0 +1,63 @@ +# -------------------------------------------------------------------------- # +# 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. # +#--------------------------------------------------------------------------- # + + +module Zona + + require 'json' + + class JSONElement + def initialize(json_hash=nil) + @json_hash=json_hash + end + + def initialize_json(json_str, root_element) + rc = JSONElement.build_json(json_str,root_element) + @json_hash = rc + + if OZonesClient.is_error?(rc) || (rc.size == 0) + @json_hash=nil + end + end + + def self.build_json(json_str, root_element) + begin + parser = JSON.parser.new(json_str, {:symbolize_names => false}) + hash = parser.parse + hash[root_element] + rescue => e + OZonesClient::Error.new(e.message) + end + end + + def [](key) + @json_hash[key] + end + end + + class JSONPool < JSONElement + def initialize(json_hash=nil) + super(json_hash) + end + + def each_element(block) + @json_hash[@element_name].each do |elem| + block.call self.factory(elem) + end + end + end + +end diff --git a/src/ozones/Client/lib/api/zona/OZonesPool.rb b/src/ozones/Client/lib/api/zona/OZonesPool.rb new file mode 100644 index 0000000000..31952ef0ea --- /dev/null +++ b/src/ozones/Client/lib/api/zona/OZonesPool.rb @@ -0,0 +1,54 @@ +# -------------------------------------------------------------------------- # +# 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. # +#--------------------------------------------------------------------------- # + +module Zona + + class OZonesPool < JSONPool + + protected + + def initialize(pool,element,client) + super(nil) + + @client = client + @pool_name = pool.upcase + @element_name = element.upcase + end + + def factory(element_json) + Zona::OZonesPoolElement.new(element_json, @client) + end + + def info(kind) + rc = @client.get_pool(kind) + + if !OZonesClient.is_error?(rc) + initialize_json(rc.body,@pool_name) + rc=nil + end + + rc + end + + public + + def each(&block) + each_element(block) if @json_hash + end + + end + +end diff --git a/src/ozones/Client/lib/api/zona/VDCElement.rb b/src/ozones/Client/lib/api/zona/VDCElement.rb new file mode 100644 index 0000000000..73f57b10b0 --- /dev/null +++ b/src/ozones/Client/lib/api/zona/VDCElement.rb @@ -0,0 +1,87 @@ +# -------------------------------------------------------------------------- # +# 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. # +#--------------------------------------------------------------------------- # + +module Zona + + class VDC < OZonesElement + + VDC_KIND = "vdc" + + def self.build_json(pe_id=nil) + if pe_id + json = "{\"VDC\":{\"id\":#{pe_id}}}" + else + json = '{"VDC":{}}' + end + JSONElement.build_json(json,"VDC") + end + + def initialize(hash, client) + super(hash, client) + end + + def info + super(VDC_KIND,"VDC") + end + + def allocate_hash(template) + super(VDC_KIND,template) + end + + def allocate(template) + super(VDC_KIND,template) + end + + def delete + super(VDC_KIND) + end + + def addhosts(hosts_array,options={}) + return Error.new('VDC not info-ed') if !@json_hash + + # array of hosts, integers + hosts = self["hosts"].split(',').collect!{|x| x.to_i} + hosts.concat(hosts_array).uniq! + + new_hosts = hosts.join(',') + template = {:id => @pe_id, :hosts => new_hosts} + template[:force] = "yes" if options[:force] + + template = {:vdc => template} + + rc = @client.put_resource(VDC_KIND,@pe_id,template.to_json) + return rc if OZonesClient.is_error?(rc) + nil + end + + def delhosts(hosts_array) + return Error.new('VDC not info-ed') if !@json_hash + + hosts = self["hosts"].split(',').collect!{|x| x.to_i} + + new_hosts = (hosts - hosts_array).join(',') + template = {:vdc => {:id => @pe_id, :hosts => new_hosts}} + + rc = @client.put_resource(VDC_KIND,@pe_id,template.to_json) + return rc if OZonesClient.is_error?(rc) + nil + end + + alias :addhost :addhosts + alias :delhost :delhosts + + end +end diff --git a/src/ozones/Client/lib/api/zona/VDCPool.rb b/src/ozones/Client/lib/api/zona/VDCPool.rb new file mode 100644 index 0000000000..c019829ca5 --- /dev/null +++ b/src/ozones/Client/lib/api/zona/VDCPool.rb @@ -0,0 +1,34 @@ +# -------------------------------------------------------------------------- # +# 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. # +#--------------------------------------------------------------------------- # + +module Zona + + class VDCPool < OZonesPool + VDC_POOL_KIND="vdc" + + def initialize(client) + super("VDC_POOL", "VDC", client) + end + + def factory(element_json) + Zona::VDC.new(element_json,@client) + end + + def info + super(VDC_POOL_KIND) + end + end +end diff --git a/src/ozones/Client/lib/api/zona/ZoneElement.rb b/src/ozones/Client/lib/api/zona/ZoneElement.rb new file mode 100644 index 0000000000..31b891a979 --- /dev/null +++ b/src/ozones/Client/lib/api/zona/ZoneElement.rb @@ -0,0 +1,52 @@ +# -------------------------------------------------------------------------- # +# 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. # +#--------------------------------------------------------------------------- # + +module Zona + + class Zone < OZonesElement + + ZONE_KIND = "zone" + + def self.build_json(pe_id=nil) + if pe_id + json = "{\"ZONE\":{\"id\":#{pe_id}}}" + else + json = '{"ZONE":{}}' + end + JSONElement.build_json(json,"ZONE") + end + + def initialize(hash, client) + super(hash, client) + end + + def info + super(ZONE_KIND,"ZONE") + end + + def allocate_hash(template) + super(ZONE_KIND,template) + end + + def allocate(template) + super(ZONE_KIND,template) + end + + def delete + super(ZONE_KIND) + end + end +end diff --git a/src/ozones/Client/lib/api/zona/ZonePool.rb b/src/ozones/Client/lib/api/zona/ZonePool.rb new file mode 100644 index 0000000000..1cfe72280d --- /dev/null +++ b/src/ozones/Client/lib/api/zona/ZonePool.rb @@ -0,0 +1,36 @@ +# -------------------------------------------------------------------------- # +# 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. # +#--------------------------------------------------------------------------- # + +module Zona + + class ZonePool < OZonesPool + + ZONE_POOL_KIND = "zone" + + def initialize(client) + super("ZONE_POOL", "ZONE", client) + end + + def factory(element_json) + Zona::Zone.new(element_json,@client) + end + + def info + super(ZONE_POOL_KIND) + end + end + +end From 6dc5797bd9b05a913b4f5326b9caf015d38686da Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Tue, 11 Oct 2011 15:24:19 +0200 Subject: [PATCH 03/27] Feature #789: Update install file Include OZones API files among the client files to be installed with ozones or opennebula client files --- install.sh | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/install.sh b/install.sh index cd25ed8d40..5bba4752ea 100755 --- a/install.sh +++ b/install.sh @@ -198,6 +198,7 @@ ETC_DIRS="$ETC_LOCATION/im_kvm \ LIB_DIRS="$LIB_LOCATION/ruby \ $LIB_LOCATION/ruby/OpenNebula \ + $LIB_LOCATION/ruby/zona \ $LIB_LOCATION/ruby/cloud/ \ $LIB_LOCATION/ruby/cloud/econe \ $LIB_LOCATION/ruby/cloud/econe/views \ @@ -272,7 +273,8 @@ OZONES_DIRS="$OZONES_LOCATION/lib \ OZONES_CLIENT_DIRS="$LIB_LOCATION/ruby \ $LIB_LOCATION/ruby/OpenNebula \ $LIB_LOCATION/ruby/cli \ - $LIB_LOCATION/ruby/cli/ozones_helper" + $LIB_LOCATION/ruby/cli/ozones_helper \ + $LIB_LOCATION/ruby/zona" LIB_ECO_CLIENT_DIRS="$LIB_LOCATION/ruby \ $LIB_LOCATION/ruby/OpenNebula \ @@ -374,6 +376,8 @@ INSTALL_CLIENT_FILES=( OZONES_BIN_CLIENT_FILES:$BIN_LOCATION OZONES_LIB_CLIENT_CLI_FILES:$LIB_LOCATION/ruby/cli OZONES_LIB_CLIENT_CLI_HELPER_FILES:$LIB_LOCATION/ruby/cli/ozones_helper + OZONES_LIB_API_FILES:$LIB_LOCATION/ruby + OZONES_LIB_API_ZONA_FILES:$LIB_LOCATION/ruby/zona CLI_CONF_FILES:$ETC_LOCATION/cli OCA_LIB_FILES:$LIB_LOCATION/ruby RUBY_OPENNEBULA_LIB_FILES:$LIB_LOCATION/ruby/OpenNebula @@ -432,6 +436,8 @@ INSTALL_OZONES_FILES=( OZONES_BIN_CLIENT_FILES:$BIN_LOCATION OZONES_LIB_CLIENT_CLI_FILES:$LIB_LOCATION/ruby/cli OZONES_LIB_CLIENT_CLI_HELPER_FILES:$LIB_LOCATION/ruby/cli/ozones_helper + OZONES_LIB_API_FILES:$LIB_LOCATION/ruby + OZONES_LIB_API_ZONA_FILES:$LIB_LOCATION/ruby/zona ) INSTALL_OZONES_ETC_FILES=( @@ -1055,6 +1061,16 @@ OZONES_LIB_ZONE_FILES="src/ozones/Server/lib/OZones/Zones.rb \ src/ozones/Server/lib/OZones/AggregatedImages.rb \ src/ozones/Server/lib/OZones/AggregatedTemplates.rb" +OZONES_LIB_API_FILES="src/ozones/Client/lib/api/zona.rb" + +OZONES_LIB_API_ZONA_FILES="src/ozones/Client/lib/api/zona/ZoneElement.rb \ + src/ozones/Client/lib/api/zona/OZonesPool.rb \ + src/ozones/Client/lib/api/zona/OZonesJSON.rb \ + src/ozones/Client/lib/api/zona/VDCPool.rb \ + src/ozones/Client/lib/api/zona/VDCElement.rb \ + src/ozones/Client/lib/api/zona/OZonesElement.rb \ + src/ozones/Client/lib/api/zona/ZonePool.rb" + OZONES_PUBLIC_VENDOR_JQUERY=$SUNSTONE_PUBLIC_VENDOR_JQUERY OZONES_PUBLIC_VENDOR_DATATABLES=$SUNSTONE_PUBLIC_VENDOR_DATATABLES From 5412c6fec253798da1b047d092909e56cd662778 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Thu, 13 Oct 2011 17:09:13 +0200 Subject: [PATCH 04/27] feature #789: Fixes parser for NAME attributes --- src/oca/ruby/OpenNebula/Configuration.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/oca/ruby/OpenNebula/Configuration.rb b/src/oca/ruby/OpenNebula/Configuration.rb index fed14323b6..d21d2c78a2 100644 --- a/src/oca/ruby/OpenNebula/Configuration.rb +++ b/src/oca/ruby/OpenNebula/Configuration.rb @@ -77,10 +77,7 @@ module OpenNebula conf_file.scan(SINGLE_VARIABLE_REG) {|m| key=m[0].strip.upcase value=m[1].strip - - # hack to skip multiline VM_TYPE values - next if %w{NAME TEMPLATE}.include? key.upcase - + add_value(key, value) } From d28dd0b44574aa1abca1a96ac094e099bd90193e Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Thu, 13 Oct 2011 20:12:03 +0200 Subject: [PATCH 05/27] Task #908: Integrate OzonesClient in zona.rb api. This commit deletes OzonesClient.rb. All functionality has been merged to zona.rb and OzonesJSON.rb. All dependent files have been accordingly updated. Cli operations have been manually tested. API operations have not been tested yet. --- install.sh | 4 - src/ozones/Client/bin/onevdc | 3 +- src/ozones/Client/bin/onezone | 3 +- src/ozones/Client/lib/OZonesClient.rb | 286 ------------------ src/ozones/Client/lib/api/zona.rb | 249 ++++++++++++++- .../Client/lib/api/zona/OZonesElement.rb | 16 +- src/ozones/Client/lib/api/zona/OZonesJSON.rb | 51 +++- src/ozones/Client/lib/api/zona/OZonesPool.rb | 8 +- src/ozones/Client/lib/api/zona/VDCElement.rb | 12 +- src/ozones/Client/lib/api/zona/VDCPool.rb | 2 +- src/ozones/Client/lib/api/zona/ZoneElement.rb | 6 +- src/ozones/Client/lib/api/zona/ZonePool.rb | 4 +- src/ozones/Client/lib/cli/ozones_helper.rb | 18 +- .../lib/cli/ozones_helper/vdc_helper.rb | 14 +- src/ozones/Server/lib/OZones/Zones.rb | 2 +- 15 files changed, 329 insertions(+), 349 deletions(-) delete mode 100644 src/ozones/Client/lib/OZonesClient.rb diff --git a/install.sh b/install.sh index ad6eb4074c..4b79fbb55e 100755 --- a/install.sh +++ b/install.sh @@ -372,7 +372,6 @@ INSTALL_CLIENT_FILES=( CLI_LIB_FILES:$LIB_LOCATION/ruby/cli ONE_CLI_LIB_FILES:$LIB_LOCATION/ruby/cli/one_helper ETC_CLIENT_FILES:$ETC_LOCATION - OZONES_LIB_CLIENT_FILES:$LIB_LOCATION/ruby OZONES_BIN_CLIENT_FILES:$BIN_LOCATION OZONES_LIB_CLIENT_CLI_FILES:$LIB_LOCATION/ruby/cli OZONES_LIB_CLIENT_CLI_HELPER_FILES:$LIB_LOCATION/ruby/cli/ozones_helper @@ -432,7 +431,6 @@ INSTALL_OZONES_FILES=( OZONES_PUBLIC_IMAGES_FILES:$OZONES_LOCATION/public/images OZONES_PUBLIC_CSS_FILES:$OZONES_LOCATION/public/css OZONES_PUBLIC_JS_PLUGINS_FILES:$OZONES_LOCATION/public/js/plugins - OZONES_LIB_CLIENT_FILES:$LIB_LOCATION/ruby OZONES_BIN_CLIENT_FILES:$BIN_LOCATION OZONES_LIB_CLIENT_CLI_FILES:$LIB_LOCATION/ruby/cli OZONES_LIB_CLIENT_CLI_HELPER_FILES:$LIB_LOCATION/ruby/cli/ozones_helper @@ -1106,8 +1104,6 @@ OZONES_PUBLIC_JS_PLUGINS_FILES="src/ozones/Server/public/js/plugins/zones-tab.js src/ozones/Server/public/js/plugins/aggregated-tab.js \ src/ozones/Server/public/js/plugins/dashboard-tab.js" -OZONES_LIB_CLIENT_FILES="src/ozones/Client/lib/OZonesClient.rb" - OZONES_LIB_CLIENT_CLI_FILES="src/ozones/Client/lib/cli/ozones_helper.rb" OZONES_LIB_CLIENT_CLI_HELPER_FILES="\ diff --git a/src/ozones/Client/bin/onevdc b/src/ozones/Client/bin/onevdc index 246487f312..a181a1fb3d 100755 --- a/src/ozones/Client/bin/onevdc +++ b/src/ozones/Client/bin/onevdc @@ -49,8 +49,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do helper.show_resource(args[0],options) end - command :list, 'Lists VDCs in the pool', - :options=>CLIHelper::OPTIONS+OpenNebulaHelper::OPTIONS do + command :list, 'Lists VDCs in the pool' do helper.list_pool(options) end diff --git a/src/ozones/Client/bin/onezone b/src/ozones/Client/bin/onezone index 33e9b96ad8..6ba31eb8a8 100755 --- a/src/ozones/Client/bin/onezone +++ b/src/ozones/Client/bin/onezone @@ -114,8 +114,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do 0 end - command :list, 'Lists Zones in the pool', - :options=>CLIHelper::OPTIONS+OpenNebulaHelper::OPTIONS do + command :list, 'Lists Zones in the pool' do helper.list_pool(options) end diff --git a/src/ozones/Client/lib/OZonesClient.rb b/src/ozones/Client/lib/OZonesClient.rb deleted file mode 100644 index 2320bb8d07..0000000000 --- a/src/ozones/Client/lib/OZonesClient.rb +++ /dev/null @@ -1,286 +0,0 @@ -# -------------------------------------------------------------------------- # -# 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 'rubygems' -require 'uri' -require 'net/https' -require 'json' -require 'OpenNebula/Configuration' - -module OZonesClient - class Client - - OZONES_VERSION = < e - str = "Error connecting to server (#{e.to_s}).\n" - str << "Server: #{url.host}:#{url.port}" - - return OZonesClient::Error.new(str) - rescue Errno::ETIMEDOUT => e - str = "Error timeout connecting to server (#{e.to_s}).\n" - str << "Server: #{url.host}:#{url.port}" - - return OZonesClient::Error.new(str) - rescue Timeout::Error => e - str = "Error timeout while connected to server (#{e.to_s}).\n" - str << "Server: #{url.host}:#{url.port}" - - return OZonesClient::Error.new(str) - end - end - - ########################################################################## - # JSON & Template utils - ########################################################################## - - def self.to_body(kind, tmpl_str) - tmpl = OpenNebula::Configuration.new(tmpl_str) - res = { "#{kind}" => tmpl.conf } - - return JSON::generate(res) - end - - def self.parse_json(json_str, root_element) - begin - hash = JSON.parse(json_str) - rescue Exception => e - return OZonesClient::Error.new(e.message) - end - - if hash.has_key?(root_element) - return hash[root_element] - else - return OZonesClient::Error.new("Error parsing JSON: Wrong resource type") - end - end - - def self.to_json(hash_to_convert) - begin - JSON.pretty_generate hash_to_convert - rescue Exception => e - OZonesClient::Error.new(e.message) - end - end -end diff --git a/src/ozones/Client/lib/api/zona.rb b/src/ozones/Client/lib/api/zona.rb index bdb392371e..f28008a4ea 100644 --- a/src/ozones/Client/lib/api/zona.rb +++ b/src/ozones/Client/lib/api/zona.rb @@ -15,7 +15,9 @@ #--------------------------------------------------------------------------- # require 'rubygems' -require 'OZonesClient.rb' +require 'uri' +require 'net/https' +require 'OpenNebula/Configuration' require 'zona/OZonesJSON' @@ -30,4 +32,249 @@ require 'zona/VDCElement' module Zona + class Client + + OZONES_VERSION = < e + str = "Error connecting to server (#{e.to_s}).\n" + str << "Server: #{url.host}:#{url.port}" + return Error.new(str) + rescue Errno::ETIMEDOUT => e + str = "Error timeout connecting to server (#{e.to_s}).\n" + str << "Server: #{url.host}:#{url.port}" + return Error.new(str) + rescue Timeout::Error => e + str = "Error timeout while connected to server (#{e.to_s}).\n" + str << "Server: #{url.host}:#{url.port}" + return Error.new(str) + rescue Errno::ENETUNREACH => e + str = "Error trying to reach network (#{e.to_s}).\n" + str << "Server: #{url.host}:#{url.port}" + return Error.new(str) + end + end + + def self.parse_error(value, kind) + if Zona.is_error?(value) + return value + else + if Zona.is_http_error?(value) + str = "Operating with #{kind.upcase} failed with HTTP error" + str = " " + str + "code: #{value.code}\n" + if value.body + # Try to extract error message + begin + str << "Body: " << + OZonesJSON.parse_json(value.body, + "error")["message"] + rescue + str.gsub!("\nBody:","") + end + end + return Error.new(str) + end + end + value # If it is not an error, return it as-is + end + + end + + # ############################################ + # Template helpers + # ############################################ + + def self.to_body(kind, tmpl_str) + tmpl = OpenNebula::Configuration.new(tmpl_str) + res = { "#{kind}" => tmpl.conf } + + return OZonesJSON.to_json(res) + end + + # ######################################################################### + # Error handling functions + # ######################################################################### + + def self.is_error?(value) + value.class==Zona::Error + end + + def self.is_http_error?(value) + value.class != Net::HTTPOK + end + + # ######################################################################### + # The Error Class represents a generic error in the Zona + # library. It contains a readable representation of the error. + # ######################################################################### + class Error + attr_reader :message + + # +message+ a description of the error + def initialize(message=nil) + @message=message + end + + def to_s() + @message + end + end + end diff --git a/src/ozones/Client/lib/api/zona/OZonesElement.rb b/src/ozones/Client/lib/api/zona/OZonesElement.rb index c375875bdc..2aefab0446 100644 --- a/src/ozones/Client/lib/api/zona/OZonesElement.rb +++ b/src/ozones/Client/lib/api/zona/OZonesElement.rb @@ -17,7 +17,7 @@ module Zona class OZonesElement < JSONElement - + protected def initialize(hash, client) @@ -30,16 +30,16 @@ module Zona def info(kind, root_element) return Error.new('ID not defined') if !@pe_id - + rc = @client.get_resource(kind,@pe_id) - if !OZonesClient.is_error?(rc) + if !Zona.is_error?(rc) initialize_json(rc.body,root_element) rc = nil - + @pe_id = self["id"] ? self["id"].to_i : nil @name = self["name"] ? self["name"] : nil - + end rc end @@ -50,8 +50,8 @@ module Zona def allocate(kind, tmpl_json) rc = @client.post_resource(kind, tmpl_json) - - if !OZonesClient.is_error?(rc) + + if !Zona.is_error?(rc) initialize_json(rc.body,kind.upcase) @pe_id = self["id"].to_i rc = nil @@ -63,7 +63,7 @@ module Zona return Error.new('ID not defined') if !@pe_id rc = @client.delete_resource(kind,@pe_id) - return rc if OZonesClient.is_error?(rc) + return rc if Zona.is_error?(rc) nil end diff --git a/src/ozones/Client/lib/api/zona/OZonesJSON.rb b/src/ozones/Client/lib/api/zona/OZonesJSON.rb index 0cfd1fbd17..f0a4e0a0f5 100644 --- a/src/ozones/Client/lib/api/zona/OZonesJSON.rb +++ b/src/ozones/Client/lib/api/zona/OZonesJSON.rb @@ -19,33 +19,58 @@ module Zona require 'json' + class OZonesJSON + + def self.build_json(json_str, root_element) + begin + parser = JSON.parser.new(json_str, {:symbolize_names => false}) + hash = parser.parse + + if hash.has_key?(root_element) + return hash[root_element] + end + + Error.new("Error parsing JSON:\ root element not present") + + rescue => e + Error.new(e.message) + end + end + + # Alias for compatibility + def self.parse_json(json_str, root_element) + OZonesJSON.build_json(json_str, root_element) + end + + + def self.to_json(hash_to_convert) + begin + JSON.pretty_generate(hash_to_convert) + rescue Exception => e + Error.new(e.message) + end + end + + end + class JSONElement def initialize(json_hash=nil) @json_hash=json_hash end def initialize_json(json_str, root_element) - rc = JSONElement.build_json(json_str,root_element) + rc = OZonesJSON.build_json(json_str,root_element) @json_hash = rc - if OZonesClient.is_error?(rc) || (rc.size == 0) + if Zona.is_error?(rc) || (rc.size == 0) @json_hash=nil end end - - def self.build_json(json_str, root_element) - begin - parser = JSON.parser.new(json_str, {:symbolize_names => false}) - hash = parser.parse - hash[root_element] - rescue => e - OZonesClient::Error.new(e.message) - end - end - def [](key) @json_hash[key] end + + end class JSONPool < JSONElement diff --git a/src/ozones/Client/lib/api/zona/OZonesPool.rb b/src/ozones/Client/lib/api/zona/OZonesPool.rb index 31952ef0ea..bb4a5ac6c8 100644 --- a/src/ozones/Client/lib/api/zona/OZonesPool.rb +++ b/src/ozones/Client/lib/api/zona/OZonesPool.rb @@ -19,7 +19,7 @@ module Zona class OZonesPool < JSONPool protected - + def initialize(pool,element,client) super(nil) @@ -29,13 +29,13 @@ module Zona end def factory(element_json) - Zona::OZonesPoolElement.new(element_json, @client) + OZonesPoolElement.new(element_json, @client) end def info(kind) rc = @client.get_pool(kind) - if !OZonesClient.is_error?(rc) + if !Zona.is_error?(rc) initialize_json(rc.body,@pool_name) rc=nil end @@ -44,7 +44,7 @@ module Zona end public - + def each(&block) each_element(block) if @json_hash end diff --git a/src/ozones/Client/lib/api/zona/VDCElement.rb b/src/ozones/Client/lib/api/zona/VDCElement.rb index 73f57b10b0..41faebc1c1 100644 --- a/src/ozones/Client/lib/api/zona/VDCElement.rb +++ b/src/ozones/Client/lib/api/zona/VDCElement.rb @@ -26,13 +26,13 @@ module Zona else json = '{"VDC":{}}' end - JSONElement.build_json(json,"VDC") + OZonesJSON.build_json(json,"VDC") end def initialize(hash, client) super(hash, client) end - + def info super(VDC_KIND,"VDC") end @@ -51,11 +51,11 @@ module Zona def addhosts(hosts_array,options={}) return Error.new('VDC not info-ed') if !@json_hash - + # array of hosts, integers hosts = self["hosts"].split(',').collect!{|x| x.to_i} hosts.concat(hosts_array).uniq! - + new_hosts = hosts.join(',') template = {:id => @pe_id, :hosts => new_hosts} template[:force] = "yes" if options[:force] @@ -63,7 +63,7 @@ module Zona template = {:vdc => template} rc = @client.put_resource(VDC_KIND,@pe_id,template.to_json) - return rc if OZonesClient.is_error?(rc) + return rc if Zona.is_error?(rc) nil end @@ -76,7 +76,7 @@ module Zona template = {:vdc => {:id => @pe_id, :hosts => new_hosts}} rc = @client.put_resource(VDC_KIND,@pe_id,template.to_json) - return rc if OZonesClient.is_error?(rc) + return rc if Zona.is_error?(rc) nil end diff --git a/src/ozones/Client/lib/api/zona/VDCPool.rb b/src/ozones/Client/lib/api/zona/VDCPool.rb index c019829ca5..0984ba584b 100644 --- a/src/ozones/Client/lib/api/zona/VDCPool.rb +++ b/src/ozones/Client/lib/api/zona/VDCPool.rb @@ -24,7 +24,7 @@ module Zona end def factory(element_json) - Zona::VDC.new(element_json,@client) + VDC.new(element_json,@client) end def info diff --git a/src/ozones/Client/lib/api/zona/ZoneElement.rb b/src/ozones/Client/lib/api/zona/ZoneElement.rb index 31b891a979..ce51cbeafa 100644 --- a/src/ozones/Client/lib/api/zona/ZoneElement.rb +++ b/src/ozones/Client/lib/api/zona/ZoneElement.rb @@ -17,7 +17,7 @@ module Zona class Zone < OZonesElement - + ZONE_KIND = "zone" def self.build_json(pe_id=nil) @@ -26,13 +26,13 @@ module Zona else json = '{"ZONE":{}}' end - JSONElement.build_json(json,"ZONE") + OZonesJSON.build_json(json,"ZONE") end def initialize(hash, client) super(hash, client) end - + def info super(ZONE_KIND,"ZONE") end diff --git a/src/ozones/Client/lib/api/zona/ZonePool.rb b/src/ozones/Client/lib/api/zona/ZonePool.rb index 1cfe72280d..663d313a36 100644 --- a/src/ozones/Client/lib/api/zona/ZonePool.rb +++ b/src/ozones/Client/lib/api/zona/ZonePool.rb @@ -17,7 +17,7 @@ module Zona class ZonePool < OZonesPool - + ZONE_POOL_KIND = "zone" def initialize(client) @@ -25,7 +25,7 @@ module Zona end def factory(element_json) - Zona::Zone.new(element_json,@client) + Zone.new(element_json,@client) end def info diff --git a/src/ozones/Client/lib/cli/ozones_helper.rb b/src/ozones/Client/lib/cli/ozones_helper.rb index 70115f8832..20c319d1d7 100644 --- a/src/ozones/Client/lib/cli/ozones_helper.rb +++ b/src/ozones/Client/lib/cli/ozones_helper.rb @@ -14,14 +14,14 @@ # limitations under the License. # #--------------------------------------------------------------------------- # -require 'OZonesClient' +require 'zona' module OZonesHelper class OZHelper def initialize(user=nil, pass=nil, endpoint_str=nil, timeout=nil, debug_flag=true) - @client = OZonesClient::Client.new(user, + @client = Zona::Client.new(user, pass, endpoint_str, timeout, @@ -31,7 +31,7 @@ module OZonesHelper def create_resource(kind, template) rc = @client.post_resource_file(kind, template) - if OZonesClient::is_error?(rc) + if Zona::is_error?(rc) [-1, rc.message] else id = get_id(rc) @@ -42,10 +42,10 @@ module OZonesHelper def list_pool(kind, options) rc = @client.get_pool(kind) - if OZonesClient::is_error?(rc) + if Zona::is_error?(rc) [-1, rc.message] else - pool=OZonesClient::parse_json(rc.body, kind.upcase + "_POOL") + pool=Zona::OZonesJSON.parse_json(rc.body, kind.upcase + "_POOL") format_pool(pool, options) end end @@ -53,10 +53,10 @@ module OZonesHelper def show_resource(kind, id, options) rc = @client.get_resource(kind, id) - if OZonesClient::is_error?(rc) + if Zona::is_error?(rc) [-1, rc.message] else - resource=OZonesClient::parse_json(rc.body, kind.upcase) + resource=Zona::OZonesJSON.parse_json(rc.body, kind.upcase) format_resource(resource, options) end end @@ -64,10 +64,10 @@ module OZonesHelper def delete_resource(kind, id, options) rc = @client.delete_resource(kind, id) - if OZonesClient::is_error?(rc) + if Zona::is_error?(rc) [-1, rc.message] else - message=OZonesClient::parse_json(rc.body, "message") + message=Zona::OZonesJSON.parse_json(rc.body, "message") [0, "#{message}"] end end diff --git a/src/ozones/Client/lib/cli/ozones_helper/vdc_helper.rb b/src/ozones/Client/lib/cli/ozones_helper/vdc_helper.rb index 6ddb48e412..58c0b57b60 100644 --- a/src/ozones/Client/lib/cli/ozones_helper/vdc_helper.rb +++ b/src/ozones/Client/lib/cli/ozones_helper/vdc_helper.rb @@ -33,7 +33,7 @@ class VDCHelper < OZonesHelper::OZHelper rc = @client.post_resource_str(@vdc_str, tmpl_str) - if OZonesClient::is_error?(rc) + if Zona::is_error?(rc) [-1, rc.message] else id = get_id(rc) @@ -56,10 +56,10 @@ class VDCHelper < OZonesHelper::OZHelper def addhost(id, host_array, options) rc = @client.get_resource(@vdc_str, id) - if OZonesClient::is_error?(rc) + if Zona::is_error?(rc) return [-1, rc.message] else - vdc = OZonesClient::parse_json(rc.body, @vdc_str.upcase) + vdc = Zona::OZonesJSON.parse_json(rc.body, @vdc_str.upcase) end hosts = vdc['hosts'].split(',').collect!{|x| x.to_i} @@ -74,7 +74,7 @@ class VDCHelper < OZonesHelper::OZHelper rc = @client.put_resource_str(@vdc_str, id, template) - if OZonesClient::is_error?(rc) + if Zona::is_error?(rc) return [-1, rc.message] end @@ -84,10 +84,10 @@ class VDCHelper < OZonesHelper::OZHelper def delhost(id, host_array, options) rc = @client.get_resource(@vdc_str, id) - if OZonesClient::is_error?(rc) + if Zona::is_error?(rc) return [-1, rc.message] else - vdc = OZonesClient::parse_json(rc.body, @vdc_str.upcase) + vdc = Zona::OZonesJSON.parse_json(rc.body, @vdc_str.upcase) end hosts = vdc['hosts'].split(',').collect!{|x| x.to_i} @@ -97,7 +97,7 @@ class VDCHelper < OZonesHelper::OZHelper rc = @client.put_resource_str(@vdc_str, id, template) - if OZonesClient::is_error?(rc) + if Zona.is_error?(rc) return [-1, rc.message] end diff --git a/src/ozones/Server/lib/OZones/Zones.rb b/src/ozones/Server/lib/OZones/Zones.rb index 6c1567aee6..3c40601f48 100644 --- a/src/ozones/Server/lib/OZones/Zones.rb +++ b/src/ozones/Server/lib/OZones/Zones.rb @@ -60,7 +60,7 @@ module OZones zone_attributes["ZONE"][:vdcs] = Array.new self.vdcs.all.each{|vdc| - zone_attributes["ZONE"][:vdcs]< Date: Fri, 14 Oct 2011 15:50:54 +0200 Subject: [PATCH 06/27] feature #873: Add errno value to the OpenNebula Error class --- src/oca/ruby/OpenNebula.rb | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/oca/ruby/OpenNebula.rb b/src/oca/ruby/OpenNebula.rb index 9dc67bb237..4bf84d51db 100644 --- a/src/oca/ruby/OpenNebula.rb +++ b/src/oca/ruby/OpenNebula.rb @@ -50,11 +50,22 @@ module OpenNebula # Any function in the OpenNebula module will return an Error # object in case of error. class Error - attr_reader :message + ESUCCESS = 0x0000 + EAUTHENTICATION = 0x0100 + EAUTHORIZATION = 0x0200 + ENO_EXISTS = 0x0400 + EACTION = 0x0800 + EXML_RPC_API = 0x1000 + EINTERNAL = 0x2000 + ENOTDEFINED = 0x1111 - # +message+ a description of the error - def initialize(message=nil) - @message=message + attr_reader :message, :errno + + # +message+ Description of the error + # +errno+ OpenNebula code error + def initialize(message=nil, errno=0x1111) + @message = message + @errno = errno end def to_str() @@ -127,7 +138,7 @@ module OpenNebula response = @server.call_async("one."+action, @one_auth, *args) if response[0] == false - Error.new(response[1]) + Error.new(response[1], response[2]) else response[1] #response[1..-1] end From 20a0a78184f56b98d15c5d5734c20c372e615402 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Fri, 14 Oct 2011 15:51:52 +0200 Subject: [PATCH 07/27] feature #873: Add mapping for errno to HTTP codes --- src/cloud/common/CloudServer.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/cloud/common/CloudServer.rb b/src/cloud/common/CloudServer.rb index 91c5335701..59ad085e7f 100755 --- a/src/cloud/common/CloudServer.rb +++ b/src/cloud/common/CloudServer.rb @@ -22,6 +22,18 @@ require 'CloudAuth' # API (OCA). Any cloud implementation should derive from this class ############################################################################## class CloudServer + ########################################################################## + # Class Constants. Define the OpenNebula Error and HTTP codes mapping + ########################################################################## + HTTP_ERROR_CODE = { + OpenNebula::Error::EAUTHENTICATION => 401, + OpenNebula::Error::EAUTHORIZATION => 403, + OpenNebula::Error::ENO_EXISTS => 404, + OpenNebula::Error::EACTION => 500, + OpenNebula::Error::EXML_RPC_API => 500, + OpenNebula::Error::EINTERNAL => 500, + OpenNebula::Error::ENOTDEFINED => 500 + } ########################################################################## # Public attributes From 591182404514fff95ca9b207d99404e39925cab3 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Fri, 14 Oct 2011 15:52:54 +0200 Subject: [PATCH 08/27] feature #873: Add quota information to OCCI --- src/authm_mad/remotes/quota/quota.rb | 2 +- src/cloud/occi/lib/OCCIServer.rb | 81 ++++++++++++++++++++-------- src/cloud/occi/lib/occi-server.rb | 10 ++++ 3 files changed, 71 insertions(+), 22 deletions(-) diff --git a/src/authm_mad/remotes/quota/quota.rb b/src/authm_mad/remotes/quota/quota.rb index 1f13234e45..466cfe5013 100644 --- a/src/authm_mad/remotes/quota/quota.rb +++ b/src/authm_mad/remotes/quota/quota.rb @@ -242,9 +242,9 @@ class Quota pool = get_pool(res, user_id) base_xpath = "/#{res}_POOL/#{resource}" Quota.const_get("#{res}_USAGE".to_sym).each { |key, params| + usage[key] ||= 0 pool.each_xpath("#{base_xpath}/#{params[:xpath]}") { |elem| if elem - usage[key] ||= 0 if params[:count] usage[key] += 1 else diff --git a/src/cloud/occi/lib/OCCIServer.rb b/src/cloud/occi/lib/OCCIServer.rb index 85a8f4432a..e666651546 100755 --- a/src/cloud/occi/lib/OCCIServer.rb +++ b/src/cloud/occi/lib/OCCIServer.rb @@ -27,6 +27,8 @@ require 'VirtualNetworkOCCI' require 'VirtualNetworkPoolOCCI' require 'ImageOCCI' require 'ImagePoolOCCI' +require 'UserOCCI' +require 'UserPoolOCCI' require 'pp' @@ -36,7 +38,6 @@ require 'pp' # OpenNebula Engine ############################################################################## class OCCIServer < CloudServer - # Server initializer # config_file:: _String_ path of the config file # template:: _String_ path to the location of the templates @@ -72,7 +73,7 @@ class OCCIServer < CloudServer def get_computes(request) # --- Get User's VMs --- user_flag = -1 - + vmpool = VirtualMachinePoolOCCI.new( self.client, user_flag) @@ -99,14 +100,14 @@ class OCCIServer < CloudServer def get_networks(request) # --- Get User's VNETs --- user_flag = -1 - + network_pool = VirtualNetworkPoolOCCI.new( self.client, user_flag) # --- Prepare XML Response --- rc = network_pool.info - + if OpenNebula.is_error?(rc) if rc.message.match("Error getting") return rc, 404 @@ -125,14 +126,14 @@ class OCCIServer < CloudServer def get_storages(request) # --- Get User's Images --- user_flag = -1 - + image_pool = ImagePoolOCCI.new( self.client, user_flag) # --- Prepare XML Response --- rc = image_pool.info - + if OpenNebula.is_error?(rc) if rc.message.match("Error getting") return rc, 404 @@ -144,6 +145,24 @@ class OCCIServer < CloudServer return to_occi_xml(image_pool, 200) end + # Gets the pool representation of USERs + # request:: _Hash_ hash containing the data of the request + # [return] _String_,_Integer_ User pool representation or error, + # status code + def get_users(request) + # --- Get Users Pool --- + user_pool = UserPoolOCCI.new(self.client) + + # --- Prepare XML Response --- + rc = user_pool.info + + if OpenNebula.is_error?(rc) + return rc, CloudServer::HTTP_ERROR_CODE[rc.errno] + end + + return to_occi_xml(user_pool, 200) + end + ############################################################################ ############################################################################ # ENTITY RESOURCE METHODS @@ -190,7 +209,7 @@ class OCCIServer < CloudServer # --- Prepare XML Response --- rc = vm.info - + if OpenNebula.is_error?(rc) if rc.message.match("Error getting") return rc, 404 @@ -232,13 +251,13 @@ class OCCIServer < CloudServer vm = VirtualMachineOCCI.new( VirtualMachine.build_xml(params[:id]), self.client) - + rc = vm.info return rc, 400 if OpenNebula.is_error?(rc) - + xmldoc = XMLElement.build_xml(request.body, 'COMPUTE') vm_info = XMLElement.new(xmldoc) if xmldoc != nil - + # Check the number of changes in the request image_name = nil image_type = nil @@ -251,7 +270,7 @@ class OCCIServer < CloudServer image_type = disk.attr('.', 'type') } state = vm_info['STATE'] - + if image_name && state error_msg = "It is not allowed to change the state and save_as" << " a disk in the same request" @@ -270,12 +289,12 @@ class OCCIServer < CloudServer " suppossed to be saved" return OpenNebula::Error.new(error_msg), 400 end - + rc = vm.save_as(disk_id, image_name) if OpenNebula.is_error?(rc) image.delete return rc, 400 - end + end elsif state rc = vm.mk_action(state) return rc, 400 if OpenNebula.is_error?(rc) @@ -324,7 +343,7 @@ class OCCIServer < CloudServer # --- Prepare XML Response --- rc = network.info - + if OpenNebula.is_error?(rc) if rc.message.match("Error getting") return rc, 404 @@ -354,7 +373,7 @@ class OCCIServer < CloudServer return "", 204 end - + # Updates a NETWORK resource # request:: _Hash_ hash containing the data of the request # [return] _String_,_Integer_ Update confirmation msg or error, @@ -366,10 +385,10 @@ class OCCIServer < CloudServer vnet = VirtualNetworkOCCI.new( VirtualNetwork.build_xml(params[:id]), self.client) - + rc = vnet.info return rc, 400 if OpenNebula.is_error?(rc) - + if vnet_info['PUBLIC'] == 'YES' rc = vnet.publish return rc, 400 if OpenNebula.is_error?(rc) @@ -432,7 +451,7 @@ class OCCIServer < CloudServer self.client) rc = image.info - + if OpenNebula.is_error?(rc) if rc.message.match("Error getting") return rc, 404 @@ -464,7 +483,7 @@ class OCCIServer < CloudServer return "", 204 end - + # Updates a STORAGE resource # request:: _Hash_ hash containing the data of the request # [return] _String_,_Integer_ Update confirmation msg or error, @@ -476,10 +495,10 @@ class OCCIServer < CloudServer image = ImageOCCI.new( Image.build_xml(params[:id]), self.client) - + rc = image.info return rc, 400 if OpenNebula.is_error?(rc) - + if image_info['PERSISTENT'] && image_info['PUBLIC'] error_msg = "It is not allowed more than one change per request" return OpenNebula::Error.new(error_msg), 400 @@ -501,4 +520,24 @@ class OCCIServer < CloudServer image.info return to_occi_xml(image, 202) end + + # Get the representation of a USER + # request:: _Hash_ hash containing the data of the request + # [return] _String_,_Integer_ USER representation or error, + # status code + def get_user(request, params) + # --- Get the USER --- + user = UserOCCI.new( + User.build_xml(params[:id]), + self.client) + + # --- Prepare XML Response --- + rc = user.info + + if OpenNebula.is_error?(rc) + return rc, CloudServer::HTTP_ERROR_CODE[rc.errno] + end + + return to_occi_xml(user, 200) + end end diff --git a/src/cloud/occi/lib/occi-server.rb b/src/cloud/occi/lib/occi-server.rb index 06ac629054..d0d355dce9 100755 --- a/src/cloud/occi/lib/occi-server.rb +++ b/src/cloud/occi/lib/occi-server.rb @@ -144,6 +144,11 @@ get '/storage' do treat_response(result,rc) end +get '/user' do + result,rc = @occi_server.get_users(request) + treat_response(result,rc) +end + ################################################### # Entity Resources Methods ################################################### @@ -192,3 +197,8 @@ put '/storage/:id' do result,rc = @occi_server.put_storage(request, params) treat_response(result,rc) end + +get '/user/:id' do + result,rc = @occi_server.get_user(request, params) + treat_response(result,rc) +end \ No newline at end of file From 409b565dc8067da25b0003dde51e6e2d427d322a Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Fri, 14 Oct 2011 15:53:32 +0200 Subject: [PATCH 09/27] feature #873: Add UserOCCI and UserPoolOCCI classes --- src/cloud/occi/lib/UserOCCI.rb | 64 ++++++++++++++++++++++++++++++ src/cloud/occi/lib/UserPoolOCCI.rb | 43 ++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 src/cloud/occi/lib/UserOCCI.rb create mode 100644 src/cloud/occi/lib/UserPoolOCCI.rb diff --git a/src/cloud/occi/lib/UserOCCI.rb b/src/cloud/occi/lib/UserOCCI.rb new file mode 100644 index 0000000000..e12b2cb7f7 --- /dev/null +++ b/src/cloud/occi/lib/UserOCCI.rb @@ -0,0 +1,64 @@ +# -------------------------------------------------------------------------- # +# 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 'OpenNebula' + +include OpenNebula + +require 'quota' + +class UserOCCI < User + FORCE_USAGE = true + + OCCI_USER = %q{ + + <%= self.id.to_s %> + <%= self.name %> + + <% user_quota.each { |key,value| + key_s = key.to_s.upcase + value_i = value.to_i %> + <<%= key_s %>><%= value_i %>> + <% } %> + + + <% user_usage.each { |key,value| + key_s = key.to_s.upcase + value_i = value.to_i %> + <<%= key_s %>><%= value_i %>> + <% } %> + + + } + + # Class constructor + def initialize(xml, client) + super(xml, client) + end + + # Creates the OCCI representation of a User + def to_occi(base_url) + quota = Quota.new + user_usage = quota.get_usage(self.id, nil, FORCE_USAGE) + user_usage.delete(:uid) + + user_quota = quota.get_quota(self.id) + user_quota.delete(:uid) + + occi = ERB.new(OCCI_USER) + return occi.result(binding).gsub(/\n\s*/,'') + end +end diff --git a/src/cloud/occi/lib/UserPoolOCCI.rb b/src/cloud/occi/lib/UserPoolOCCI.rb new file mode 100644 index 0000000000..acb745a5f7 --- /dev/null +++ b/src/cloud/occi/lib/UserPoolOCCI.rb @@ -0,0 +1,43 @@ +# -------------------------------------------------------------------------- # +# 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 'OpenNebula' + +include OpenNebula + +class UserPoolOCCI < UserPool + OCCI_USER_POOL = %q{ + + <% self.each{ |user| %> + + <% } %> + + } + + + # Creates the OCCI representation of a User Pool + def to_occi(base_url) + begin + occi = ERB.new(OCCI_USER_POOL) + occi_text = occi.result(binding) + rescue Exception => e + error = OpenNebula::Error.new(e.message) + return error + end + + return occi_text.gsub(/\n\s*/,'') + end +end \ No newline at end of file From 1040d34766de55ce42bef4f4ce83fb3179060894 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Fri, 14 Oct 2011 15:54:01 +0200 Subject: [PATCH 10/27] feature #873: Add OCCI GET /user tests --- src/cloud/occi/test/fixtures/user.xml | 1 + .../occi/test/fixtures/user_collection.xml | 1 + src/cloud/occi/test/spec/spec_helper.rb | 39 ++++++++++ src/cloud/occi/test/spec/user_spec.rb | 73 +++++++++++++++++++ src/cloud/occi/test/test.sh | 50 +++++++++++++ 5 files changed, 164 insertions(+) create mode 100644 src/cloud/occi/test/fixtures/user.xml create mode 100644 src/cloud/occi/test/fixtures/user_collection.xml create mode 100644 src/cloud/occi/test/spec/spec_helper.rb create mode 100644 src/cloud/occi/test/spec/user_spec.rb create mode 100755 src/cloud/occi/test/test.sh diff --git a/src/cloud/occi/test/fixtures/user.xml b/src/cloud/occi/test/fixtures/user.xml new file mode 100644 index 0000000000..e48812af7b --- /dev/null +++ b/src/cloud/occi/test/fixtures/user.xml @@ -0,0 +1 @@ +0oneadmin00000000 \ No newline at end of file diff --git a/src/cloud/occi/test/fixtures/user_collection.xml b/src/cloud/occi/test/fixtures/user_collection.xml new file mode 100644 index 0000000000..67f7f0baa6 --- /dev/null +++ b/src/cloud/occi/test/fixtures/user_collection.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/cloud/occi/test/spec/spec_helper.rb b/src/cloud/occi/test/spec/spec_helper.rb new file mode 100644 index 0000000000..b942548ed1 --- /dev/null +++ b/src/cloud/occi/test/spec/spec_helper.rb @@ -0,0 +1,39 @@ +# -------------------------------------------------------------------------- # +# 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. # +#--------------------------------------------------------------------------- # + +FIXTURES_PATH = File.join(File.dirname(__FILE__),'../fixtures') +$: << File.join(File.dirname(__FILE__), '..', '..', 'lib') + +# Load the testing libraries +require 'rubygems' +require 'rspec' +require 'rack/test' + +# Load the Sinatra app +require 'occi-server' + +# Make Rack::Test available to all spec contexts +RSpec.configure do |conf| + conf.include Rack::Test::Methods +end + +# Set the Sinatra environment +set :environment, :test + +# Add an app method for RSpec +def app + Sinatra::Application +end diff --git a/src/cloud/occi/test/spec/user_spec.rb b/src/cloud/occi/test/spec/user_spec.rb new file mode 100644 index 0000000000..1a66f454ef --- /dev/null +++ b/src/cloud/occi/test/spec/user_spec.rb @@ -0,0 +1,73 @@ +# -------------------------------------------------------------------------- # +# 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 File.expand_path(File.dirname(__FILE__) + '/spec_helper') + +describe 'OCCI User tests' do + before(:all) do + @username_1 = "my_first_occi_user" + @userpass_1 = "my_first_occi_pass" + `oneuser create #{@username_1} #{@userpass_1}` + end + + it "should list the user collection" do + basic_authorize('oneadmin','4478db59d30855454ece114e8ccfa5563d21c9bd') + get '/user' + + last_response.status.should eql(200) + + xml_body = last_response.body + + user_collection = File.read(FIXTURES_PATH + '/user_collection.xml') + + xml_body.strip.should eql(user_collection.strip) + end + + + it "should check the error if the user collection is retrieved by a non oneadmin user" do + basic_authorize('my_first_occi_user','c08c5a6c535b6060b7b2af34e0d2f0ffb7e63b28') + get '/user' + + last_response.status.should eql(403) + end + + it "should show the user information, no quotas and no usage" do + basic_authorize('oneadmin','4478db59d30855454ece114e8ccfa5563d21c9bd') + get '/user/0' + + last_response.status.should eql(200) + + xml_body = last_response.body + + user = File.read(FIXTURES_PATH + '/user.xml') + + xml_body.strip.should eql(user.strip) + end + + it "should get a 404 error when trying to get a non existing user" do + basic_authorize('oneadmin','4478db59d30855454ece114e8ccfa5563d21c9bd') + get '/user/99' + + last_response.status.should eql(404) + end + + it "should get a 403 error when trying to get a different user" do + basic_authorize('my_first_occi_user','c08c5a6c535b6060b7b2af34e0d2f0ffb7e63b28') + get '/user/0' + + last_response.status.should eql(403) + end +end diff --git a/src/cloud/occi/test/test.sh b/src/cloud/occi/test/test.sh new file mode 100755 index 0000000000..e61a10bb6f --- /dev/null +++ b/src/cloud/occi/test/test.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +# -------------------------------------------------------------------------- # +# 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. # +#--------------------------------------------------------------------------- # + +if [ -z $ONE_LOCATION ]; then + echo "ONE_LOCATION not defined." + exit -1 +fi + +VAR_LOCATION="$ONE_LOCATION/var" +rm -rf $VAR_LOCATION/* + +if [ "$(ls -A $VAR_LOCATION)" ]; then + echo "$VAR_LOCATION is not empty." + exit -1 +fi + +for j in `ls ./spec/*_spec.rb` ; do + PID=$$ + + oned -f & + sleep 2s; + + rspec $j -f s + CODE=$? + + pkill -P $PID oned + sleep 2s; + pkill -9 -P $PID oned + + if [ $CODE != 0 ] ; then + exit 1 + fi + + find $VAR_LOCATION -mindepth 1 -delete +done From faa3a8b8c687afee7feda3372878106352624dff Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Fri, 14 Oct 2011 16:47:56 +0200 Subject: [PATCH 11/27] feature #801: Add onequota unset --- src/authm_mad/remotes/quota/onequota | 24 ++++++++++- src/authm_mad/remotes/quota/quota.rb | 41 ++++++++++++++++--- .../remotes/quota/test/quota_spec.rb | 26 ++++++------ 3 files changed, 71 insertions(+), 20 deletions(-) diff --git a/src/authm_mad/remotes/quota/onequota b/src/authm_mad/remotes/quota/onequota index a6fd24e669..0638a299c5 100755 --- a/src/authm_mad/remotes/quota/onequota +++ b/src/authm_mad/remotes/quota/onequota @@ -99,7 +99,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do arg_list.map! {|a| a.to_i } [0, arg_list] end - + set :format, :userid, OpenNebulaHelper.rname_to_id_desc("USER") do |arg| OpenNebulaHelper.rname_to_id(arg, "USER") end @@ -130,6 +130,26 @@ cmd=CommandParser::CmdParser.new(ARGV) do exit_with_code 0 end + ######################################################################## + unset_desc = <<-EOT.unindent + Unset a quota for a given user. + Examples: + onequota unset 3 cpu + onequota unset 4 cpu,memory,storage + EOT + + command :unset, unset_desc, :userid, :quota_list do + user_id, keys = args + + values_hash = Hash.new + keys.each_with_index { |k,i| + values_hash[k.to_sym] = 0 + } + + quota.set_quota(user_id, values_hash) + exit_with_code 0 + end + ######################################################################## delete_desc = "Delete the defined quotas for the given user" @@ -140,7 +160,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do ######################################################################## show_desc = "Show the user's quota and usage. (usage/quota)" - + FORCE={ :name => "force", :short => "-f", diff --git a/src/authm_mad/remotes/quota/quota.rb b/src/authm_mad/remotes/quota/quota.rb index 466cfe5013..805eff1d6e 100644 --- a/src/authm_mad/remotes/quota/quota.rb +++ b/src/authm_mad/remotes/quota/quota.rb @@ -154,6 +154,19 @@ class Quota set(QUOTA_TABLE, uid, quota) end + # Retrieves quota information for a given user + # + # @param [Integer, nil] uid the user id from which get the quota + # information, if nil will retrieve the quotas for all users. + # @return [Hash] Hash containing the quota information and the user id + # + # { + # :uid => 4, + # :cpu => 8, + # :memory => 8064, + # :num_vms => 4, + # :storage => 1240019 + # } def get_quota(uid=nil) limit = get(QUOTA_TABLE, uid) limit ? limit : @conf[:defaults].merge!(:uid => uid) @@ -192,14 +205,16 @@ class Quota msg = "" separator = "" info.each { |qname, quota_requested| - unless quota[qname] + unless quota[qname] || quota[qname]==0 next end - used = send(DB_QUOTA_SCHEMA[qname].name.to_sym, total[qname]) - request = send(DB_QUOTA_SCHEMA[qname].name.to_sym, quota_requested) - limit = send(DB_QUOTA_SCHEMA[qname].name.to_sym, quota[qname]) - spent = used + request + type = DB_QUOTA_SCHEMA[qname].name.to_sym + + used = send(type, total[qname]) + request = send(type, quota_requested) + limit = send(type, quota[qname]) + spent = used + request if spent > limit msg << separator @@ -228,6 +243,22 @@ class Quota ########################################################################### # Usage ########################################################################### + # Retrieves usage information for a given user + # + # @param [Integer] uid the user id from which get the usage information. + # @param ["VM", "IMAGE"] resource kind of resource. If nil will return + # the usage for all kinds of resources + # @param [true, false] force If true will force the usage calculation + # instead of retrieving it from the cache + # @return [Hash] Hash containing the usage information and the user id + # + # { + # :uid => 4, + # :cpu => 8, + # :memory => 8064, + # :num_vms => 4, + # :storage => 1240019 + # } def get_usage(user_id, resource=nil, force=false) if force if RESOURCES.include?(resource) diff --git a/src/authm_mad/remotes/quota/test/quota_spec.rb b/src/authm_mad/remotes/quota/test/quota_spec.rb index ff80f0c6c8..fd6d656f18 100644 --- a/src/authm_mad/remotes/quota/test/quota_spec.rb +++ b/src/authm_mad/remotes/quota/test/quota_spec.rb @@ -80,10 +80,10 @@ describe "Quota testing" do it "should check default cache (force)" do usage1force = @quota.get_usage(@uid1, nil, true) usage1force[:uid].should eql(0) - usage1force[:num_vms].should eql(nil) - usage1force[:cpu].should eql(nil) - usage1force[:memory].should eql(nil) - usage1force[:storage].should eql(nil) + usage1force[:num_vms].should eql(0) + usage1force[:cpu].should eql(0) + usage1force[:memory].should eql(0) + usage1force[:storage].should eql(0) end it "should authorize the user because there is no quota defined" do @@ -106,10 +106,10 @@ describe "Quota testing" do it "should check the usage cache is not updated" do usage1cache = @quota.get_usage(@uid1) usage1cache[:uid].should eql(0) - usage1cache[:num_vms].should eql(nil) - usage1cache[:cpu].should eql(nil) - usage1cache[:memory].should eql(nil) - usage1cache[:storage].should eql(nil) + usage1cache[:num_vms].should eql(0) + usage1cache[:cpu].should eql(0.0) + usage1cache[:memory].should eql(0) + usage1cache[:storage].should eql(0) end it "should check the cache (force)" do @@ -118,7 +118,7 @@ describe "Quota testing" do usage1force[:num_vms].should eql(1) usage1force[:cpu].should eql(2.0) usage1force[:memory].should eql(128) - usage1force[:storage].should eql(nil) + usage1force[:storage].should eql(0) end it "should check the usage cache is updated and contains the last usage" do @@ -127,7 +127,7 @@ describe "Quota testing" do usage1cache[:num_vms].should eql(1) usage1cache[:cpu].should eql(2.0) usage1cache[:memory].should eql(128) - usage1cache[:storage].should eql(nil) + usage1cache[:storage].should eql(0) end it "should add a new Image" do @@ -146,7 +146,7 @@ describe "Quota testing" do usage1cache[:num_vms].should eql(1) usage1cache[:cpu].should eql(2.0) usage1cache[:memory].should eql(128) - usage1cache[:storage].should eql(nil) + usage1cache[:storage].should eql(0) end it "should check the cache (force)" do @@ -252,7 +252,7 @@ describe "Quota testing" do end it "should not authorize the user because the vm quota is spent" do - err_msg = "CPU quota exceeded (Quota: 2.4, Used: 4.0, Asked: 2.0)." + err_msg = "CPU quota exceeded (Quota: 2.4, Used: 4.0, Requested: 2.0)" @quota.authorize(@uid1, @acl_vm_create).should eql(err_msg) @quota.authorize(@uid1, @acl_template_instantiate).should eql(err_msg) @@ -320,7 +320,7 @@ describe "Quota testing" do @quota.authorize(@uid1, @acl_vm_create).should eql(false) @quota.authorize(@uid1, @acl_template_instantiate).should eql(false) - err_msg = "STORAGE quota exceeded (Quota: 0, Used: 2000, Asked: 1474)." + err_msg = "STORAGE quota exceeded (Quota: 0, Used: 2000, Requested: 271)" @quota.authorize(@uid1, @acl_image_create).should eql(err_msg) end From 241ea1265a92436e301bea304dd3da1c77371a85 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Sun, 16 Oct 2011 18:58:25 +0200 Subject: [PATCH 12/27] Add missing license header to onevdc --- src/ozones/Client/bin/onevdc | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/ozones/Client/bin/onevdc b/src/ozones/Client/bin/onevdc index a181a1fb3d..2039bd8b27 100755 --- a/src/ozones/Client/bin/onevdc +++ b/src/ozones/Client/bin/onevdc @@ -1,5 +1,21 @@ #!/usr/bin/env ruby +# -------------------------------------------------------------------------- # +# 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. # +#--------------------------------------------------------------------------- # + ONE_LOCATION=ENV["ONE_LOCATION"] if !ONE_LOCATION From 5ab4becd3f4ba6c0b8284d2604239bb874ee4603 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Mon, 17 Oct 2011 01:36:42 +0200 Subject: [PATCH 13/27] Task #904: Document new oZones API Added comments to all "module zona" files. Comments can be processed with YARD to produce nice documentation. --- src/ozones/Client/lib/api/zona.rb | 96 +++++++++++++------ .../Client/lib/api/zona/OZonesElement.rb | 26 +++++ src/ozones/Client/lib/api/zona/OZonesJSON.rb | 31 +++++- src/ozones/Client/lib/api/zona/OZonesPool.rb | 16 +++- src/ozones/Client/lib/api/zona/VDCElement.rb | 36 +++++++ src/ozones/Client/lib/api/zona/VDCPool.rb | 12 +++ src/ozones/Client/lib/api/zona/ZoneElement.rb | 22 +++++ src/ozones/Client/lib/api/zona/ZonePool.rb | 12 ++- 8 files changed, 219 insertions(+), 32 deletions(-) diff --git a/src/ozones/Client/lib/api/zona.rb b/src/ozones/Client/lib/api/zona.rb index f28008a4ea..a514508665 100644 --- a/src/ozones/Client/lib/api/zona.rb +++ b/src/ozones/Client/lib/api/zona.rb @@ -14,6 +14,7 @@ # limitations under the License. # #--------------------------------------------------------------------------- # + require 'rubygems' require 'uri' require 'net/https' @@ -30,10 +31,21 @@ require 'zona/ZoneElement' require 'zona/VDCPool' require 'zona/VDCElement' +################################################################################ +# This module contains all the OZones API related classes and utilities. +################################################################################ module Zona + ############################################################################ + # OZones Client provides functionality to send and retrieve information + # from the OZones server side. It is used by CLI and API to handle the + # http requests to the server and basic error control on the + # responses. + ############################################################################ class Client + # Provides current version information. + # Should match server's oZones version. OZONES_VERSION = < tmpl.conf } @@ -248,33 +292,29 @@ EOT return OZonesJSON.to_json(res) end - # ######################################################################### - # Error handling functions - # ######################################################################### - + # @return [Boolean] Returns true if instance of {Zona::Error} def self.is_error?(value) value.class==Zona::Error end + # @return [Boolean] Returns true if HTTP return code is not OK def self.is_http_error?(value) value.class != Net::HTTPOK end - # ######################################################################### # The Error Class represents a generic error in the Zona # library. It contains a readable representation of the error. - # ######################################################################### class Error attr_reader :message - # +message+ a description of the error + # @param [String] A description of the error def initialize(message=nil) @message=message end + # @return [String] Error message description def to_s() @message end end - end diff --git a/src/ozones/Client/lib/api/zona/OZonesElement.rb b/src/ozones/Client/lib/api/zona/OZonesElement.rb index 2aefab0446..502b0a20d4 100644 --- a/src/ozones/Client/lib/api/zona/OZonesElement.rb +++ b/src/ozones/Client/lib/api/zona/OZonesElement.rb @@ -14,12 +14,18 @@ # limitations under the License. # #--------------------------------------------------------------------------- # + module Zona + # Standard abstraction of an OZones element. To be inherited. class OZonesElement < JSONElement protected + # Initializes an OZones Element instance. Tries to set @pe_id and @name + # @param [Hash] hash element description + # @param [Zona::Client] client OZones client + # @return [String] Element's name or nil def initialize(hash, client) @client = client @json_hash = hash @@ -28,6 +34,11 @@ module Zona @name = self["name"] ? self["name"] : nil end + # Retrieves details about an object and fills in + # the information hash + # @param [String] kind element kind: zone, vdc... + # @param [String] root_element root element of the JSON object description + # @return [Zona::Error] nil or Error def info(kind, root_element) return Error.new('ID not defined') if !@pe_id @@ -44,10 +55,18 @@ module Zona rc end + # Allocates a new element from a hash description + # @param [String] kind element kind: zone, vdc... + # @param [Hash] tmpl_hash element template hash + # @return [Zona::Error] nil or Error def allocate_hash(kind, tmpl_hash) allocate(kind, tmpl_hash.to_json) end + # Allocates a new element from a JSON description + # @param [String] kind element kind: zone, vdc... + # @param [String] tmpl_json element JSON template + # @return [Zona::Error] nil or Error def allocate(kind, tmpl_json) rc = @client.post_resource(kind, tmpl_json) @@ -59,6 +78,9 @@ module Zona rc end + # Deletes current element + # @param [String] kind element kind: zone, vdc... + # @return [Zona::Error] nil or Error def delete(kind) return Error.new('ID not defined') if !@pe_id @@ -71,6 +93,10 @@ module Zona attr_reader :pe_id, :name + # Creates a new element with the custom ID + # @param [#to_i] id element ID + # @param [Zona::Client] client OZones Client for this element + # @return [OZonesElement] A new element object def self.new_with_id(id, client=nil) self.new(self.build_json(id),client) end diff --git a/src/ozones/Client/lib/api/zona/OZonesJSON.rb b/src/ozones/Client/lib/api/zona/OZonesJSON.rb index f0a4e0a0f5..62e1ebfd19 100644 --- a/src/ozones/Client/lib/api/zona/OZonesJSON.rb +++ b/src/ozones/Client/lib/api/zona/OZonesJSON.rb @@ -19,8 +19,14 @@ module Zona require 'json' + # Several class methods regarding the handling of JSON descriptions + # for the OZones utilities. class OZonesJSON + # Build an element description hash. + # @param [String] json_str JSON description of the element + # @param [String] root_element root element of the JSON object + # @return [Hash,Zona::Error] The parsed JSON hash, or Error def self.build_json(json_str, root_element) begin parser = JSON.parser.new(json_str, {:symbolize_names => false}) @@ -37,12 +43,14 @@ module Zona end end - # Alias for compatibility + # @see build_json def self.parse_json(json_str, root_element) OZonesJSON.build_json(json_str, root_element) end - + # Generates a pretty JSON string from a hash + # @param [Hash] hash_to_convert a hash to be converted + # @return [String, Zona::Error] JSON string or Error if conversion fails def self.to_json(hash_to_convert) begin JSON.pretty_generate(hash_to_convert) @@ -53,11 +61,20 @@ module Zona end + # This class represents an element described by a JSON string + # In practice, this is represented by a hash, + # result of parsing the JSON string. class JSONElement + + # Initializes an instance + # @param [Hash] json_hash a hash with the object description def initialize(json_hash=nil) @json_hash=json_hash end + # Initializes an instance with a JSON description + # @param [String] json_str JSON description + # @param [String] root_element root element in the element description def initialize_json(json_str, root_element) rc = OZonesJSON.build_json(json_str,root_element) @json_hash = rc @@ -66,6 +83,10 @@ module Zona @json_hash=nil end end + + # Accesses the value of a JSON element key + # @param [String] key + # @return [String] Value def [](key) @json_hash[key] end @@ -73,11 +94,17 @@ module Zona end + # This class represents a collection of JSON Elements and it is itself one class JSONPool < JSONElement + + # Initializes an instance + # @param [Hash] json_hash a hash with the object description def initialize(json_hash=nil) super(json_hash) end + # Allows to iterate through the elements of a JSONPool + # @param [Block] block a block to be called in each iteration def each_element(block) @json_hash[@element_name].each do |elem| block.call self.factory(elem) diff --git a/src/ozones/Client/lib/api/zona/OZonesPool.rb b/src/ozones/Client/lib/api/zona/OZonesPool.rb index bb4a5ac6c8..7c86132c5e 100644 --- a/src/ozones/Client/lib/api/zona/OZonesPool.rb +++ b/src/ozones/Client/lib/api/zona/OZonesPool.rb @@ -14,12 +14,18 @@ # limitations under the License. # #--------------------------------------------------------------------------- # + module Zona + # Standard pool abstraction. To be inherited. class OZonesPool < JSONPool protected + # Initializes a Pool instance + # @param [String] pool pool name tag + # @param [String] pool pool elements name tag + # @param [Zona::Client] client OZones Client def initialize(pool,element,client) super(nil) @@ -28,10 +34,16 @@ module Zona @element_name = element.upcase end + # Produces a new Pool element with the provided description + # @param [String] element_json JSON string of the element + # @return [String] Element's name or nil def factory(element_json) - OZonesPoolElement.new(element_json, @client) + OZonesElement.new(element_json, @client) end + # Retrieves the Pool information + # @param [String] kind pool kind: vdc, zone... + # @return [Zona:Error] nil or Error def info(kind) rc = @client.get_pool(kind) @@ -45,6 +57,8 @@ module Zona public + # Allows iteration on pools elements + # @param [Block] block a block to call for each iteration def each(&block) each_element(block) if @json_hash end diff --git a/src/ozones/Client/lib/api/zona/VDCElement.rb b/src/ozones/Client/lib/api/zona/VDCElement.rb index 41faebc1c1..c3152f23c0 100644 --- a/src/ozones/Client/lib/api/zona/VDCElement.rb +++ b/src/ozones/Client/lib/api/zona/VDCElement.rb @@ -14,12 +14,20 @@ # limitations under the License. # #--------------------------------------------------------------------------- # + module Zona + # This class describes a single VDC element. It can be used to + # allocate, delete, add hosts, remove hosts and retrieve full information + # for a VDC. class VDC < OZonesElement + # String describing the kind of this resource VDC_KIND = "vdc" + # Builds minimal JSON description for a VDC + # @param [#to_i] pe_id VDC's ID + # @return [Hash,Zona::Error] Hash description of the object, or Error def self.build_json(pe_id=nil) if pe_id json = "{\"VDC\":{\"id\":#{pe_id}}}" @@ -29,26 +37,50 @@ module Zona OZonesJSON.build_json(json,"VDC") end + # Initializes a VDC object instance + # @param [Hash] hash VDC description + # @param [Zona::Client] client OZones Client + # @return [String] Element's name or nil def initialize(hash, client) super(hash, client) end + # Retrieves details about this object and fills in + # the information hash + # @return [Zona::Error] nil or Error def info super(VDC_KIND,"VDC") end + # Allocates a new element from a hash description + # @param [Hash] template element description + # @return [Zona::Error] nil or Error def allocate_hash(template) super(VDC_KIND,template) end + # Allocates a new element from a JSON description + # @param [String] template element description + # @return [Zona::Error] nil or Error def allocate(template) super(VDC_KIND,template) end + # Deletes current element + # @return [Zona::Error] nil or Error def delete super(VDC_KIND) end + + # Adds hosts to a VDC. The specified hosts are added to the VDC's + # current ones. + # @param [Array<#to_i>] hosts_array array of hosts IDs + # in the zone to be added + # @param [Hash] options a hash of options + # @option options [Boolean] :force allows hosts to add hosts + # which already belong to other VDCs + # @return [Zona::Error] nil or Error def addhosts(hosts_array,options={}) return Error.new('VDC not info-ed') if !@json_hash @@ -67,6 +99,10 @@ module Zona nil end + # Delete hosts from a VDC. The specified hosts are removed from the VDC. + # @param [Array<#to_i>] hosts_array array of the VDC's hosts IDs + # to be removed. If a host is not in the VDC, then it is ignored. + # @return [Zona::Error] nil or Error def delhosts(hosts_array) return Error.new('VDC not info-ed') if !@json_hash diff --git a/src/ozones/Client/lib/api/zona/VDCPool.rb b/src/ozones/Client/lib/api/zona/VDCPool.rb index 0984ba584b..ab1894b429 100644 --- a/src/ozones/Client/lib/api/zona/VDCPool.rb +++ b/src/ozones/Client/lib/api/zona/VDCPool.rb @@ -14,19 +14,31 @@ # limitations under the License. # #--------------------------------------------------------------------------- # + module Zona + # This class represents a set of VDCs. It allows to list the defined + # VDCs and iterate on them. class VDCPool < OZonesPool + + # String describing the kind of this resource VDC_POOL_KIND="vdc" + # Initializes a VDC Pool instance + # @param [Zona::Client] client OZones Client def initialize(client) super("VDC_POOL", "VDC", client) end + # Produces a new VDC element with the provided description + # @param [String] element_json JSON string of the element + # @return [String] Element's name or nil def factory(element_json) VDC.new(element_json,@client) end + # Retrieves the information for this pool + # @return [Zona:Error] nil or Error def info super(VDC_POOL_KIND) end diff --git a/src/ozones/Client/lib/api/zona/ZoneElement.rb b/src/ozones/Client/lib/api/zona/ZoneElement.rb index ce51cbeafa..ca54acd10d 100644 --- a/src/ozones/Client/lib/api/zona/ZoneElement.rb +++ b/src/ozones/Client/lib/api/zona/ZoneElement.rb @@ -14,12 +14,19 @@ # limitations under the License. # #--------------------------------------------------------------------------- # + module Zona + # This class describes a single OZones Zone element. It can be used to + # allocate, delete and retrieve full information for a Zone. class Zone < OZonesElement + # String describing the kind of this resource ZONE_KIND = "zone" + # Builds minimal JSON description for a Zone + # @param [#to_i] pe_id zone's ID + # @return [Hash,Zona::Error] Hash description of the object, or Error def self.build_json(pe_id=nil) if pe_id json = "{\"ZONE\":{\"id\":#{pe_id}}}" @@ -29,22 +36,37 @@ module Zona OZonesJSON.build_json(json,"ZONE") end + # Initializes a Zone object instance + # @param [Hash] hash zone description + # @param [Zona::Client] client OZones Client + # @return [String] Element's name or nil def initialize(hash, client) super(hash, client) end + # Retrieves details about this object and fills in + # the information hash + # @return [Zona::Error] nil or Error def info super(ZONE_KIND,"ZONE") end + # Allocates a new element from a hash description + # @param [Hash] template element description + # @return [Zona::Error] nil or Error def allocate_hash(template) super(ZONE_KIND,template) end + # Allocates a new element from a JSON description + # @param [String] template element description + # @return [Zona::Error] nil or Error def allocate(template) super(ZONE_KIND,template) end + # Deletes current element + # @return [Zona::Error] nil or Error def delete super(ZONE_KIND) end diff --git a/src/ozones/Client/lib/api/zona/ZonePool.rb b/src/ozones/Client/lib/api/zona/ZonePool.rb index 663d313a36..0a50e0c7e4 100644 --- a/src/ozones/Client/lib/api/zona/ZonePool.rb +++ b/src/ozones/Client/lib/api/zona/ZonePool.rb @@ -14,23 +14,33 @@ # limitations under the License. # #--------------------------------------------------------------------------- # + module Zona + # This class represents a set of Zones. It allows to list the defined + # Zones and iterate on them. class ZonePool < OZonesPool + # String describing the kind of this resource ZONE_POOL_KIND = "zone" + # Initializes a Zone Pool instance + # @param [Zona::Client] client OZones Client def initialize(client) super("ZONE_POOL", "ZONE", client) end + # Produces a new Zone element with the provided description + # @param [String] element_json JSON string of the element + # @return [String] Element's name or nil def factory(element_json) Zone.new(element_json,@client) end + # Retrieves the information for this pool + # @return [Zona:Error] nil or Error def info super(ZONE_POOL_KIND) end end - end From c806c7288d793c187b2badf0e0337a5809d381c4 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Mon, 17 Oct 2011 01:45:00 +0200 Subject: [PATCH 14/27] Feature #789: Move ozones api files one level up zona.rb can be found directly in ozones lib/ dir. Install script updated accordingly. --- install.sh | 16 ++++++++-------- src/ozones/Client/lib/{api => }/zona.rb | 0 .../Client/lib/{api => }/zona/OZonesElement.rb | 0 .../Client/lib/{api => }/zona/OZonesJSON.rb | 0 .../Client/lib/{api => }/zona/OZonesPool.rb | 0 .../Client/lib/{api => }/zona/VDCElement.rb | 0 src/ozones/Client/lib/{api => }/zona/VDCPool.rb | 0 .../Client/lib/{api => }/zona/ZoneElement.rb | 0 src/ozones/Client/lib/{api => }/zona/ZonePool.rb | 0 9 files changed, 8 insertions(+), 8 deletions(-) rename src/ozones/Client/lib/{api => }/zona.rb (100%) rename src/ozones/Client/lib/{api => }/zona/OZonesElement.rb (100%) rename src/ozones/Client/lib/{api => }/zona/OZonesJSON.rb (100%) rename src/ozones/Client/lib/{api => }/zona/OZonesPool.rb (100%) rename src/ozones/Client/lib/{api => }/zona/VDCElement.rb (100%) rename src/ozones/Client/lib/{api => }/zona/VDCPool.rb (100%) rename src/ozones/Client/lib/{api => }/zona/ZoneElement.rb (100%) rename src/ozones/Client/lib/{api => }/zona/ZonePool.rb (100%) diff --git a/install.sh b/install.sh index 4b79fbb55e..f7404fca77 100755 --- a/install.sh +++ b/install.sh @@ -1059,15 +1059,15 @@ OZONES_LIB_ZONE_FILES="src/ozones/Server/lib/OZones/Zones.rb \ src/ozones/Server/lib/OZones/AggregatedImages.rb \ src/ozones/Server/lib/OZones/AggregatedTemplates.rb" -OZONES_LIB_API_FILES="src/ozones/Client/lib/api/zona.rb" +OZONES_LIB_API_FILES="src/ozones/Client/lib/zona.rb" -OZONES_LIB_API_ZONA_FILES="src/ozones/Client/lib/api/zona/ZoneElement.rb \ - src/ozones/Client/lib/api/zona/OZonesPool.rb \ - src/ozones/Client/lib/api/zona/OZonesJSON.rb \ - src/ozones/Client/lib/api/zona/VDCPool.rb \ - src/ozones/Client/lib/api/zona/VDCElement.rb \ - src/ozones/Client/lib/api/zona/OZonesElement.rb \ - src/ozones/Client/lib/api/zona/ZonePool.rb" +OZONES_LIB_API_ZONA_FILES="src/ozones/Client/lib/zona/ZoneElement.rb \ + src/ozones/Client/lib/zona/OZonesPool.rb \ + src/ozones/Client/lib/zona/OZonesJSON.rb \ + src/ozones/Client/lib/zona/VDCPool.rb \ + src/ozones/Client/lib/zona/VDCElement.rb \ + src/ozones/Client/lib/zona/OZonesElement.rb \ + src/ozones/Client/lib/zona/ZonePool.rb" OZONES_PUBLIC_VENDOR_JQUERY=$SUNSTONE_PUBLIC_VENDOR_JQUERY diff --git a/src/ozones/Client/lib/api/zona.rb b/src/ozones/Client/lib/zona.rb similarity index 100% rename from src/ozones/Client/lib/api/zona.rb rename to src/ozones/Client/lib/zona.rb diff --git a/src/ozones/Client/lib/api/zona/OZonesElement.rb b/src/ozones/Client/lib/zona/OZonesElement.rb similarity index 100% rename from src/ozones/Client/lib/api/zona/OZonesElement.rb rename to src/ozones/Client/lib/zona/OZonesElement.rb diff --git a/src/ozones/Client/lib/api/zona/OZonesJSON.rb b/src/ozones/Client/lib/zona/OZonesJSON.rb similarity index 100% rename from src/ozones/Client/lib/api/zona/OZonesJSON.rb rename to src/ozones/Client/lib/zona/OZonesJSON.rb diff --git a/src/ozones/Client/lib/api/zona/OZonesPool.rb b/src/ozones/Client/lib/zona/OZonesPool.rb similarity index 100% rename from src/ozones/Client/lib/api/zona/OZonesPool.rb rename to src/ozones/Client/lib/zona/OZonesPool.rb diff --git a/src/ozones/Client/lib/api/zona/VDCElement.rb b/src/ozones/Client/lib/zona/VDCElement.rb similarity index 100% rename from src/ozones/Client/lib/api/zona/VDCElement.rb rename to src/ozones/Client/lib/zona/VDCElement.rb diff --git a/src/ozones/Client/lib/api/zona/VDCPool.rb b/src/ozones/Client/lib/zona/VDCPool.rb similarity index 100% rename from src/ozones/Client/lib/api/zona/VDCPool.rb rename to src/ozones/Client/lib/zona/VDCPool.rb diff --git a/src/ozones/Client/lib/api/zona/ZoneElement.rb b/src/ozones/Client/lib/zona/ZoneElement.rb similarity index 100% rename from src/ozones/Client/lib/api/zona/ZoneElement.rb rename to src/ozones/Client/lib/zona/ZoneElement.rb diff --git a/src/ozones/Client/lib/api/zona/ZonePool.rb b/src/ozones/Client/lib/zona/ZonePool.rb similarity index 100% rename from src/ozones/Client/lib/api/zona/ZonePool.rb rename to src/ozones/Client/lib/zona/ZonePool.rb From f1272b23d880f1581727a14b58e0ccda17019f7f Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Mon, 17 Oct 2011 18:37:45 +0200 Subject: [PATCH 15/27] feature #849: Improve OCCI PUT compute --- src/cloud/occi/lib/OCCIServer.rb | 58 ++-------- src/cloud/occi/lib/VirtualMachineOCCI.rb | 135 +++++++++++++++++------ 2 files changed, 111 insertions(+), 82 deletions(-) diff --git a/src/cloud/occi/lib/OCCIServer.rb b/src/cloud/occi/lib/OCCIServer.rb index e666651546..6edf28d972 100755 --- a/src/cloud/occi/lib/OCCIServer.rb +++ b/src/cloud/occi/lib/OCCIServer.rb @@ -253,56 +253,18 @@ class OCCIServer < CloudServer self.client) rc = vm.info - return rc, 400 if OpenNebula.is_error?(rc) - - xmldoc = XMLElement.build_xml(request.body, 'COMPUTE') - vm_info = XMLElement.new(xmldoc) if xmldoc != nil - - # Check the number of changes in the request - image_name = nil - image_type = nil - vm_info.each('DISK/SAVE_AS') { |disk| - if image_name - error_msg = "It is only allowed one save_as per request" - return OpenNebula::Error.new(error_msg), 400 - end - image_name = disk.attr('.', 'name') - image_type = disk.attr('.', 'type') - } - state = vm_info['STATE'] - - if image_name && state - error_msg = "It is not allowed to change the state and save_as" << - " a disk in the same request" - return OpenNebula::Error.new(error_msg), 400 - elsif image_name - # Get the disk id - disk_id = vm_info.attr('DISK/SAVE_AS/..', 'id') - if disk_id.nil? - error_msg = "DISK id attribute not specified" - return OpenNebula::Error.new(error_msg), 400 - end - - disk_id = disk_id.to_i - if vm["TEMPLATE/DISK[DISK_ID=\"#{disk_id}\"]/SAVE_AS"] - error_msg = "The disk #{disk_id} is already" << - " suppossed to be saved" - return OpenNebula::Error.new(error_msg), 400 - end - - rc = vm.save_as(disk_id, image_name) - if OpenNebula.is_error?(rc) - image.delete - return rc, 400 - end - elsif state - rc = vm.mk_action(state) - return rc, 400 if OpenNebula.is_error?(rc) + if OpenNebula.is_error?(rc) + return rc, CloudServer::HTTP_ERROR_CODE[rc.errno] end - # --- Prepare XML Response --- - vm.info - return to_occi_xml(vm, 202) + result, code = vm.update_from_xml(request.body) + + if OpenNebula.is_error?(result) + return result, code + else + vm.info + return to_occi_xml(vm, code) + end end ############################################################################ diff --git a/src/cloud/occi/lib/VirtualMachineOCCI.rb b/src/cloud/occi/lib/VirtualMachineOCCI.rb index 7ed361cc00..1f00212020 100755 --- a/src/cloud/occi/lib/VirtualMachineOCCI.rb +++ b/src/cloud/occi/lib/VirtualMachineOCCI.rb @@ -61,62 +61,48 @@ class VirtualMachineOCCI < VirtualMachine <% end %> } - + + OCCI_ACTION = { + "STOPPED" => { :from => ["ACTIVE"], :action => :stop}, + "SUSPENDED" => { :from => ["ACTIVE"], :action => :suspend}, + "RESUME" => { :from => ["STOPPED", "SUSPENDED"], :action => :resume}, + "CANCEL" => { :from => ["ACTIVE"], :action => :cancel}, + "SHUTDOWN" => { :from => ["ACTIVE"], :action => :shutdown}, + "DONE" => { :from => VM_STATE, :action => :finalize}, + } + # Class constructor def initialize(xml, client, xml_info=nil, types=nil, base=nil) super(xml, client) @vm_info = nil @template = nil @common_template = base + '/common.erb' if base - + if xml_info != nil xmldoc = XMLElement.build_xml(xml_info, 'COMPUTE') @vm_info = XMLElement.new(xmldoc) if xmldoc != nil end - + if @vm_info != nil itype = @vm_info['INSTANCE_TYPE'] - + if itype != nil and types[itype.to_sym] != nil @template = base + "/#{types[itype.to_sym][:template]}" end end - + end - - def mk_action(action_str) - case action_str.downcase - when "stopped" - rc = self.stop - when "suspended" - rc = self.suspend - when "resume" - rc = self.resume - when "cancel" - rc = self.cancel - when "shutdown" - rc = self.shutdown - when "done" - rc = self.finalize - else - error_msg = "Invalid state" - error = OpenNebula::Error.new(error_msg) - return error - end - - return rc - end - + def to_one_template() if @vm_info == nil error_msg = "Missing COMPUTE section in the XML body" return OpenNebula::Error.new(error_msg), 400 end - + if @template == nil return OpenNebula::Error.new("Bad instance type"), 500 end - + begin template = ERB.new(File.read(@common_template)).result(binding) template << ERB.new(File.read(@template)).result(binding) @@ -124,10 +110,10 @@ class VirtualMachineOCCI < VirtualMachine error = OpenNebula::Error.new(e.message) return error end - + return template end - + # Creates the VMI representation of a Virtual Machine def to_occi(base_url) begin @@ -138,9 +124,90 @@ class VirtualMachineOCCI < VirtualMachine return error end - return occi_vm_text.gsub(/\n\s*/,'') end + + # Update de resource from an XML representation of the COMPUTE + # @param [String] xml_compute XML representation of the COMPUTE + # @return [[nil, OpenNebula::Error], HTTP_CODE] If there is no error + #  the first component is nil. + def update_from_xml(xml_compute) + xmldoc = XMLElement.build_xml(xml_compute, 'COMPUTE') + vm_info = XMLElement.new(xmldoc) if xmldoc != nil + + action = nil + args = [] + + # Check if a state change is required + occi_state = vm_info['STATE'] + + if occi_state + # If a state is provided + occi_state.upcase! + if OCCI_ACTION.keys.include?(occi_state) + # If the requested state is one the OCCI action states + shash = OCCI_ACTION[occi_state] + if shash[:from].include?(state_str) + # Action to be performed + action = shash[:action] + elsif occi_state != state_str + # If the requested state is different from the resource + # state but it does not belong to the "from" state array + error_msg = "The state of the resource cannot be changed" \ + " from #{state_str} to #{occi_state}." + error = OpenNebula::Error.new(error_msg) + return error, 403 + end + elsif !VM_STATE.include?(occi_state) + # The requested state is not one of the OCCI action states nor + # a resource state + error_msg = "Invalid state: \"#{occi_state}\"" + error = OpenNebula::Error.new(error_msg) + return error, 400 + end + end + + # Check if a disk image save as is required + image_name = nil + vm_info.each('DISK/SAVE_AS') { |save_as| + image_name = save_as.attr('.', 'name') + if image_name + if action + # Return erro if an action has been defined before + if action == :save_as + error_msg = "Only one disk can be saved per request" + else + error_msg = "Changig the state of the resource and" \ + " saving a disk is not allowed in the same request" + end + error = OpenNebula::Error.new(error_msg) + return error, 403 + else + # if no action is defined yet and a save_as is requested + action = :save_as + disk_id = save_as.attr('..', 'id') + + # Params for the save_as action: + # save_as(disk_id, image_name) + args << disk_id.to_i + args << image_name + end + end + } + + # Perform the requested action + if action + rc = self.send(action, *args) + if OpenNebula.is_error?(rc) + return rc, CloudServer::HTTP_ERROR_CODE[rc.errno] + else + return nil, 202 + end + else + # There is no change requested + return nil, 200 + end + end end From 612dc314891a68fd7b8ab9e91ff9c198fe32b442 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Mon, 17 Oct 2011 18:40:19 +0200 Subject: [PATCH 16/27] feature #849: Add OCCI PUT compute tests --- .../remotes/quota/test/quota_spec.rb | 6 +- .../occi/test/fixtures/{ => user}/user.xml | 0 .../fixtures/{ => user}/user_collection.xml | 0 .../test/fixtures/vm_save_as/newcompute.xml | 1 + .../save_a_disk_and_change_state.xml | 1 + .../fixtures/vm_save_as/save_first_disk.xml | 1 + .../fixtures/vm_save_as/save_second_disk.xml | 1 + .../fixtures/vm_save_as/save_two_disks.xml | 1 + src/cloud/occi/test/spec/spec_helper.rb | 4 +- src/cloud/occi/test/spec/user_spec.rb | 4 +- src/cloud/occi/test/spec/vm_saveas_spec.rb | 77 +++++++++++++++++++ src/cloud/occi/test/templates/image1.template | 2 + src/cloud/occi/test/templates/image2.template | 3 + src/cloud/occi/test/templates/vm.template | 10 +++ src/cloud/occi/test/test.sh | 5 +- 15 files changed, 107 insertions(+), 9 deletions(-) rename src/cloud/occi/test/fixtures/{ => user}/user.xml (100%) rename src/cloud/occi/test/fixtures/{ => user}/user_collection.xml (100%) create mode 100644 src/cloud/occi/test/fixtures/vm_save_as/newcompute.xml create mode 100644 src/cloud/occi/test/fixtures/vm_save_as/save_a_disk_and_change_state.xml create mode 100644 src/cloud/occi/test/fixtures/vm_save_as/save_first_disk.xml create mode 100644 src/cloud/occi/test/fixtures/vm_save_as/save_second_disk.xml create mode 100644 src/cloud/occi/test/fixtures/vm_save_as/save_two_disks.xml create mode 100644 src/cloud/occi/test/spec/vm_saveas_spec.rb create mode 100644 src/cloud/occi/test/templates/image1.template create mode 100644 src/cloud/occi/test/templates/image2.template create mode 100644 src/cloud/occi/test/templates/vm.template diff --git a/src/authm_mad/remotes/quota/test/quota_spec.rb b/src/authm_mad/remotes/quota/test/quota_spec.rb index fd6d656f18..cf58842847 100644 --- a/src/authm_mad/remotes/quota/test/quota_spec.rb +++ b/src/authm_mad/remotes/quota/test/quota_spec.rb @@ -31,7 +31,7 @@ describe "Quota testing" do