From 0ed4a668c579c46803553e48601ee3d0c3875ed8 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Fri, 9 Jul 2010 12:42:26 +0200 Subject: [PATCH 01/27] feature #200 Added ImageManager for Image management in OCA --- src/oca/ruby/OpenNebula/Image.rb | 83 ++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/src/oca/ruby/OpenNebula/Image.rb b/src/oca/ruby/OpenNebula/Image.rb index a3150d6953..ed9f4c5afc 100644 --- a/src/oca/ruby/OpenNebula/Image.rb +++ b/src/oca/ruby/OpenNebula/Image.rb @@ -1,4 +1,5 @@ require 'OpenNebula/Pool' +require 'ftools' module OpenNebula class Image < PoolElement @@ -55,6 +56,7 @@ module OpenNebula super(xml,client) @client = client + @immanager = ImageManager.new end ####################################################################### @@ -97,6 +99,18 @@ module OpenNebula super(IMAGE_METHODS[:delete]) end + def copy(path, source) + @immanager.copy(path, source) + end + + def mk_datablock(size, fstype, source) + rc = @immanager.dd(size, source) + + return rc if OpenNebula.is_error?(rc) + + @immanager.mkfs(fstype, source) + end + ####################################################################### # Helpers to get Image information ####################################################################### @@ -132,6 +146,7 @@ module OpenNebula end private + def set_enabled(enabled) return Error.new('ID not defined') if !@pe_id @@ -160,4 +175,72 @@ module OpenNebula end end + + class ImageManager + # --------------------------------------------------------------------- + # Constants and Class Methods + # --------------------------------------------------------------------- + FS_UTILS = { + :dd => "/bin/dd", + :mkfs => "/bin/mkfs" + } + + + def copy(path, source) + if source.nil? and size.nil? + return OpenNebula::Error.new( + "Cannot copy image (Missing parameters), aborting.") + end + + if !File.copy(path, source) + return OpenNebula::Error.new( + "Cannot copy image, aborting.") + end + + return nil + end + + def dd(size, source) + if source.nil? and size.nil? + return OpenNebula::Error.new( + "Cannot create datablock " + + "(Missing parameters), aborting.") + end + + command = "" + command << FS_UTILS[:dd] + command << " if=/dev/zero of=#{source} ibs=1 count=1" + command << " obs=1048576 oseek=#{size}" + + local_command=LocalCommand.run(command) + + if local_command.code!=0 + return OpenNebula::Error.new( + "Cannot create datablock, aborting.") + end + + return nil + end + + def mkfs(fstype, source) + if source.nil? and fstype.nil? + return OpenNebula::Error.new( + "Cannot format datablock " + + "(Missing parameters), aborting.") + end + + command = "" + command << FS_UTILS[:mkfs] + command << " -t #{fstype} -F #{source}" + + local_command=LocalCommand.run(command) + + if local_command.code!=0 + return OpenNebula::Error.new( + "Cannot format datablock, aborting.") + end + + return nil + end + end end From 83454dfbd8c04e78421731ed94a4d5abbb36982c Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Sun, 11 Jul 2010 21:48:52 +0200 Subject: [PATCH 02/27] feature #200: Minor modifications to ImageManager class --- src/oca/ruby/OpenNebula/Image.rb | 97 +++++++++++++++----------------- 1 file changed, 44 insertions(+), 53 deletions(-) diff --git a/src/oca/ruby/OpenNebula/Image.rb b/src/oca/ruby/OpenNebula/Image.rb index ed9f4c5afc..aced329878 100644 --- a/src/oca/ruby/OpenNebula/Image.rb +++ b/src/oca/ruby/OpenNebula/Image.rb @@ -15,7 +15,7 @@ module OpenNebula :publish => "image.publish", :delete => "image.delete" } - + IMAGE_STATES=%w{INIT LOCKED READY USED DISABLED} SHORT_IMAGE_STATES={ @@ -25,7 +25,7 @@ module OpenNebula "USED" => "used", "DISABLED" => "disa" } - + IMAGE_TYPES=%w{OS CDROM DATABLOCK} SHORT_IMAGE_TYPES={ @@ -62,7 +62,7 @@ module OpenNebula ####################################################################### # XML-RPC Methods for the Image Object ####################################################################### - + def info() super(IMAGE_METHODS[:info], 'IMAGE') end @@ -70,27 +70,27 @@ module OpenNebula def allocate(description) super(IMAGE_METHODS[:allocate],description) end - + def update(name, value) super(IMAGE_METHODS[:update], name, value) end - + def remove_attr(name) do_rm_attr(name) end - + def enable - set_enabled(true) + set_enabled(true) end - + def disable - set_enabled(false) + set_enabled(false) end - + def publish set_publish(true) end - + def unpublish set_publish(false) end @@ -98,16 +98,16 @@ module OpenNebula def delete() super(IMAGE_METHODS[:delete]) end - + def copy(path, source) @immanager.copy(path, source) end - + def mk_datablock(size, fstype, source) rc = @immanager.dd(size, source) - + return rc if OpenNebula.is_error?(rc) - + @immanager.mkfs(fstype, source) end @@ -129,7 +129,7 @@ module OpenNebula def short_state_str SHORT_IMAGE_STATES[state_str] end - + # Returns the type of the Image (numeric value) def type self['TYPE'].to_i @@ -143,10 +143,10 @@ module OpenNebula # Returns the state of the Image (string value) def short_type_str SHORT_IMAGE_TYPES[type_str] - end - + end + private - + def set_enabled(enabled) return Error.new('ID not defined') if !@pe_id @@ -155,7 +155,7 @@ module OpenNebula return rc end - + def set_publish(published) return Error.new('ID not defined') if !@pe_id @@ -164,18 +164,18 @@ module OpenNebula return rc end - + def do_rm_attr(name) return Error.new('ID not defined') if !@pe_id rc = @client.call(IMAGE_METHODS[:rmattr], @pe_id, name) rc = nil if !OpenNebula.is_error?(rc) - return rc + return rc end end - + class ImageManager # --------------------------------------------------------------------- # Constants and Class Methods @@ -184,62 +184,53 @@ module OpenNebula :dd => "/bin/dd", :mkfs => "/bin/mkfs" } - - + def copy(path, source) - if source.nil? and size.nil? - return OpenNebula::Error.new( - "Cannot copy image (Missing parameters), aborting.") + if source.nil? or path.nil? + return OpenNebula::Error.new("copy Image: missing parameters.") end if !File.copy(path, source) - return OpenNebula::Error.new( - "Cannot copy image, aborting.") + return OpenNebula::Error.new("copy Image: in File.copy") end - + return nil end - + def dd(size, source) - if source.nil? and size.nil? - return OpenNebula::Error.new( - "Cannot create datablock " + - "(Missing parameters), aborting.") + if source.nil? or size.nil? + return OpenNebula::Error.new("dd Image: missing parameters.") end - + command = "" command << FS_UTILS[:dd] command << " if=/dev/zero of=#{source} ibs=1 count=1" command << " obs=1048576 oseek=#{size}" - + local_command=LocalCommand.run(command) - + if local_command.code!=0 - return OpenNebula::Error.new( - "Cannot create datablock, aborting.") + return OpenNebula::Error.new("dd Image: in dd command.") end - + return nil end - + def mkfs(fstype, source) - if source.nil? and fstype.nil? - return OpenNebula::Error.new( - "Cannot format datablock " + - "(Missing parameters), aborting.") + if source.nil? or fstype.nil? + return OpenNebula::Error.new("mkfs Image: missing parameters.") end - + command = "" command << FS_UTILS[:mkfs] command << " -t #{fstype} -F #{source}" - + local_command=LocalCommand.run(command) - + if local_command.code!=0 - return OpenNebula::Error.new( - "Cannot format datablock, aborting.") + return OpenNebula::Error.new("mkfs Image: in mkfs command.") end - + return nil end end From c0149a5bb161cddc6f7696ceb20cb35a563661d7 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Thu, 15 Jul 2010 17:04:37 +0200 Subject: [PATCH 03/27] feature #200 Changed OCCI XML Representation --- src/cloud/common/CloudServer.rb | 81 +++- src/cloud/occi/bin/occi-storage | 12 +- src/cloud/occi/etc/templates/large.erb | 81 ++-- src/cloud/occi/lib/ImageOCCI.rb | 70 ++- src/cloud/occi/lib/ImagePoolOCCI.rb | 36 +- src/cloud/occi/lib/OCCIClient.rb | 24 +- src/cloud/occi/lib/OCCIServer.rb | 454 +++++++++---------- src/cloud/occi/lib/VirtualMachineOCCI.rb | 147 ++++-- src/cloud/occi/lib/VirtualMachinePoolOCCI.rb | 48 +- src/cloud/occi/lib/VirtualNetworkOCCI.rb | 60 ++- src/cloud/occi/lib/VirtualNetworkPoolOCCI.rb | 56 ++- src/cloud/occi/lib/occi-server.rb | 2 + src/oca/ruby/OpenNebula/XMLUtils.rb | 7 +- 13 files changed, 661 insertions(+), 417 deletions(-) diff --git a/src/cloud/common/CloudServer.rb b/src/cloud/common/CloudServer.rb index a76a6a5040..74b2d62985 100755 --- a/src/cloud/common/CloudServer.rb +++ b/src/cloud/common/CloudServer.rb @@ -14,7 +14,6 @@ # limitations under the License. # #--------------------------------------------------------------------------- # -require 'repo_manager' require 'Configuration' require 'OpenNebula' require 'pp' @@ -55,11 +54,6 @@ class CloudServer @instance_types[@config[:vm_type]['NAME']]=@config[:vm_type] end - # --- Start a Repository Manager --- - - @rm = RepoManager.new(@config[:database]) - Image.image_dir = @config[:image_dir] - # --- Start an OpenNebula Session --- @one_client = Client.new() @@ -124,6 +118,31 @@ class CloudServer return user end + def xml_to_hash(xml) + begin + hash = Crack::XML.parse(xml) + rescue Exception => e + error = OpenNebula::Error.new(e.message) + return error + end + + return hash + end + + def get_template_path(instance_type_name) + if instance_type_name.nil? + instance_type=@instance_types.first + end + + instance_type=@instance_types[instance_type_name] + + if !instance_type + error = OpenNebula::Error.new("Bad instance type") + return error + end + + return @config[:template_location]+"/#{instance_type['TEMPLATE']}" + end ########################################################################### # Repository Methods @@ -134,18 +153,58 @@ class CloudServer # path:: _String_ path of the tmp file # metadata:: Additional metadata for the file # [return] _Image_ Newly created image object - def add_image(uid, file, metadata={}) - image = @rm.add(uid,file.path,metadata) - file.unlink + def add_image(image, file=nil) + if file + if file[:tempfile] + file_path = file[:tempfile].path + else + error_msg = "Image not present, aborting." + error = OpenNebula::Error.new(error_msg) + return error + end + + if !File.exists?(file_path) + error_msg = "Image file could not be found, aborting." + error = OpenNebula::Error.new(error_msg) + return error + end + end + + template = image.to_one_template - return image + rc = image.allocate(template) + if OpenNebula.is_error?(rc) + return rc + end + + # Copy the Image file + image.info + template=image.to_hash + template=template['IMAGE']['TEMPLATE'] + + if file_path + rc = image.copy(file_path, image['SOURCE']) + file[:tempfile].unlink + elsif template['SIZE'] and template['FSTYPE'] + rc = image.mk_datablock( + template['SIZE'], + template['FSTYPE'], + image['SOURCE']) + end + + if OpenNebula.is_error?(rc) + image.delete + return rc + end + + return nil end # Gets an image from the repository # image_id:: _Integer_ Image identifier # [return] _Image_ Image object def get_image(image_id) - return @rm.get(image_id) + return nil end end diff --git a/src/cloud/occi/bin/occi-storage b/src/cloud/occi/bin/occi-storage index 3e6e2dbf0d..93b6436d3f 100755 --- a/src/cloud/occi/bin/occi-storage +++ b/src/cloud/occi/bin/occi-storage @@ -82,7 +82,7 @@ require 'occi/OCCIClient' require 'CloudClient' require 'getoptlong' require "rexml/document" - +require 'pp' include CloudCLI opts = GetoptLong.new( @@ -166,8 +166,14 @@ case ARGV[0].downcase rc = occi_client.get_image(image_id) when 'delete' - puts 'Delete not yet implemented' - exit(-1) + image_id = ARGV[1] + + if !image_id + puts "#{cmd_name} show: missing storage id parameter" + exit(-1) + end + + rc = occi_client.delete_image(image_id) else puts "Command #{ARGV[0]} not valid." diff --git a/src/cloud/occi/etc/templates/large.erb b/src/cloud/occi/etc/templates/large.erb index b88a916363..cbc429b343 100644 --- a/src/cloud/occi/etc/templates/large.erb +++ b/src/cloud/occi/etc/templates/large.erb @@ -1,55 +1,34 @@ -NAME = <%= vm_info['NAME']%> - CPU = 8 MEMORY = 8192 -OS = [ kernel = /vmlinuz, - initrd = /initrd.img, - root = sda1, - kernel_cmd = "ro xencons=tty console=tty1"] - -<% if vm_info['STORAGE'] - vm_info['STORAGE'].each do |key, image| - image=[image].flatten -case key - when "SWAP" - image.each do |img| -%> -DISK = [ type = "swap", - size=<%= img['size']%>, - target=<%= img['dev']%> ] -<% - end - when "DISK" - image.each do |img| -%> -DISK = [ type = "disk", - target=<%= img['dev']%>, - source=<%= img['source']%>, - image_id=<%= img['image']%> ] -<% - end - when "FS" - image.each do |img| -%> -DISK = [ type = "fs", - target=<%= img['dev']%>, - size=<%= img['size']%>, - format=<%= @config[:fs_format]||"ext3"%> ] -<% end %> -<% end %> -<% end %> -<% end %> -<% if vm_info['NETWORK'] and vm_info['NETWORK']['NIC'] %> -<% vm_info['NETWORK']['NIC'].each do |nic| %> -NIC = [ -<% if nic['ip'] %> - IP=<%= nic['ip'] %>, -<% end %> - NETWORK="<%= nic['network']%>", - NETWORK_ID=<%= nic['network_id'] %> -] -<% end %> -<% end %> -INSTANCE_TYPE = <%= vm_info[:instance_type ]%> +NAME = <%= vm_info['NAME'] %> + +<% if vm_info['DISK'] %> + <% vm_info['DISK'].each do |disk| %> + <% if disk['STORAGE'] && disk['STORAGE']['href'] %> + DISK = [ IMAGE_ID = <%= disk['STORAGE']['href'].split('/').last %> + <% if disk['OVERWRITE'] %> + OVERWRITE = yes + <% end %> + <% if disk['SAVE_AS'] %> + SAVE_AS = "<%= disk['SAVE_AS'] %>" + <% end %> + ] + <% end %> + <% end %> +<% end %> + +<% if vm_info['NIC'] %> + <% vm_info['NIC'].each do |nic| %> + <% if nic['NETWORK'] && nic['NETWORK']['href'] %> + NIC = [ NETWORK_ID = <%= nic['NETWORK']['href'].split('/').last %>, + <% if nic['IP'] %> + IP = <%= nic['IP'] %> + <% end %> + ] + <% end %> + <% end %> +<% end %> + +INSTANCE_TYPE = <%= vm_info['INSTANCE_TYPE']%> diff --git a/src/cloud/occi/lib/ImageOCCI.rb b/src/cloud/occi/lib/ImageOCCI.rb index 781423a5c9..acee97b1eb 100755 --- a/src/cloud/occi/lib/ImageOCCI.rb +++ b/src/cloud/occi/lib/ImageOCCI.rb @@ -15,24 +15,82 @@ #--------------------------------------------------------------------------- # require 'OpenNebula' -require 'erb' include OpenNebula -module ImageOCCI +class ImageOCCI < Image OCCI_IMAGE = %q{ - <%= self.id %> - <%= name %> - <%= ((size/1024)/1024).to_s %> - <%= description %> + <%= self.id.to_s %> + <%= self.name %> + <% if template['TYPE'] %> + <%= template['TYPE'] %> + <% end %> + <% if template['DESCRIPTION'] %> + <%= template['DESCRIPTION'] %> + <% end %> + <% if size %> + <%= size %> + <% end %> } + ONE_IMAGE = %q{ + NAME = "<%= image_info['NAME'] %>" + <% if image_info['DESCRIPTION'] %> + DESCRIPTION = "<%= image_info['DESCRIPTION'] %>" + <% end %> + <% if image_info['TYPE'] %> + TYPE = <%= image_info['TYPE'] %> + <% end %> + <% if image_info['FSTYPE'] %> + FSTYPE = <%= image_info['FSTYPE'] %> + <% end %> + <% if image_info['SIZE'] %> + SIZE = <%= image_info['SIZE'] %> + <% end %> + }.gsub(/^ /, '') + + # Class constructor + def initialize(image_info, xml, client) + super(xml, client) + + @image_info = image_info + end + # Creates the OCCI representation of an Image def to_occi() + image_hash = self.to_hash + return image_hash, 500 if OpenNebula.is_error?(image_hash) + + template = image_hash['IMAGE']['TEMPLATE'] + begin + size = File.stat(template['SOURCE']).size if template['SOURCE'] + rescue Exception => e + error = OpenNebula::Error.new(e.message) + return error + end + occi = ERB.new(OCCI_IMAGE) return occi.result(binding).gsub(/\n\s*/,'') end + + def to_one_template() + if @image_info['STORAGE'] + image_info = @image_info['STORAGE'] + if !image_info['NAME'] + error_msg = "Missing Image NAME in the XML DISK section" + error = OpenNebula::Error.new(error_msg) + return error + end + else + error_msg = "Missing STORAGE section in the XML body" + error = OpenNebula::Error.new(error_msg) + return error + end + + one = ERB.new(ONE_IMAGE) + return one.result(binding) + end end diff --git a/src/cloud/occi/lib/ImagePoolOCCI.rb b/src/cloud/occi/lib/ImagePoolOCCI.rb index 596c139575..ebc73dd0b3 100755 --- a/src/cloud/occi/lib/ImagePoolOCCI.rb +++ b/src/cloud/occi/lib/ImagePoolOCCI.rb @@ -16,25 +16,35 @@ require 'OpenNebula' - include OpenNebula -class ImagePoolOCCI +class ImagePoolOCCI < ImagePool OCCI_IMAGE_POOL = %q{ - <% - for image in @images do %> - <% - end %> - + + <% if pool_hash['IMAGE_POOL'] && pool_hash['IMAGE_POOL']['IMAGE'] %> + <% imagelist=[pool_hash['IMAGE_POOL']['IMAGE']].flatten %> + <% imagelist.each{ |image| %> + + <% } %> + <% end %> + } - - def initialize(user_id) - @images=Image.filter(:owner => user_id) - end + + # Creates the OCCI representation of a Virtual Machine Pool def to_occi(base_url) - occi = ERB.new(OCCI_IMAGE_POOL) - return occi.result(binding).gsub(/\n\s*/,'') + pool_hash = self.to_hash + return pool_hash, 500 if OpenNebula.is_error?(pool_hash) + + begin + occi = ERB.new(OCCI_IMAGE_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 diff --git a/src/cloud/occi/lib/OCCIClient.rb b/src/cloud/occi/lib/OCCIClient.rb index ab94afe059..25e29edc74 100755 --- a/src/cloud/occi/lib/OCCIClient.rb +++ b/src/cloud/occi/lib/OCCIClient.rb @@ -164,7 +164,7 @@ module OCCIClient xml=File.read(xmlfile) image_info=Crack::XML.parse(xml) - file_path = image_info['DISK']['URL'] + file_path = image_info['STORAGE']['URL'] m=file_path.match(/^\w+:\/\/(.*)$/) @@ -210,7 +210,7 @@ module OCCIClient end file.close - + pp res if CloudClient::is_error?(res) return res else @@ -370,5 +370,25 @@ module OCCIClient return res.body end end + + ###################################################################### + # :id VM identifier + ###################################################################### + def delete_image(id) + url = URI.parse(@endpoint+"/storage/" + id.to_s) + req = Net::HTTP::Delete.new(url.path) + + req.basic_auth @occiauth[0], @occiauth[1] + + res = CloudClient::http_start(url, @timeout) {|http| + http.request(req) + } + + if CloudClient::is_error?(res) + return res + else + return res.body + end + end end end diff --git a/src/cloud/occi/lib/OCCIServer.rb b/src/cloud/occi/lib/OCCIServer.rb index 4e46eef40c..8b10e079fc 100755 --- a/src/cloud/occi/lib/OCCIServer.rb +++ b/src/cloud/occi/lib/OCCIServer.rb @@ -31,7 +31,7 @@ require 'VirtualNetworkPoolOCCI' require 'ImageOCCI' require 'ImagePoolOCCI' -include ImageOCCI +require 'pp' ############################################################################## @@ -102,153 +102,110 @@ class OCCIServer < CloudServer # request:: _Hash_ hash containing the data of the request # [return] _String_,_Integer_ COMPUTE Representation or error, status code def post_compute(request) - # Get client with user credentials + # --- Get client with user credentials --- client = get_client(request.env) + # --- Check OCCI XML from POST --- if request.body - vm_info=Crack::XML.parse(request.body.read) + vm_info = xml_to_hash(request.body.read) + return vm_info, 400 if OpenNebula.is_error?(vm_info) else - error = OpenNebula::Error.new( - "OCCI XML representation of VM not present") + error_msg = "OCCI XML representation of VM not present" + error = OpenNebula::Error.new(error_msg) return error, 400 end - vm_info=vm_info['COMPUTE'] - - disks=vm_info['STORAGE'] - - disks['DISK']=[disks['DISK']].flatten if disks and disks['DISK'] - - disks['DISK'].each{|disk| - next if !disk['image'] - image = get_image(disk['image']) - if !image - error = OpenNebula::Error.new( - "Invalid image (#{disk['image']}) referred") - return error, 400 - end - disk['source']=image.path - } if disks and disks['DISK'] - - vm_info['STORAGE']=disks - - if vm_info['NETWORK'] and vm_info['NETWORK']['NIC'] - - if vm_info['NETWORK']['NIC'].class==Array - nics=vm_info['NETWORK']['NIC'] - else - nics=[vm_info['NETWORK']['NIC']] - end - - nics.each{|nic| - next if nic==nil - vn=VirtualNetwork.new( - VirtualNetwork.build_xml(nic['network']), - client) - vn.info - vn_xml=Crack::XML.parse(vn.to_xml) - if !vn_xml['VNET']['NAME'] - error = OpenNebula::Error.new( - "Invalid network referred") - return error, 400 - end - nic['network_id']=nic['network'] - nic['network']=vn_xml['VNET']['NAME'].strip - } if nics - - vm_info['NETWORK']['NIC']=nics + # --- Get Template Path --- + if vm_info['COMPUTE'] + template_path = get_template_path( + vm_info['COMPUTE']['INSTANCE_TYPE']) end - - instance_type_name=vm_info['INSTANCE_TYPE'] - instance_type=@instance_types[instance_type_name] - - if !instance_type - error = OpenNebula::Error.new("Bad instance type") - return error, 400 - end - - vm_info[:instance_type]=instance_type_name - - template=ERB.new(File.read( - @config[:template_location]+"/#{instance_type['TEMPLATE']}")) - template_text=template.result(binding) - - vm=VirtualMachineOCCI.new( + return template_path, 500 if OpenNebula.is_error?(template_path) + + vm_info['TEMPLATE_PATH'] = template_path + + # --- Create the new Instance --- + vm = VirtualMachineOCCI.new( + vm_info, VirtualMachine.build_xml, client) - response=vm.allocate(template_text) - if OpenNebula.is_error?(response) - return response, 400 - else - vm.info - return vm.to_occi(@base_url), 201 - end + # --- Generate the template and Allocate the new Instance --- + template = vm.to_one_template + return template, 500 if OpenNebula.is_error?(template) + + rc = vm.allocate(template) + return rc, 500 if OpenNebula.is_error?(rc) + + # --- Prepare XML Response --- + vm.info + xml_response = vm.to_occi(@base_url) + return xml_response, 500 if OpenNebula.is_error?(xml_response) + + return xml_response, 201 end # Gets the pool representation of COMPUTES # request:: _Hash_ hash containing the data of the request # [return] _String_,_Integer_ Pool Representation or error, status code def get_computes(request) - # Get client with user credentials + # --- Get client with user credentials --- client = get_client(request.env) - # Just show resources from the user making the request + # --- Get User's VMs --- user_flag = -1 - - vmpool = VirtualMachinePoolOCCI.new(client,user_flag) - vmpool.info - - # OCCI conversion - begin - compute_xml = vmpool.to_occi(@base_url) - return compute_xml, 200 - rescue Exception => e - error = OpenNebula::Error.new(e.message) - return error, 500 - end + vmpool = VirtualMachinePoolOCCI.new(client, user_flag) + + rc = vmpool.info + return rc, 404 if OpenNebula.is_error?(rc) + + # --- Prepare XML Response --- + xml_response = vmpool.to_occi(@base_url) + return xml_response, 500 if OpenNebula.is_error?(xml_response) + + return xml_response, 201 end # Post a new network to the NETWORK pool # request:: _Hash_ hash containing the data of the request # [return] _String_,_Integer_ Network Representation or error, status code def post_network(request) - # Get client with user credentials + # --- Get client with user credentials --- client = get_client(request.env) - - # Info retrieval from post params + + # --- Check OCCI XML from POST --- if request.body - network_info=Crack::XML.parse(request.body.read) + network_info = xml_to_hash(request.body.read) + return network_info, 400 if OpenNebula.is_error?(network_info) else - error_msg = "OCCI XML representation of Virtual Network" + - " not present in the request" - error = OpenNebula::Error.new(error_msg) - return error, 400 + error_msg = "OCCI XML representation of VNET not present" + error = OpenNebula::Error.new(error_msg) + return error, 400 end - # Allocate the VirtualNetwork + + if network_info['NETWORK'] + network_info['NETWORK']['BRIDGE'] = @config[:bridge] + end + + # --- Create the new Instance --- network = VirtualNetworkOCCI.new( - VirtualNetwork.build_xml, - client) + network_info, + VirtualNetwork.build_xml, + client) - begin - vntemplate = network.to_one_template( - network_info['NETWORK'], - @config[:bridge]) - rc = network.allocate(vntemplate) + # --- Generate the template and Allocate the new Instance --- + template = network.to_one_template + return template, 500 if OpenNebula.is_error?(template) - if OpenNebula::is_error?(rc) - return rc, 404 - end + rc = network.allocate(template) + return rc, 500 if OpenNebula.is_error?(rc) - network.info - network_xml = network.to_occi - return network_xml, 201 - rescue Exception => e - error_msg = "Error creating the Virtual Network:" + e.to_s - error_msg = ".Reason:" + rc if rc - error = OpenNebula::Error.new(error_msg) - return error, 500 - end + # --- Prepare XML Response --- + network.info + xml_response = network.to_occi + return xml_response, 500 if OpenNebula.is_error?(xml_response) + + return xml_response, 201 end # Gets the pool representation of NETWORKS @@ -256,54 +213,52 @@ class OCCIServer < CloudServer # [return] _String_,_Integer_ Network pool representation or error, # => status code def get_networks(request) - # Get client with user credentials + # --- Get client with user credentials --- client = get_client(request.env) + + # --- Get User's VNETs --- + user_flag = -1 + network_pool = VirtualNetworkPoolOCCI.new(client, user_flag) - # Info retrieval - network_pool = VirtualNetworkPoolOCCI.new(client) - network_pool.info - # OCCI conversion - begin - network_pool.to_occi(@base_url) - rescue Exception => e - error = OpenNebula::Error.new(e.message) - return error, 500 - end + rc = network_pool.info + return rc, 404 if OpenNebula.is_error?(rc) + + # --- Prepare XML Response --- + xml_response = network_pool.to_occi(@base_url) + return xml_response, 500 if OpenNebula.is_error?(xml_response) + + return xml_response, 201 end # Post a new image to the STORAGE pool # request:: _Hash_ hash containing the data of the request # [return] _String_,_Integer_ Image representation or error, status code def post_storage(request) - # Info retrieval from post params + # Get client with user credentials + client = get_client(request.env) + + # --- Check OCCI XML from POST --- if request.params['occixml'] - image_info=Crack::XML.parse(request.params['occixml']) + image_info = xml_to_hash(request.params['occixml']) + return image_info, 400 if OpenNebula.is_error?(image_info) else error_msg = "OCCI XML representation of Image" + " not present in the request" - error = OpenNebula::Error.new(error_msg) + error = OpenNebula::Error.new(error_msg) return error, 400 end + + # --- Create and Add the new Image --- + image = ImageOCCI.new(image_info, Image.build_xml, client) - if request.params['file'] - file=request.params["file"] - else - error_msg = "File not present in the request" - error = OpenNebula::Error.new(error_msg) - return error, 400 - end - - user = get_user(request.env) - - # tmpfile where the file is stored - f_tmp=file[:tempfile] - img=add_image(user[:id], f_tmp, {:name=>image_info['DISK']['NAME'], - :description=>image_info['DISK']['URL']}) - - img.extend(ImageOCCI) - xml_response = img.to_occi + rc = add_image(image, request.params['file']) + return rc, 500 if OpenNebula.is_error?(rc) - return xml_response, 201 + # --- Enable the new Image --- + rc = image.enable + return rc, 500 if OpenNebula.is_error?(rc) + + return image.to_occi, 201 end # Gets the pool representation of STORAGES @@ -311,11 +266,21 @@ class OCCIServer < CloudServer # [return] _String_,_Integer_ Image pool representation or error, # status code def get_storages(request) - # Retrieve images owned by this user - user = get_user(request.env) - - image_pool = ImagePoolOCCI.new(user[:id]) - return image_pool.to_occi(@base_url), 200 + # --- Get client with user credentials --- + client = get_client(request.env) + + # --- Get User's Images --- + user_flag = -1 + image_pool = ImagePoolOCCI.new(client, user_flag) + + result = image_pool.info + return result, 404 if OpenNebula.is_error?(result) + + # --- Prepare XML Response --- + xml_response = image_pool.to_occi(@base_url) + return xml_response, 500 if OpenNebula.is_error?(xml_response) + + return xml_response, 201 end ################################################### @@ -327,27 +292,23 @@ class OCCIServer < CloudServer # [return] _String_,_Integer_ COMPUTE representation or error, # status code def get_compute(request, params) - # Get client with user credentials + # --- Get client with user credentials --- client = get_client(request.env) - + + # --- Get the VM --- vm = VirtualMachineOCCI.new( - VirtualMachine.build_xml(params[:id]), - client) + nil, + VirtualMachine.build_xml(params[:id]), + client) - result=vm.info + result = vm.info + return result, 404 if OpenNebula::is_error?(result) - if OpenNebula::is_error?(result) - return result, 404 - end - - begin - return vm.to_occi(@base_url), 200 - rescue Exception => e - error_msg = "Error converting COMPUTE resource to OCCI format" - error_msg = "\n Reason: " + e.message - error = OpenNebula::Error.new(error_msg) - return error, 500 - end + # --- Prepare XML Response --- + xml_response = vm.to_occi(@base_url) + return xml_response, 500 if OpenNebula.is_error?(xml_response) + + return xml_response, 201 end # Deletes a COMPUTE resource @@ -355,20 +316,20 @@ class OCCIServer < CloudServer # [return] _String_,_Integer_ Delete confirmation msg or error, # status code def delete_compute(request, params) - # Get client with user credentials + # --- Get client with user credentials --- client = get_client(request.env) vm = VirtualMachineOCCI.new( + nil, VirtualMachine.build_xml(params[:id]), client) + # --- Finalize the VM --- result = vm.finalize + pp result + return result, 500 if OpenNebula::is_error?(result) - if OpenNebula::is_error?(result) - return result, 500 - else - return "", 204 - end + return "", 204 end # Updates a COMPUTE resource @@ -376,53 +337,40 @@ class OCCIServer < CloudServer # [return] _String_,_Integer_ Update confirmation msg or error, # status code def put_compute(request, params) - # Get client with user credentials + # --- Get client with user credentials --- client = get_client(request.env) - + + # --- Check OCCI XML from POST --- if request.body - vm_info=Crack::XML.parse(request.body.read) + vm_info = xml_to_hash(request.body.read) + return vm_info, 400 if OpenNebula.is_error?(vm_info) else error_msg = "OCCI XML representation of VM not present" - error = OpenNebula::Error.new(error_msg) + error = OpenNebula::Error.new(error_msg) return error, 400 end - vm=VirtualMachineOCCI.new( - VirtualMachine.build_xml(params[:id]), - client) - - if !vm_info['COMPUTE']['STATE'] - error_msg = "State not defined in the OCCI XML" - error = OpenNebula::Error.new(error_msg) + # --- Get the VM and Action on it --- + if vm_info['COMPUTE'] && vm_info['COMPUTE']['STATE'] + vm = VirtualMachineOCCI.new( + vm_info, + VirtualMachine.build_xml(params[:id]), + client) + + rc = vm.mk_action(vm_info['COMPUTE']['STATE']) + return rc, 400 if OpenNebula.is_error?(rc) + else + error_msg = "State not defined in the OCCI XML" + error = OpenNebula::Error.new(error_msg) return error, 400 end - - case vm_info['COMPUTE']['STATE'].downcase - when "stopped" - rc = vm.stop - when "suspended" - rc = vm.suspend - when "resume" - rc = vm.resume - when "cancel" - rc = vm.cancel - when "shutdown" - rc = vm.shutdown - when "done" - rc = vm.finalize - else - error_msg = "Invalid state" - error = OpenNebula::Error.new(error_msg) - return error, 400 - end - - if OpenNebula.is_error?(rc) - return rc, 400 - else - vm.info - response_text = vm.to_occi(@base_url) - return response_text, 202 - end + + # --- Prepare XML Response --- + vm.info + xml_response = vm.to_occi(@base_url) + return xml_response, 500 if OpenNebula.is_error?(xml_response) + + return xml_response, 202 end # Retrieves a NETWORK resource @@ -430,25 +378,23 @@ class OCCIServer < CloudServer # [return] _String_,_Integer_ NETWORK occi representation or error, # status code def get_network(request, params) - # Get client with user credentials + # --- Get client with user credentials --- client = get_client(request.env) + + # --- Get the VM --- + vn = VirtualNetworkOCCI.new( + nil, + VirtualNetwork.build_xml(params[:id]), + client) + + result = vn.info + return result, 404 if OpenNebula::is_error?(result) + + # --- Prepare XML Response --- + xml_response = vn.to_occi + return xml_response, 500 if OpenNebula.is_error?(xml_response) - vn = VirtualNetworkOCCI.new( - VirtualNetwork.build_xml(params[:id]), - client) - - result=vn.info - - if OpenNebula::is_error?(result) - return result, 404 - end - - begin - return vn.to_occi, 200 - rescue Exception => e - error = OpenNebula::Error.new(e.message) - return error, 500 - end + return xml_response, 200 end # Deletes a NETWORK resource @@ -456,20 +402,19 @@ class OCCIServer < CloudServer # [return] _String_,_Integer_ Delete confirmation msg or error, # status code def delete_network(request, params) - # Get client with user credentials + # --- Get client with user credentials --- client = get_client(request.env) vn = VirtualNetworkOCCI.new( + nil, VirtualNetwork.build_xml(params[:id]), client) - + + # --- Delete the VNET --- result = vn.delete - - if OpenNebula::is_error?(result) - return result, 500 - else - return "", 204 - end + return result, 500 if OpenNebula::is_error?(result) + + return "", 204 end # Get a STORAGE resource @@ -477,19 +422,20 @@ class OCCIServer < CloudServer # [return] _String_,_Integer_ STORAGE occi representation or error, # status code def get_storage(request, params) - # Get client with user credentials + # --- Get client with user credentials --- client = get_client(request.env) - - image=get_image(params[:id]) - if image - image.extend(ImageOCCI) - return image.to_occi, 200 - else - msg="Disk with id = \"" + params[:id] + "\" not found" - error = OpenNebula::Error.new(msg) - return error, 404 - end + # --- Get the Image --- + image = ImageOCCI.new(nil, Image.build_xml(params[:id]), client) + + result = image.info + return result, 404 if OpenNebula::is_error?(result) + + # --- Prepare XML Response --- + xml_response = image.to_occi + return xml_response, 500 if OpenNebula.is_error?(xml_response) + + return xml_response, 200 end # Deletes a STORAGE resource (Not yet implemented) @@ -497,7 +443,15 @@ class OCCIServer < CloudServer # [return] _String_,_Integer_ Delete confirmation msg or error, # status code def delete_storage(request, params) - error = OpenNebula::Error.new("Not yet implemented") - return error, 501 + # --- Get client with user credentials --- + client = get_client(request.env) + + image = ImageOCCI.new(nil, Image.build_xml(params[:id]), client) + + # --- Delete the Image --- + result = image.delete + return result, 500 if OpenNebula::is_error?(result) + + return "", 204 end end diff --git a/src/cloud/occi/lib/VirtualMachineOCCI.rb b/src/cloud/occi/lib/VirtualMachineOCCI.rb index 3b0923de50..1f9954cab6 100755 --- a/src/cloud/occi/lib/VirtualMachineOCCI.rb +++ b/src/cloud/occi/lib/VirtualMachineOCCI.rb @@ -1,3 +1,19 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2010, 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 @@ -5,50 +21,111 @@ include OpenNebula class VirtualMachineOCCI < VirtualMachine OCCI_VM = %q{ - <%= id.to_s%> - <%= self['NAME']%> - <%= state_str %> - <% if template['DISK']!=nil - %><% - template['DISK'].each do |disk| - next if !disk - case disk['TYPE'] - when "swap"%> - <% when "fs" %> - <% - else %> - <% - end - end %> - - <% end - if template['NIC'] - %><% - template['NIC'].each do |nic| - next if !nic %> - ip="<%= nic['IP']%>"<% end %>/><% - end - %> - <% - end - if template['INSTANCE_TYPE'] %> - <%=template['INSTANCE_TYPE']%><% - end %> + <%= self.id.to_s%> + <%= self.name%> + <% if template['INSTANCE_TYPE'] %> + <%= template['INSTANCE_TYPE'] %> + <% end %> + <%= self.state_str %> + <% if template['DISK'] %> + <% template['DISK'].each do |disk| %> + + + <%= disk['NAME'] %> + <%= disk['TYPE'] %> + <%= disk['TARGET'] %> + <% if disk['CLONE'] %> + + <% end %> + <% if disk['SAVE_AS'] %> + <%= disk['SAVE_AS'] %> + <% end %> + + <% end %> + <% end %> + <% if template['NIC'] %> + <% template['NIC'].each do |nic| %> + + + <% if nic['IP'] %> + <%= nic['IP'] %> + <% end %> + + <% end %> + <% end %> } + # Class constructor + def initialize(vm_info, xml, client) + super(xml, client) + + @vm_info = vm_info + 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['COMPUTE'] + vm_info = @vm_info['COMPUTE'] + vm_info['DISK'] = [vm_info['DISK']].flatten if vm_info['DISK'] + vm_info['NIC'] = [vm_info['NIC']].flatten if vm_info['NIC'] + else + error_msg = "Missing COMPUTE section in the XML body" + error = OpenNebula::Error.new(error_msg) + return error, 400 + end + + begin + template = ERB.new(File.read(@vm_info['TEMPLATE_PATH'])) + template_text = template.result(binding) + rescue Exception => e + error = OpenNebula::Error.new(e.message) + return error + end + + return template_text + end # Creates the VMI representation of a Virtual Machine def to_occi(base_url) - # Let's parse the template - template=self.to_hash - template=template['VM']['TEMPLATE'] + vm_hash = self.to_hash + return vm_hash, 500 if OpenNebula.is_error?(vm_hash) + + template = vm_hash['VM']['TEMPLATE'] template['DISK']=[template['DISK']].flatten if template['DISK'] template['NIC']=[template['NIC']].flatten if template['NIC'] - - occi = ERB.new(OCCI_VM) - return occi.result(binding).gsub(/\n\s*/,'') + begin + occi_vm = ERB.new(OCCI_VM) + occi_vm_text = occi_vm.result(binding) + rescue Exception => e + error = OpenNebula::Error.new(e.message) + return error + end + + return occi_vm_text.gsub(/\n\s*/,'') end end diff --git a/src/cloud/occi/lib/VirtualMachinePoolOCCI.rb b/src/cloud/occi/lib/VirtualMachinePoolOCCI.rb index 2488f491b1..40f2910a0d 100755 --- a/src/cloud/occi/lib/VirtualMachinePoolOCCI.rb +++ b/src/cloud/occi/lib/VirtualMachinePoolOCCI.rb @@ -1,26 +1,50 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2010, 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 VirtualMachinePoolOCCI < VirtualMachinePool OCCI_VM_POOL = %q{ - <% - if pool_hash['VM_POOL'] != nil - vmlist=[pool_hash['VM_POOL']['VM']].flatten - vmlist.each{|vm| %> - <% - } - end %> - + + <% if pool_hash['VM_POOL'] && pool_hash['VM_POOL']['VM'] %> + <% vmlist=[pool_hash['VM_POOL']['VM']].flatten %> + <% vmlist.each{ |vm| %> + + <% } %> + <% end %> + } # Creates the OCCI representation of a Virtual Machine Pool def to_occi(base_url) - pool_hash=to_hash - - occi = ERB.new(OCCI_VM_POOL) - return occi.result(binding).gsub(/\n\s*/,'') + pool_hash = self.to_hash + return pool_hash, 500 if OpenNebula.is_error?(pool_hash) + + begin + occi = ERB.new(OCCI_VM_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 diff --git a/src/cloud/occi/lib/VirtualNetworkOCCI.rb b/src/cloud/occi/lib/VirtualNetworkOCCI.rb index 7da7094b14..b2a46e415b 100755 --- a/src/cloud/occi/lib/VirtualNetworkOCCI.rb +++ b/src/cloud/occi/lib/VirtualNetworkOCCI.rb @@ -15,38 +15,64 @@ #--------------------------------------------------------------------------- # require 'OpenNebula' -require 'erb' include OpenNebula class VirtualNetworkOCCI < VirtualNetwork OCCI_NETWORK = %q{ - <%= vn_hash['VNET']['ID'].strip %> - <%= vn_hash['VNET']['NAME'].strip %> -
<%= vn_hash['VNET']['TEMPLATE']['NETWORK_ADDRESS'].strip %>
- <%= vn_hash['VNET']['TEMPLATE']['NETWORK_SIZE'].strip %> + <%= self.id.to_s %> + <%= self.name %> +
<%= template['NETWORK_ADDRESS'] %>
+ <% if template['NETWORK_SIZE'] %> + <%= template['NETWORK_SIZE'] %> + <% end %>
} ONE_NETWORK = %q{ - NAME = <%= network_hash['NAME'] %> + NAME = <%= vnet_info['NAME'] %> TYPE = RANGED - BRIDGE = <%= bridge %> - NETWORK_ADDRESS = <%= network_hash['ADDRESS'] %> - NETWORK_SIZE = <%= network_hash['SIZE'] %> + BRIDGE = <%= vnet_info['BRIDGE'] %> + NETWORK_ADDRESS = <%= vnet_info['ADDRESS'] %> + NETWORK_SIZE = <%= vnet_info['SIZE'] %> }.gsub(/^ /, '') - # Creates the OCCI representation of a Virtual Network - def to_occi() - vn_hash = to_hash + # Class constructor + def initialize(vnet_info, xml, client) + super(xml, client) - occi = ERB.new(OCCI_NETWORK) - return occi.result(binding).gsub(/\n\s*/,'') + @vnet_info = vnet_info end - def to_one_template(network_hash, bridge) - one = ERB.new(ONE_NETWORK) - return one.result(binding) + # Creates the OCCI representation of a Virtual Network + def to_occi() + vn_hash = self.to_hash + return vn_hash, 500 if OpenNebula.is_error?(vn_hash) + + template = vn_hash['VNET']['TEMPLATE'] + + begin + occi = ERB.new(OCCI_NETWORK) + occi_text = occi.result(binding) + rescue Exception => e + error = OpenNebula::Error.new(e.message) + return error + end + + return occi_text.gsub(/\n\s*/,'') + end + + def to_one_template() + if @vnet_info['NETWORK'] + vnet_info = @vnet_info['NETWORK'] + else + error_msg = "Missing STORAGE section in the XML body" + error = OpenNebula::Error.new(error_msg) + return error + end + + one = ERB.new(ONE_NETWORK) + return one.result(binding) end end diff --git a/src/cloud/occi/lib/VirtualNetworkPoolOCCI.rb b/src/cloud/occi/lib/VirtualNetworkPoolOCCI.rb index 3f640e100a..da1941271a 100755 --- a/src/cloud/occi/lib/VirtualNetworkPoolOCCI.rb +++ b/src/cloud/occi/lib/VirtualNetworkPoolOCCI.rb @@ -1,25 +1,49 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2010, 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 VirtualNetworkPoolOCCI < VirtualNetworkPool OCCI_NETWORK_POOL = %q{ - <% - if network_pool_hash['VNET_POOL'] != nil - vnlist=[network_pool_hash['VNET_POOL']['VNET']].flatten - vnlist.each{|network|%> - <% - } - end %> - + + <% if pool_hash['VNET_POOL'] && pool_hash['VNET_POOL']['VNET'] %> + <% vnlist=[pool_hash['VNET_POOL']['VNET']].flatten %> + <% vnlist.each{ |vn| %> + + <% } %> + <% end %> + } - # Creates the OCCI representation of a Virtual Network - def to_occi(base_url) - network_pool_hash=to_hash - - occi = ERB.new(OCCI_NETWORK_POOL) - return occi.result(binding).gsub(/\n\s*/,'') + + # Creates the OCCI representation of a Virtual Machine Pool + def to_occi(base_url) + pool_hash = self.to_hash + return pool_hash, 500 if OpenNebula.is_error?(pool_hash) + + begin + occi = ERB.new(OCCI_NETWORK_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 +end \ No newline at end of file diff --git a/src/cloud/occi/lib/occi-server.rb b/src/cloud/occi/lib/occi-server.rb index f42af095fa..81da9ce723 100755 --- a/src/cloud/occi/lib/occi-server.rb +++ b/src/cloud/occi/lib/occi-server.rb @@ -72,6 +72,8 @@ end helpers do def treat_response(result,rc) if OpenNebula::is_error?(result) + pp 'siiii' + pp rc halt rc, result.message end diff --git a/src/oca/ruby/OpenNebula/XMLUtils.rb b/src/oca/ruby/OpenNebula/XMLUtils.rb index 6ee470d0f3..a0dfe43539 100644 --- a/src/oca/ruby/OpenNebula/XMLUtils.rb +++ b/src/oca/ruby/OpenNebula/XMLUtils.rb @@ -99,7 +99,12 @@ module OpenNebula def to_hash if !@hash && @xml - @hash=Crack::XML.parse(to_xml) + begin + @hash = Crack::XML.parse(to_xml) + rescue Exception => e + error = OpenNebula::Error.new(e.message) + return error + end end return @hash end From 478d5b3b5f75a810de650cabd3d9587cd41561b0 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Thu, 15 Jul 2010 18:47:36 +0200 Subject: [PATCH 04/27] feature #200 Fixed minor Errors in OCCI --- src/cloud/occi/etc/occi-server.conf | 4 - src/cloud/occi/etc/templates/large.erb | 13 ++-- src/cloud/occi/etc/templates/medium.erb | 80 +++++++------------- src/cloud/occi/etc/templates/small.erb | 80 +++++++------------- src/cloud/occi/lib/ImagePoolOCCI.rb | 13 +--- src/cloud/occi/lib/VirtualMachineOCCI.rb | 10 ++- src/cloud/occi/lib/VirtualMachinePoolOCCI.rb | 10 +-- src/cloud/occi/lib/VirtualNetworkPoolOCCI.rb | 13 +--- 8 files changed, 78 insertions(+), 145 deletions(-) diff --git a/src/cloud/occi/etc/occi-server.conf b/src/cloud/occi/etc/occi-server.conf index dfca56bb37..4b525a05bf 100644 --- a/src/cloud/occi/etc/occi-server.conf +++ b/src/cloud/occi/etc/occi-server.conf @@ -14,14 +14,10 @@ PORT=4567 # Configuration for the image repository DATABASE=/var/occi.db -IMAGE_DIR= # Configuration for OpenNebula's Virtual Networks BRIDGE= -# Default format for FS -FS_FORMAT=ext3 - # VM types allowed and its template file (inside templates directory) VM_TYPE=[NAME=small, TEMPLATE=small.erb] VM_TYPE=[NAME=medium, TEMPLATE=medium.erb] diff --git a/src/cloud/occi/etc/templates/large.erb b/src/cloud/occi/etc/templates/large.erb index cbc429b343..e59ed9a0f2 100644 --- a/src/cloud/occi/etc/templates/large.erb +++ b/src/cloud/occi/etc/templates/large.erb @@ -7,11 +7,11 @@ NAME = <%= vm_info['NAME'] %> <% vm_info['DISK'].each do |disk| %> <% if disk['STORAGE'] && disk['STORAGE']['href'] %> DISK = [ IMAGE_ID = <%= disk['STORAGE']['href'].split('/').last %> - <% if disk['OVERWRITE'] %> - OVERWRITE = yes + <% if disk.key?('OVERWRITE') %> + ,OVERWRITE = "yes" <% end %> <% if disk['SAVE_AS'] %> - SAVE_AS = "<%= disk['SAVE_AS'] %>" + ,SAVE_AS = "<%= disk['SAVE_AS'] %>" <% end %> ] <% end %> @@ -21,14 +21,13 @@ NAME = <%= vm_info['NAME'] %> <% if vm_info['NIC'] %> <% vm_info['NIC'].each do |nic| %> <% if nic['NETWORK'] && nic['NETWORK']['href'] %> - NIC = [ NETWORK_ID = <%= nic['NETWORK']['href'].split('/').last %>, + NIC = [ NETWORK_ID = <%= nic['NETWORK']['href'].split('/').last %> <% if nic['IP'] %> - IP = <%= nic['IP'] %> + ,IP = <%= nic['IP'] %> <% end %> ] <% end %> <% end %> <% end %> -INSTANCE_TYPE = <%= vm_info['INSTANCE_TYPE']%> - +INSTANCE_TYPE = <%= vm_info['INSTANCE_TYPE']%> \ No newline at end of file diff --git a/src/cloud/occi/etc/templates/medium.erb b/src/cloud/occi/etc/templates/medium.erb index 1fa7f80b75..6263c34cf9 100644 --- a/src/cloud/occi/etc/templates/medium.erb +++ b/src/cloud/occi/etc/templates/medium.erb @@ -1,55 +1,33 @@ -NAME = <%= vm_info['NAME']%> - CPU = 4 MEMORY = 4096 -OS = [ kernel = /vmlinuz, - initrd = /initrd.img, - root = sda1, - kernel_cmd = "ro xencons=tty console=tty1"] - -<% if vm_info['STORAGE'] - vm_info['STORAGE'].each do |key, image| - image=[image].flatten -case key - when "SWAP" - image.each do |img| -%> -DISK = [ type = "swap", - size=<%= img['size']%>, - target=<%= img['dev']%> ] -<% - end - when "DISK" - image.each do |img| -%> -DISK = [ type = "disk", - target=<%= img['dev']%>, - source=<%= img['source']%>, - image_id=<%= img['image']%> ] -<% - end - when "FS" - image.each do |img| -%> -DISK = [ type = "fs", - target=<%= img['dev']%>, - size=<%= img['size']%>, - format=<%= @config[:fs_format]||"ext3"%> ] -<% end %> -<% end %> -<% end %> -<% end %> -<% if vm_info['NETWORK'] and vm_info['NETWORK']['NIC'] %> -<% vm_info['NETWORK']['NIC'].each do |nic| %> -NIC = [ -<% if nic['ip'] %> - IP=<%= nic['ip'] %>, -<% end %> - NETWORK="<%= nic['network']%>", - NETWORK_ID=<%= nic['network_id'] %> -] -<% end %> -<% end %> -INSTANCE_TYPE = <%= vm_info[:instance_type ]%> +NAME = <%= vm_info['NAME'] %> +<% if vm_info['DISK'] %> + <% vm_info['DISK'].each do |disk| %> + <% if disk['STORAGE'] && disk['STORAGE']['href'] %> + DISK = [ IMAGE_ID = <%= disk['STORAGE']['href'].split('/').last %> + <% if disk.key?('OVERWRITE') %> + ,OVERWRITE = "yes" + <% end %> + <% if disk['SAVE_AS'] %> + ,SAVE_AS = "<%= disk['SAVE_AS'] %>" + <% end %> + ] + <% end %> + <% end %> +<% end %> + +<% if vm_info['NIC'] %> + <% vm_info['NIC'].each do |nic| %> + <% if nic['NETWORK'] && nic['NETWORK']['href'] %> + NIC = [ NETWORK_ID = <%= nic['NETWORK']['href'].split('/').last %> + <% if nic['IP'] %> + ,IP = <%= nic['IP'] %> + <% end %> + ] + <% end %> + <% end %> +<% end %> + +INSTANCE_TYPE = <%= vm_info['INSTANCE_TYPE']%> \ No newline at end of file diff --git a/src/cloud/occi/etc/templates/small.erb b/src/cloud/occi/etc/templates/small.erb index 84ec3648c0..fb28e17cb2 100644 --- a/src/cloud/occi/etc/templates/small.erb +++ b/src/cloud/occi/etc/templates/small.erb @@ -1,55 +1,33 @@ -NAME = <%= vm_info['NAME']%> - CPU = 1 MEMORY = 1024 -OS = [ kernel = /vmlinuz, - initrd = /initrd.img, - root = sda1, - kernel_cmd = "ro xencons=tty console=tty1"] - -<% if vm_info['STORAGE'] - vm_info['STORAGE'].each do |key, image| - image=[image].flatten -case key - when "SWAP" - image.each do |img| -%> -DISK = [ type = "swap", - size=<%= img['size']%>, - target=<%= img['dev']%> ] -<% - end - when "DISK" - image.each do |img| -%> -DISK = [ type = "disk", - target=<%= img['dev']%>, - source=<%= img['source']%>, - image_id=<%= img['image']%> ] -<% - end - when "FS" - image.each do |img| -%> -DISK = [ type = "fs", - target=<%= img['dev']%>, - size=<%= img['size']%>, - format=<%= @config[:fs_format]||"ext3"%> ] -<% end %> -<% end %> -<% end %> -<% end %> -<% if vm_info['NETWORK'] and vm_info['NETWORK']['NIC'] %> -<% vm_info['NETWORK']['NIC'].each do |nic| %> -NIC = [ -<% if nic['ip'] %> - IP=<%= nic['ip'] %>, -<% end %> - NETWORK="<%= nic['network']%>", - NETWORK_ID=<%= nic['network_id'] %> -] -<% end %> -<% end %> -INSTANCE_TYPE = <%= vm_info[:instance_type ]%> +NAME = <%= vm_info['NAME'] %> +<% if vm_info['DISK'] %> + <% vm_info['DISK'].each do |disk| %> + <% if disk['STORAGE'] && disk['STORAGE']['href'] %> + DISK = [ IMAGE_ID = <%= disk['STORAGE']['href'].split('/').last %> + <% if disk.key?('OVERWRITE') %> + ,OVERWRITE = "yes" + <% end %> + <% if disk['SAVE_AS'] %> + ,SAVE_AS = "<%= disk['SAVE_AS'] %>" + <% end %> + ] + <% end %> + <% end %> +<% end %> + +<% if vm_info['NIC'] %> + <% vm_info['NIC'].each do |nic| %> + <% if nic['NETWORK'] && nic['NETWORK']['href'] %> + NIC = [ NETWORK_ID = <%= nic['NETWORK']['href'].split('/').last %> + <% if nic['IP'] %> + ,IP = <%= nic['IP'] %> + <% end %> + ] + <% end %> + <% end %> +<% end %> + +INSTANCE_TYPE = <%= vm_info['INSTANCE_TYPE']%> \ No newline at end of file diff --git a/src/cloud/occi/lib/ImagePoolOCCI.rb b/src/cloud/occi/lib/ImagePoolOCCI.rb index ebc73dd0b3..8087249db4 100755 --- a/src/cloud/occi/lib/ImagePoolOCCI.rb +++ b/src/cloud/occi/lib/ImagePoolOCCI.rb @@ -21,22 +21,15 @@ include OpenNebula class ImagePoolOCCI < ImagePool OCCI_IMAGE_POOL = %q{ - <% if pool_hash['IMAGE_POOL'] && pool_hash['IMAGE_POOL']['IMAGE'] %> - <% imagelist=[pool_hash['IMAGE_POOL']['IMAGE']].flatten %> - <% imagelist.each{ |image| %> - + <% self.each{ |im| %> + <% } %> - <% end %> } # Creates the OCCI representation of a Virtual Machine Pool - def to_occi(base_url) - pool_hash = self.to_hash - return pool_hash, 500 if OpenNebula.is_error?(pool_hash) - - begin + def to_occi(base_url)begin occi = ERB.new(OCCI_IMAGE_POOL) occi_text = occi.result(binding) rescue Exception => e diff --git a/src/cloud/occi/lib/VirtualMachineOCCI.rb b/src/cloud/occi/lib/VirtualMachineOCCI.rb index 1f9954cab6..379d8a4424 100755 --- a/src/cloud/occi/lib/VirtualMachineOCCI.rb +++ b/src/cloud/occi/lib/VirtualMachineOCCI.rb @@ -30,11 +30,10 @@ class VirtualMachineOCCI < VirtualMachine <% if template['DISK'] %> <% template['DISK'].each do |disk| %> - - <%= disk['NAME'] %> + <%= disk['TYPE'] %> <%= disk['TARGET'] %> - <% if disk['CLONE'] %> + <% if disk['CLONE']=='NO' %> <% end %> <% if disk['SAVE_AS'] %> @@ -46,10 +45,13 @@ class VirtualMachineOCCI < VirtualMachine <% if template['NIC'] %> <% template['NIC'].each do |nic| %> - + <% if nic['IP'] %> <%= nic['IP'] %> <% end %> + <% if nic['MAC'] %> + <%= nic['MAC'] %> + <% end %> <% end %> <% end %> diff --git a/src/cloud/occi/lib/VirtualMachinePoolOCCI.rb b/src/cloud/occi/lib/VirtualMachinePoolOCCI.rb index 40f2910a0d..0638cd4702 100755 --- a/src/cloud/occi/lib/VirtualMachinePoolOCCI.rb +++ b/src/cloud/occi/lib/VirtualMachinePoolOCCI.rb @@ -21,21 +21,15 @@ include OpenNebula class VirtualMachinePoolOCCI < VirtualMachinePool OCCI_VM_POOL = %q{ - <% if pool_hash['VM_POOL'] && pool_hash['VM_POOL']['VM'] %> - <% vmlist=[pool_hash['VM_POOL']['VM']].flatten %> - <% vmlist.each{ |vm| %> - + <% self.each{ |vm| %> + <% } %> - <% end %> } # Creates the OCCI representation of a Virtual Machine Pool def to_occi(base_url) - pool_hash = self.to_hash - return pool_hash, 500 if OpenNebula.is_error?(pool_hash) - begin occi = ERB.new(OCCI_VM_POOL) occi_text = occi.result(binding) diff --git a/src/cloud/occi/lib/VirtualNetworkPoolOCCI.rb b/src/cloud/occi/lib/VirtualNetworkPoolOCCI.rb index da1941271a..c8deffea37 100755 --- a/src/cloud/occi/lib/VirtualNetworkPoolOCCI.rb +++ b/src/cloud/occi/lib/VirtualNetworkPoolOCCI.rb @@ -21,22 +21,15 @@ include OpenNebula class VirtualNetworkPoolOCCI < VirtualNetworkPool OCCI_NETWORK_POOL = %q{ - <% if pool_hash['VNET_POOL'] && pool_hash['VNET_POOL']['VNET'] %> - <% vnlist=[pool_hash['VNET_POOL']['VNET']].flatten %> - <% vnlist.each{ |vn| %> - + <% self.each{ |vn| %> + <% } %> - <% end %> } # Creates the OCCI representation of a Virtual Machine Pool - def to_occi(base_url) - pool_hash = self.to_hash - return pool_hash, 500 if OpenNebula.is_error?(pool_hash) - - begin + def to_occi(base_url)begin occi = ERB.new(OCCI_NETWORK_POOL) occi_text = occi.result(binding) rescue Exception => e From 632f7957bb519af891a56e3d6214e12f9a2f7395 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Fri, 16 Jul 2010 19:10:08 +0200 Subject: [PATCH 05/27] feature #200 Show more information in OCCI resources --- src/cloud/occi/lib/ImageOCCI.rb | 6 +- src/cloud/occi/lib/ImagePoolOCCI.rb | 3 +- src/cloud/occi/lib/OCCIServer.rb | 117 +++++++++-------------- src/cloud/occi/lib/VirtualMachineOCCI.rb | 2 +- src/cloud/occi/lib/VirtualNetworkOCCI.rb | 4 +- 5 files changed, 54 insertions(+), 78 deletions(-) diff --git a/src/cloud/occi/lib/ImageOCCI.rb b/src/cloud/occi/lib/ImageOCCI.rb index acee97b1eb..175743d8b9 100755 --- a/src/cloud/occi/lib/ImageOCCI.rb +++ b/src/cloud/occi/lib/ImageOCCI.rb @@ -20,7 +20,7 @@ include OpenNebula class ImageOCCI < Image OCCI_IMAGE = %q{ - + <%= self.id.to_s %> <%= self.name %> <% if template['TYPE'] %> @@ -32,7 +32,7 @@ class ImageOCCI < Image <% if size %> <%= size %> <% end %> - + } @@ -60,7 +60,7 @@ class ImageOCCI < Image end # Creates the OCCI representation of an Image - def to_occi() + def to_occi(base_url) image_hash = self.to_hash return image_hash, 500 if OpenNebula.is_error?(image_hash) diff --git a/src/cloud/occi/lib/ImagePoolOCCI.rb b/src/cloud/occi/lib/ImagePoolOCCI.rb index 8087249db4..32b85351fe 100755 --- a/src/cloud/occi/lib/ImagePoolOCCI.rb +++ b/src/cloud/occi/lib/ImagePoolOCCI.rb @@ -29,7 +29,8 @@ class ImagePoolOCCI < ImagePool # Creates the OCCI representation of a Virtual Machine Pool - def to_occi(base_url)begin + def to_occi(base_url) + begin occi = ERB.new(OCCI_IMAGE_POOL) occi_text = occi.result(binding) rescue Exception => e diff --git a/src/cloud/occi/lib/OCCIServer.rb b/src/cloud/occi/lib/OCCIServer.rb index 8b10e079fc..36e813b76d 100755 --- a/src/cloud/occi/lib/OCCIServer.rb +++ b/src/cloud/occi/lib/OCCIServer.rb @@ -94,6 +94,27 @@ class OCCIServer < CloudServer return one_client_user(user) end + # Prepare the OCCI XML Response + # resource:: _Pool_ or _PoolElement_ that represents a OCCI resource + # [return] _String_,_Integer_ Resource Representation or error, status code + def to_occi_xml(resource) + xml_response = resource.to_occi(@base_url) + return xml_response, 500 if OpenNebula.is_error?(xml_response) + + return xml_response, 201 + end + + def get_info_hash(body) + if body + info = xml_to_hash(body.read) + return info + else + error_msg = "OCCI XML representation not present" + error = OpenNebula::Error.new(error_msg) + return error + end + end + ################################################### # Pool Resources methods ################################################### @@ -106,23 +127,16 @@ class OCCIServer < CloudServer client = get_client(request.env) # --- Check OCCI XML from POST --- - if request.body - vm_info = xml_to_hash(request.body.read) - return vm_info, 400 if OpenNebula.is_error?(vm_info) - else - error_msg = "OCCI XML representation of VM not present" - error = OpenNebula::Error.new(error_msg) - return error, 400 - end + vm_info = get_info_hash(request.body) + return vm_info, 400 if OpenNebula.is_error?(vm_info) # --- Get Template Path --- if vm_info['COMPUTE'] - template_path = get_template_path( - vm_info['COMPUTE']['INSTANCE_TYPE']) + path = get_template_path(vm_info['COMPUTE']['INSTANCE_TYPE']) + return path, 500 if OpenNebula.is_error?(path) + + vm_info['TEMPLATE_PATH'] = path end - return template_path, 500 if OpenNebula.is_error?(template_path) - - vm_info['TEMPLATE_PATH'] = template_path # --- Create the new Instance --- vm = VirtualMachineOCCI.new( @@ -138,11 +152,8 @@ class OCCIServer < CloudServer return rc, 500 if OpenNebula.is_error?(rc) # --- Prepare XML Response --- - vm.info - xml_response = vm.to_occi(@base_url) - return xml_response, 500 if OpenNebula.is_error?(xml_response) - - return xml_response, 201 + vm.info + return to_occi_xml(vm) end # Gets the pool representation of COMPUTES @@ -156,14 +167,11 @@ class OCCIServer < CloudServer user_flag = -1 vmpool = VirtualMachinePoolOCCI.new(client, user_flag) + # --- Prepare XML Response --- rc = vmpool.info return rc, 404 if OpenNebula.is_error?(rc) - # --- Prepare XML Response --- - xml_response = vmpool.to_occi(@base_url) - return xml_response, 500 if OpenNebula.is_error?(xml_response) - - return xml_response, 201 + return to_occi_xml(vmpool) end # Post a new network to the NETWORK pool @@ -174,14 +182,8 @@ class OCCIServer < CloudServer client = get_client(request.env) # --- Check OCCI XML from POST --- - if request.body - network_info = xml_to_hash(request.body.read) - return network_info, 400 if OpenNebula.is_error?(network_info) - else - error_msg = "OCCI XML representation of VNET not present" - error = OpenNebula::Error.new(error_msg) - return error, 400 - end + network_info = get_info_hash(request.body) + return network_info, 400 if OpenNebula.is_error?(network_info) if network_info['NETWORK'] network_info['NETWORK']['BRIDGE'] = @config[:bridge] @@ -202,10 +204,7 @@ class OCCIServer < CloudServer # --- Prepare XML Response --- network.info - xml_response = network.to_occi - return xml_response, 500 if OpenNebula.is_error?(xml_response) - - return xml_response, 201 + return to_occi_xml(network) end # Gets the pool representation of NETWORKS @@ -224,10 +223,7 @@ class OCCIServer < CloudServer return rc, 404 if OpenNebula.is_error?(rc) # --- Prepare XML Response --- - xml_response = network_pool.to_occi(@base_url) - return xml_response, 500 if OpenNebula.is_error?(xml_response) - - return xml_response, 201 + return to_occi_xml(network_pool) end # Post a new image to the STORAGE pool @@ -258,7 +254,8 @@ class OCCIServer < CloudServer rc = image.enable return rc, 500 if OpenNebula.is_error?(rc) - return image.to_occi, 201 + # --- Prepare XML Response --- + return to_occi_xml(image) end # Gets the pool representation of STORAGES @@ -277,10 +274,7 @@ class OCCIServer < CloudServer return result, 404 if OpenNebula.is_error?(result) # --- Prepare XML Response --- - xml_response = image_pool.to_occi(@base_url) - return xml_response, 500 if OpenNebula.is_error?(xml_response) - - return xml_response, 201 + return to_occi_xml(image_pool) end ################################################### @@ -305,10 +299,7 @@ class OCCIServer < CloudServer return result, 404 if OpenNebula::is_error?(result) # --- Prepare XML Response --- - xml_response = vm.to_occi(@base_url) - return xml_response, 500 if OpenNebula.is_error?(xml_response) - - return xml_response, 201 + return to_occi_xml(vm) end # Deletes a COMPUTE resource @@ -326,7 +317,6 @@ class OCCIServer < CloudServer # --- Finalize the VM --- result = vm.finalize - pp result return result, 500 if OpenNebula::is_error?(result) return "", 204 @@ -341,14 +331,8 @@ class OCCIServer < CloudServer client = get_client(request.env) # --- Check OCCI XML from POST --- - if request.body - vm_info = xml_to_hash(request.body.read) - return vm_info, 400 if OpenNebula.is_error?(vm_info) - else - error_msg = "OCCI XML representation of VM not present" - error = OpenNebula::Error.new(error_msg) - return error, 400 - end + vm_info = get_info_hash(request.body) + return vm_info, 400 if OpenNebula.is_error?(vm_info) # --- Get the VM and Action on it --- if vm_info['COMPUTE'] && vm_info['COMPUTE']['STATE'] @@ -367,10 +351,7 @@ class OCCIServer < CloudServer # --- Prepare XML Response --- vm.info - xml_response = vm.to_occi(@base_url) - return xml_response, 500 if OpenNebula.is_error?(xml_response) - - return xml_response, 202 + return to_occi_xml(vm) end # Retrieves a NETWORK resource @@ -382,19 +363,16 @@ class OCCIServer < CloudServer client = get_client(request.env) # --- Get the VM --- - vn = VirtualNetworkOCCI.new( + network = VirtualNetworkOCCI.new( nil, VirtualNetwork.build_xml(params[:id]), client) - result = vn.info + result = network.info return result, 404 if OpenNebula::is_error?(result) # --- Prepare XML Response --- - xml_response = vn.to_occi - return xml_response, 500 if OpenNebula.is_error?(xml_response) - - return xml_response, 200 + return to_occi_xml(network) end # Deletes a NETWORK resource @@ -432,10 +410,7 @@ class OCCIServer < CloudServer return result, 404 if OpenNebula::is_error?(result) # --- Prepare XML Response --- - xml_response = image.to_occi - return xml_response, 500 if OpenNebula.is_error?(xml_response) - - return xml_response, 200 + return to_occi_xml(image) end # Deletes a STORAGE resource (Not yet implemented) diff --git a/src/cloud/occi/lib/VirtualMachineOCCI.rb b/src/cloud/occi/lib/VirtualMachineOCCI.rb index 379d8a4424..4fb2e2e119 100755 --- a/src/cloud/occi/lib/VirtualMachineOCCI.rb +++ b/src/cloud/occi/lib/VirtualMachineOCCI.rb @@ -20,7 +20,7 @@ include OpenNebula class VirtualMachineOCCI < VirtualMachine OCCI_VM = %q{ - + <%= self.id.to_s%> <%= self.name%> <% if template['INSTANCE_TYPE'] %> diff --git a/src/cloud/occi/lib/VirtualNetworkOCCI.rb b/src/cloud/occi/lib/VirtualNetworkOCCI.rb index b2a46e415b..1ab7baa1a5 100755 --- a/src/cloud/occi/lib/VirtualNetworkOCCI.rb +++ b/src/cloud/occi/lib/VirtualNetworkOCCI.rb @@ -20,7 +20,7 @@ include OpenNebula class VirtualNetworkOCCI < VirtualNetwork OCCI_NETWORK = %q{ - + <%= self.id.to_s %> <%= self.name %>
<%= template['NETWORK_ADDRESS'] %>
@@ -46,7 +46,7 @@ class VirtualNetworkOCCI < VirtualNetwork end # Creates the OCCI representation of a Virtual Network - def to_occi() + def to_occi(base_url) vn_hash = self.to_hash return vn_hash, 500 if OpenNebula.is_error?(vn_hash) From 9f5a24e951b2d486fa35db4aab296837fd5742c6 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Fri, 16 Jul 2010 19:12:25 +0200 Subject: [PATCH 06/27] feature #200 EC2 using ImagePool --- install.sh | 1 + src/cloud/ec2/bin/econe-describe-images | 11 +- src/cloud/ec2/etc/templates/m1.small.erb | 7 +- src/cloud/ec2/lib/EC2QueryServer.rb | 105 +++++++++++--------- src/cloud/ec2/lib/views/describe_images.erb | 37 ++++--- src/cloud/ec2/lib/views/register_image.erb | 2 +- src/cloud/ec2/lib/views/run_instances.erb | 2 +- 7 files changed, 95 insertions(+), 70 deletions(-) diff --git a/install.sh b/install.sh index 733ab6bb53..624e14ea41 100755 --- a/install.sh +++ b/install.sh @@ -500,6 +500,7 @@ COMMON_CLOUD_CLIENT_LIB_FILES="src/cloud/common/CloudClient.rb" ECO_LIB_FILES="src/cloud/ec2/lib/EC2QueryClient.rb \ src/cloud/ec2/lib/EC2QueryServer.rb \ + src/cloud/ec2/lib/ImageEC2.rb \ src/cloud/ec2/lib/econe-server.rb" ECO_LIB_CLIENT_FILES="src/cloud/ec2/lib/EC2QueryClient.rb" diff --git a/src/cloud/ec2/bin/econe-describe-images b/src/cloud/ec2/bin/econe-describe-images index ffe5fdf0ee..6ebb50a12b 100755 --- a/src/cloud/ec2/bin/econe-describe-images +++ b/src/cloud/ec2/bin/econe-describe-images @@ -115,16 +115,21 @@ end images = rc['imagesSet']['item'] -fmt = "%-4s %-36s %s" +fmt = "%-8s %-20s %-30s %-40s %s" if headers - puts fmt % ["Owner", "ImageId", "Location"] + puts fmt % ["Owner", "ImageId", "Status", "Visibility", "Location"] puts "------------------------------------------------------------------------------" end if images images.each { |img| - puts fmt % [img['imageOwnerId'],img['imageId'],img['imageLocation']] + if img['isPublic'] == 'true' + visibility = "public" + elsif img['isPublic'] == 'false' + visibility = "private" + end + puts fmt % [img['imageOwnerId'],img['imageId'], img['imageState'], visibility,img['imageLocation']] } end diff --git a/src/cloud/ec2/etc/templates/m1.small.erb b/src/cloud/ec2/etc/templates/m1.small.erb index f8c099ee5d..b2f47f269a 100644 --- a/src/cloud/ec2/etc/templates/m1.small.erb +++ b/src/cloud/ec2/etc/templates/m1.small.erb @@ -11,14 +11,11 @@ MEMORY = 256 # root = sda1, # kernel_cmd = "ro xencons=tty console=tty1"] -DISK = [ source = <%= erb_vm_info[:img_path] %>, - clone = no, - target = sda1, - readonly = no] +DISK = [ IMAGE_ID = <%= erb_vm_info[:img_id] %> ] NIC=[NETWORK="Public EC2"] -IMAGE_ID = <%= erb_vm_info[:img_id] %> +IMAGE_ID = <%= erb_vm_info[:ec2_img_id] %> INSTANCE_TYPE = <%= erb_vm_info[:instance_type ]%> <% if erb_vm_info[:user_data] %> diff --git a/src/cloud/ec2/lib/EC2QueryServer.rb b/src/cloud/ec2/lib/EC2QueryServer.rb index c07e766a0b..5acd526f0b 100644 --- a/src/cloud/ec2/lib/EC2QueryServer.rb +++ b/src/cloud/ec2/lib/EC2QueryServer.rb @@ -19,9 +19,12 @@ require 'sinatra' require 'erb' require 'time' require 'AWS' -require 'CloudServer' require 'base64' +require 'CloudServer' + +require 'ImageEC2' + ############################################################################### # The EC2Query Server implements a EC2 compatible server based on the # OpenNebula Engine @@ -149,27 +152,38 @@ class EC2QueryServer < CloudServer ########################################################################### def upload_image(params) - user = get_user(params['AWSAccessKeyId']) + user = get_user(params['AWSAccessKeyId']) + one_client = one_client_user(user) - image = add_image(user[:id],params["file"][:tempfile]) - erb_img_id = image.id - erb_version = params['Version'] + image = ImageEC2.new(Image.build_xml, one_client) + + rc = add_image(image, params['file']) + if OpenNebula.is_error?(rc) + return OpenNebula::Error.new('Unsupported'),400 + end + + erb_version = params['Version'] response = ERB.new(File.read(@config[:views]+"/register_image.erb")) return response.result(binding), 200 end def register_image(params) - user = get_user(params['AWSAccessKeyId']) - image = get_image(params['ImageLocation']) + user = get_user(params['AWSAccessKeyId']) + one_client = one_client_user(user) + + tmp, img=params['ImageLocation'].split('-') - if !image + image = Image.new(Image.build_xml(img.to_i), one_client) + + # Enable the new Image + rc = image.info + if OpenNebula.is_error?(rc) return OpenNebula::Error.new('InvalidAMIID.NotFound'), 400 - elsif user[:id] != image[:owner] - return OpenNebula::Error.new('AuthFailure'), 400 end - - erb_img_id=image.id + + image.enable + erb_version = params['Version'] response = ERB.new(File.read(@config[:views]+"/register_image.erb")) @@ -177,13 +191,20 @@ class EC2QueryServer < CloudServer end def describe_images(params) - erb_user = get_user(params['AWSAccessKeyId']) - erb_images = Image.filter(:owner => erb_user[:id]) - erb_version = params['Version'] - - response = ERB.new(File.read(@config[:views]+"/describe_images.erb")) + user = get_user(params['AWSAccessKeyId']) + one_client = one_client_user(user) + + user_flag=-1 + erb_impool = ImagePool.new(one_client, user_flag) + erb_impool.info - return response.result(binding), 200 + erb_user_name = user[:name] + erb_version = params['Version'] + + response = ERB.new(File.read(@config[:views]+"/describe_images.erb")) + a = response.result(binding) + pp a + return a, 200 end ########################################################################### @@ -191,49 +212,46 @@ class EC2QueryServer < CloudServer ########################################################################### def run_instances(params) - # Get the instance type + user = get_user(params['AWSAccessKeyId']) + one_client = one_client_user(user) + + # Get the instance type and path instance_type_name = params['InstanceType'] instance_type = @instance_types[instance_type_name] - return OpenNebula::Error.new('Unsupported'),400 if !instance_type - + path = get_template_path(params['InstanceType']) + if OpenNebula.is_error?(path) + return OpenNebula::Error.new('Unsupported'),400 + end + # Get the image tmp, img=params['ImageId'].split('-') - image = get_image(img.to_i) - - return OpenNebula::Error.new('InvalidAMIID.NotFound'),400 if !image - - # Get the user - user = get_user(params['AWSAccessKeyId']) - one_client = one_client_user(user) - erb_user_name = user[:name] # Build the VM erb_vm_info=Hash.new - - - erb_vm_info[:img_path] = image.path - erb_vm_info[:img_id] = params['ImageId'] + erb_vm_info[:img_id] = img.to_i + erb_vm_info[:ec2_img_id] = params['ImageId'] erb_vm_info[:instance_type] = instance_type_name - erb_vm_info[:template] = @config[:template_location] + - "/#{instance_type['TEMPLATE']}" + erb_vm_info[:template] = path erb_vm_info[:user_data] = params['UserData'] template = ERB.new(File.read(erb_vm_info[:template])) template_text = template.result(binding) - - #Start the VM. + + # Start the VM. vm = VirtualMachine.new(VirtualMachine.build_xml, one_client) rc = vm.allocate(template_text) + if OpenNebula::is_error?(rc) + return OpenNebula::Error.new('Unsupported'),400 + end - return OpenNebula::Error.new('Unsupported'),400 if OpenNebula::is_error?(rc) - vm.info erb_vm_info[:vm_id]=vm.id erb_vm_info[:vm]=vm - + erb_vm_info[:user_name] = user[:name] + erb_version = params['Version'] response = ERB.new(File.read(@config[:views]+"/run_instances.erb")) @@ -248,12 +266,7 @@ class EC2QueryServer < CloudServer erb_user_name = user[:name] - if user[:id]==0 - user_flag=-2 - else - user_flag=-1 - end - + user_flag=-1 erb_vmpool = VirtualMachinePool.new(one_client, user_flag) erb_vmpool.info diff --git a/src/cloud/ec2/lib/views/describe_images.erb b/src/cloud/ec2/lib/views/describe_images.erb index 6d5156ba5a..222ab62e30 100644 --- a/src/cloud/ec2/lib/views/describe_images.erb +++ b/src/cloud/ec2/lib/views/describe_images.erb @@ -1,16 +1,25 @@ - - - <% for image in erb_images %> - - ami-<%= sprintf('%08i', image.id) %> - <%= image.path.gsub(/^\//,'') %> - available - <%= erb_user[:name] %> - false - i386 - machine - - <% end %> - + + + <% erb_impool.each do |im| %> + <% im.info %> + + ami-<%= sprintf('%08i', im.id) %> + <%= im['SOURCE'].split('/').last %> + <% if im['STATE'] == '4' %> + deregistered + <% elsif im['STATE'] == '3' %> + available + <% end %> + <%= erb_user_name %> + <% if im['PUBLIC'] == '0' %> + false + <% elsif im['PUBLIC'] == '1' %> + true + <% end %> + i386 + machine + + <% end %> + diff --git a/src/cloud/ec2/lib/views/register_image.erb b/src/cloud/ec2/lib/views/register_image.erb index 6f2fbf608d..cd80d75982 100644 --- a/src/cloud/ec2/lib/views/register_image.erb +++ b/src/cloud/ec2/lib/views/register_image.erb @@ -1,3 +1,3 @@ - <%= erb_img_id %> + ami-<%= sprintf('%08i', image.id) %> diff --git a/src/cloud/ec2/lib/views/run_instances.erb b/src/cloud/ec2/lib/views/run_instances.erb index a33481372c..c0ae168ed2 100644 --- a/src/cloud/ec2/lib/views/run_instances.erb +++ b/src/cloud/ec2/lib/views/run_instances.erb @@ -1,6 +1,6 @@ r-47a5402e - <%= erb_user_name %> + <%= erb_vm_info[:user_name] %> default From 54e8dfd1afe465898037c79c077fe06702e3e512 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Sat, 17 Jul 2010 01:58:24 +0200 Subject: [PATCH 07/27] scons helper now uses fileutils instead of ftools --- share/scons/get_xmlrpc_config | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/share/scons/get_xmlrpc_config b/share/scons/get_xmlrpc_config index ebbdd45b55..d89e721ed4 100755 --- a/share/scons/get_xmlrpc_config +++ b/share/scons/get_xmlrpc_config @@ -1,7 +1,8 @@ #!/usr/bin/env ruby # -------------------------------------------------------------------------- # -# Copyright 2002-2010, OpenNebula Project Leads (OpenNebula.org) # +# Copyright 2002-2009, Distributed Systems Architecture Group, Universidad # +# Complutense de Madrid (dsa-research.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 # @@ -18,8 +19,7 @@ require 'pp' require 'digest/md5' -require 'ftools' - +require 'fileutils' ########################################### # Code to test compilation/linkning flags # @@ -207,7 +207,7 @@ def gen_test_file(kind) #fname="xmlrpc_test.cc" full_path=dir+"/"+fname - File.makedirs(dir) + FileUtils::mkdir_p(dir) f=open(full_path, "w") f.write(TestCode[kind]) f.close From d89cc916876c459d5f9d548c50902ac3eb9ad8c9 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Sat, 17 Jul 2010 01:59:17 +0200 Subject: [PATCH 08/27] feature #200: Image now uses fileutils instead of ftools --- src/oca/ruby/OpenNebula/Image.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/oca/ruby/OpenNebula/Image.rb b/src/oca/ruby/OpenNebula/Image.rb index aced329878..f5b7d31b42 100644 --- a/src/oca/ruby/OpenNebula/Image.rb +++ b/src/oca/ruby/OpenNebula/Image.rb @@ -1,5 +1,5 @@ require 'OpenNebula/Pool' -require 'ftools' +require 'fileutils' module OpenNebula class Image < PoolElement @@ -190,7 +190,7 @@ module OpenNebula return OpenNebula::Error.new("copy Image: missing parameters.") end - if !File.copy(path, source) + if !FileUtils.copy(path, source) return OpenNebula::Error.new("copy Image: in File.copy") end From 7b41a7c1bc9d3c6889423f2c61fdf1fbc5e4f9bb Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Sat, 17 Jul 2010 02:00:36 +0200 Subject: [PATCH 09/27] feature #200: get rid of unneeded variables in config file --- src/cloud/occi/etc/occi-server.conf | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/cloud/occi/etc/occi-server.conf b/src/cloud/occi/etc/occi-server.conf index 4b525a05bf..025dd492b1 100644 --- a/src/cloud/occi/etc/occi-server.conf +++ b/src/cloud/occi/etc/occi-server.conf @@ -1,7 +1,3 @@ -# OpenNebula administrator user -USER=oneadmin -PASSWORD= - # OpenNebula server contact information ONE_XMLRPC=http://localhost:2633/RPC2 @@ -12,9 +8,6 @@ PORT=4567 # SSL proxy that serves the API (set if is being used) #SSL_SERVER=https://localhost:443 -# Configuration for the image repository -DATABASE=/var/occi.db - # Configuration for OpenNebula's Virtual Networks BRIDGE= @@ -22,4 +15,3 @@ BRIDGE= VM_TYPE=[NAME=small, TEMPLATE=small.erb] VM_TYPE=[NAME=medium, TEMPLATE=medium.erb] VM_TYPE=[NAME=large, TEMPLATE=large.erb] - From bb4939fba7c5c701152a234bd2e61bdb97426c4d Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Sat, 17 Jul 2010 02:01:29 +0200 Subject: [PATCH 10/27] feature #200: removed uneeded print messages --- src/cloud/occi/lib/occi-server.rb | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/cloud/occi/lib/occi-server.rb b/src/cloud/occi/lib/occi-server.rb index 81da9ce723..0c69e43c94 100755 --- a/src/cloud/occi/lib/occi-server.rb +++ b/src/cloud/occi/lib/occi-server.rb @@ -15,7 +15,7 @@ #--------------------------------------------------------------------------- # ############################################################################## -# The OCCI Server provides compatible server based on the +# The OCCI Server provides compatible server based on the # OpenNebula Engine ############################################################################## @@ -26,7 +26,7 @@ ONE_LOCATION=ENV["ONE_LOCATION"] if !ONE_LOCATION RUBY_LIB_LOCATION="/usr/lib/one/ruby" - TEMPLATE_LOCATION="/etc/one/occi_templates" + TEMPLATE_LOCATION="/etc/one/occi_templates" CONFIGURATION_FILE = "/etc/one/occi-server.conf" else RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby" @@ -72,13 +72,11 @@ end helpers do def treat_response(result,rc) if OpenNebula::is_error?(result) - pp 'siiii' - pp rc halt rc, result.message end - + status rc - result + result end end @@ -90,12 +88,12 @@ end # Pool Resources methods ################################################### -post '/compute' do - result,rc = $occi_server.post_compute(request) +post '/compute' do + result,rc = $occi_server.post_compute(request) treat_response(result,rc) end -get '/compute' do +get '/compute' do result,rc = $occi_server.get_computes(request) treat_response(result,rc) end @@ -124,7 +122,7 @@ end # Entity Resources Methods ################################################### -get '/compute/:id' do +get '/compute/:id' do result,rc = $occi_server.get_compute(request, params) treat_response(result,rc) end @@ -136,20 +134,20 @@ end put '/compute/:id' do result,rc = $occi_server.put_compute(request, params) - treat_response(result,rc) + treat_response(result,rc) end -get '/network/:id' do +get '/network/:id' do result,rc = $occi_server.get_network(request, params) treat_response(result,rc) end delete '/network/:id' do result,rc = $occi_server.delete_network(request, params) - treat_response(result,rc) + treat_response(result,rc) end -get '/storage/:id' do +get '/storage/:id' do result,rc = $occi_server.get_storage(request, params) treat_response(result,rc) end From e3b9eb63c00e93d34d87b1a795bb44dcdb369f1a Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Sat, 17 Jul 2010 02:05:06 +0200 Subject: [PATCH 11/27] feature #200: Better XML parsing --- src/cloud/common/CloudServer.rb | 58 +++---- src/cloud/occi/lib/OCCIServer.rb | 187 +++++++++++------------ src/cloud/occi/lib/VirtualNetworkOCCI.rb | 52 ++++--- src/oca/ruby/OpenNebula/XMLUtils.rb | 53 ++++--- 4 files changed, 170 insertions(+), 180 deletions(-) diff --git a/src/cloud/common/CloudServer.rb b/src/cloud/common/CloudServer.rb index 74b2d62985..528654d424 100755 --- a/src/cloud/common/CloudServer.rb +++ b/src/cloud/common/CloudServer.rb @@ -31,7 +31,7 @@ class CloudServer attr_reader :one_client # Initializes the Cloud server based on a config file - # config_file:: _String_ for the server. MUST include the following + # config_file:: _String_ for the server. MUST include the following # variables: # USER # PASSWORD @@ -43,7 +43,7 @@ class CloudServer # --- Load the Cloud Server configuration file --- @config = Configuration.new(config_file) - + @instance_types = Hash.new if @config[:vm_type].kind_of?(Array) @@ -55,7 +55,7 @@ class CloudServer end # --- Start an OpenNebula Session --- - + @one_client = Client.new() @user_pool = UserPool.new(@one_client) end @@ -72,7 +72,7 @@ class CloudServer puts "--------------------------------------" puts " Registered Instance Types " puts "--------------------------------------" - pp @instance_types + pp @instance_types end ########################################################################### @@ -80,19 +80,19 @@ class CloudServer ########################################################################### # Generates an OpenNebula Session for the given user - # user:: _Hash_ the user information - # [return] an OpenNebula client session + # user:: _Hash_ the user information + # [return] an OpenNebula client session def one_client_user(user) client = Client.new("dummy:dummy") client.one_auth = "#{user[:name]}:#{user[:password]}" - + return client end # Authenticates a user # name:: _String_ of the user # password:: _String_ of the user - # [return] true if authenticated + # [return] true if authenticated def authenticate?(name, password) user = get_user(name) @@ -104,7 +104,7 @@ class CloudServer # [return] _Hash_ with the user data def get_user(name) user = nil - + @user_pool.info @user_pool.each{ |u| if u.name==name @@ -117,31 +117,17 @@ class CloudServer } return user end - - def xml_to_hash(xml) - begin - hash = Crack::XML.parse(xml) - rescue Exception => e - error = OpenNebula::Error.new(e.message) - return error - end - - return hash - end - + def get_template_path(instance_type_name) - if instance_type_name.nil? - instance_type=@instance_types.first - end - + instance_type=@instance_types[instance_type_name] - + if !instance_type error = OpenNebula::Error.new("Bad instance type") - return error + return error end - - return @config[:template_location]+"/#{instance_type['TEMPLATE']}" + + return @config[:template_location]+"/#{instance_type['TEMPLATE']}" end ########################################################################### @@ -162,14 +148,14 @@ class CloudServer error = OpenNebula::Error.new(error_msg) return error end - + if !File.exists?(file_path) error_msg = "Image file could not be found, aborting." error = OpenNebula::Error.new(error_msg) return error end end - + template = image.to_one_template rc = image.allocate(template) @@ -181,22 +167,22 @@ class CloudServer image.info template=image.to_hash template=template['IMAGE']['TEMPLATE'] - + if file_path rc = image.copy(file_path, image['SOURCE']) file[:tempfile].unlink elsif template['SIZE'] and template['FSTYPE'] rc = image.mk_datablock( - template['SIZE'], - template['FSTYPE'], + template['SIZE'], + template['FSTYPE'], image['SOURCE']) end - + if OpenNebula.is_error?(rc) image.delete return rc end - + return nil end diff --git a/src/cloud/occi/lib/OCCIServer.rb b/src/cloud/occi/lib/OCCIServer.rb index 36e813b76d..fceae8e458 100755 --- a/src/cloud/occi/lib/OCCIServer.rb +++ b/src/cloud/occi/lib/OCCIServer.rb @@ -35,37 +35,37 @@ require 'pp' ############################################################################## -# The OCCI Server provides an OCCI implementation based on the +# The OCCI Server provides an OCCI implementation based on the # OpenNebula Engine ############################################################################## class OCCIServer < CloudServer - + # Server initializer # config_file:: _String_ path of the config file - # template:: _String_ path to the location of the templates + # template:: _String_ path to the location of the templates def initialize(config_file,template) super(config_file) - + @config.add_configuration_value("TEMPLATE_LOCATION",template) - + if @config[:ssl_server] @base_url=@config[:ssl_server] else @base_url="http://#{@config[:server]}:#{@config[:port]}" end - + print_configuration end - + # Authorization function # requestenv:: _Hash_ Hash containing the environment of the request - # [return] _Boolean_ Whether the user is authorized or not + # [return] _Boolean_ Whether the user is authorized or not def authenticate?(requestenv) auth ||= Rack::Auth::Basic::Request.new(requestenv) if !(auth.provided? && auth.basic? && auth.credentials) return false - end + end user = get_user(requestenv, auth) @@ -85,7 +85,7 @@ class OCCIServer < CloudServer auth = Rack::Auth::Basic::Request.new(requestenv) if !auth super(auth.credentials.first) end - + # Retrieve a client with the user credentials # requestenv:: _Hash_ Hash containing the environment of the request # [return] _Client_ client with the user credentials @@ -93,20 +93,20 @@ class OCCIServer < CloudServer user = get_user(requestenv) return one_client_user(user) end - + # Prepare the OCCI XML Response # resource:: _Pool_ or _PoolElement_ that represents a OCCI resource # [return] _String_,_Integer_ Resource Representation or error, status code def to_occi_xml(resource) xml_response = resource.to_occi(@base_url) return xml_response, 500 if OpenNebula.is_error?(xml_response) - - return xml_response, 201 + + return xml_response, 201 end - + def get_info_hash(body) if body - info = xml_to_hash(body.read) + info = XMLUtilsElement::xml_to_hash(body.read) return info else error_msg = "OCCI XML representation not present" @@ -114,18 +114,18 @@ class OCCIServer < CloudServer return error end end - + ################################################### # Pool Resources methods ################################################### - + # Post a new compute to the COMPUTE pool # request:: _Hash_ hash containing the data of the request - # [return] _String_,_Integer_ COMPUTE Representation or error, status code + # [return] _String_,_Integer_ COMPUTE Representation or error, status code def post_compute(request) # --- Get client with user credentials --- client = get_client(request.env) - + # --- Check OCCI XML from POST --- vm_info = get_info_hash(request.body) return vm_info, 400 if OpenNebula.is_error?(vm_info) @@ -134,16 +134,16 @@ class OCCIServer < CloudServer if vm_info['COMPUTE'] path = get_template_path(vm_info['COMPUTE']['INSTANCE_TYPE']) return path, 500 if OpenNebula.is_error?(path) - + vm_info['TEMPLATE_PATH'] = path end # --- Create the new Instance --- vm = VirtualMachineOCCI.new( vm_info, - VirtualMachine.build_xml, + VirtualMachine.build_xml, client) - + # --- Generate the template and Allocate the new Instance --- template = vm.to_one_template return template, 500 if OpenNebula.is_error?(template) @@ -155,7 +155,7 @@ class OCCIServer < CloudServer vm.info return to_occi_xml(vm) end - + # Gets the pool representation of COMPUTES # request:: _Hash_ hash containing the data of the request # [return] _String_,_Integer_ Pool Representation or error, status code @@ -164,36 +164,29 @@ class OCCIServer < CloudServer client = get_client(request.env) # --- Get User's VMs --- - user_flag = -1 + user_flag = -1 vmpool = VirtualMachinePoolOCCI.new(client, user_flag) - + # --- Prepare XML Response --- - rc = vmpool.info + rc = vmpool.info return rc, 404 if OpenNebula.is_error?(rc) - + return to_occi_xml(vmpool) end - + # Post a new network to the NETWORK pool # request:: _Hash_ hash containing the data of the request # [return] _String_,_Integer_ Network Representation or error, status code def post_network(request) # --- Get client with user credentials --- client = get_client(request.env) - - # --- Check OCCI XML from POST --- - network_info = get_info_hash(request.body) - return network_info, 400 if OpenNebula.is_error?(network_info) - - if network_info['NETWORK'] - network_info['NETWORK']['BRIDGE'] = @config[:bridge] - end - + # --- Create the new Instance --- network = VirtualNetworkOCCI.new( - network_info, VirtualNetwork.build_xml, - client) + client, + request.body, + @config[:bridge]) # --- Generate the template and Allocate the new Instance --- template = network.to_one_template @@ -203,39 +196,39 @@ class OCCIServer < CloudServer return rc, 500 if OpenNebula.is_error?(rc) # --- Prepare XML Response --- - network.info + network.info return to_occi_xml(network) end - + # Gets the pool representation of NETWORKS # request:: _Hash_ hash containing the data of the request - # [return] _String_,_Integer_ Network pool representation or error, - # => status code + # [return] _String_,_Integer_ Network pool representation or error, + # => status code def get_networks(request) # --- Get client with user credentials --- client = get_client(request.env) # --- Get User's VNETs --- - user_flag = -1 + user_flag = -1 network_pool = VirtualNetworkPoolOCCI.new(client, user_flag) - - rc = network_pool.info + + rc = network_pool.info return rc, 404 if OpenNebula.is_error?(rc) - + # --- Prepare XML Response --- return to_occi_xml(network_pool) end - + # Post a new image to the STORAGE pool # request:: _Hash_ hash containing the data of the request - # [return] _String_,_Integer_ Image representation or error, status code + # [return] _String_,_Integer_ Image representation or error, status code def post_storage(request) # Get client with user credentials client = get_client(request.env) - + # --- Check OCCI XML from POST --- if request.params['occixml'] - image_info = xml_to_hash(request.params['occixml']) + image_info = XMLUtilsElement::xml_to_hash(request.params['occixml']) return image_info, 400 if OpenNebula.is_error?(image_info) else error_msg = "OCCI XML representation of Image" + @@ -243,53 +236,53 @@ class OCCIServer < CloudServer error = OpenNebula::Error.new(error_msg) return error, 400 end - + # --- Create and Add the new Image --- image = ImageOCCI.new(image_info, Image.build_xml, client) rc = add_image(image, request.params['file']) return rc, 500 if OpenNebula.is_error?(rc) - + # --- Enable the new Image --- rc = image.enable return rc, 500 if OpenNebula.is_error?(rc) - + # --- Prepare XML Response --- return to_occi_xml(image) end - + # Gets the pool representation of STORAGES # request:: _Hash_ hash containing the data of the request - # [return] _String_,_Integer_ Image pool representation or error, - # status code + # [return] _String_,_Integer_ Image pool representation or error, + # status code def get_storages(request) # --- Get client with user credentials --- client = get_client(request.env) # --- Get User's Images --- - user_flag = -1 + user_flag = -1 image_pool = ImagePoolOCCI.new(client, user_flag) - - result = image_pool.info + + result = image_pool.info return result, 404 if OpenNebula.is_error?(result) - + # --- Prepare XML Response --- return to_occi_xml(image_pool) end - + ################################################### # Entity Resources methods ################################################### - + # Get the representation of a COMPUTE resource # request:: _Hash_ hash containing the data of the request - # [return] _String_,_Integer_ COMPUTE representation or error, + # [return] _String_,_Integer_ COMPUTE representation or error, # status code def get_compute(request, params) # --- Get client with user credentials --- client = get_client(request.env) - # --- Get the VM --- + # --- Get the VM --- vm = VirtualMachineOCCI.new( nil, VirtualMachine.build_xml(params[:id]), @@ -301,31 +294,31 @@ class OCCIServer < CloudServer # --- Prepare XML Response --- return to_occi_xml(vm) end - + # Deletes a COMPUTE resource # request:: _Hash_ hash containing the data of the request - # [return] _String_,_Integer_ Delete confirmation msg or error, + # [return] _String_,_Integer_ Delete confirmation msg or error, # status code def delete_compute(request, params) # --- Get client with user credentials --- client = get_client(request.env) - + vm = VirtualMachineOCCI.new( nil, VirtualMachine.build_xml(params[:id]), client) - + # --- Finalize the VM --- result = vm.finalize return result, 500 if OpenNebula::is_error?(result) return "", 204 end - + # Updates a COMPUTE resource # request:: _Hash_ hash containing the data of the request - # [return] _String_,_Integer_ Update confirmation msg or error, - # status code + # [return] _String_,_Integer_ Update confirmation msg or error, + # status code def put_compute(request, params) # --- Get client with user credentials --- client = get_client(request.env) @@ -338,33 +331,32 @@ class OCCIServer < CloudServer if vm_info['COMPUTE'] && vm_info['COMPUTE']['STATE'] vm = VirtualMachineOCCI.new( vm_info, - VirtualMachine.build_xml(params[:id]), + VirtualMachine.build_xml(params[:id]), client) - + rc = vm.mk_action(vm_info['COMPUTE']['STATE']) return rc, 400 if OpenNebula.is_error?(rc) else - error_msg = "State not defined in the OCCI XML" + error_msg = "State not defined in the OCCI XML" error = OpenNebula::Error.new(error_msg) - return error, 400 + return error, 400 end - + # --- Prepare XML Response --- - vm.info + vm.info return to_occi_xml(vm) end - + # Retrieves a NETWORK resource # request:: _Hash_ hash containing the data of the request - # [return] _String_,_Integer_ NETWORK occi representation or error, - # status code + # [return] _String_,_Integer_ NETWORK occi representation or error, + # status code def get_network(request, params) # --- Get client with user credentials --- client = get_client(request.env) - # --- Get the VM --- + # --- Get the VM --- network = VirtualNetworkOCCI.new( - nil, VirtualNetwork.build_xml(params[:id]), client) @@ -374,36 +366,35 @@ class OCCIServer < CloudServer # --- Prepare XML Response --- return to_occi_xml(network) end - + # Deletes a NETWORK resource # request:: _Hash_ hash containing the data of the request - # [return] _String_,_Integer_ Delete confirmation msg or error, - # status code + # [return] _String_,_Integer_ Delete confirmation msg or error, + # status code def delete_network(request, params) # --- Get client with user credentials --- client = get_client(request.env) - + vn = VirtualNetworkOCCI.new( - nil, VirtualNetwork.build_xml(params[:id]), client) - + # --- Delete the VNET --- result = vn.delete return result, 500 if OpenNebula::is_error?(result) return "", 204 end - + # Get a STORAGE resource # request:: _Hash_ hash containing the data of the request - # [return] _String_,_Integer_ STORAGE occi representation or error, - # status code + # [return] _String_,_Integer_ STORAGE occi representation or error, + # status code def get_storage(request, params) # --- Get client with user credentials --- client = get_client(request.env) - # --- Get the Image --- + # --- Get the Image --- image = ImageOCCI.new(nil, Image.build_xml(params[:id]), client) result = image.info @@ -412,17 +403,17 @@ class OCCIServer < CloudServer # --- Prepare XML Response --- return to_occi_xml(image) end - + # Deletes a STORAGE resource (Not yet implemented) # request:: _Hash_ hash containing the data of the request - # [return] _String_,_Integer_ Delete confirmation msg or error, - # status code + # [return] _String_,_Integer_ Delete confirmation msg or error, + # status code def delete_storage(request, params) # --- Get client with user credentials --- client = get_client(request.env) - + image = ImageOCCI.new(nil, Image.build_xml(params[:id]), client) - + # --- Delete the Image --- result = image.delete return result, 500 if OpenNebula::is_error?(result) diff --git a/src/cloud/occi/lib/VirtualNetworkOCCI.rb b/src/cloud/occi/lib/VirtualNetworkOCCI.rb index 1ab7baa1a5..85222223f9 100755 --- a/src/cloud/occi/lib/VirtualNetworkOCCI.rb +++ b/src/cloud/occi/lib/VirtualNetworkOCCI.rb @@ -23,55 +23,57 @@ class VirtualNetworkOCCI < VirtualNetwork <%= self.id.to_s %> <%= self.name %> -
<%= template['NETWORK_ADDRESS'] %>
- <% if template['NETWORK_SIZE'] %> - <%= template['NETWORK_SIZE'] %> +
<%= self['TEMPLATE/NETWORK_ADDRESS'] %>
+ <% if self['TEMPLATE/NETWORK_SIZE'] %> + <%= self['TEMPLATE/NETWORK_SIZE'] %> <% end %>
} ONE_NETWORK = %q{ - NAME = <%= vnet_info['NAME'] %> + NAME = <%= @vnet_info.elements['NAME'].text %> TYPE = RANGED - BRIDGE = <%= vnet_info['BRIDGE'] %> - NETWORK_ADDRESS = <%= vnet_info['ADDRESS'] %> - NETWORK_SIZE = <%= vnet_info['SIZE'] %> + BRIDGE = <%= @vnet_info.elements['BRIDGE'].text %> + NETWORK_ADDRESS = <%= @vnet_info.elements['ADDRESS'].text %> + NETWORK_SIZE = <%= @vnet_info.elements['SIZE'].text %> }.gsub(/^ /, '') # Class constructor - def initialize(vnet_info, xml, client) + def initialize(xml, client, xml_info=nil, bridge=nil) super(xml, client) - @vnet_info = vnet_info - end - - # Creates the OCCI representation of a Virtual Network - def to_occi(base_url) - vn_hash = self.to_hash - return vn_hash, 500 if OpenNebula.is_error?(vn_hash) - - template = vn_hash['VNET']['TEMPLATE'] + if xml_info != nil and bridge != nil + @vnet_info = REXML::Document.new(xml_info).root + bridge_element = REXML::Element.new("BRIDGE") + bridge_element.add_text(bridge) + + @vnet_info.add(bridge_element) + else + @vnet_info = nil + end + end + + # Creates the OCCI representation of a Virtual Network + def to_occi(base_url) begin occi = ERB.new(OCCI_NETWORK) - occi_text = occi.result(binding) + occi_text = occi.result(binding) rescue Exception => e error = OpenNebula::Error.new(e.message) return error - end + end return occi_text.gsub(/\n\s*/,'') end - + def to_one_template() - if @vnet_info['NETWORK'] - vnet_info = @vnet_info['NETWORK'] - else - error_msg = "Missing STORAGE section in the XML body" + if @vnet_info.name != 'NETWORK' + error_msg = "Missing NETWORK section in the XML body" error = OpenNebula::Error.new(error_msg) return error end - + one = ERB.new(ONE_NETWORK) return one.result(binding) end diff --git a/src/oca/ruby/OpenNebula/XMLUtils.rb b/src/oca/ruby/OpenNebula/XMLUtils.rb index a0dfe43539..713cc121ed 100644 --- a/src/oca/ruby/OpenNebula/XMLUtils.rb +++ b/src/oca/ruby/OpenNebula/XMLUtils.rb @@ -7,7 +7,7 @@ module OpenNebula rescue LoadError NOKOGIRI=false end - + # Require crack library if present, otherwise don't bother # This is just for OCCI use begin @@ -17,7 +17,7 @@ module OpenNebula ########################################################################### # The XMLUtilsElement module provides an abstraction of the underlying - # XML parser engine. It provides XML-related methods for the Pool Elements + # XML parser engine. It provides XML-related methods for the Pool Elements ########################################################################### module XMLUtilsElement # Initialize a XML document for the element @@ -34,7 +34,7 @@ module OpenNebula # Extract an element from the XML description of the PoolElement. # key::_String_ The name of the element - # [return] _String_ the value of the element + # [return] _String_ the value of the element # Examples: # ['VID'] # gets VM id # ['HISTORY/HOSTNAME'] # get the hostname from the history @@ -47,16 +47,16 @@ module OpenNebula else element=@xml.elements[key.to_s.upcase] end - - if element + + if element element.text end end - + def template_str(indent=true) template_like_str('TEMPLATE', indent) end - + def template_like_str(root_element, indent=true) if NOKOGIRI xml_template=@xml.xpath(root_element).to_s @@ -64,7 +64,7 @@ module OpenNebula else rexml=@xml.elements[root_element] end - + if indent ind_enter="\n" ind_tab=' ' @@ -72,7 +72,7 @@ module OpenNebula ind_enter='' ind_tab=' ' end - + str=rexml.collect {|n| if n.class==REXML::Element str_line="" @@ -93,11 +93,11 @@ module OpenNebula str_line end }.compact.join("\n") - + str end - - def to_hash + + def to_hash if !@hash && @xml begin @hash = Crack::XML.parse(to_xml) @@ -116,18 +116,29 @@ module OpenNebula str = "" if pretty REXML::Formatters::Pretty.new(1).write(@xml,str) - else + else REXML::Formatters::Default.new.write(@xml,str) end str end end - + + def XMLUtilsElement.xml_to_hash(xml) + begin + hash = Crack::XML.parse(xml) + rescue Exception => e + error = OpenNebula::Error.new(e.message) + return error + end + + return hash + end + end - + ########################################################################### # The XMLUtilsPool module provides an abstraction of the underlying - # XML parser engine. It provides XML-related methods for the Pools + # XML parser engine. It provides XML-related methods for the Pools ########################################################################### module XMLUtilsPool @@ -141,9 +152,9 @@ module OpenNebula xml=REXML::Document.new(xml).root end end - + #Executes the given block for each element of the Pool - #block:: _Block_ + #block:: _Block_ def each_element(block) if NOKOGIRI @xml.xpath( @@ -165,14 +176,14 @@ module OpenNebula str = "" if pretty REXML::Formatters::Pretty.new(1).write(@xml,str) - else + else REXML::Formatters::Default.new.write(@xml,str) end str end end - - def to_hash + + def to_hash if !@hash && @xml @hash=Crack::XML.parse(to_xml) end From 32e106858c3aac85e8b53387d6d57fe17762b3aa Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Sat, 17 Jul 2010 03:43:34 +0200 Subject: [PATCH 12/27] feature #200: Better XML parsing for ImageOCCI --- src/cloud/common/CloudServer.rb | 22 +-- src/cloud/occi/lib/ImageOCCI.rb | 69 ++++---- src/cloud/occi/lib/OCCIClient.rb | 160 ++++++++++--------- src/cloud/occi/lib/OCCIServer.rb | 261 ++++++++++++++++--------------- src/oca/ruby/OpenNebula/Image.rb | 6 +- 5 files changed, 267 insertions(+), 251 deletions(-) diff --git a/src/cloud/common/CloudServer.rb b/src/cloud/common/CloudServer.rb index 528654d424..11c11d1c33 100755 --- a/src/cloud/common/CloudServer.rb +++ b/src/cloud/common/CloudServer.rb @@ -156,25 +156,24 @@ class CloudServer end end - template = image.to_one_template + # ---------- Allocate the Image file ------------ - rc = image.allocate(template) + rc = image.allocate(image.to_one_template) if OpenNebula.is_error?(rc) return rc end - # Copy the Image file + # ---------- Copy the Image file ------------ + image.info - template=image.to_hash - template=template['IMAGE']['TEMPLATE'] if file_path rc = image.copy(file_path, image['SOURCE']) file[:tempfile].unlink - elsif template['SIZE'] and template['FSTYPE'] + elsif image['TEMPLATE/SIZE'] and image['TEMPLATE/FSTYPE'] rc = image.mk_datablock( - template['SIZE'], - template['FSTYPE'], + image['TEMPLATE/SIZE'], + image['TEMPLATE/FSTYPE'], image['SOURCE']) end @@ -185,12 +184,5 @@ class CloudServer return nil end - - # Gets an image from the repository - # image_id:: _Integer_ Image identifier - # [return] _Image_ Image object - def get_image(image_id) - return nil - end end diff --git a/src/cloud/occi/lib/ImageOCCI.rb b/src/cloud/occi/lib/ImageOCCI.rb index 175743d8b9..c680f8a0b4 100755 --- a/src/cloud/occi/lib/ImageOCCI.rb +++ b/src/cloud/occi/lib/ImageOCCI.rb @@ -23,13 +23,13 @@ class ImageOCCI < Image <%= self.id.to_s %> <%= self.name %> - <% if template['TYPE'] %> - <%= template['TYPE'] %> + <% if self['TEMPLATE/TYPE'] != nil %> + <%= self['TEMPLATE/TYPE'] %> <% end %> - <% if template['DESCRIPTION'] %> - <%= template['DESCRIPTION'] %> + <% if self['TEMPLATE/DESCRIPTION'] != nil %> + <%= self['TEMPLATE/DESCRIPTION'] %> <% end %> - <% if size %> + <% if size != nil %> <%= size %> <% end %> @@ -37,59 +37,62 @@ class ImageOCCI < Image ONE_IMAGE = %q{ - NAME = "<%= image_info['NAME'] %>" - <% if image_info['DESCRIPTION'] %> - DESCRIPTION = "<%= image_info['DESCRIPTION'] %>" + NAME = "<%= @image_info.elements['NAME'].text %>" + <% if @image_info.elements['DESCRIPTION'] != nil %> + DESCRIPTION = "<%= @image_info.elements['DESCRIPTION'].text %>" <% end %> - <% if image_info['TYPE'] %> - TYPE = <%= image_info['TYPE'] %> + <% if @image_info.elements['TYPE'] != nil %> + TYPE = <%= @image_info.elements['TYPE'].text %> <% end %> - <% if image_info['FSTYPE'] %> - FSTYPE = <%= image_info['FSTYPE'] %> + <% if @image_info.elements['FSTYPE'] != nil %> + FSTYPE = <%= @image_info.elements['FSTYPE'].text %> <% end %> - <% if image_info['SIZE'] %> - SIZE = <%= image_info['SIZE'] %> + <% if @image_info.elements['SIZE'] != nil %> + SIZE = <%= @image_info.elements['SIZE'].text %> <% end %> }.gsub(/^ /, '') # Class constructor - def initialize(image_info, xml, client) + def initialize(xml, client, xml_info=nil) super(xml, client) - @image_info = image_info + if xml_info != nil + @image_info = REXML::Document.new(xml_info).root + else + @image_info = nil + end end - + # Creates the OCCI representation of an Image def to_occi(base_url) - image_hash = self.to_hash - return image_hash, 500 if OpenNebula.is_error?(image_hash) - - template = image_hash['IMAGE']['TEMPLATE'] + size = nil + begin - size = File.stat(template['SOURCE']).size if template['SOURCE'] + if self['TEMPLATE/SOURCE'] != nil + size = File.stat(self['TEMPLATE/SOURCE']).size + end rescue Exception => e error = OpenNebula::Error.new(e.message) return error end - + occi = ERB.new(OCCI_IMAGE) return occi.result(binding).gsub(/\n\s*/,'') end - + def to_one_template() - if @image_info['STORAGE'] - image_info = @image_info['STORAGE'] - if !image_info['NAME'] - error_msg = "Missing Image NAME in the XML DISK section" - error = OpenNebula::Error.new(error_msg) - return error - end - else + if @image_info.name != 'STORAGE' error_msg = "Missing STORAGE section in the XML body" error = OpenNebula::Error.new(error_msg) return error end - + + if @image_info.elements['NAME'] == nil + error_msg = "Missing Image NAME in the XML DISK section" + error = OpenNebula::Error.new(error_msg) + return error + end + one = ERB.new(ONE_IMAGE) return one.result(binding) end diff --git a/src/cloud/occi/lib/OCCIClient.rb b/src/cloud/occi/lib/OCCIClient.rb index 25e29edc74..244ef2ccad 100755 --- a/src/cloud/occi/lib/OCCIClient.rb +++ b/src/cloud/occi/lib/OCCIClient.rb @@ -17,27 +17,27 @@ #--------------------------------------------------------------------------- # require 'rubygems' -require 'crack' +require 'rexml/document' require 'uri' require 'CloudClient' module OCCIClient - + ##################################################################### # Client Library to interface with the OpenNebula OCCI Service ##################################################################### - class Client - + class Client + ###################################################################### # Initialize client library ###################################################################### - def initialize(endpoint_str=nil, user=nil, pass=nil, + def initialize(endpoint_str=nil, user=nil, pass=nil, timeout=nil, debug_flag=true) @debug = debug_flag @timeout = timeout - + # Server location if endpoint_str @endpoint = endpoint_str @@ -46,25 +46,25 @@ module OCCIClient else @endpoint = "http://localhost:4567" end - + # Autentication if user && pass @occiauth = [user, pass] else @occiauth = CloudClient::get_one_auth end - + if !@occiauth raise "No authorization data present" end - + @occiauth[1] = Digest::SHA1.hexdigest(@occiauth[1]) end - + ################################# # Pool Resource Request Methods # ################################# - + ###################################################################### # Post a new VM to the VM Pool # :instance_type @@ -72,14 +72,14 @@ module OCCIClient ###################################################################### def post_vms(xmlfile) xml=File.read(xmlfile) - + url = URI.parse(@endpoint+"/compute") - + req = Net::HTTP::Post.new(url.path) req.body=xml - + req.basic_auth @occiauth[0], @occiauth[1] - + res = CloudClient::http_start(url, @timeout) do |http| http.request(req) end @@ -90,88 +90,92 @@ module OCCIClient return res.body end end - + ###################################################################### # Retieves the pool of Virtual Machines ###################################################################### def get_vms url = URI.parse(@endpoint+"/compute") req = Net::HTTP::Get.new(url.path) - + req.basic_auth @occiauth[0], @occiauth[1] - + res = CloudClient::http_start(url, @timeout) {|http| http.request(req) } - + if CloudClient::is_error?(res) return res else return res.body end end - + ###################################################################### # Post a new Network to the VN Pool # :xmlfile xml description of the Virtual Network ###################################################################### def post_network(xmlfile) xml=File.read(xmlfile) - + url = URI.parse(@endpoint+"/network") - + req = Net::HTTP::Post.new(url.path) req.body=xml - + req.basic_auth @occiauth[0], @occiauth[1] - + res = CloudClient::http_start(url, @timeout) do |http| http.request(req) end - + if CloudClient::is_error?(res) return res else return res.body end end - + ###################################################################### # Retieves the pool of Virtual Networks ###################################################################### def get_networks url = URI.parse(@endpoint+"/network") req = Net::HTTP::Get.new(url.path) - + req.basic_auth @occiauth[0], @occiauth[1] - + res = CloudClient::http_start(url, @timeout) {|http| http.request(req) } - + if CloudClient::is_error?(res) return res else return res.body end end - + ###################################################################### # Post a new Image to the Image Pool # :xmlfile ###################################################################### def post_image(xmlfile, curb=true) - xml=File.read(xmlfile) - image_info=Crack::XML.parse(xml) - - file_path = image_info['STORAGE']['URL'] - - m=file_path.match(/^\w+:\/\/(.*)$/) - - if m + xml = File.read(xmlfile) + image_info = REXML::Document.new(xml).root + + if image_info.elements['URL'] == nil + return CloudClient::Error.new("Can not find URL") + end + + file_path = image_info.elements['URL'].text + + m = file_path.match(/^\w+:\/\/(.*)$/) + + if m file_path="/"+m[1] end - + if curb and CURL_LOADED curl=Curl::Easy.new(@endpoint+"/storage") @@ -179,7 +183,7 @@ module OCCIClient curl.userpwd = "#{@occiauth[0]}:#{@occiauth[1]}" curl.verbose = true if @debug curl.multipart_form_post = true - + begin curl.http_post( Curl::PostField.content('occixml', xml), @@ -188,23 +192,23 @@ module OCCIClient rescue Exception => e return CloudClient::Error.new(e.message) end - + return curl.body_str else file=File.open(file_path) - + params=Hash.new params["file"]=UploadIO.new(file, 'application/octet-stream', file_path) - + params['occixml'] = xml - + url = URI.parse(@endpoint+"/storage") - + req = Net::HTTP::Post::Multipart.new(url.path, params) - + req.basic_auth @occiauth[0], @occiauth[1] - + res = CloudClient::http_start(url, @timeout) do |http| http.request(req) end @@ -216,53 +220,53 @@ module OCCIClient else return res.body end - end + end end - + ###################################################################### # Retieves the pool of Images owned by the user ###################################################################### def get_images url = URI.parse(@endpoint+"/storage") req = Net::HTTP::Get.new(url.path) - + req.basic_auth @occiauth[0], @occiauth[1] - + res = CloudClient::http_start(url, @timeout) {|http| http.request(req) } - + if CloudClient::is_error?(res) return res else return res.body end end - + #################################### # Entity Resource Request Methods # #################################### - + ###################################################################### # :id VM identifier ###################################################################### def get_vm(id) url = URI.parse(@endpoint+"/compute/" + id.to_s) req = Net::HTTP::Get.new(url.path) - + req.basic_auth @occiauth[0], @occiauth[1] - + res = CloudClient::http_start(url, @timeout) {|http| http.request(req) } - + if CloudClient::is_error?(res) return res else return res.body end end - + ###################################################################### # Puts a new Compute representation in order to change its state # :xmlfile Compute OCCI xml representation @@ -270,34 +274,34 @@ module OCCIClient def put_vm(xmlfile) xml=File.read(xmlfile) vm_info=Crack::XML.parse(xml) - + url = URI.parse(@endpoint+'/compute/' + vm_info['COMPUTE']['ID']) - + req = Net::HTTP::Put.new(url.path) req.body = xml - + req.basic_auth @occiauth[0], @occiauth[1] - + res = CloudClient::http_start(url, @timeout) do |http| http.request(req) end - + if CloudClient::is_error?(res) return res else return res.body end end - + #################################################################### # :id Compute identifier #################################################################### def delete_vm(id) url = URI.parse(@endpoint+"/compute/" + id.to_s) req = Net::HTTP::Delete.new(url.path) - + req.basic_auth @occiauth[0], @occiauth[1] - + res = CloudClient::http_start(url, @timeout) {|http| http.request(req) } @@ -308,7 +312,7 @@ module OCCIClient return res.body end end - + ###################################################################### # Retrieves a Virtual Network # :id Virtual Network identifier @@ -316,9 +320,9 @@ module OCCIClient def get_network(id) url = URI.parse(@endpoint+"/network/" + id.to_s) req = Net::HTTP::Get.new(url.path) - + req.basic_auth @occiauth[0], @occiauth[1] - + res = CloudClient::http_start(url, @timeout) {|http| http.request(req) } @@ -329,16 +333,16 @@ module OCCIClient return res.body end end - + ###################################################################### # :id VM identifier ###################################################################### def delete_network(id) url = URI.parse(@endpoint+"/network/" + id.to_s) req = Net::HTTP::Delete.new(url.path) - + req.basic_auth @occiauth[0], @occiauth[1] - + res = CloudClient::http_start(url, @timeout) {|http| http.request(req) } @@ -349,7 +353,7 @@ module OCCIClient return res.body end end - + ####################################################################### # Retieves an Image # :image_uuid Image identifier @@ -357,9 +361,9 @@ module OCCIClient def get_image(image_uuid) url = URI.parse(@endpoint+"/storage/"+image_uuid) req = Net::HTTP::Get.new(url.path) - + req.basic_auth @occiauth[0], @occiauth[1] - + res = CloudClient::http_start(url, @timeout) {|http| http.request(req) } @@ -370,16 +374,16 @@ module OCCIClient return res.body end end - + ###################################################################### # :id VM identifier ###################################################################### def delete_image(id) url = URI.parse(@endpoint+"/storage/" + id.to_s) req = Net::HTTP::Delete.new(url.path) - + req.basic_auth @occiauth[0], @occiauth[1] - + res = CloudClient::http_start(url, @timeout) {|http| http.request(req) } diff --git a/src/cloud/occi/lib/OCCIServer.rb b/src/cloud/occi/lib/OCCIServer.rb index fceae8e458..e5d85ac827 100755 --- a/src/cloud/occi/lib/OCCIServer.rb +++ b/src/cloud/occi/lib/OCCIServer.rb @@ -115,9 +115,78 @@ class OCCIServer < CloudServer end end - ################################################### - # Pool Resources methods - ################################################### + ############################################################################ + ############################################################################ + # POOL RESOURCE METHODS + ############################################################################ + ############################################################################ + + # Gets the pool representation of COMPUTES + # request:: _Hash_ hash containing the data of the request + # [return] _String_,_Integer_ Pool Representation or error, status code + def get_computes(request) + # --- Get client with user credentials --- + client = get_client(request.env) + + # --- Get User's VMs --- + user_flag = -1 + vmpool = VirtualMachinePoolOCCI.new(client, user_flag) + + # --- Prepare XML Response --- + rc = vmpool.info + return rc, 404 if OpenNebula.is_error?(rc) + + return to_occi_xml(vmpool) + end + + + # Gets the pool representation of NETWORKS + # request:: _Hash_ hash containing the data of the request + # [return] _String_,_Integer_ Network pool representation or error, + # => status code + def get_networks(request) + # --- Get client with user credentials --- + client = get_client(request.env) + + # --- Get User's VNETs --- + user_flag = -1 + network_pool = VirtualNetworkPoolOCCI.new(client, user_flag) + + rc = network_pool.info + return rc, 404 if OpenNebula.is_error?(rc) + + # --- Prepare XML Response --- + return to_occi_xml(network_pool) + end + + # Gets the pool representation of STORAGES + # request:: _Hash_ hash containing the data of the request + # [return] _String_,_Integer_ Image pool representation or error, + # status code + def get_storages(request) + # --- Get client with user credentials --- + client = get_client(request.env) + + # --- Get User's Images --- + user_flag = -1 + image_pool = ImagePoolOCCI.new(client, user_flag) + + result = image_pool.info + return result, 404 if OpenNebula.is_error?(result) + + # --- Prepare XML Response --- + return to_occi_xml(image_pool) + end + + ############################################################################ + ############################################################################ + # ENTITY RESOURCE METHODS + ############################################################################ + ############################################################################ + + ############################################################################ + # COMPUTE Methods + ############################################################################ # Post a new compute to the COMPUTE pool # request:: _Hash_ hash containing the data of the request @@ -156,124 +225,6 @@ class OCCIServer < CloudServer return to_occi_xml(vm) end - # Gets the pool representation of COMPUTES - # request:: _Hash_ hash containing the data of the request - # [return] _String_,_Integer_ Pool Representation or error, status code - def get_computes(request) - # --- Get client with user credentials --- - client = get_client(request.env) - - # --- Get User's VMs --- - user_flag = -1 - vmpool = VirtualMachinePoolOCCI.new(client, user_flag) - - # --- Prepare XML Response --- - rc = vmpool.info - return rc, 404 if OpenNebula.is_error?(rc) - - return to_occi_xml(vmpool) - end - - # Post a new network to the NETWORK pool - # request:: _Hash_ hash containing the data of the request - # [return] _String_,_Integer_ Network Representation or error, status code - def post_network(request) - # --- Get client with user credentials --- - client = get_client(request.env) - - # --- Create the new Instance --- - network = VirtualNetworkOCCI.new( - VirtualNetwork.build_xml, - client, - request.body, - @config[:bridge]) - - # --- Generate the template and Allocate the new Instance --- - template = network.to_one_template - return template, 500 if OpenNebula.is_error?(template) - - rc = network.allocate(template) - return rc, 500 if OpenNebula.is_error?(rc) - - # --- Prepare XML Response --- - network.info - return to_occi_xml(network) - end - - # Gets the pool representation of NETWORKS - # request:: _Hash_ hash containing the data of the request - # [return] _String_,_Integer_ Network pool representation or error, - # => status code - def get_networks(request) - # --- Get client with user credentials --- - client = get_client(request.env) - - # --- Get User's VNETs --- - user_flag = -1 - network_pool = VirtualNetworkPoolOCCI.new(client, user_flag) - - rc = network_pool.info - return rc, 404 if OpenNebula.is_error?(rc) - - # --- Prepare XML Response --- - return to_occi_xml(network_pool) - end - - # Post a new image to the STORAGE pool - # request:: _Hash_ hash containing the data of the request - # [return] _String_,_Integer_ Image representation or error, status code - def post_storage(request) - # Get client with user credentials - client = get_client(request.env) - - # --- Check OCCI XML from POST --- - if request.params['occixml'] - image_info = XMLUtilsElement::xml_to_hash(request.params['occixml']) - return image_info, 400 if OpenNebula.is_error?(image_info) - else - error_msg = "OCCI XML representation of Image" + - " not present in the request" - error = OpenNebula::Error.new(error_msg) - return error, 400 - end - - # --- Create and Add the new Image --- - image = ImageOCCI.new(image_info, Image.build_xml, client) - - rc = add_image(image, request.params['file']) - return rc, 500 if OpenNebula.is_error?(rc) - - # --- Enable the new Image --- - rc = image.enable - return rc, 500 if OpenNebula.is_error?(rc) - - # --- Prepare XML Response --- - return to_occi_xml(image) - end - - # Gets the pool representation of STORAGES - # request:: _Hash_ hash containing the data of the request - # [return] _String_,_Integer_ Image pool representation or error, - # status code - def get_storages(request) - # --- Get client with user credentials --- - client = get_client(request.env) - - # --- Get User's Images --- - user_flag = -1 - image_pool = ImagePoolOCCI.new(client, user_flag) - - result = image_pool.info - return result, 404 if OpenNebula.is_error?(result) - - # --- Prepare XML Response --- - return to_occi_xml(image_pool) - end - - ################################################### - # Entity Resources methods - ################################################### - # Get the representation of a COMPUTE resource # request:: _Hash_ hash containing the data of the request # [return] _String_,_Integer_ COMPUTE representation or error, @@ -295,6 +246,7 @@ class OCCIServer < CloudServer return to_occi_xml(vm) end + # Deletes a COMPUTE resource # request:: _Hash_ hash containing the data of the request # [return] _String_,_Integer_ Delete confirmation msg or error, @@ -347,6 +299,36 @@ class OCCIServer < CloudServer return to_occi_xml(vm) end + ############################################################################ + # NETWORK Methods + ############################################################################ + + # Post a new network to the NETWORK pool + # request:: _Hash_ hash containing the data of the request + # [return] _String_,_Integer_ Network Representation or error, status code + def post_network(request) + # --- Get client with user credentials --- + client = get_client(request.env) + + # --- Create the new Instance --- + network = VirtualNetworkOCCI.new( + VirtualNetwork.build_xml, + client, + request.body, + @config[:bridge]) + + # --- Generate the template and Allocate the new Instance --- + template = network.to_one_template + return template, 500 if OpenNebula.is_error?(template) + + rc = network.allocate(template) + return rc, 500 if OpenNebula.is_error?(rc) + + # --- Prepare XML Response --- + network.info + return to_occi_xml(network) + end + # Retrieves a NETWORK resource # request:: _Hash_ hash containing the data of the request # [return] _String_,_Integer_ NETWORK occi representation or error, @@ -386,6 +368,39 @@ class OCCIServer < CloudServer return "", 204 end + ############################################################################ + # STORAGE Methods + ############################################################################ + + # Post a new image to the STORAGE pool + # request:: _Hash_ hash containing the data of the request + # [return] _String_,_Integer_ Image representation or error, status code + def post_storage(request) + # Get client with user credentials + client = get_client(request.env) + + # --- Check OCCI XML from POST --- + if request.params['occixml'] == nil + error_msg = "OCCI XML representation of Image" + + " not present in the request" + error = OpenNebula::Error.new(error_msg) + return error, 400 + end + + # --- Create and Add the new Image --- + image = ImageOCCI.new(Image.build_xml,client, request.params['occixml']) + + rc = add_image(image, request.params['file']) + return rc, 500 if OpenNebula.is_error?(rc) + + # --- Enable the new Image --- + rc = image.enable + return rc, 500 if OpenNebula.is_error?(rc) + + # --- Prepare XML Response --- + return to_occi_xml(image) + end + # Get a STORAGE resource # request:: _Hash_ hash containing the data of the request # [return] _String_,_Integer_ STORAGE occi representation or error, @@ -395,7 +410,7 @@ class OCCIServer < CloudServer client = get_client(request.env) # --- Get the Image --- - image = ImageOCCI.new(nil, Image.build_xml(params[:id]), client) + image = ImageOCCI.new(Image.build_xml(params[:id]), client) result = image.info return result, 404 if OpenNebula::is_error?(result) @@ -412,7 +427,7 @@ class OCCIServer < CloudServer # --- Get client with user credentials --- client = get_client(request.env) - image = ImageOCCI.new(nil, Image.build_xml(params[:id]), client) + image = ImageOCCI.new(Image.build_xml(params[:id]), client) # --- Delete the Image --- result = image.delete diff --git a/src/oca/ruby/OpenNebula/Image.rb b/src/oca/ruby/OpenNebula/Image.rb index f5b7d31b42..70da993ec7 100644 --- a/src/oca/ruby/OpenNebula/Image.rb +++ b/src/oca/ruby/OpenNebula/Image.rb @@ -190,8 +190,10 @@ module OpenNebula return OpenNebula::Error.new("copy Image: missing parameters.") end - if !FileUtils.copy(path, source) - return OpenNebula::Error.new("copy Image: in File.copy") + begin + FileUtils.copy(path, source) + rescue Exception => e + return OpenNebula::Error.new(e.message) end return nil From 1078c304c0cde772b66aed3292a06ba9a20016a4 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Sat, 17 Jul 2010 03:44:48 +0200 Subject: [PATCH 13/27] feature #200: Examples for the OCCI service --- src/cloud/occi/share/examples/network | 5 +++++ src/cloud/occi/share/examples/storage | 6 ++++++ 2 files changed, 11 insertions(+) create mode 100644 src/cloud/occi/share/examples/network create mode 100644 src/cloud/occi/share/examples/storage diff --git a/src/cloud/occi/share/examples/network b/src/cloud/occi/share/examples/network new file mode 100644 index 0000000000..c460184059 --- /dev/null +++ b/src/cloud/occi/share/examples/network @@ -0,0 +1,5 @@ + + MyServiceNetwork +
192.168.1.1
+ 200 +
diff --git a/src/cloud/occi/share/examples/storage b/src/cloud/occi/share/examples/storage new file mode 100644 index 0000000000..368ce71e21 --- /dev/null +++ b/src/cloud/occi/share/examples/storage @@ -0,0 +1,6 @@ + + Ubuntu Desktop + Ubuntu 10.04 desktop for students. + OS + file:///images/ubuntu/jaunty.img + From 64560518ce060ef0e32efaf397b207a0c26ef0aa Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Sat, 17 Jul 2010 03:45:43 +0200 Subject: [PATCH 14/27] feature #200: Removed unneeded rm component for cloud servers --- src/cloud/rm/image.rb | 182 ----------------------------------- src/cloud/rm/repo_manager.rb | 66 ------------- 2 files changed, 248 deletions(-) delete mode 100644 src/cloud/rm/image.rb delete mode 100644 src/cloud/rm/repo_manager.rb diff --git a/src/cloud/rm/image.rb b/src/cloud/rm/image.rb deleted file mode 100644 index 15e9695d06..0000000000 --- a/src/cloud/rm/image.rb +++ /dev/null @@ -1,182 +0,0 @@ -# -------------------------------------------------------------------------- # -# Copyright 2002-2010, 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 OpenNebula - class Image < Sequel::Model - plugin :schema - plugin :hook_class_methods - - # Creates the database table asociated with the model. It first - # checks for table existence before creating it so it is reasonably - # safe to call it when you load the library. - def self.initialize_table - set_schema do - primary_key :id, :type => Integer - int :owner - varchar :name - varchar :description - varchar :path - int :size - varchar :md5 - end - - create_table unless table_exists? - end - - # Makes sure the image is deleted from the repository after - # the record is deleted. Make sure that you use destroy and not - # delete as delete method does not call hooks. - before_destroy do - FileUtils.rm(self.path) - end - - # Specifies the directory where images will be stored - # dir:: _String_ directory where the images are stored - def self.image_dir=(dir) - @@image_dir=dir - end - - # Strips out non user writable columns - # metadata:: _Hash_ hash containing the data to add to the db - # [return] _Hash_ clean metadata - def self.sanitize_metadata(metadata) - metadata.reject {|key,value| - ![:name, :description].include? key - } - end - - # Creates a new Image object, fills it, copies the image - # to the repository and saves to the database - # owner:: _Integer_ identifier of the user that owns this image - # path:: _String_ place where to copy the image from - # metadata:: _Hash_ extra data to add to the image, like name and description - # [return] _Image_ newly created image - def self.create_image(owner, path, metadata={}) - sanitized_metadata=sanitize_metadata(metadata) - - data={ - :owner => owner, - }.merge(sanitized_metadata) - - image=Image.new(data) - - image.save - - # TODO: make copy or movement configurable - image.copy_image(path, true) - image.get_image_info - - image.save - - image - - # set metadata - end - - def identifier - self.id - end - - # Updates the image with the metadata provided. Currently only - # name and description can be changed - def change_metadata(metadata) - update(Image.sanitize_metadata(metadata)) - end - - # Copies the image from the source path to the image repository. - # Its name will be the image id. It also stores its new location - # in the object. - def copy_image(path, move=false) - if move - FileUtils.mv(path, image_path) - else - FileUtils.cp(path, image_path) - end - self.path=image_path - end - - # Returns the filename and path of the image file associated with - # this Image object. - def image_path - @@image_dir||='images' - File.join(@@image_dir, self.id.to_s) - end - - # Extracts md5 and size from the image file and stores these data - # in the object. - def get_image_info - self.md5=`md5sum #{image_path}`.split.first - self.size=File.size(image_path) - end - - # Adds a user to the list of allowed users of this image - def add_acl(user) - acl=ImageAcl.new({:image_id => self.id, :user => user}) - acl.save - end - - # Deletes a user fom the list of allowed users of this image - def del_acl(user) - acl=ImageAcl[:image_id => self.id, :user => user] - acl.destroy if acl - end - - # Checks if a user has permissions to use this image - def has_permission?(user) - return true if self.owner==user - ImageAcl[:image_id => self.id, :user => user]!=nil - end - - # Returns the xml representation of the image. - def to_xml - xml="\n" - xml<<" #{id}\n" - xml<<" #{owner}\n" - xml<<" #{name}\n" - xml<<" #{description}\n" - xml<<" #{path}\n" - xml<<" #{size}\n" - xml<<" #{md5}\n" - xml<<"\n" - end - - # Like to_xml but does not show image file path data - def to_xml_lite - xml="\n" - xml<<" #{id}\n" - xml<<" #{owner}\n" - xml<<" #{name}\n" - xml<<" #{description}\n" - xml<<" #{size}\n" - xml<<" #{md5}\n" - xml<<"\n" - end - end - - class ImageAcl < Sequel::Model - plugin :schema - - def self.initialize_table - set_schema do - primary_key :id, :type => Integer - varchar :image_id - int :user - end - - create_table unless table_exists? - end - end -end diff --git a/src/cloud/rm/repo_manager.rb b/src/cloud/rm/repo_manager.rb deleted file mode 100644 index fd3139f83f..0000000000 --- a/src/cloud/rm/repo_manager.rb +++ /dev/null @@ -1,66 +0,0 @@ -# -------------------------------------------------------------------------- # -# Copyright 2002-2010, 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 'fileutils' -require 'sequel' -require 'logger' - -module OpenNebula - class RepoManager - def initialize(rm_db=nil) - raise "DB not defined" if !rm_db - - @db=Sequel.sqlite(rm_db) - - require 'image' - - Image.initialize_table - ImageAcl.initialize_table - end - - def add(owner, path, metadata={}) - Image.create_image(owner, path, metadata) - end - - def get(image_id) - Image[:id => image_id] - end - - def update(image_id, metadata) - image=get(image_id) - image.update(metadata) - end - - - end - -end - -=begin -OpenNebula::Image.create_image(10, 'repo_manager.rb', - :name => 'nombre', - :noexiste => 'nada' -) -=end - -if $0 == __FILE__ - rm=OpenNebula::RepoManager.new - img=rm.add_image(rand(100), 'image.rb', - :name => 'nombre', - :description => 'desc') - puts img.to_xml -end From 95d0cf7841ca640a3ae32551022958280fdb2c93 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Sat, 17 Jul 2010 03:48:07 +0200 Subject: [PATCH 15/27] feature #200: rm is no longer installed --- install.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/install.sh b/install.sh index 624e14ea41..964a77bcff 100755 --- a/install.sh +++ b/install.sh @@ -488,9 +488,7 @@ HOOK_SHARE_FILES="share/hooks/ebtables-xen \ COMMON_CLOUD_LIB_FILES="src/cloud/common/CloudServer.rb \ src/cloud/common/CloudClient.rb \ - src/cloud/common/Configuration.rb \ - src/cloud/rm/image.rb \ - src/cloud/rm/repo_manager.rb" + src/cloud/common/Configuration.rb" COMMON_CLOUD_CLIENT_LIB_FILES="src/cloud/common/CloudClient.rb" From a6edd2483a8d6a9b0983ef934056a25d0a012c6d Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Sat, 17 Jul 2010 06:42:26 +0200 Subject: [PATCH 16/27] feature #200: Get rid of Crack library for OCCI. OCCI now uses OpenNebula authorization mechanisms --- src/cloud/common/CloudServer.rb | 45 +-------- src/cloud/occi/bin/occi-storage | 30 +++--- src/cloud/occi/etc/templates/large.erb | 57 ++++++----- src/cloud/occi/etc/templates/medium.erb | 58 ++++++----- src/cloud/occi/etc/templates/small.erb | 58 ++++++----- src/cloud/occi/lib/ImageOCCI.rb | 28 +++--- src/cloud/occi/lib/OCCIServer.rb | 120 +++++------------------ src/cloud/occi/lib/VirtualMachineOCCI.rb | 90 +++++++++-------- src/cloud/occi/lib/VirtualNetworkOCCI.rb | 24 ++--- src/cloud/occi/lib/occi-server.rb | 7 -- src/oca/ruby/OpenNebula/XMLUtils.rb | 71 +++++++++++--- 11 files changed, 269 insertions(+), 319 deletions(-) diff --git a/src/cloud/common/CloudServer.rb b/src/cloud/common/CloudServer.rb index 11c11d1c33..762f51d2ab 100755 --- a/src/cloud/common/CloudServer.rb +++ b/src/cloud/common/CloudServer.rb @@ -82,54 +82,13 @@ class CloudServer # Generates an OpenNebula Session for the given user # user:: _Hash_ the user information # [return] an OpenNebula client session - def one_client_user(user) + def one_client_user(name, password) client = Client.new("dummy:dummy") - client.one_auth = "#{user[:name]}:#{user[:password]}" + client.one_auth = "#{name}:#{password}" return client end - # Authenticates a user - # name:: _String_ of the user - # password:: _String_ of the user - # [return] true if authenticated - def authenticate?(name, password) - user = get_user(name) - - return user && user.password == password - end - - # Gets the data associated with a user - # name:: _String_ the name of the user - # [return] _Hash_ with the user data - def get_user(name) - user = nil - - @user_pool.info - @user_pool.each{ |u| - if u.name==name - user=Hash.new - - user[:id] = u.id - user[:name] = u.name - user[:password] = u[:password] - end - } - return user - end - - def get_template_path(instance_type_name) - - instance_type=@instance_types[instance_type_name] - - if !instance_type - error = OpenNebula::Error.new("Bad instance type") - return error - end - - return @config[:template_location]+"/#{instance_type['TEMPLATE']}" - end - ########################################################################### # Repository Methods ########################################################################### diff --git a/src/cloud/occi/bin/occi-storage b/src/cloud/occi/bin/occi-storage index 93b6436d3f..4387b2ab27 100755 --- a/src/cloud/occi/bin/occi-storage +++ b/src/cloud/occi/bin/occi-storage @@ -31,7 +31,7 @@ $: << RUBY_LIB_LOCATION+"/cloud" COMMANDS_HELP=<<-EOT ** Synopsis occi-storage - + Manages OCCI storage resource ** Usage @@ -40,7 +40,7 @@ occi-storage [OPTIONS] [PARAMETERS] COMMANDS create - creates a new storage resource described by the provided + creates a new storage resource described by the provided list @@ -81,7 +81,7 @@ EOT require 'occi/OCCIClient' require 'CloudClient' require 'getoptlong' -require "rexml/document" +require 'rexml/document' require 'pp' include CloudCLI @@ -120,12 +120,12 @@ begin when '--debug' debug = true when '--multipart' - curb = false + curb = false end end rescue Exception => e exit(-1) -end +end if !ARGV[0] puts "#{cmd_name}: [COMMAND] not present" @@ -158,21 +158,21 @@ case ARGV[0].downcase when 'show' image_id = ARGV[1] - if !image_id + if !image_id puts "#{cmd_name} show: missing storage id parameter" exit(-1) end - + rc = occi_client.get_image(image_id) when 'delete' image_id = ARGV[1] - if !image_id + if !image_id puts "#{cmd_name} show: missing storage id parameter" exit(-1) end - + rc = occi_client.delete_image(image_id) else @@ -182,22 +182,22 @@ end if CloudClient::is_error?(rc) puts rc.to_s() -else +else begin doc = REXML::Document.new(rc) rescue REXML::ParseException => e - puts e.message + puts e.message exit(-1) end - + xml = doc.root - + if xml.nil? puts rc exit(-1) end - + str = "" REXML::Formatters::Pretty.new(4).write(xml,str) - puts "\n" + str + "\n " + puts "\n" + str + "\n " end diff --git a/src/cloud/occi/etc/templates/large.erb b/src/cloud/occi/etc/templates/large.erb index e59ed9a0f2..e6d1a94155 100644 --- a/src/cloud/occi/etc/templates/large.erb +++ b/src/cloud/occi/etc/templates/large.erb @@ -1,33 +1,40 @@ +# +# Virtual Machine Template generated for large instance types. Adjust this +# by setting the desired capacity (CPU,MEMORY) or adding specific +# attributes for your cloud (e.g. OS). You should not need to change the DISK +# and NIC sections +# + CPU = 8 MEMORY = 8192 -NAME = <%= vm_info['NAME'] %> +NAME = <%= @vm_info['NAME'] %> -<% if vm_info['DISK'] %> - <% vm_info['DISK'].each do |disk| %> - <% if disk['STORAGE'] && disk['STORAGE']['href'] %> - DISK = [ IMAGE_ID = <%= disk['STORAGE']['href'].split('/').last %> - <% if disk.key?('OVERWRITE') %> - ,OVERWRITE = "yes" - <% end %> - <% if disk['SAVE_AS'] %> - ,SAVE_AS = "<%= disk['SAVE_AS'] %>" - <% end %> - ] - <% end %> - <% end %> +<% if @vm_info['DISK'] %> + <% @vm_info.each('DISK') do |disk| %> + <% if disk['STORAGE'] && disk.attr('STORAGE','href') %> + DISK = [ IMAGE_ID = <%= disk.attr('STORAGE','href').split('/').last %> + <% if disk['OVERWRITE'] %> + ,OVERWRITE = "yes" + <% end %> + <% if disk['SAVE_AS'] %> + ,SAVE_AS = "<%= disk['SAVE_AS'] %>" + <% end %> + ] + <% end %> + <% end %> <% end %> -<% if vm_info['NIC'] %> - <% vm_info['NIC'].each do |nic| %> - <% if nic['NETWORK'] && nic['NETWORK']['href'] %> - NIC = [ NETWORK_ID = <%= nic['NETWORK']['href'].split('/').last %> - <% if nic['IP'] %> - ,IP = <%= nic['IP'] %> - <% end %> - ] - <% end %> - <% end %> +<% if @vm_info['NIC'] %> + <% @vm_info.each('NIC') do |nic| %> + <% if nic['NETWORK'] && nic.attr('NETWORK','href') %> + NIC = [ NETWORK_ID = <%= nic.attr('NETWORK','href').split('/').last %> + <% if nic['IP'] %> + ,IP = <%= nic['IP'] %> + <% end %> + ] + <% end %> + <% end %> <% end %> -INSTANCE_TYPE = <%= vm_info['INSTANCE_TYPE']%> \ No newline at end of file +INSTANCE_TYPE = <%= @vm_info['INSTANCE_TYPE']%> \ No newline at end of file diff --git a/src/cloud/occi/etc/templates/medium.erb b/src/cloud/occi/etc/templates/medium.erb index 6263c34cf9..ab6bda21c7 100644 --- a/src/cloud/occi/etc/templates/medium.erb +++ b/src/cloud/occi/etc/templates/medium.erb @@ -1,33 +1,41 @@ +# +# Virtual Machine Template generated for medium instance types. Adjust this +# by setting the desired capacity (CPU,MEMORY) or adding specific +# attributes for your cloud (e.g. OS). You should not need to change the DISK +# and NIC sections +# + CPU = 4 MEMORY = 4096 -NAME = <%= vm_info['NAME'] %> +NAME = <%= @vm_info['NAME'] %> -<% if vm_info['DISK'] %> - <% vm_info['DISK'].each do |disk| %> - <% if disk['STORAGE'] && disk['STORAGE']['href'] %> - DISK = [ IMAGE_ID = <%= disk['STORAGE']['href'].split('/').last %> - <% if disk.key?('OVERWRITE') %> - ,OVERWRITE = "yes" - <% end %> - <% if disk['SAVE_AS'] %> - ,SAVE_AS = "<%= disk['SAVE_AS'] %>" - <% end %> - ] - <% end %> - <% end %> +<% if @vm_info['DISK'] %> + <% @vm_info.each('DISK') do |disk| %> + <% if disk['STORAGE'] && disk.attr('STORAGE','href') %> + DISK = [ IMAGE_ID = <%= disk.attr('STORAGE','href').split('/').last %> + <% if disk['OVERWRITE'] %> + ,OVERWRITE = "yes" + <% end %> + <% if disk['SAVE_AS'] %> + ,SAVE_AS = "<%= disk['SAVE_AS'] %>" + <% end %> + ] + <% end %> + <% end %> <% end %> -<% if vm_info['NIC'] %> - <% vm_info['NIC'].each do |nic| %> - <% if nic['NETWORK'] && nic['NETWORK']['href'] %> - NIC = [ NETWORK_ID = <%= nic['NETWORK']['href'].split('/').last %> - <% if nic['IP'] %> - ,IP = <%= nic['IP'] %> - <% end %> - ] - <% end %> - <% end %> +<% if @vm_info['NIC'] %> + <% @vm_info.each('NIC') do |nic| %> + <% if nic['NETWORK'] && nic.attr('NETWORK','href') %> + NIC = [ NETWORK_ID = <%= nic.attr('NETWORK','href').split('/').last %> + <% if nic['IP'] %> + ,IP = <%= nic['IP'] %> + <% end %> + ] + <% end %> + <% end %> <% end %> -INSTANCE_TYPE = <%= vm_info['INSTANCE_TYPE']%> \ No newline at end of file +INSTANCE_TYPE = <%= @vm_info['INSTANCE_TYPE']%> + diff --git a/src/cloud/occi/etc/templates/small.erb b/src/cloud/occi/etc/templates/small.erb index fb28e17cb2..9c448bb7fd 100644 --- a/src/cloud/occi/etc/templates/small.erb +++ b/src/cloud/occi/etc/templates/small.erb @@ -1,33 +1,41 @@ +# +# Virtual Machine Template generated for small instance types. Adjust this +# by setting the desired capacity (CPU,MEMORY) or adding specific +# attributes for your cloud (e.g. OS). You should not need to change the DISK +# and NIC sections +# + CPU = 1 MEMORY = 1024 -NAME = <%= vm_info['NAME'] %> +NAME = <%= @vm_info['NAME'] %> -<% if vm_info['DISK'] %> - <% vm_info['DISK'].each do |disk| %> - <% if disk['STORAGE'] && disk['STORAGE']['href'] %> - DISK = [ IMAGE_ID = <%= disk['STORAGE']['href'].split('/').last %> - <% if disk.key?('OVERWRITE') %> - ,OVERWRITE = "yes" - <% end %> - <% if disk['SAVE_AS'] %> - ,SAVE_AS = "<%= disk['SAVE_AS'] %>" - <% end %> - ] - <% end %> - <% end %> +<% if @vm_info['DISK'] %> + <% @vm_info.each('DISK') do |disk| %> + <% if disk['STORAGE'] && disk.attr('STORAGE','href') %> + DISK = [ IMAGE_ID = <%= disk.attr('STORAGE','href').split('/').last %> + <% if disk['OVERWRITE'] %> + ,OVERWRITE = "yes" + <% end %> + <% if disk['SAVE_AS'] %> + ,SAVE_AS = "<%= disk['SAVE_AS'] %>" + <% end %> + ] + <% end %> + <% end %> <% end %> -<% if vm_info['NIC'] %> - <% vm_info['NIC'].each do |nic| %> - <% if nic['NETWORK'] && nic['NETWORK']['href'] %> - NIC = [ NETWORK_ID = <%= nic['NETWORK']['href'].split('/').last %> - <% if nic['IP'] %> - ,IP = <%= nic['IP'] %> - <% end %> - ] - <% end %> - <% end %> +<% if @vm_info['NIC'] %> + <% @vm_info.each('NIC') do |nic| %> + <% if nic['NETWORK'] && nic.attr('NETWORK','href') %> + NIC = [ NETWORK_ID = <%= nic.attr('NETWORK','href').split('/').last %> + <% if nic['IP'] %> + ,IP = <%= nic['IP'] %> + <% end %> + ] + <% end %> + <% end %> <% end %> -INSTANCE_TYPE = <%= vm_info['INSTANCE_TYPE']%> \ No newline at end of file +INSTANCE_TYPE = <%= @vm_info['INSTANCE_TYPE']%> + diff --git a/src/cloud/occi/lib/ImageOCCI.rb b/src/cloud/occi/lib/ImageOCCI.rb index c680f8a0b4..62e66a1d1f 100755 --- a/src/cloud/occi/lib/ImageOCCI.rb +++ b/src/cloud/occi/lib/ImageOCCI.rb @@ -37,29 +37,29 @@ class ImageOCCI < Image ONE_IMAGE = %q{ - NAME = "<%= @image_info.elements['NAME'].text %>" - <% if @image_info.elements['DESCRIPTION'] != nil %> - DESCRIPTION = "<%= @image_info.elements['DESCRIPTION'].text %>" + NAME = "<%= @image_info['NAME'] %>" + <% if @image_info['DESCRIPTION'] != nil %> + DESCRIPTION = "<%= @image_info['DESCRIPTION'] %>" <% end %> - <% if @image_info.elements['TYPE'] != nil %> - TYPE = <%= @image_info.elements['TYPE'].text %> + <% if @image_info['TYPE'] != nil %> + TYPE = <%= @image_info['TYPE'] %> <% end %> - <% if @image_info.elements['FSTYPE'] != nil %> - FSTYPE = <%= @image_info.elements['FSTYPE'].text %> + <% if @image_info['FSTYPE'] != nil %> + FSTYPE = <%= @image_info['FSTYPE'] %> <% end %> - <% if @image_info.elements['SIZE'] != nil %> - SIZE = <%= @image_info.elements['SIZE'].text %> + <% if @image_info['SIZE'] != nil %> + SIZE = <%= @image_info['SIZE'] %> <% end %> }.gsub(/^ /, '') # Class constructor def initialize(xml, client, xml_info=nil) super(xml, client) + @image_info = nil if xml_info != nil - @image_info = REXML::Document.new(xml_info).root - else - @image_info = nil + xmldoc = XMLUtilsElement.initialize_xml(xml_info, 'STORAGE') + @image_info = XMLElement.new(xmldoc) if xmldoc != nil end end @@ -81,13 +81,13 @@ class ImageOCCI < Image end def to_one_template() - if @image_info.name != 'STORAGE' + if @image_info == nil error_msg = "Missing STORAGE section in the XML body" error = OpenNebula::Error.new(error_msg) return error end - if @image_info.elements['NAME'] == nil + if @image_info['NAME'] == nil error_msg = "Missing Image NAME in the XML DISK section" error = OpenNebula::Error.new(error_msg) return error diff --git a/src/cloud/occi/lib/OCCIServer.rb b/src/cloud/occi/lib/OCCIServer.rb index e5d85ac827..88de9df234 100755 --- a/src/cloud/occi/lib/OCCIServer.rb +++ b/src/cloud/occi/lib/OCCIServer.rb @@ -57,41 +57,13 @@ class OCCIServer < CloudServer print_configuration end - # Authorization function - # requestenv:: _Hash_ Hash containing the environment of the request - # [return] _Boolean_ Whether the user is authorized or not - def authenticate?(requestenv) - auth ||= Rack::Auth::Basic::Request.new(requestenv) - - if !(auth.provided? && auth.basic? && auth.credentials) - return false - end - - user = get_user(requestenv, auth) - - if user - if user[:password] == auth.credentials[1] - return true - end - else - return false - end - end - - # Retrieve the user crendentials - # requestenv:: _Hash_ Hash containing the environment of the request - # [return] _User_ User structure - def get_user(requestenv, auth=nil) - auth = Rack::Auth::Basic::Request.new(requestenv) if !auth - super(auth.credentials.first) - end - # Retrieve a client with the user credentials # requestenv:: _Hash_ Hash containing the environment of the request # [return] _Client_ client with the user credentials def get_client(requestenv) - user = get_user(requestenv) - return one_client_user(user) + auth = Rack::Auth::Basic::Request.new(requestenv) + + return one_client_user(auth.credentials[0], auth.credentials[1]) end # Prepare the OCCI XML Response @@ -104,17 +76,6 @@ class OCCIServer < CloudServer return xml_response, 201 end - def get_info_hash(body) - if body - info = XMLUtilsElement::xml_to_hash(body.read) - return info - else - error_msg = "OCCI XML representation not present" - error = OpenNebula::Error.new(error_msg) - return error - end - end - ############################################################################ ############################################################################ # POOL RESOURCE METHODS @@ -192,26 +153,14 @@ class OCCIServer < CloudServer # request:: _Hash_ hash containing the data of the request # [return] _String_,_Integer_ COMPUTE Representation or error, status code def post_compute(request) - # --- Get client with user credentials --- - client = get_client(request.env) - - # --- Check OCCI XML from POST --- - vm_info = get_info_hash(request.body) - return vm_info, 400 if OpenNebula.is_error?(vm_info) - - # --- Get Template Path --- - if vm_info['COMPUTE'] - path = get_template_path(vm_info['COMPUTE']['INSTANCE_TYPE']) - return path, 500 if OpenNebula.is_error?(path) - - vm_info['TEMPLATE_PATH'] = path - end # --- Create the new Instance --- vm = VirtualMachineOCCI.new( - vm_info, VirtualMachine.build_xml, - client) + get_client(request.env), + request.body.read, + @instance_types, + @config[:template_location]) # --- Generate the template and Allocate the new Instance --- template = vm.to_one_template @@ -230,14 +179,11 @@ class OCCIServer < CloudServer # [return] _String_,_Integer_ COMPUTE representation or error, # status code def get_compute(request, params) - # --- Get client with user credentials --- - client = get_client(request.env) # --- Get the VM --- vm = VirtualMachineOCCI.new( - nil, VirtualMachine.build_xml(params[:id]), - client) + get_client(request.env)) result = vm.info return result, 404 if OpenNebula::is_error?(result) @@ -252,13 +198,11 @@ class OCCIServer < CloudServer # [return] _String_,_Integer_ Delete confirmation msg or error, # status code def delete_compute(request, params) - # --- Get client with user credentials --- - client = get_client(request.env) + # --- Get the VM --- vm = VirtualMachineOCCI.new( - nil, VirtualMachine.build_xml(params[:id]), - client) + get_client(request.env)) # --- Finalize the VM --- result = vm.finalize @@ -272,21 +216,16 @@ class OCCIServer < CloudServer # [return] _String_,_Integer_ Update confirmation msg or error, # status code def put_compute(request, params) - # --- Get client with user credentials --- - client = get_client(request.env) - - # --- Check OCCI XML from POST --- - vm_info = get_info_hash(request.body) - return vm_info, 400 if OpenNebula.is_error?(vm_info) + vm_info = XMLUtilsElement.initialize_xml(xml_info, 'COMPUTE') # --- Get the VM and Action on it --- - if vm_info['COMPUTE'] && vm_info['COMPUTE']['STATE'] + if vm_info['STATE'] != nil vm = VirtualMachineOCCI.new( - vm_info, VirtualMachine.build_xml(params[:id]), - client) + get_client(request.env)) + + rc = vm.mk_action(vm_info['STATE']) - rc = vm.mk_action(vm_info['COMPUTE']['STATE']) return rc, 400 if OpenNebula.is_error?(rc) else error_msg = "State not defined in the OCCI XML" @@ -307,13 +246,11 @@ class OCCIServer < CloudServer # request:: _Hash_ hash containing the data of the request # [return] _String_,_Integer_ Network Representation or error, status code def post_network(request) - # --- Get client with user credentials --- - client = get_client(request.env) # --- Create the new Instance --- network = VirtualNetworkOCCI.new( VirtualNetwork.build_xml, - client, + get_client(request.env), request.body, @config[:bridge]) @@ -334,13 +271,10 @@ class OCCIServer < CloudServer # [return] _String_,_Integer_ NETWORK occi representation or error, # status code def get_network(request, params) - # --- Get client with user credentials --- - client = get_client(request.env) - # --- Get the VM --- network = VirtualNetworkOCCI.new( VirtualNetwork.build_xml(params[:id]), - client) + get_client(request.env)) result = network.info return result, 404 if OpenNebula::is_error?(result) @@ -354,12 +288,10 @@ class OCCIServer < CloudServer # [return] _String_,_Integer_ Delete confirmation msg or error, # status code def delete_network(request, params) - # --- Get client with user credentials --- - client = get_client(request.env) vn = VirtualNetworkOCCI.new( VirtualNetwork.build_xml(params[:id]), - client) + get_client(request.env)) # --- Delete the VNET --- result = vn.delete @@ -376,8 +308,6 @@ class OCCIServer < CloudServer # request:: _Hash_ hash containing the data of the request # [return] _String_,_Integer_ Image representation or error, status code def post_storage(request) - # Get client with user credentials - client = get_client(request.env) # --- Check OCCI XML from POST --- if request.params['occixml'] == nil @@ -388,7 +318,9 @@ class OCCIServer < CloudServer end # --- Create and Add the new Image --- - image = ImageOCCI.new(Image.build_xml,client, request.params['occixml']) + image = ImageOCCI.new(Image.build_xml, + get_client(request.env), + request.params['occixml']) rc = add_image(image, request.params['file']) return rc, 500 if OpenNebula.is_error?(rc) @@ -406,11 +338,10 @@ class OCCIServer < CloudServer # [return] _String_,_Integer_ STORAGE occi representation or error, # status code def get_storage(request, params) - # --- Get client with user credentials --- - client = get_client(request.env) # --- Get the Image --- - image = ImageOCCI.new(Image.build_xml(params[:id]), client) + image = ImageOCCI.new(Image.build_xml(params[:id]), + get_client(request.env)) result = image.info return result, 404 if OpenNebula::is_error?(result) @@ -424,10 +355,9 @@ class OCCIServer < CloudServer # [return] _String_,_Integer_ Delete confirmation msg or error, # status code def delete_storage(request, params) - # --- Get client with user credentials --- - client = get_client(request.env) - image = ImageOCCI.new(Image.build_xml(params[:id]), client) + image = ImageOCCI.new(Image.build_xml(params[:id]), + get_client(request.env)) # --- Delete the Image --- result = image.delete diff --git a/src/cloud/occi/lib/VirtualMachineOCCI.rb b/src/cloud/occi/lib/VirtualMachineOCCI.rb index 4fb2e2e119..91ea253585 100755 --- a/src/cloud/occi/lib/VirtualMachineOCCI.rb +++ b/src/cloud/occi/lib/VirtualMachineOCCI.rb @@ -23,12 +23,12 @@ class VirtualMachineOCCI < VirtualMachine <%= self.id.to_s%> <%= self.name%> - <% if template['INSTANCE_TYPE'] %> - <%= template['INSTANCE_TYPE'] %> + <% if self['TEMPLATE/INSTANCE_TYPE'] %> + <%= self['TEMPLATE/INSTANCE_TYPE'] %> <% end %> <%= self.state_str %> - <% if template['DISK'] %> - <% template['DISK'].each do |disk| %> + <% if self['TEMPLATE/DISK'] %> + <% self.each('TEMPLATE/DISK') do |disk| %> <%= disk['TYPE'] %> @@ -42,8 +42,8 @@ class VirtualMachineOCCI < VirtualMachine <% end %> <% end %> - <% if template['NIC'] %> - <% template['NIC'].each do |nic| %> + <% if self['TEMPLATE/NIC'] %> + <% self.each('TEMPLATE/NIC') do |nic| %> <% if nic['IP'] %> @@ -55,19 +55,33 @@ class VirtualMachineOCCI < VirtualMachine <% end %> <% end %> - +
} - - # Class constructor - def initialize(vm_info, xml, client) - super(xml, client) - @vm_info = vm_info + # Class constructor + def initialize(xml, client, xml_info = nil, types=nil, base=nil) + super(xml, client) + @vm_info = nil + @template = nil + + if xml_info != nil + xmldoc = XMLUtilsElement.initialize_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] != nil + @template = base + "/#{types[itype]['TEMPLATE']}" + end + end + end - + def mk_action(action_str) case action_str.downcase - when "stopped" + when "stopped" rc = self.stop when "suspended" rc = self.suspend @@ -77,55 +91,47 @@ class VirtualMachineOCCI < VirtualMachine rc = self.cancel when "shutdown" rc = self.shutdown - when "done" - rc = self.finalize - else + 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['COMPUTE'] - vm_info = @vm_info['COMPUTE'] - vm_info['DISK'] = [vm_info['DISK']].flatten if vm_info['DISK'] - vm_info['NIC'] = [vm_info['NIC']].flatten if vm_info['NIC'] - else + if @vm_info == nil error_msg = "Missing COMPUTE section in the XML body" - error = OpenNebula::Error.new(error_msg) - return error, 400 - end - + 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(@vm_info['TEMPLATE_PATH'])) - template_text = template.result(binding) + template = ERB.new(File.read(@template)) + template_text = template.result(binding) rescue Exception => e error = OpenNebula::Error.new(e.message) return error - end + end - return template_text + return template_text end - + # Creates the VMI representation of a Virtual Machine def to_occi(base_url) - vm_hash = self.to_hash - return vm_hash, 500 if OpenNebula.is_error?(vm_hash) - - template = vm_hash['VM']['TEMPLATE'] - template['DISK']=[template['DISK']].flatten if template['DISK'] - template['NIC']=[template['NIC']].flatten if template['NIC'] - begin occi_vm = ERB.new(OCCI_VM) - occi_vm_text = occi_vm.result(binding) + occi_vm_text = occi_vm.result(binding) rescue Exception => e error = OpenNebula::Error.new(e.message) return error - end + end return occi_vm_text.gsub(/\n\s*/,'') end diff --git a/src/cloud/occi/lib/VirtualNetworkOCCI.rb b/src/cloud/occi/lib/VirtualNetworkOCCI.rb index 85222223f9..c307c021cd 100755 --- a/src/cloud/occi/lib/VirtualNetworkOCCI.rb +++ b/src/cloud/occi/lib/VirtualNetworkOCCI.rb @@ -31,26 +31,22 @@ class VirtualNetworkOCCI < VirtualNetwork } ONE_NETWORK = %q{ - NAME = <%= @vnet_info.elements['NAME'].text %> + NAME = <%= @vnet_info['NAME'] %> TYPE = RANGED - BRIDGE = <%= @vnet_info.elements['BRIDGE'].text %> - NETWORK_ADDRESS = <%= @vnet_info.elements['ADDRESS'].text %> - NETWORK_SIZE = <%= @vnet_info.elements['SIZE'].text %> + BRIDGE = <%= @bridge %> + NETWORK_ADDRESS = <%= @vnet_info['ADDRESS'] %> + NETWORK_SIZE = <%= @vnet_info['SIZE']%> }.gsub(/^ /, '') # Class constructor def initialize(xml, client, xml_info=nil, bridge=nil) super(xml, client) + @bridge = bridge + @vnet_info = nil - if xml_info != nil and bridge != nil - @vnet_info = REXML::Document.new(xml_info).root - - bridge_element = REXML::Element.new("BRIDGE") - bridge_element.add_text(bridge) - - @vnet_info.add(bridge_element) - else - @vnet_info = nil + if xml_info != nil + xmldoc = XMLUtilsElement.initialize_xml(xml_info, 'NETWORK') + @vnet_info = XMLElement.new(xmldoc) if xmldoc != nil end end @@ -68,7 +64,7 @@ class VirtualNetworkOCCI < VirtualNetwork end def to_one_template() - if @vnet_info.name != 'NETWORK' + if @vnet_info == nil error_msg = "Missing NETWORK section in the XML body" error = OpenNebula::Error.new(error_msg) return error diff --git a/src/cloud/occi/lib/occi-server.rb b/src/cloud/occi/lib/occi-server.rb index 0c69e43c94..3434824aac 100755 --- a/src/cloud/occi/lib/occi-server.rb +++ b/src/cloud/occi/lib/occi-server.rb @@ -61,13 +61,6 @@ set :port, $occi_server.config[:port] # Helpers ############################################################################## -# Authentication -before do - if !$occi_server.authenticate?(request.env) - halt 401, 'Invalid credentials' - end -end - # Response treatment helpers do def treat_response(result,rc) diff --git a/src/oca/ruby/OpenNebula/XMLUtils.rb b/src/oca/ruby/OpenNebula/XMLUtils.rb index 713cc121ed..2163eb5c10 100644 --- a/src/oca/ruby/OpenNebula/XMLUtils.rb +++ b/src/oca/ruby/OpenNebula/XMLUtils.rb @@ -26,10 +26,18 @@ module OpenNebula # [return] _XML_ object for the underlying XML engine def self.initialize_xml(xml, root_element) if NOKOGIRI - Nokogiri::XML(xml).xpath("/#{root_element}") + xmldoc = Nokogiri::XML(xml).xpath("/#{root_element}") + if xmldoc.size == 0 + xmldoc = nil + end else - REXML::Document.new(xml).root + xmldoc = REXML::Document.new(xml).root + if xmldoc.name != root_element + xmldoc = nil + end end + + return xmldoc end # Extract an element from the XML description of the PoolElement. @@ -53,6 +61,45 @@ module OpenNebula end end + # Gets an attribute from an elemenT + # key:: _String_ xpath for the element + # name:: _String_ name of the attribute + def attr(key,name) + value = nil + + if NOKOGIRI + element=@xml.xpath(key.to_s.upcase) + if element.size == 0 + return nil + end + + attribute = element.attr(name) + + value = attribute.text if attribute != nil + else + element=@xml.elements[key.to_s.upcase] + + value = element.attributes[name] if element != nil + end + + return value + end + + # Iterates over every Element in the XPath and calls the block with a + # a XMLElement + # block:: _Block_ + def each(xpath_str,&block) + if NOKOGIRI + @xml.xpath(xpath_str).each { |pelem| + block.call XMLElement.new(pelem) + } + else + @xml.elements.each(xpath_str) { |pelem| + block.call XMLElement.new(pelem) + } + end + end + def template_str(indent=true) template_like_str('TEMPLATE', indent) end @@ -122,18 +169,6 @@ module OpenNebula str end end - - def XMLUtilsElement.xml_to_hash(xml) - begin - hash = Crack::XML.parse(xml) - rescue Exception => e - error = OpenNebula::Error.new(e.message) - return error - end - - return hash - end - end ########################################################################### @@ -190,6 +225,14 @@ module OpenNebula return @hash end end + + class XMLElement + include XMLUtilsElement + + def initialize(xml) + @xml = xml + end + end end From 79432c7bd3bc630da752132a5f4fbdd42ae50ec2 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Sat, 17 Jul 2010 06:51:23 +0200 Subject: [PATCH 17/27] feature #200: restored get_user for the EC2 Server --- src/cloud/common/CloudServer.rb | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/cloud/common/CloudServer.rb b/src/cloud/common/CloudServer.rb index 762f51d2ab..47f49c326f 100755 --- a/src/cloud/common/CloudServer.rb +++ b/src/cloud/common/CloudServer.rb @@ -89,6 +89,25 @@ class CloudServer return client end + # Gets the data associated with a user + # name:: _String_ the name of the user + # [return] _Hash_ with the user data + def get_user(name) + user = nil + + @user_pool.info + @user_pool.each{ |u| + if u.name==name + user=Hash.new + + user[:id] = u.id + user[:name] = u.name + user[:password] = u[:password] + end + } + return user + end + ########################################################################### # Repository Methods ########################################################################### From 572e83aa536265577a109f74a393c85ce6e7f0cc Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Mon, 19 Jul 2010 12:23:52 +0200 Subject: [PATCH 18/27] feature #200: Image Repository Integration for EC2 query --- src/cloud/ec2/lib/ImageEC2.rb | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/cloud/ec2/lib/ImageEC2.rb diff --git a/src/cloud/ec2/lib/ImageEC2.rb b/src/cloud/ec2/lib/ImageEC2.rb new file mode 100644 index 0000000000..4e5fa23e91 --- /dev/null +++ b/src/cloud/ec2/lib/ImageEC2.rb @@ -0,0 +1,35 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2010, 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 'uuid' +require 'OpenNebula' + +include OpenNebula + +class ImageEC2 < Image + + ONE_IMAGE = %q{ + NAME = "ec2-<%= uuid %>" + TYPE = OS + }.gsub(/^ /, '') + + def to_one_template() + uuid = UUID.generate + + one = ERB.new(ONE_IMAGE) + return one.result(binding) + end +end \ No newline at end of file From 3b536928b8ffa1d869389da2ba8b98f10f3cf65e Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Mon, 19 Jul 2010 14:35:35 +0200 Subject: [PATCH 19/27] feature #200: Some work on the cloud servers --- src/cloud/common/CloudServer.rb | 15 +---- src/cloud/ec2/lib/EC2QueryServer.rb | 95 ++++++++++++++++------------- src/cloud/occi/lib/OCCIServer.rb | 2 +- 3 files changed, 55 insertions(+), 57 deletions(-) diff --git a/src/cloud/common/CloudServer.rb b/src/cloud/common/CloudServer.rb index 47f49c326f..8d9dce4b9b 100755 --- a/src/cloud/common/CloudServer.rb +++ b/src/cloud/common/CloudServer.rb @@ -92,20 +92,9 @@ class CloudServer # Gets the data associated with a user # name:: _String_ the name of the user # [return] _Hash_ with the user data - def get_user(name) - user = nil - + def get_user_password(name) @user_pool.info - @user_pool.each{ |u| - if u.name==name - user=Hash.new - - user[:id] = u.id - user[:name] = u.name - user[:password] = u[:password] - end - } - return user + return @user_pool["USER[NAME=\"#{name}\"]/PASSWORD"] end ########################################################################### diff --git a/src/cloud/ec2/lib/EC2QueryServer.rb b/src/cloud/ec2/lib/EC2QueryServer.rb index 5acd526f0b..8b53b938b3 100644 --- a/src/cloud/ec2/lib/EC2QueryServer.rb +++ b/src/cloud/ec2/lib/EC2QueryServer.rb @@ -26,7 +26,7 @@ require 'CloudServer' require 'ImageEC2' ############################################################################### -# The EC2Query Server implements a EC2 compatible server based on the +# The EC2Query Server implements a EC2 compatible server based on the # OpenNebula Engine ############################################################################### class EC2QueryServer < CloudServer @@ -67,7 +67,7 @@ class EC2QueryServer < CloudServer super(config_file) @config.add_configuration_value("TEMPLATE_LOCATION",template) @config.add_configuration_value("VIEWS",views) - + if @config[:ssl_server] @server_host=@config[:ssl_server] else @@ -79,6 +79,15 @@ class EC2QueryServer < CloudServer print_configuration end + # Retrieve a client with the user credentials + # requestenv:: _Hash_ Hash containing the environment of the request + # [return] _Client_ client with the user credentials + def get_client(params) + usepassword = get_user() + return one_client_user(params['AWSAccessKeyId'], + get_user_()password) + end + ########################################################################### # Authentication functions ########################################################################### @@ -87,13 +96,13 @@ class EC2QueryServer < CloudServer # params:: of the request # [return] true if authenticated def authenticate?(params,env) - user = get_user(params['AWSAccessKeyId']) + user,password = get_user(params['AWSAccessKeyId']) return false if !user signature = case params['SignatureVersion'] when "1" then signature_version_1(params.clone, user[:password]) - when "2" then signature_version_2(params, - user[:password], + when "2" then signature_version_2(params, + user[:password], env, false) end @@ -113,20 +122,20 @@ class EC2QueryServer < CloudServer b64sig = Base64.b64encode(digest) return b64sig.strip end - - # Calculates signature version 2 + + # Calculates signature version 2 def signature_version_2(params, secret_key, env, urlencode=true) - signature_params = params.reject { |key,value| + signature_params = params.reject { |key,value| key=='Signature' or key=='file' } server_str = @server_host server_str = server_str + ":" + @server_port unless %w{2008-12-01 2009-11-30}.include? params["Version"] - canonical_str = AWS.canonical_string(signature_params, + canonical_str = AWS.canonical_string(signature_params, server_str, env['REQUEST_METHOD']) - + # Use the correct signature strength sha_strength = case params['SignatureMethod'] @@ -136,10 +145,10 @@ class EC2QueryServer < CloudServer end digest = OpenSSL::Digest::Digest.new(sha_strength) - b64hmac = + b64hmac = Base64.encode64( OpenSSL::HMAC.digest(digest, secret_key, canonical_str)).gsub("\n","") - + if urlencode return CGI::escape(b64hmac) else @@ -156,34 +165,34 @@ class EC2QueryServer < CloudServer one_client = one_client_user(user) image = ImageEC2.new(Image.build_xml, one_client) - + rc = add_image(image, params['file']) if OpenNebula.is_error?(rc) - return OpenNebula::Error.new('Unsupported'),400 + return OpenNebula::Error.new('Unsupported'),400 end - + erb_version = params['Version'] response = ERB.new(File.read(@config[:views]+"/register_image.erb")) return response.result(binding), 200 end - + def register_image(params) user = get_user(params['AWSAccessKeyId']) one_client = one_client_user(user) - + tmp, img=params['ImageLocation'].split('-') image = Image.new(Image.build_xml(img.to_i), one_client) - + # Enable the new Image rc = image.info if OpenNebula.is_error?(rc) return OpenNebula::Error.new('InvalidAMIID.NotFound'), 400 end - + image.enable - + erb_version = params['Version'] response = ERB.new(File.read(@config[:views]+"/register_image.erb")) @@ -192,15 +201,15 @@ class EC2QueryServer < CloudServer def describe_images(params) user = get_user(params['AWSAccessKeyId']) - one_client = one_client_user(user) + one_client = one_client_user(user) user_flag=-1 erb_impool = ImagePool.new(one_client, user_flag) erb_impool.info - + erb_user_name = user[:name] erb_version = params['Version'] - + response = ERB.new(File.read(@config[:views]+"/describe_images.erb")) a = response.result(binding) pp a @@ -218,23 +227,23 @@ class EC2QueryServer < CloudServer # Get the instance type and path instance_type_name = params['InstanceType'] instance_type = @instance_types[instance_type_name] - + path = get_template_path(params['InstanceType']) if OpenNebula.is_error?(path) return OpenNebula::Error.new('Unsupported'),400 end - + # Get the image tmp, img=params['ImageId'].split('-') - - # Build the VM + + # Build the VM erb_vm_info=Hash.new erb_vm_info[:img_id] = img.to_i erb_vm_info[:ec2_img_id] = params['ImageId'] erb_vm_info[:instance_type] = instance_type_name erb_vm_info[:template] = path erb_vm_info[:user_data] = params['UserData'] - + template = ERB.new(File.read(erb_vm_info[:template])) template_text = template.result(binding) @@ -245,15 +254,15 @@ class EC2QueryServer < CloudServer if OpenNebula::is_error?(rc) return OpenNebula::Error.new('Unsupported'),400 end - + vm.info - + erb_vm_info[:vm_id]=vm.id erb_vm_info[:vm]=vm erb_vm_info[:user_name] = user[:name] - + erb_version = params['Version'] - + response = ERB.new(File.read(@config[:views]+"/run_instances.erb")) return response.result(binding), 200 end @@ -262,7 +271,7 @@ class EC2QueryServer < CloudServer def describe_instances(params) # Get the user user = get_user(params['AWSAccessKeyId']) - one_client = one_client_user(user) + one_client = one_client_user(user) erb_user_name = user[:name] @@ -271,37 +280,37 @@ class EC2QueryServer < CloudServer erb_vmpool.info erb_version = params['Version'] - + response = ERB.new(File.read(@config[:views]+"/describe_instances.erb")) - + return response.result(binding), 200 end def terminate_instances(params) # Get the user user = get_user(params['AWSAccessKeyId']) - one_client = one_client_user(user) + one_client = one_client_user(user) vmid=params['InstanceId.1'] vmid=params['InstanceId.01'] if !vmid tmp, vmid=vmid.split('-') if vmid[0]==?i - + erb_vm = VirtualMachine.new(VirtualMachine.build_xml(vmid),one_client) rc = erb_vm.info - + return OpenNebula::Error.new('Unsupported'),400 if OpenNebula::is_error?(rc) - + if erb_vm.status == 'runn' rc = erb_vm.shutdown else rc = erb_vm.finalize end - + return OpenNebula::Error.new('Unsupported'),400 if OpenNebula::is_error?(rc) erb_version = params['Version'] - + response =ERB.new(File.read(@config[:views]+"/terminate_instances.erb")) return response.result(binding), 200 end @@ -312,8 +321,8 @@ private ########################################################################### def render_state(vm) ec2_state = EC2_STATES[ONE_STATES[vm.status]] - - return "#{ec2_state[:code]} + + return "#{ec2_state[:code]} #{ec2_state[:name]}" end diff --git a/src/cloud/occi/lib/OCCIServer.rb b/src/cloud/occi/lib/OCCIServer.rb index 88de9df234..04875e3179 100755 --- a/src/cloud/occi/lib/OCCIServer.rb +++ b/src/cloud/occi/lib/OCCIServer.rb @@ -216,7 +216,7 @@ class OCCIServer < CloudServer # [return] _String_,_Integer_ Update confirmation msg or error, # status code def put_compute(request, params) - vm_info = XMLUtilsElement.initialize_xml(xml_info, 'COMPUTE') + vm_info = XMLUtilsElement.initialize_xml(request.body.read, 'COMPUTE') # --- Get the VM and Action on it --- if vm_info['STATE'] != nil From 33b35e5966eaaafbcb38a88b6d5dbc0c412f9f16 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Mon, 19 Jul 2010 18:42:45 +0200 Subject: [PATCH 20/27] feature #200: Removed unneeded attribute variables --- src/cloud/ec2/etc/econe.conf | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/cloud/ec2/etc/econe.conf b/src/cloud/ec2/etc/econe.conf index dac46dd86c..0af12150f4 100644 --- a/src/cloud/ec2/etc/econe.conf +++ b/src/cloud/ec2/etc/econe.conf @@ -1,7 +1,3 @@ -# OpenNebula administrator user -USER=oneadmin -PASSWORD= - # OpenNebula sever contact information ONE_XMLRPC=http://localhost:2633/RPC2 @@ -12,9 +8,5 @@ PORT=4567 # SSL proxy that serves the API (set if is being used) #SSL_SERVER=fqdm.of.the.server -# Configuration for the image repository -DATABASE= - # VM types allowed and its template file (inside templates directory) VM_TYPE=[NAME=m1.small, TEMPLATE=m1.small.erb] From 4075bd89ac8082df72aa4b1cf3537badfeadf861 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Tue, 20 Jul 2010 00:32:48 +0200 Subject: [PATCH 21/27] feature #200 Changes in EC2 --- src/cloud/common/CloudServer.rb | 12 +- src/cloud/ec2/lib/EC2QueryServer.rb | 197 ++++++++---------- src/cloud/ec2/lib/econe-server.rb | 23 +- src/cloud/ec2/lib/views/describe_images.erb | 4 +- .../ec2/lib/views/describe_instances.erb | 2 +- src/cloud/ec2/lib/views/run_instances.erb | 2 +- .../ec2/lib/views/terminate_instances.erb | 4 +- 7 files changed, 112 insertions(+), 132 deletions(-) diff --git a/src/cloud/common/CloudServer.rb b/src/cloud/common/CloudServer.rb index 8d9dce4b9b..f4f70baaad 100755 --- a/src/cloud/common/CloudServer.rb +++ b/src/cloud/common/CloudServer.rb @@ -95,7 +95,7 @@ class CloudServer def get_user_password(name) @user_pool.info return @user_pool["USER[NAME=\"#{name}\"]/PASSWORD"] - end + end ########################################################################### # Repository Methods @@ -137,11 +137,13 @@ class CloudServer if file_path rc = image.copy(file_path, image['SOURCE']) file[:tempfile].unlink - elsif image['TEMPLATE/SIZE'] and image['TEMPLATE/FSTYPE'] + elsif image['TEMPLATE/SIZE'] and + image['TEMPLATE/FSTYPE'] and + image['TEMPLATE/TYPE'] == 'DATABLOCK' rc = image.mk_datablock( - image['TEMPLATE/SIZE'], - image['TEMPLATE/FSTYPE'], - image['SOURCE']) + image['TEMPLATE/SIZE'], + image['TEMPLATE/FSTYPE'], + image['SOURCE']) end if OpenNebula.is_error?(rc) diff --git a/src/cloud/ec2/lib/EC2QueryServer.rb b/src/cloud/ec2/lib/EC2QueryServer.rb index 8b53b938b3..8b6c46f3bc 100644 --- a/src/cloud/ec2/lib/EC2QueryServer.rb +++ b/src/cloud/ec2/lib/EC2QueryServer.rb @@ -79,15 +79,6 @@ class EC2QueryServer < CloudServer print_configuration end - # Retrieve a client with the user credentials - # requestenv:: _Hash_ Hash containing the environment of the request - # [return] _Client_ client with the user credentials - def get_client(params) - usepassword = get_user() - return one_client_user(params['AWSAccessKeyId'], - get_user_()password) - end - ########################################################################### # Authentication functions ########################################################################### @@ -95,75 +86,31 @@ class EC2QueryServer < CloudServer # EC2 protocol authentication function # params:: of the request # [return] true if authenticated - def authenticate?(params,env) - user,password = get_user(params['AWSAccessKeyId']) - return false if !user - + def authenticate(params,env) + password = get_user_password(params['AWSAccessKeyId']) + return nil if !password + signature = case params['SignatureVersion'] - when "1" then signature_version_1(params.clone, user[:password]) + when "1" then signature_version_1(params.clone, password) when "2" then signature_version_2(params, - user[:password], + password, env, false) end - return params['Signature']==signature - end - - # Calculates signature version 1 - def signature_version_1(params, secret_key, digest='sha1') - params.delete('Signature') - req_desc = params.sort {|x,y| x[0].downcase <=> y[0].downcase}.to_s - - digest_generator = OpenSSL::Digest::Digest.new(digest) - digest = OpenSSL::HMAC.digest(digest_generator, - secret_key, - req_desc) - b64sig = Base64.b64encode(digest) - return b64sig.strip - end - - # Calculates signature version 2 - def signature_version_2(params, secret_key, env, urlencode=true) - signature_params = params.reject { |key,value| - key=='Signature' or key=='file' } - - - server_str = @server_host - server_str = server_str + ":" + @server_port unless %w{2008-12-01 2009-11-30}.include? params["Version"] - - canonical_str = AWS.canonical_string(signature_params, - server_str, - env['REQUEST_METHOD']) - - - # Use the correct signature strength - sha_strength = case params['SignatureMethod'] - when "HmacSHA1" then 'sha1' - when "HmacSHA256" then 'sha256' - else 'sha1' - end - - digest = OpenSSL::Digest::Digest.new(sha_strength) - b64hmac = - Base64.encode64( - OpenSSL::HMAC.digest(digest, secret_key, canonical_str)).gsub("\n","") - - if urlencode - return CGI::escape(b64hmac) - else - return b64hmac + if params['Signature']==signature + return one_client_user(params['AWSAccessKeyId'], password) + else + return nil end end + ########################################################################### # Repository Interface ########################################################################### - def upload_image(params) - user = get_user(params['AWSAccessKeyId']) - one_client = one_client_user(user) - + def upload_image(params, one_client) image = ImageEC2.new(Image.build_xml, one_client) rc = add_image(image, params['file']) @@ -177,10 +124,8 @@ class EC2QueryServer < CloudServer return response.result(binding), 200 end - def register_image(params) - user = get_user(params['AWSAccessKeyId']) - one_client = one_client_user(user) - + def register_image(params, one_client) + # Get the Image ID tmp, img=params['ImageLocation'].split('-') image = Image.new(Image.build_xml(img.to_i), one_client) @@ -199,38 +144,31 @@ class EC2QueryServer < CloudServer return response.result(binding), 200 end - def describe_images(params) - user = get_user(params['AWSAccessKeyId']) - one_client = one_client_user(user) - + def describe_images(params, one_client) user_flag=-1 - erb_impool = ImagePool.new(one_client, user_flag) - erb_impool.info + impool = ImagePool.new(one_client, user_flag) + impool.info - erb_user_name = user[:name] + erb_user_name = params['AWSAccessKeyId'] erb_version = params['Version'] response = ERB.new(File.read(@config[:views]+"/describe_images.erb")) - a = response.result(binding) - pp a - return a, 200 + return response.result(binding), 200 end ########################################################################### # Instance Interface ########################################################################### - def run_instances(params) - user = get_user(params['AWSAccessKeyId']) - one_client = one_client_user(user) - + def run_instances(params, one_client) # Get the instance type and path - instance_type_name = params['InstanceType'] - instance_type = @instance_types[instance_type_name] + if params['InstanceType'] != nil + instance_type_name = params['InstanceType'] + instance_type = @instance_types[instance_type_name] - path = get_template_path(params['InstanceType']) - if OpenNebula.is_error?(path) - return OpenNebula::Error.new('Unsupported'),400 + if instance_type != nil + path = @config[:template_location] + "/#{instance_type['TEMPLATE']}" + end end # Get the image @@ -259,8 +197,7 @@ class EC2QueryServer < CloudServer erb_vm_info[:vm_id]=vm.id erb_vm_info[:vm]=vm - erb_vm_info[:user_name] = user[:name] - + erb_user_name = params['AWSAccessKeyId'] erb_version = params['Version'] response = ERB.new(File.read(@config[:views]+"/run_instances.erb")) @@ -268,43 +205,34 @@ class EC2QueryServer < CloudServer end - def describe_instances(params) - # Get the user - user = get_user(params['AWSAccessKeyId']) - one_client = one_client_user(user) - - erb_user_name = user[:name] - + def describe_instances(params, one_client) user_flag=-1 - erb_vmpool = VirtualMachinePool.new(one_client, user_flag) - erb_vmpool.info + vmpool = VirtualMachinePool.new(one_client, user_flag) + vmpool.info erb_version = params['Version'] - + erb_user_name = params['AWSAccessKeyId'] + response = ERB.new(File.read(@config[:views]+"/describe_instances.erb")) - return response.result(binding), 200 end - def terminate_instances(params) - # Get the user - user = get_user(params['AWSAccessKeyId']) - one_client = one_client_user(user) - + def terminate_instances(params, one_client) + # Get the VM ID vmid=params['InstanceId.1'] vmid=params['InstanceId.01'] if !vmid tmp, vmid=vmid.split('-') if vmid[0]==?i - erb_vm = VirtualMachine.new(VirtualMachine.build_xml(vmid),one_client) - rc = erb_vm.info + vm = VirtualMachine.new(VirtualMachine.build_xml(vmid),one_client) + rc = vm.info return OpenNebula::Error.new('Unsupported'),400 if OpenNebula::is_error?(rc) - if erb_vm.status == 'runn' - rc = erb_vm.shutdown + if vm.status == 'runn' + rc = vm.shutdown else - rc = erb_vm.finalize + rc = vm.finalize end return OpenNebula::Error.new('Unsupported'),400 if OpenNebula::is_error?(rc) @@ -316,6 +244,53 @@ class EC2QueryServer < CloudServer end private + + # Calculates signature version 1 + def signature_version_1(params, secret_key, digest='sha1') + params.delete('Signature') + req_desc = params.sort {|x,y| x[0].downcase <=> y[0].downcase}.to_s + + digest_generator = OpenSSL::Digest::Digest.new(digest) + digest = OpenSSL::HMAC.digest(digest_generator, + secret_key, + req_desc) + b64sig = Base64.b64encode(digest) + return b64sig.strip + end + + # Calculates signature version 2 + def signature_version_2(params, secret_key, env, urlencode=true) + signature_params = params.reject { |key,value| + key=='Signature' or key=='file' } + + + server_str = @server_host + server_str = server_str + ":" + @server_port unless %w{2008-12-01 2009-11-30}.include? params["Version"] + + canonical_str = AWS.canonical_string(signature_params, + server_str, + env['REQUEST_METHOD']) + + + # Use the correct signature strength + sha_strength = case params['SignatureMethod'] + when "HmacSHA1" then 'sha1' + when "HmacSHA256" then 'sha256' + else 'sha1' + end + + digest = OpenSSL::Digest::Digest.new(sha_strength) + b64hmac = + Base64.encode64( + OpenSSL::HMAC.digest(digest, secret_key, canonical_str)).gsub("\n","") + + if urlencode + return CGI::escape(b64hmac) + else + return b64hmac + end + end + ########################################################################### # Helper functions ########################################################################### diff --git a/src/cloud/ec2/lib/econe-server.rb b/src/cloud/ec2/lib/econe-server.rb index 9fbc06f46e..1364639bca 100644 --- a/src/cloud/ec2/lib/econe-server.rb +++ b/src/cloud/ec2/lib/econe-server.rb @@ -59,7 +59,9 @@ set :port, $econe_server.config[:port] ############################################################################## before do - if !$econe_server.authenticate?(params,env) + @client = $econe_server.authenticate(params,env) + + if @client.nil? error 400, error_xml("AuthFailure", 0) end end @@ -92,27 +94,28 @@ helpers do end post '/' do - do_http_request(params) + do_http_request(params, @client) end get '/' do - do_http_request(params) + do_http_request(params, @client) end -def do_http_request(params) +def do_http_request(params, client) + case params['Action'] when 'UploadImage' - result,rc = $econe_server.upload_image(params) + result,rc = $econe_server.upload_image(params, client) when 'RegisterImage' - result,rc = $econe_server.register_image(params) + result,rc = $econe_server.register_image(params, client) when 'DescribeImages' - result,rc = $econe_server.describe_images(params) + result,rc = $econe_server.describe_images(params, client) when 'RunInstances' - result,rc = $econe_server.run_instances(params) + result,rc = $econe_server.run_instances(params, client) when 'DescribeInstances' - result,rc = $econe_server.describe_instances(params) + result,rc = $econe_server.describe_instances(params, client) when 'TerminateInstances' - result,rc = $econe_server.terminate_instances(params) + result,rc = $econe_server.terminate_instances(params, client) end if OpenNebula::is_error?(result) diff --git a/src/cloud/ec2/lib/views/describe_images.erb b/src/cloud/ec2/lib/views/describe_images.erb index 222ab62e30..05a84f57eb 100644 --- a/src/cloud/ec2/lib/views/describe_images.erb +++ b/src/cloud/ec2/lib/views/describe_images.erb @@ -1,14 +1,14 @@ - <% erb_impool.each do |im| %> + <% impool.each do |im| %> <% im.info %> ami-<%= sprintf('%08i', im.id) %> <%= im['SOURCE'].split('/').last %> <% if im['STATE'] == '4' %> deregistered - <% elsif im['STATE'] == '3' %> + <% elsif im['STATE'] == '2' %> available <% end %> <%= erb_user_name %> diff --git a/src/cloud/ec2/lib/views/describe_instances.erb b/src/cloud/ec2/lib/views/describe_instances.erb index db1bc36c79..e07e4e7179 100644 --- a/src/cloud/ec2/lib/views/describe_instances.erb +++ b/src/cloud/ec2/lib/views/describe_instances.erb @@ -11,7 +11,7 @@ - <% erb_vmpool.each do |vm| %> + <% vmpool.each do |vm| %> <% vm.info %> i-<%= vm.id %> diff --git a/src/cloud/ec2/lib/views/run_instances.erb b/src/cloud/ec2/lib/views/run_instances.erb index c0ae168ed2..a33481372c 100644 --- a/src/cloud/ec2/lib/views/run_instances.erb +++ b/src/cloud/ec2/lib/views/run_instances.erb @@ -1,6 +1,6 @@ r-47a5402e - <%= erb_vm_info[:user_name] %> + <%= erb_user_name %> default diff --git a/src/cloud/ec2/lib/views/terminate_instances.erb b/src/cloud/ec2/lib/views/terminate_instances.erb index 954460988c..0accdbf283 100644 --- a/src/cloud/ec2/lib/views/terminate_instances.erb +++ b/src/cloud/ec2/lib/views/terminate_instances.erb @@ -1,13 +1,13 @@ - i-<%= erb_vm.id %> + i-<%= vm.id %> 32 shutting-down - <%= render_state(erb_vm) %> + <%= render_state(vm) %> From 5f70d69b55bdb49d29c44b58e276d57e67dccdcb Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Tue, 20 Jul 2010 00:34:02 +0200 Subject: [PATCH 22/27] feature #200 Delete upcase from XMLUtils and XMLElement and XMLPool for Pool --- src/oca/ruby/OpenNebula/Pool.rb | 4 +++- src/oca/ruby/OpenNebula/XMLUtils.rb | 28 ++-------------------------- 2 files changed, 5 insertions(+), 27 deletions(-) diff --git a/src/oca/ruby/OpenNebula/Pool.rb b/src/oca/ruby/OpenNebula/Pool.rb index f2138abf2e..f9636eca3e 100644 --- a/src/oca/ruby/OpenNebula/Pool.rb +++ b/src/oca/ruby/OpenNebula/Pool.rb @@ -2,8 +2,10 @@ module OpenNebula # The Pool class represents a generic OpenNebula Pool in XML format # and provides the basic functionality to handle the Pool elements + require 'pp' class Pool include Enumerable + include XMLUtilsElement include XMLUtilsPool protected @@ -42,7 +44,7 @@ module OpenNebula rc = @client.call(xml_method,*args) if !OpenNebula.is_error?(rc) - @xml = initialize_xml(rc) + @xml = XMLUtilsElement::initialize_xml(rc,@pool_name) rc = nil end diff --git a/src/oca/ruby/OpenNebula/XMLUtils.rb b/src/oca/ruby/OpenNebula/XMLUtils.rb index 2163eb5c10..c0c9dca0ff 100644 --- a/src/oca/ruby/OpenNebula/XMLUtils.rb +++ b/src/oca/ruby/OpenNebula/XMLUtils.rb @@ -48,12 +48,12 @@ module OpenNebula # ['HISTORY/HOSTNAME'] # get the hostname from the history def [](key) if NOKOGIRI - element=@xml.xpath(key.to_s.upcase) + element=@xml.xpath(key.to_s) if element.size == 0 return nil end else - element=@xml.elements[key.to_s.upcase] + element=@xml.elements[key.to_s] end if element @@ -177,17 +177,6 @@ module OpenNebula ########################################################################### module XMLUtilsPool - #Initialize a XML document for the element - #xml:: _String_ the XML document of the object - #[return] _XML_ object for the underlying XML engine - def initialize_xml(xml) - if NOKOGIRI - Nokogiri::XML(xml).xpath("/#{@pool_name}") - else - xml=REXML::Document.new(xml).root - end - end - #Executes the given block for each element of the Pool #block:: _Block_ def each_element(block) @@ -204,19 +193,6 @@ module OpenNebula end end - def to_xml(pretty=false) - if NOKOGIRI - @xml.to_xml - else - str = "" - if pretty - REXML::Formatters::Pretty.new(1).write(@xml,str) - else - REXML::Formatters::Default.new.write(@xml,str) - end - str - end - end def to_hash if !@hash && @xml From fe0e6927e925af48dbecd45a2d7cb3d310c4d2d6 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Tue, 20 Jul 2010 00:34:51 +0200 Subject: [PATCH 23/27] feature #200 Changes in OCCI --- src/cloud/occi/lib/ImageOCCI.rb | 2 +- src/cloud/occi/lib/OCCIClient.rb | 12 +- src/cloud/occi/lib/OCCIServer.rb | 143 +++++++++++------------ src/cloud/occi/lib/VirtualNetworkOCCI.rb | 2 + 4 files changed, 81 insertions(+), 78 deletions(-) diff --git a/src/cloud/occi/lib/ImageOCCI.rb b/src/cloud/occi/lib/ImageOCCI.rb index 62e66a1d1f..5cc01fddd4 100755 --- a/src/cloud/occi/lib/ImageOCCI.rb +++ b/src/cloud/occi/lib/ImageOCCI.rb @@ -58,7 +58,7 @@ class ImageOCCI < Image @image_info = nil if xml_info != nil - xmldoc = XMLUtilsElement.initialize_xml(xml_info, 'STORAGE') + xmldoc = XMLUtilsElement.initialize_xml(xml_info, 'STORAGE') @image_info = XMLElement.new(xmldoc) if xmldoc != nil end end diff --git a/src/cloud/occi/lib/OCCIClient.rb b/src/cloud/occi/lib/OCCIClient.rb index 244ef2ccad..5ca53f22a1 100755 --- a/src/cloud/occi/lib/OCCIClient.rb +++ b/src/cloud/occi/lib/OCCIClient.rb @@ -272,10 +272,16 @@ module OCCIClient # :xmlfile Compute OCCI xml representation ###################################################################### def put_vm(xmlfile) - xml=File.read(xmlfile) - vm_info=Crack::XML.parse(xml) + xml = File.read(xmlfile) + vm_info = REXML::Document.new(xml).root - url = URI.parse(@endpoint+'/compute/' + vm_info['COMPUTE']['ID']) + if vm_info.elements['ID'] == nil + return CloudClient::Error.new("Can not find VM_ID") + end + + vm_id = vm_info.elements['ID'].text + + url = URI.parse(@endpoint+'/compute/' + vm_id) req = Net::HTTP::Put.new(url.path) req.body = xml diff --git a/src/cloud/occi/lib/OCCIServer.rb b/src/cloud/occi/lib/OCCIServer.rb index 04875e3179..f12172ddab 100755 --- a/src/cloud/occi/lib/OCCIServer.rb +++ b/src/cloud/occi/lib/OCCIServer.rb @@ -69,11 +69,11 @@ class OCCIServer < CloudServer # Prepare the OCCI XML Response # resource:: _Pool_ or _PoolElement_ that represents a OCCI resource # [return] _String_,_Integer_ Resource Representation or error, status code - def to_occi_xml(resource) + def to_occi_xml(resource, code) xml_response = resource.to_occi(@base_url) return xml_response, 500 if OpenNebula.is_error?(xml_response) - return xml_response, 201 + return xml_response, code end ############################################################################ @@ -86,18 +86,17 @@ class OCCIServer < CloudServer # request:: _Hash_ hash containing the data of the request # [return] _String_,_Integer_ Pool Representation or error, status code def get_computes(request) - # --- Get client with user credentials --- - client = get_client(request.env) - # --- Get User's VMs --- user_flag = -1 - vmpool = VirtualMachinePoolOCCI.new(client, user_flag) + vmpool = VirtualMachinePoolOCCI.new( + get_client(request.env), + user_flag) # --- Prepare XML Response --- rc = vmpool.info return rc, 404 if OpenNebula.is_error?(rc) - return to_occi_xml(vmpool) + return to_occi_xml(vmpool, 200) end @@ -106,18 +105,17 @@ class OCCIServer < CloudServer # [return] _String_,_Integer_ Network pool representation or error, # => status code def get_networks(request) - # --- Get client with user credentials --- - client = get_client(request.env) - # --- Get User's VNETs --- user_flag = -1 - network_pool = VirtualNetworkPoolOCCI.new(client, user_flag) + network_pool = VirtualNetworkPoolOCCI.new( + get_client(request.env), + user_flag) + # --- Prepare XML Response --- rc = network_pool.info return rc, 404 if OpenNebula.is_error?(rc) - # --- Prepare XML Response --- - return to_occi_xml(network_pool) + return to_occi_xml(network_pool, 200) end # Gets the pool representation of STORAGES @@ -125,18 +123,17 @@ class OCCIServer < CloudServer # [return] _String_,_Integer_ Image pool representation or error, # status code def get_storages(request) - # --- Get client with user credentials --- - client = get_client(request.env) - # --- Get User's Images --- user_flag = -1 - image_pool = ImagePoolOCCI.new(client, user_flag) - - result = image_pool.info - return result, 404 if OpenNebula.is_error?(result) - + image_pool = ImagePoolOCCI.new( + get_client(request.env), + user_flag) + # --- Prepare XML Response --- - return to_occi_xml(image_pool) + rc = image_pool.info + return rc, 404 if OpenNebula.is_error?(rc) + + return to_occi_xml(image_pool, 200) end ############################################################################ @@ -153,7 +150,6 @@ class OCCIServer < CloudServer # request:: _Hash_ hash containing the data of the request # [return] _String_,_Integer_ COMPUTE Representation or error, status code def post_compute(request) - # --- Create the new Instance --- vm = VirtualMachineOCCI.new( VirtualMachine.build_xml, @@ -171,7 +167,7 @@ class OCCIServer < CloudServer # --- Prepare XML Response --- vm.info - return to_occi_xml(vm) + return to_occi_xml(vm, 201) end # Get the representation of a COMPUTE resource @@ -179,17 +175,16 @@ class OCCIServer < CloudServer # [return] _String_,_Integer_ COMPUTE representation or error, # status code def get_compute(request, params) - # --- Get the VM --- vm = VirtualMachineOCCI.new( - VirtualMachine.build_xml(params[:id]), - get_client(request.env)) - - result = vm.info - return result, 404 if OpenNebula::is_error?(result) - + VirtualMachine.build_xml(params[:id]), + get_client(request.env)) + # --- Prepare XML Response --- - return to_occi_xml(vm) + rc = vm.info + return rc, 404 if OpenNebula::is_error?(rc) + + return to_occi_xml(vm, 200) end @@ -198,11 +193,10 @@ class OCCIServer < CloudServer # [return] _String_,_Integer_ Delete confirmation msg or error, # status code def delete_compute(request, params) - # --- Get the VM --- vm = VirtualMachineOCCI.new( - VirtualMachine.build_xml(params[:id]), - get_client(request.env)) + VirtualMachine.build_xml(params[:id]), + get_client(request.env)) # --- Finalize the VM --- result = vm.finalize @@ -216,13 +210,14 @@ class OCCIServer < CloudServer # [return] _String_,_Integer_ Update confirmation msg or error, # status code def put_compute(request, params) - vm_info = XMLUtilsElement.initialize_xml(request.body.read, 'COMPUTE') + xmldoc = XMLUtilsElement.initialize_xml(request.body, 'COMPUTE') + vm_info = XMLElement.new(xmldoc) if xmldoc != nil # --- Get the VM and Action on it --- if vm_info['STATE'] != nil vm = VirtualMachineOCCI.new( - VirtualMachine.build_xml(params[:id]), - get_client(request.env)) + VirtualMachine.build_xml(params[:id]), + get_client(request.env)) rc = vm.mk_action(vm_info['STATE']) @@ -235,7 +230,7 @@ class OCCIServer < CloudServer # --- Prepare XML Response --- vm.info - return to_occi_xml(vm) + return to_occi_xml(vm, 202) end ############################################################################ @@ -246,13 +241,12 @@ class OCCIServer < CloudServer # request:: _Hash_ hash containing the data of the request # [return] _String_,_Integer_ Network Representation or error, status code def post_network(request) - # --- Create the new Instance --- network = VirtualNetworkOCCI.new( - VirtualNetwork.build_xml, - get_client(request.env), - request.body, - @config[:bridge]) + VirtualNetwork.build_xml, + get_client(request.env), + request.body, + @config[:bridge]) # --- Generate the template and Allocate the new Instance --- template = network.to_one_template @@ -263,7 +257,7 @@ class OCCIServer < CloudServer # --- Prepare XML Response --- network.info - return to_occi_xml(network) + return to_occi_xml(network, 201) end # Retrieves a NETWORK resource @@ -271,16 +265,16 @@ class OCCIServer < CloudServer # [return] _String_,_Integer_ NETWORK occi representation or error, # status code def get_network(request, params) - # --- Get the VM --- + # --- Get the VNET --- network = VirtualNetworkOCCI.new( - VirtualNetwork.build_xml(params[:id]), - get_client(request.env)) - - result = network.info - return result, 404 if OpenNebula::is_error?(result) + VirtualNetwork.build_xml(params[:id]), + get_client(request.env)) # --- Prepare XML Response --- - return to_occi_xml(network) + rc = network.info + return rc, 404 if OpenNebula::is_error?(rc) + + return to_occi_xml(network, 200) end # Deletes a NETWORK resource @@ -288,14 +282,14 @@ class OCCIServer < CloudServer # [return] _String_,_Integer_ Delete confirmation msg or error, # status code def delete_network(request, params) - - vn = VirtualNetworkOCCI.new( - VirtualNetwork.build_xml(params[:id]), - get_client(request.env)) + # --- Get the VNET --- + network = VirtualNetworkOCCI.new( + VirtualNetwork.build_xml(params[:id]), + get_client(request.env)) # --- Delete the VNET --- - result = vn.delete - return result, 500 if OpenNebula::is_error?(result) + rc = network.delete + return rc, 500 if OpenNebula::is_error?(rc) return "", 204 end @@ -308,7 +302,6 @@ class OCCIServer < CloudServer # request:: _Hash_ hash containing the data of the request # [return] _String_,_Integer_ Image representation or error, status code def post_storage(request) - # --- Check OCCI XML from POST --- if request.params['occixml'] == nil error_msg = "OCCI XML representation of Image" + @@ -318,9 +311,10 @@ class OCCIServer < CloudServer end # --- Create and Add the new Image --- - image = ImageOCCI.new(Image.build_xml, - get_client(request.env), - request.params['occixml']) + image = ImageOCCI.new( + Image.build_xml, + get_client(request.env), + request.params['occixml']) rc = add_image(image, request.params['file']) return rc, 500 if OpenNebula.is_error?(rc) @@ -330,7 +324,7 @@ class OCCIServer < CloudServer return rc, 500 if OpenNebula.is_error?(rc) # --- Prepare XML Response --- - return to_occi_xml(image) + return to_occi_xml(image, 201) end # Get a STORAGE resource @@ -338,16 +332,16 @@ class OCCIServer < CloudServer # [return] _String_,_Integer_ STORAGE occi representation or error, # status code def get_storage(request, params) - # --- Get the Image --- - image = ImageOCCI.new(Image.build_xml(params[:id]), - get_client(request.env)) + image = ImageOCCI.new( + Image.build_xml(params[:id]), + get_client(request.env)) - result = image.info - return result, 404 if OpenNebula::is_error?(result) + rc = image.info + return rc, 404 if OpenNebula::is_error?(rc) # --- Prepare XML Response --- - return to_occi_xml(image) + return to_occi_xml(image, 200) end # Deletes a STORAGE resource (Not yet implemented) @@ -355,13 +349,14 @@ class OCCIServer < CloudServer # [return] _String_,_Integer_ Delete confirmation msg or error, # status code def delete_storage(request, params) - - image = ImageOCCI.new(Image.build_xml(params[:id]), - get_client(request.env)) + # --- Get the Image --- + image = ImageOCCI.new( + Image.build_xml(params[:id]), + get_client(request.env)) # --- Delete the Image --- - result = image.delete - return result, 500 if OpenNebula::is_error?(result) + rc = image.delete + return rc, 500 if OpenNebula::is_error?(rc) return "", 204 end diff --git a/src/cloud/occi/lib/VirtualNetworkOCCI.rb b/src/cloud/occi/lib/VirtualNetworkOCCI.rb index c307c021cd..8a71cd4c8a 100755 --- a/src/cloud/occi/lib/VirtualNetworkOCCI.rb +++ b/src/cloud/occi/lib/VirtualNetworkOCCI.rb @@ -33,7 +33,9 @@ class VirtualNetworkOCCI < VirtualNetwork ONE_NETWORK = %q{ NAME = <%= @vnet_info['NAME'] %> TYPE = RANGED + <% if @bridge %> BRIDGE = <%= @bridge %> + <% end %> NETWORK_ADDRESS = <%= @vnet_info['ADDRESS'] %> NETWORK_SIZE = <%= @vnet_info['SIZE']%> }.gsub(/^ /, '') From 923294c236de47e74154b6ae3604f3d68621bf26 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Tue, 20 Jul 2010 16:52:41 +0200 Subject: [PATCH 24/27] feature #200: XMLUtil class hierarchy --- src/cloud/occi/lib/ImageOCCI.rb | 2 +- src/cloud/occi/lib/OCCIServer.rb | 12 ++--- src/cloud/occi/lib/VirtualMachineOCCI.rb | 2 +- src/cloud/occi/lib/VirtualNetworkOCCI.rb | 2 +- src/oca/ruby/OpenNebula/Cluster.rb | 2 +- src/oca/ruby/OpenNebula/Host.rb | 6 +-- src/oca/ruby/OpenNebula/Image.rb | 2 +- src/oca/ruby/OpenNebula/Pool.rb | 62 +++++++++++------------ src/oca/ruby/OpenNebula/User.rb | 2 +- src/oca/ruby/OpenNebula/VirtualMachine.rb | 18 +++---- src/oca/ruby/OpenNebula/VirtualNetwork.rb | 12 ++--- src/oca/ruby/OpenNebula/XMLUtils.rb | 52 +++++++++++-------- 12 files changed, 92 insertions(+), 82 deletions(-) diff --git a/src/cloud/occi/lib/ImageOCCI.rb b/src/cloud/occi/lib/ImageOCCI.rb index 5cc01fddd4..478f868ff4 100755 --- a/src/cloud/occi/lib/ImageOCCI.rb +++ b/src/cloud/occi/lib/ImageOCCI.rb @@ -58,7 +58,7 @@ class ImageOCCI < Image @image_info = nil if xml_info != nil - xmldoc = XMLUtilsElement.initialize_xml(xml_info, 'STORAGE') + xmldoc = XMLElement.build_xml(xml_info, 'STORAGE') @image_info = XMLElement.new(xmldoc) if xmldoc != nil end end diff --git a/src/cloud/occi/lib/OCCIServer.rb b/src/cloud/occi/lib/OCCIServer.rb index f12172ddab..a5b3abf2aa 100755 --- a/src/cloud/occi/lib/OCCIServer.rb +++ b/src/cloud/occi/lib/OCCIServer.rb @@ -89,7 +89,7 @@ class OCCIServer < CloudServer # --- Get User's VMs --- user_flag = -1 vmpool = VirtualMachinePoolOCCI.new( - get_client(request.env), + get_client(request.env), user_flag) # --- Prepare XML Response --- @@ -108,7 +108,7 @@ class OCCIServer < CloudServer # --- Get User's VNETs --- user_flag = -1 network_pool = VirtualNetworkPoolOCCI.new( - get_client(request.env), + get_client(request.env), user_flag) # --- Prepare XML Response --- @@ -126,9 +126,9 @@ class OCCIServer < CloudServer # --- Get User's Images --- user_flag = -1 image_pool = ImagePoolOCCI.new( - get_client(request.env), + get_client(request.env), user_flag) - + # --- Prepare XML Response --- rc = image_pool.info return rc, 404 if OpenNebula.is_error?(rc) @@ -179,7 +179,7 @@ class OCCIServer < CloudServer vm = VirtualMachineOCCI.new( VirtualMachine.build_xml(params[:id]), get_client(request.env)) - + # --- Prepare XML Response --- rc = vm.info return rc, 404 if OpenNebula::is_error?(rc) @@ -210,7 +210,7 @@ class OCCIServer < CloudServer # [return] _String_,_Integer_ Update confirmation msg or error, # status code def put_compute(request, params) - xmldoc = XMLUtilsElement.initialize_xml(request.body, 'COMPUTE') + xmldoc = XMLElement.build_xml(request.body, 'COMPUTE') vm_info = XMLElement.new(xmldoc) if xmldoc != nil # --- Get the VM and Action on it --- diff --git a/src/cloud/occi/lib/VirtualMachineOCCI.rb b/src/cloud/occi/lib/VirtualMachineOCCI.rb index 91ea253585..06be235725 100755 --- a/src/cloud/occi/lib/VirtualMachineOCCI.rb +++ b/src/cloud/occi/lib/VirtualMachineOCCI.rb @@ -65,7 +65,7 @@ class VirtualMachineOCCI < VirtualMachine @template = nil if xml_info != nil - xmldoc = XMLUtilsElement.initialize_xml(xml_info, 'COMPUTE') + xmldoc = XMLElement.build_xml(xml_info, 'COMPUTE') @vm_info = XMLElement.new(xmldoc) if xmldoc != nil end diff --git a/src/cloud/occi/lib/VirtualNetworkOCCI.rb b/src/cloud/occi/lib/VirtualNetworkOCCI.rb index 8a71cd4c8a..541899349b 100755 --- a/src/cloud/occi/lib/VirtualNetworkOCCI.rb +++ b/src/cloud/occi/lib/VirtualNetworkOCCI.rb @@ -47,7 +47,7 @@ class VirtualNetworkOCCI < VirtualNetwork @vnet_info = nil if xml_info != nil - xmldoc = XMLUtilsElement.initialize_xml(xml_info, 'NETWORK') + xmldoc = XMLElement.build_xml(xml_info, 'NETWORK') @vnet_info = XMLElement.new(xmldoc) if xmldoc != nil end end diff --git a/src/oca/ruby/OpenNebula/Cluster.rb b/src/oca/ruby/OpenNebula/Cluster.rb index 57f78f0f52..19a069b7f9 100644 --- a/src/oca/ruby/OpenNebula/Cluster.rb +++ b/src/oca/ruby/OpenNebula/Cluster.rb @@ -27,7 +27,7 @@ module OpenNebula user_xml = "" end - XMLUtilsElement.initialize_xml(user_xml, 'CLUSTER') + XMLElement.build_xml(user_xml,'CLUSTER') end # --------------------------------------------------------------------- diff --git a/src/oca/ruby/OpenNebula/Host.rb b/src/oca/ruby/OpenNebula/Host.rb index e8aadd0bb2..50130d008a 100644 --- a/src/oca/ruby/OpenNebula/Host.rb +++ b/src/oca/ruby/OpenNebula/Host.rb @@ -36,7 +36,7 @@ module OpenNebula host_xml = "" end - XMLUtilsElement.initialize_xml(host_xml, 'HOST') + XMLElement.build_xml(host_xml, 'HOST') end ####################################################################### @@ -91,7 +91,7 @@ module OpenNebula SHORT_HOST_STATES[state_str] end - # Returns the cluster of the Host + # Returns the cluster of the Host def cluster self['CLUSTER'] end @@ -103,7 +103,7 @@ module OpenNebula rc = @client.call(HOST_METHODS[:enable], @pe_id, enabled) rc = nil if !OpenNebula.is_error?(rc) - + return rc end end diff --git a/src/oca/ruby/OpenNebula/Image.rb b/src/oca/ruby/OpenNebula/Image.rb index 70da993ec7..a10ef34f7d 100644 --- a/src/oca/ruby/OpenNebula/Image.rb +++ b/src/oca/ruby/OpenNebula/Image.rb @@ -48,7 +48,7 @@ module OpenNebula image_xml = "" end - XMLUtilsElement.initialize_xml(image_xml, 'IMAGE') + XMLElement.build_xml(image_xml,'IMAGE') end # Class constructor diff --git a/src/oca/ruby/OpenNebula/Pool.rb b/src/oca/ruby/OpenNebula/Pool.rb index f9636eca3e..51ec16995c 100644 --- a/src/oca/ruby/OpenNebula/Pool.rb +++ b/src/oca/ruby/OpenNebula/Pool.rb @@ -3,10 +3,8 @@ module OpenNebula # The Pool class represents a generic OpenNebula Pool in XML format # and provides the basic functionality to handle the Pool elements require 'pp' - class Pool + class Pool < XMLPool include Enumerable - include XMLUtilsElement - include XMLUtilsPool protected @@ -14,18 +12,19 @@ module OpenNebula #element:: _String_ XML name of the Pool elements #client:: _Client_ represents a XML-RPC connection def initialize(pool,element,client) + super(nil) + @pool_name = pool.upcase @element_name = element.upcase - @client = client - @xml = nil + @client = client @hash = nil end # Default Factory Method for the Pools. The factory method returns an - # suitable PoolElement object. Each Pool MUST implement the + # suitable PoolElement object. Each Pool MUST implement the # corresponding factory method - # element_xml:: _XML_ XML element describing the pool element + # element_xml:: _XML_ XML element describing the pool element # [return] a PoolElement object def factory(element_xml) OpenNebula::PoolElement.new(element_xml,client) @@ -39,15 +38,15 @@ module OpenNebula # representation in XML format # xml_method:: _String_ the name of the XML-RPC method # args:: _Array_ with additional arguments for the info call - # [return] nil in case of success or an Error object + # [return] nil in case of success or an Error object def info(xml_method,*args) rc = @client.call(xml_method,*args) if !OpenNebula.is_error?(rc) - @xml = XMLUtilsElement::initialize_xml(rc,@pool_name) + initialize_xml(rc,@pool_name) rc = nil end - + return rc end @@ -65,23 +64,22 @@ module OpenNebula str = "" REXML::Formatters::Pretty.new(1).write(@xml,str) - return str + return str end end - + # The PoolElement Class represents a generic element of a Pool in # XML format - class PoolElement - include XMLUtilsElement + class PoolElement < XMLElement protected - # node:: _XML_is a XML element that represents the Pool element + # node:: _XML_is a XML element that represents the Pool element # client:: _Client_ represents a XML-RPC connection def initialize(node, client) @xml = node @client = client @hash = nil - + if self['ID'] @pe_id = self['ID'].to_i else @@ -98,16 +96,16 @@ module OpenNebula # detailed information in XML format # xml_method:: _String_ the name of the XML-RPC method # root_element:: _String_ Base XML element - # [return] nil in case of success or an Error object + # [return] nil in case of success or an Error object def info(xml_method, root_element) return Error.new('ID not defined') if !@pe_id rc = @client.call(xml_method,@pe_id) if !OpenNebula.is_error?(rc) - @xml = XMLUtilsElement::initialize_xml(rc, root_element) + initialize_xml(rc, root_element) rc = nil - + @pe_id = self['ID'].to_i if self['ID'] @name = self['NAME'] if self['NAME'] end @@ -116,11 +114,11 @@ module OpenNebula end # Calls to the corresponding allocate method to create a new element - # in the OpenNebula core + # in the OpenNebula core # xml_method:: _String_ the name of the XML-RPC method # args:: _Array_ additional arguments including the template for the - # new element - # [return] nil in case of success or an Error object + # new element + # [return] nil in case of success or an Error object def allocate(xml_method, *args) rc = @client.call(xml_method, *args) @@ -131,13 +129,13 @@ module OpenNebula return rc end - + # Calls to the corresponding update method to modify # the object's template # xml_method:: _String_ the name of the XML-RPC method # name:: _String_ the name of the property to be modified # value:: _String_ the new value of the property to be modified - # [return] nil in case of success or an Error object + # [return] nil in case of success or an Error object def update(xml_method, name, value) return Error.new('ID not defined') if !@pe_id @@ -148,9 +146,9 @@ module OpenNebula end # Calls to the corresponding delete method to remove this element - # from the OpenNebula core + # from the OpenNebula core # xml_method:: _String_ the name of the XML-RPC method - # [return] nil in case of success or an Error object + # [return] nil in case of success or an Error object def delete(xml_method) return Error.new('ID not defined') if !@pe_id @@ -161,20 +159,20 @@ module OpenNebula end public - + # Creates new element specifying its id # id:: identifyier of the element # client:: initialized OpenNebula::Client object def self.new_with_id(id, client=nil) self.new(self.build_xml(id), client) end - + # Returns element identifier - # [return] _Integer_ the PoolElement ID + # [return] _Integer_ the PoolElement ID def id @pe_id end - + # Gets element name # [return] _String_ the PoolElement name def name @@ -185,8 +183,8 @@ module OpenNebula def to_str str = "" REXML::Formatters::Pretty.new(1).write(@xml,str) - - return str + + return str end end end diff --git a/src/oca/ruby/OpenNebula/User.rb b/src/oca/ruby/OpenNebula/User.rb index e345086368..7289904c6b 100644 --- a/src/oca/ruby/OpenNebula/User.rb +++ b/src/oca/ruby/OpenNebula/User.rb @@ -25,7 +25,7 @@ module OpenNebula user_xml = "" end - XMLUtilsElement.initialize_xml(user_xml, 'USER') + XMLElement.build_xml(user_xml, 'USER') end # --------------------------------------------------------------------- diff --git a/src/oca/ruby/OpenNebula/VirtualMachine.rb b/src/oca/ruby/OpenNebula/VirtualMachine.rb index 0c81b19f4c..4440117f8a 100644 --- a/src/oca/ruby/OpenNebula/VirtualMachine.rb +++ b/src/oca/ruby/OpenNebula/VirtualMachine.rb @@ -12,9 +12,9 @@ module OpenNebula :migrate => "vm.migrate", :deploy => "vm.deploy" } - + VM_STATE=%w{INIT PENDING HOLD ACTIVE STOPPED SUSPENDED DONE FAILED} - + LCM_STATE=%w{LCM_INIT PROLOG BOOT RUNNING MIGRATE SAVE_STOP SAVE_SUSPEND SAVE_MIGRATE PROLOG_MIGRATE PROLOG_RESUME EPILOG_STOP EPILOG SHUTDOWN CANCEL FAILURE DELETE UNKNOWN} @@ -72,8 +72,8 @@ module OpenNebula else vm_xml = "" end - - XMLUtilsElement.initialize_xml(vm_xml, 'VM') + + XMLElement.build_xml(vm_xml, 'VM') end def VirtualMachine.get_reason(reason) @@ -88,7 +88,7 @@ module OpenNebula ####################################################################### def initialize(xml, client) super(xml,client) - + @element_name = "VM" @client = client end @@ -110,7 +110,7 @@ module OpenNebula rc = @client.call(VM_METHODS[:deploy], @pe_id, host_id.to_i) rc = nil if !OpenNebula.is_error?(rc) - + return rc end @@ -155,7 +155,7 @@ module OpenNebula rc = @client.call(VM_METHODS[:migrate], @pe_id, host_id.to_i, false) rc = nil if !OpenNebula.is_error?(rc) - + return rc end @@ -164,14 +164,14 @@ module OpenNebula rc = @client.call(VM_METHODS[:migrate], @pe_id, host_id.to_i, true) rc = nil if !OpenNebula.is_error?(rc) - + return rc end ####################################################################### # Helpers to get VirtualMachine information ####################################################################### - + # Returns the VM state of the VirtualMachine (numeric value) def state self['STATE'].to_i diff --git a/src/oca/ruby/OpenNebula/VirtualNetwork.rb b/src/oca/ruby/OpenNebula/VirtualNetwork.rb index 0a86dc8812..2f46d6a48a 100644 --- a/src/oca/ruby/OpenNebula/VirtualNetwork.rb +++ b/src/oca/ruby/OpenNebula/VirtualNetwork.rb @@ -26,7 +26,7 @@ module OpenNebula vn_xml = "" end - XMLUtilsElement.initialize_xml(vn_xml, 'VNET') + XMLElement.build_xml(vn_xml, 'VNET') end # Class constructor @@ -39,7 +39,7 @@ module OpenNebula ####################################################################### # XML-RPC Methods for the Virtual Network Object ####################################################################### - + def info() super(VN_METHODS[:info], 'VNET') end @@ -47,11 +47,11 @@ module OpenNebula def allocate(description) super(VN_METHODS[:allocate],description) end - + def publish set_publish(true) end - + def unpublish set_publish(false) end @@ -59,7 +59,7 @@ module OpenNebula def delete() super(VN_METHODS[:delete]) end - + private def set_publish(published) return Error.new('ID not defined') if !@pe_id @@ -69,6 +69,6 @@ module OpenNebula return rc end - + end end diff --git a/src/oca/ruby/OpenNebula/XMLUtils.rb b/src/oca/ruby/OpenNebula/XMLUtils.rb index c0c9dca0ff..d1dbeb33ed 100644 --- a/src/oca/ruby/OpenNebula/XMLUtils.rb +++ b/src/oca/ruby/OpenNebula/XMLUtils.rb @@ -19,27 +19,42 @@ module OpenNebula # The XMLUtilsElement module provides an abstraction of the underlying # XML parser engine. It provides XML-related methods for the Pool Elements ########################################################################### - module XMLUtilsElement + class XMLElement + + def initialize(xml=nil) + @xml = xml + end + # Initialize a XML document for the element # xml:: _String_ the XML document of the object # root_element:: _String_ Base xml element - # [return] _XML_ object for the underlying XML engine - def self.initialize_xml(xml, root_element) + def initialize_xml(xml, root_element) if NOKOGIRI - xmldoc = Nokogiri::XML(xml).xpath("/#{root_element}") - if xmldoc.size == 0 - xmldoc = nil + @xml = Nokogiri::XML(xml).xpath("/#{root_element}") + if @xml.size == 0 + @xml = nil end else - xmldoc = REXML::Document.new(xml).root - if xmldoc.name != root_element - xmldoc = nil + @xml = REXML::Document.new(xml).root + if @xml.name != root_element + @xml = nil end end - - return xmldoc end + # Builds a XML document + # xml:: _String_ the XML document of the object + # root_element:: _String_ Base xml element + # [return] _XML_ object for the underlying XML engine + def self.build_xml(xml, root_element) + if NOKOGIRI + doc = Nokogiri::XML(xml).xpath("/#{root_element}") + else + doc = REXML::Document.new(xml).root + end + + return doc + end # Extract an element from the XML description of the PoolElement. # key::_String_ The name of the element # [return] _String_ the value of the element @@ -49,6 +64,7 @@ module OpenNebula def [](key) if NOKOGIRI element=@xml.xpath(key.to_s) + if element.size == 0 return nil end @@ -175,7 +191,11 @@ module OpenNebula # The XMLUtilsPool module provides an abstraction of the underlying # XML parser engine. It provides XML-related methods for the Pools ########################################################################### - module XMLUtilsPool + class XMLPool < XMLElement + + def initialize(xml=nil) + super(xml) + end #Executes the given block for each element of the Pool #block:: _Block_ @@ -193,7 +213,6 @@ module OpenNebula end end - def to_hash if !@hash && @xml @hash=Crack::XML.parse(to_xml) @@ -202,13 +221,6 @@ module OpenNebula end end - class XMLElement - include XMLUtilsElement - - def initialize(xml) - @xml = xml - end - end end From 10bfc260ffdab00e11c62e67aa33203283bb8ab2 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Tue, 20 Jul 2010 00:36:14 +0200 Subject: [PATCH 25/27] feature #200 Fixed error in PoolElement [] --- src/cli/onehost | 61 ++++++------- src/cli/oneimage | 217 +++++++++++++++++++---------------------------- src/cli/onevm | 67 ++++++++------- src/cli/onevnet | 2 +- 4 files changed, 150 insertions(+), 197 deletions(-) diff --git a/src/cli/onehost b/src/cli/onehost index 7bfafe8fb5..deb2a58184 100755 --- a/src/cli/onehost +++ b/src/cli/onehost @@ -250,43 +250,38 @@ when "show" result=host.info if is_successful?(result) - #puts host.template_str - else - puts "Error: "+result.message - exit -1 - end + if !ops[:xml] + str = "%-22s: %-20s" + str_h1 = "%-80s" - if !ops[:xml] - str = "%-22s: %-20s" - str_h1 = "%-80s" + print_header(str_h1, "HOST #{host_id} INFORMATION", true) + + puts str % ["ID", host.id.to_s] + puts str % ["NAME", host.name] + puts str % ["CLUSTER", host['CLUSTER']] + puts str % ["STATE", host.state_str] + puts str % ["IM_MAD", host['IM_MAD']] + puts str % ["VM_MAD", host['VM_MAD']] + puts str % ["TM_MAD", host['TM_MAD']] + puts + + print_header(str_h1, "HOST SHARES", false) - print_header(str_h1, "HOST #{host_id} INFORMATION", true) + puts str % ["MAX MEM", host['HOST_SHARE/MAX_MEM']] + puts str % ["USED MEM (REAL)", host['HOST_SHARE/USED_MEM']] + puts str % ["USED MEM (ALLOCATED)", host['HOST_SHARE/MEM_USAGE']] + puts str % ["MAX CPU", host['HOST_SHARE/MAX_CPU']] + puts str % ["USED CPU (REAL)", host['HOST_SHARE/USED_CPU']] + puts str % ["USED CPU (ALLOCATED)", host['HOST_SHARE/CPU_USAGE']] + puts str % ["RUNNING VMS", host['HOST_SHARE/RUNNING_VMS']] + puts - puts str % ["ID", host[:id]] - puts str % ["NAME", host[:name]] - puts str % ["CLUSTER", host[:cluster]] - puts str % ["STATE", host.state_str] - puts str % ["IM_MAD", host[:im_mad]] - puts str % ["VM_MAD", host[:vm_mad]] - puts str % ["TM_MAD", host[:tm_mad]] - puts + print_header(str_h1, "MONITORING INFORMATION", false) - print_header(str_h1, "HOST SHARES", false) - - puts str % ["MAX MEM", host['host_share/max_mem']] - puts str % ["USED MEM (REAL)", host['host_share/used_mem']] - puts str % ["USED MEM (ALLOCATED)", host['host_share/mem_usage']] - puts str % ["MAX CPU", host['host_share/max_cpu']] - puts str % ["USED CPU (REAL)", host['host_share/used_cpu']] - puts str % ["USED CPU (ALLOCATED)", host['host_share/cpu_usage']] - puts str % ["RUNNING VMS", host['host_share/running_vms']] - puts - - print_header(str_h1, "MONITORING INFORMATION", false) - - puts host.template_str - else - puts host.to_xml(true) + puts host.template_str + else + puts host.to_xml(true) + end end when "delete" diff --git a/src/cli/oneimage b/src/cli/oneimage index 546540bf9c..8220c2dfb9 100755 --- a/src/cli/oneimage +++ b/src/cli/oneimage @@ -31,7 +31,6 @@ require 'OpenNebula' require 'CommandManager' require 'client_utilities' require 'command_parse' -require 'ftools' ShowTableImage={ :id => { @@ -278,23 +277,19 @@ def get_user_flags ops end -def get_type_and_path(image_template_file) - image_text = open(image_template_file).read - result=Hash.new - image_text.each_line {|line| - case line - when /^\s*(#.*)?$/ - # skip empty or commented lines - next - when /^\s*(\w+)\s*=\s*(.*)\s*$/ - name = $1.strip.upcase - if name == "PATH" || name == "TYPE" || - name == "SIZE" || name == "FSTYPE" - result[name] = $2.strip - end - end - } - result +def get_template(template_path) + begin + template = File.read(ARGV[0]) + rescue + result = OpenNebula::Error.new("Can not read template: #{ARGV[0]}") + end + + if !is_successful?(result) + puts result.message + exit -1 + end + + return template end oneimage_opts=OneImageParse.new @@ -306,99 +301,59 @@ result=[false, "Unknown error"] command=ARGV.shift case command -when "register", "create", "add" +when "register", "create", "add" + # ---------- Get the Template ------------ + check_parameters("register", 1) - - # First, let's check we have everything we need in the template + template = get_template(ARGV[0]) - # Get the path and type from the template file - parser_result = get_type_and_path(ARGV[0]) + # ---------- Allocate the Image file ------------ - if parser_result['TYPE'] - type = parser_result['TYPE'].upcase - else - type = "OS" - end + image = OpenNebula::Image.new( + OpenNebula::Image.build_xml, + get_one_client) + + result = image.allocate(template) - result = true - case type - when "OS", "CDROM" - if !parser_result['PATH'] - result=OpenNebula::Error.new( - "Image path not present, aborting.") - elsif !File.exists?(parser_result['PATH']) - result=OpenNebula::Error.new( - "Image file could not be found, aborting.") - end - when "DATABLOCK" - if parser_result['PATH'] and !File.exists?(parser_result['PATH']) - if !parser_result['SIZE'] || !parser_result['FSTYPE'] - result=OpenNebula::Error.new( - "No image file present for DATABLOCK, " + - "size and/or fstype also missing, aborting.") - end - end - end - if !is_successful?(result) puts result.message exit -1 end - - # Perform the allocate if all goes well - image=OpenNebula::Image.new( - OpenNebula::Image.build_xml, get_one_client) - begin - template=File.read(ARGV[0]) - result=image.allocate(template) - rescue - result=OpenNebula::Error.new("Can not read template: #{ARGV[0]}") - end - - if !is_successful?(result) - exit -1 - end - - # Get the allocated image - image=OpenNebula::Image.new_with_id(image.id, get_one_client) + + # ---------- Copy the Image file ------------ + image.info - template=image.to_hash - template=template['IMAGE']['TEMPLATE'] - - # Perform the copy to the image repo if needed - if template['PATH'] - if File.copy(template['PATH'], image['SOURCE']) - result = image.enable - else - result=OpenNebula::Error.new( - "Cannot copy image, aborting.") - image.delete - end - elsif parser_result['SIZE'] and parser_result['FSTYPE'] - local_command=LocalCommand.run( - "dd if=/dev/zero of=#{image['SOURCE']} ibs=1 count=1 " \ - "obs=1048576 oseek=#{parser_result['SIZE']}") - if local_command.code!=0 - result=OpenNebula::Error.new( - "Cannot create datablock, aborting.") - image.delete - else - local_command=LocalCommand.run( - "mkfs -t #{parser_result['FSTYPE']} -F #{image['SOURCE']}") - if local_command.code!=0 - result=OpenNebula::Error.new( - "Cannot format datablock, aborting.") - image.delete - else - image.enable - end - end + + if image['TEMPLATE/PATH'] + file_path = image['TEMPLATE/PATH'] + + if !File.exists?(file_path) + error_msg = "Image file could not be found, aborting." + result = OpenNebula::Error.new(error_msg) + end + + result = image.copy(file_path, image['SOURCE']) + elsif image['TEMPLATE/SIZE'] and + image['TEMPLATE/FSTYPE'] and + image['TEMPLATE/TYPE'] == 'DATABLOCK' + result = image.mk_datablock( + image['TEMPLATE/SIZE'], + image['TEMPLATE/FSTYPE'], + image['SOURCE']) + else + error_msg = "Image not present, aborting." + result = OpenNebula::Error.new(error_msg) end - + + if is_successful?(result) + image.enable puts "ID: " + image.id.to_s if ops[:verbose] exit 0 - end + else + image.delete + end + when "update" check_parameters("update", 3) @@ -493,42 +448,44 @@ when "show" image_id=get_image_id(param) image=OpenNebula::Image.new_with_id(image_id, get_one_client) - image.info - - if !ops[:xml] - str="%-15s: %-20s" - str_h1="%-80s" - - print_header(str_h1, "IMAGE #{image[:id]} INFORMATION", true) - - puts str % ["ID", image[:id]] - puts str % ["NAME", image[:name]] - puts str % ["TYPE", image.type_str] + result = image.info - value=image[:regtime].to_i - if value==0 - value='-' - else - value=Time.at(value).strftime("%m/%d %H:%M:%S") - end - puts str % ["REGISTER TIME", value] - if image[:public].to_i == 1 - public_str = "Yes" - else - public_str = "No" - end - puts str % ["PUBLIC", public_str] - puts str % ["SOURCE", image[:source]] - puts str % ["STATE", image.short_state_str] - puts str % ["RUNNING_VMS", image[:runningvms]] + if is_successful?(result) + if !ops[:xml] + str="%-15s: %-20s" + str_h1="%-80s" + + print_header(str_h1, "IMAGE #{image[:id]} INFORMATION", true) + + puts str % ["ID", image.id.to_s] + puts str % ["NAME", image.name] + puts str % ["TYPE", image.type_str] + + value=image['REGTIME'].to_i + if value==0 + value='-' + else + value=Time.at(value).strftime("%m/%d %H:%M:%S") + end + puts str % ["REGISTER TIME", value] + if image['PUBLIC'].to_i == 1 + public_str = "Yes" + else + public_str = "No" + end + puts str % ["PUBLIC", public_str] + puts str % ["SOURCE", image['SOURCE']] + puts str % ["STATE", image.short_state_str] + puts str % ["RUNNING_VMS", image['RUNNING_VMS']] - puts + puts - print_header(str_h1,"IMAGE TEMPLATE",false) + print_header(str_h1,"IMAGE TEMPLATE",false) - puts image.template_str - else - puts image.to_xml + puts image.template_str + else + puts image.to_xml + end end end diff --git a/src/cli/onevm b/src/cli/onevm index b868b960e5..5fa2ccbe24 100755 --- a/src/cli/onevm +++ b/src/cli/onevm @@ -680,45 +680,46 @@ when "show" vm_id=get_vm_id(param) vm=OpenNebula::VirtualMachine.new_with_id(vm_id, get_one_client) - vm.info + result=vm.info + if is_successful?(result) + if !ops[:xml] + str="%-15s: %-20s" + str_h1="%-80s" - if !ops[:xml] - str="%-15s: %-20s" - str_h1="%-80s" + print_header(str_h1, "VIRTUAL MACHINE #{vm[:id]} INFORMATION", true) - print_header(str_h1, "VIRTUAL MACHINE #{vm[:id]} INFORMATION", true) + puts str % ["ID", vm.id.to_s] + puts str % ["NAME", vm.name] + puts str % ["STATE", vm.state_str] + puts str % ["LCM_STATE", vm.lcm_state_str] - puts str % ["ID", vm[:id]] - puts str % ["NAME", vm[:name]] - puts str % ["STATE", vm.state_str] - puts str % ["LCM_STATE", vm.lcm_state_str] + value=vm['STIME'].to_i + if value==0 + value='-' + else + value=Time.at(value).strftime("%m/%d %H:%M:%S") + end + puts str % ["START TIME", value] - value=vm[:stime].to_i - if value==0 - value='-' + value=vm['ETIME'].to_i + if value==0 + value='-' + else + value=Time.at(value).strftime("%m/%d %H:%M:%S") + end + puts str % ["END TIME", value] + + value=vm['DEPLOY_ID'] + puts str % ["DEPLOY ID:", value=="" ? "-" : value] + + puts + + print_header(str_h1,"VIRTUAL MACHINE TEMPLATE",false) + + puts vm.template_str else - value=Time.at(value).strftime("%m/%d %H:%M:%S") + puts vm.to_xml(true) end - puts str % ["START TIME", value] - - value=vm[:etime].to_i - if value==0 - value='-' - else - value=Time.at(value).strftime("%m/%d %H:%M:%S") - end - puts str % ["END TIME", value] - - value=vm[:deploy_id] - puts str % ["DEPLOY ID:", value=="" ? "-" : value] - - puts - - print_header(str_h1,"VIRTUAL MACHINE TEMPLATE",false) - - puts vm.template_str - else - puts vm.to_xml(true) end end else diff --git a/src/cli/onevnet b/src/cli/onevnet index 088fc8d5a6..0e7021a75b 100755 --- a/src/cli/onevnet +++ b/src/cli/onevnet @@ -217,7 +217,7 @@ when "show" puts str % ["ID: ",vn.id.to_s] puts str % ["UID: ",vn["UID"]] - if vn[:public].to_i == 1 + if vn['PUBLIC'].to_i == 1 public_str = "Y" else public_str = "N" From 104387a75b9a3d1ba03c58093cd34d39cb659630 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Tue, 20 Jul 2010 19:19:31 +0200 Subject: [PATCH 26/27] feature #200 Fixed uppercase paths in xml --- src/cli/client_utilities.rb | 10 +++++----- src/cli/command_parse.rb | 1 - src/cli/onehost | 6 +++--- src/cli/oneuser | 2 +- src/cli/onevm | 32 ++++++++++++++++---------------- src/cli/onevnet | 6 +++--- src/oca/ruby/OpenNebula/Pool.rb | 2 +- 7 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/cli/client_utilities.rb b/src/cli/client_utilities.rb index 874bee72ca..f35d7189ca 100644 --- a/src/cli/client_utilities.rb +++ b/src/cli/client_utilities.rb @@ -62,12 +62,12 @@ ShowTableExample={ :id => { :name => "ID", :size => 4, - :proc => lambda {|d,e| d["oid"] } + :proc => lambda {|d,e| d["OID"] } }, :name => { :name => "NAME", :size => 8, - :proc => lambda {|d,e| d["deploy_id"] } + :proc => lambda {|d,e| d["DEPLOY_ID"] } }, :stat => { :name => "STAT", @@ -294,11 +294,11 @@ def get_cluster_id(name) end def str_running_time(data) - stime=Time.at(data["stime"].to_i) - if data["etime"]=="0" + stime=Time.at(data["STIME"].to_i) + if data["ETIME"]=="0" etime=Time.now else - etime=Time.at(data["etime"].to_i) + etime=Time.at(data["ETIME"].to_i) end dtime=Time.at(etime-stime).getgm diff --git a/src/cli/command_parse.rb b/src/cli/command_parse.rb index b5385bf0c3..b86f5a1685 100644 --- a/src/cli/command_parse.rb +++ b/src/cli/command_parse.rb @@ -15,7 +15,6 @@ #--------------------------------------------------------------------------- # require 'optparse' -require 'pp' class CommandParse diff --git a/src/cli/onehost b/src/cli/onehost index deb2a58184..57e926ba4a 100755 --- a/src/cli/onehost +++ b/src/cli/onehost @@ -42,14 +42,14 @@ ShowTableHost={ :name => { :name => "NAME", :desc => "Hostname", - :size => 25, + :size => 15, :left => true, :proc => lambda {|d,e| d.name } }, :cluster => { :name => "CLUSTER", :desc => "Clustername", - :size => 25, + :size => 15, :left => true, :proc => lambda {|d,e| d.cluster } }, @@ -216,7 +216,7 @@ def vms_in_host?(host_id) exit -1 end - host['host_share/running_vms'].to_i + host['HOST_SHARE/RUNNING_VMS'].to_i end diff --git a/src/cli/oneuser b/src/cli/oneuser index e936808fde..10e62287e1 100755 --- a/src/cli/oneuser +++ b/src/cli/oneuser @@ -51,7 +51,7 @@ ShowTableUP={ :desc => "password of the user", :size => 50, :left => true, - :proc => lambda {|d,e| d[:password] } + :proc => lambda {|d,e| d['PASSWORD'] } }, :default => [:id, :user, :password] diff --git a/src/cli/onevm b/src/cli/onevm index 5fa2ccbe24..91b2d443fc 100755 --- a/src/cli/onevm +++ b/src/cli/onevm @@ -68,14 +68,14 @@ ShowTableVM={ :desc => "CPU percentage used by the VM", :size => 3, :proc => lambda {|d,e| - d["cpu"] + d["CPU"] } }, :mem => { :name => "MEM", :desc => "Memory used by the VM", :size => 7, - :proc => lambda {|d,e| d["memory"] } + :proc => lambda {|d,e| d["MEMORY"] } }, :hostname => { :name => "HOSTNAME", @@ -100,26 +100,26 @@ ShowTableHistory={ :name => "ID", :desc => "ONE identifier for the VM", :size => 4, - :proc => lambda {|d,e| d["id"] } + :proc => lambda {|d,e| d["ID"] } }, :seq => { :name => "SEQ", :desc => "Sequence number", :size => 3, - :proc => lambda {|d,e| d["seq"] } + :proc => lambda {|d,e| d["SEQ"] } }, :hostname => { :name => "HOSTNAME", :desc => "Name of the host where the VM was submited", :size => 15, - :proc => lambda {|d,e| d["host_name"] } + :proc => lambda {|d,e| d["HOST_NAME"] } }, :stime => { :name => "STIME", :desc => "Start time", :size => 14, :proc => lambda {|d,e| - t=Time.at(d["stime"].to_i) + t=Time.at(d["STIME"].to_i) t.strftime("%m/%d %H:%M:%S") } }, @@ -128,10 +128,10 @@ ShowTableHistory={ :desc => "End time", :size => 14, :proc => lambda {|d,e| - if d["etime"].to_i==0 + if d["ETIME"].to_i==0 "--" else - t=Time.at(d["etime"].to_i) + t=Time.at(d["ETIME"].to_i) t.strftime("%m/%d %H:%M:%S") end } @@ -141,7 +141,7 @@ ShowTableHistory={ :desc => "Total time", :size => 11, :proc => lambda {|d,e| - d["time"] + d["TIME"] } }, :reason => { @@ -149,7 +149,7 @@ ShowTableHistory={ :desc => "Reason for state change", :size => "6", :proc => lambda {|d,e| - OpenNebula::VirtualMachine.get_reason(d["reason"]) + OpenNebula::VirtualMachine.get_reason(d["REASON"]) } }, @@ -234,12 +234,12 @@ class VmShow def get_vm_history(vm) { 'id' => vm.id, - 'seq' => vm['history/seq'], - 'host_name' => vm['history/hostname'], - 'stime' => vm['history/stime'], - 'etime' => vm['history/etime'], + 'seq' => vm['HISTORY/SEQ'], + 'host_name' => vm['HISTORY/HOSTNAME'], + 'stime' => vm['HISTORY/STIME'], + 'etime' => vm['HISTORY/ETIME'], 'time' => str_running_time(vm), - 'reason' => vm['history/reason'] + 'reason' => vm['HISTORY/REASON'] } end @@ -274,7 +274,7 @@ class VmShow def list_vm_history_array(ids, options=nil) get_vms_history(ids).each {|vm| - puts "History for VM #{vm['id']}" + puts "History for VM #{vm['ID']}" puts list_vm_history(vm, options) puts diff --git a/src/cli/onevnet b/src/cli/onevnet index 0e7021a75b..8dcdf17d54 100755 --- a/src/cli/onevnet +++ b/src/cli/onevnet @@ -58,10 +58,10 @@ ShowTableVN={ :desc => "NType of virtual network", :size => 6, :proc => lambda {|d,e| - if(d["type"] == "0") + if(d["TYPE"] == "0") return "Ranged" else - if (d["type"] == "1") + if (d["TYPE"] == "1") return "Fixed" end end @@ -77,7 +77,7 @@ ShowTableVN={ :name => "BRIDGE", :desc => "Bridge associated to the virtual network", :size => 6, - :proc => lambda {|d,e| d["bridge"] } + :proc => lambda {|d,e| d["BRIDGE"] } }, :public => { :name => "PUBLIC", diff --git a/src/oca/ruby/OpenNebula/Pool.rb b/src/oca/ruby/OpenNebula/Pool.rb index 51ec16995c..a271352232 100644 --- a/src/oca/ruby/OpenNebula/Pool.rb +++ b/src/oca/ruby/OpenNebula/Pool.rb @@ -2,7 +2,7 @@ module OpenNebula # The Pool class represents a generic OpenNebula Pool in XML format # and provides the basic functionality to handle the Pool elements - require 'pp' + class Pool < XMLPool include Enumerable From 6ffad9cdef98254fd69b4818a5776b60e7c12e00 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Tue, 20 Jul 2010 19:42:20 +0200 Subject: [PATCH 27/27] feature #200: Fix uppercase XPATH variables --- src/cli/onehost | 58 ++++++++++++++++++++++++------------------------- src/cli/onevm | 3 ++- 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/src/cli/onehost b/src/cli/onehost index 57e926ba4a..10f49c93b9 100755 --- a/src/cli/onehost +++ b/src/cli/onehost @@ -42,14 +42,14 @@ ShowTableHost={ :name => { :name => "NAME", :desc => "Hostname", - :size => 15, + :size => 25, :left => true, :proc => lambda {|d,e| d.name } }, :cluster => { :name => "CLUSTER", :desc => "Clustername", - :size => 15, + :size => 25, :left => true, :proc => lambda {|d,e| d.cluster } }, @@ -103,7 +103,7 @@ ShowTableHost={ d.short_state_str() } }, - + :default => [:id, :name, :cluster, :rvm, :tcpu, :fcpu, :acpu, :tmem, :fmem, :stat] } @@ -113,7 +113,7 @@ class HostShow @hostpool=OpenNebula::HostPool.new(client) @table=ShowTable.new(ShowTableHost) end - + def header_host_small scr_bold scr_underline @@ -121,7 +121,7 @@ class HostShow scr_restore puts "" end - + def list_short(options=nil) res=@hostpool.info if options @@ -141,13 +141,13 @@ class HostShow result end end - + def top(options=nil) delay=1 delay=options[:delay] if options && options[:delay] - + result=nil - + begin while true scr_cls @@ -162,28 +162,28 @@ class HostShow end class OnehostParse < CommandParse - + COMMANDS_HELP=<<-EOT Commands: * create (Adds a new machine to the pool) onehost create - + * show (Gets info from a host) onehost show - + * delete (Removes a machine from the pool) onehost delete - + * list (Lists machines in the pool) onehost list - + * enable (Enables host) onehost enable - + * disable (Disables host) onehost disable - + * top (Lists hosts continuously) onehost top @@ -215,7 +215,7 @@ def vms_in_host?(host_id) puts rc.message exit -1 end - + host['HOST_SHARE/RUNNING_VMS'].to_i end @@ -234,26 +234,26 @@ when "add", "create" check_parameters("create", 4) host=OpenNebula::Host.new(OpenNebula::Host.build_xml, get_one_client) result=host.allocate(ARGV[0], ARGV[1], ARGV[2], ARGV[3]) - + if is_successful?(result) puts "ID: " + host.id.to_s if ops[:verbose] exit 0 end - + when "show" check_parameters("show", 1) #args=expand_args(ARGV) - + host_id=get_host_id(ARGV[0]) - + host=OpenNebula::Host.new_with_id(host_id, get_one_client) - + result=host.info if is_successful?(result) if !ops[:xml] str = "%-22s: %-20s" str_h1 = "%-80s" - + print_header(str_h1, "HOST #{host_id} INFORMATION", true) puts str % ["ID", host.id.to_s] @@ -266,7 +266,7 @@ when "show" puts print_header(str_h1, "HOST SHARES", false) - + puts str % ["MAX MEM", host['HOST_SHARE/MAX_MEM']] puts str % ["USED MEM (REAL)", host['HOST_SHARE/USED_MEM']] puts str % ["USED MEM (ALLOCATED)", host['HOST_SHARE/MEM_USAGE']] @@ -290,7 +290,7 @@ when "delete" args.each do |param| host_id=get_host_id(param) - + host = OpenNebula::Host.new_with_id(host_id,get_one_client) rc = host.info @@ -300,7 +300,7 @@ when "delete" exit -1 end - if host['host_share/running_vms'].to_i != 0 + if host['HOST_SHARE/RUNNING_VMS'].to_i != 0 puts "Host still has associated VMs, aborting delete." else result=host.delete @@ -310,7 +310,7 @@ when "delete" end end end - + when "list" if !ops[:xml] hostlist=HostShow.new(get_one_client) @@ -326,7 +326,7 @@ when "top" hostlist=HostShow.new(get_one_client) ops[:columns]=ops[:list] if ops[:list] result=hostlist.top(ops) - + when "enable" check_parameters("enable", 1) args=expand_args(ARGV) @@ -356,13 +356,13 @@ when "disable" break end end - + else onehost_opts.print_help exit -1 end -if is_error?(result) +if is_error?(result) puts "Error: " + result.message exit -1 end diff --git a/src/cli/onevm b/src/cli/onevm index 91b2d443fc..263ce30525 100755 --- a/src/cli/onevm +++ b/src/cli/onevm @@ -686,7 +686,8 @@ when "show" str="%-15s: %-20s" str_h1="%-80s" - print_header(str_h1, "VIRTUAL MACHINE #{vm[:id]} INFORMATION", true) + print_header(str_h1, "VIRTUAL MACHINE #{vm['ID']} INFORMATION", +true) puts str % ["ID", vm.id.to_s] puts str % ["NAME", vm.name]