From: marios <[email protected]>
Signed-off-by: marios <[email protected]> --- .../deltacloud/drivers/opennebula/cloud_client.rb | 180 +++++---- .../deltacloud/drivers/opennebula/occi_client.rb | 433 +++++++++++++------- .../drivers/opennebula/opennebula_driver.rb | 315 +++++++++------ 3 files changed, 585 insertions(+), 343 deletions(-) diff --git a/server/lib/deltacloud/drivers/opennebula/cloud_client.rb b/server/lib/deltacloud/drivers/opennebula/cloud_client.rb index 00be869..283efd9 100644 --- a/server/lib/deltacloud/drivers/opennebula/cloud_client.rb +++ b/server/lib/deltacloud/drivers/opennebula/cloud_client.rb @@ -18,11 +18,30 @@ require 'rubygems' require 'uri' +require 'digest/sha1' require 'net/https' +require "rexml/document" + +begin + require 'rexml/formatters/pretty' + REXML_FORMATTERS=true +rescue LoadError + REXML_FORMATTERS=false +end + +begin + require 'curb' + CURL_LOADED=true +rescue LoadError + CURL_LOADED=false +end + begin - require 'net/http/post/multipart' + require 'net/http/post/multipart' + MULTIPART_LOADED=true rescue LoadError + MULTIPART_LOADED=false end ############################################################################### @@ -30,85 +49,100 @@ end # Cloud Client ############################################################################### module CloudClient - # ######################################################################### - # Default location for the authentication file - # ######################################################################### - DEFAULT_AUTH_FILE = ENV["HOME"]+"/.one/one_auth" - - # ######################################################################### - # Gets authorization credentials from ONE_AUTH or default - # auth file. - # - # Raises an error if authorization is not found - # ######################################################################### - def self.get_one_auth - if ENV["ONE_AUTH"] and !ENV["ONE_AUTH"].empty? and - File.file?(ENV["ONE_AUTH"]) - one_auth=File.read(ENV["ONE_AUTH"]).strip.split(':') - elsif File.file?(DEFAULT_AUTH_FILE) - one_auth=File.read(DEFAULT_AUTH_FILE).strip.split(':') - else - raise "No authorization data present" - end - - raise "Authorization data malformed" if one_auth.length < 2 - - one_auth + # ######################################################################### + # Default location for the authentication file + # ######################################################################### + DEFAULT_AUTH_FILE = ENV["HOME"]+"/.one/one_auth" + + # ######################################################################### + # Gets authorization credentials from ONE_AUTH or default + # auth file. + # + # Raises an error if authorization is not found + # ######################################################################### + def self.get_one_auth + if ENV["ONE_AUTH"] and !ENV["ONE_AUTH"].empty? and + File.file?(ENV["ONE_AUTH"]) + one_auth=File.read(ENV["ONE_AUTH"]).strip.split(':') + elsif File.file?(DEFAULT_AUTH_FILE) + one_auth=File.read(DEFAULT_AUTH_FILE).strip.split(':') + else + raise "No authorization data present" end - # ######################################################################### - # Starts an http connection and calls the block provided. SSL flag - # is set if needed. - # ######################################################################### - def self.http_start(url, &block) - http = Net::HTTP.new(url.host, url.port) - if url.scheme=='https' - http.use_ssl = true - http.verify_mode=OpenSSL::SSL::VERIFY_NONE - end - - begin - http.start do |connection| - block.call(connection) - end - rescue Errno::ECONNREFUSED => e - str = "Error connecting to server (#{e.to_s})." - str << "Server: #{url.host}:#{url.port}" - - return CloudClient::Error.new(str) - end + raise "Authorization data malformed" if one_auth.length < 2 + + one_auth + end + + # ######################################################################### + # Starts an http connection and calls the block provided. SSL flag + # is set if needed. + # ######################################################################### + def self.http_start(url, timeout, &block) + http = Net::HTTP.new(url.host, url.port) + + if timeout + http.read_timeout = timeout.to_i end - # ######################################################################### - # The Error Class represents a generic error in the Cloud Client - # library. It contains a readable representation of the error. - # ######################################################################### - class Error - attr_reader :message - - # +message+ a description of the error - def initialize(message=nil) - @message=message - end - - def to_s() - @message - end + if url.scheme=='https' + http.use_ssl = true + http.verify_mode=OpenSSL::SSL::VERIFY_NONE end - # ######################################################################### - # Returns true if the object returned by a method of the OpenNebula - # library is an Error - # ######################################################################### - def self.is_error?(value) - value.class==CloudClient::Error + begin + res = http.start do |connection| + block.call(connection) + end + rescue Errno::ECONNREFUSED => e + str = "Error connecting to server (#{e.to_s}).\n" + str << "Server: #{url.host}:#{url.port}" + + return CloudClient::Error.new(str,"503") + rescue Errno::ETIMEDOUT => e + str = "Error timeout connecting to server (#{e.to_s}).\n" + str << "Server: #{url.host}:#{url.port}" + + return CloudClient::Error.new(str,"504") + rescue Timeout::Error => e + str = "Error timeout while connected to server (#{e.to_s}).\n" + str << "Server: #{url.host}:#{url.port}" + + return CloudClient::Error.new(str,"504") end -end -# Command line help functions -module CloudCLI - # Returns the command name - def cmd_name - File.basename($0) + if res.is_a?(Net::HTTPSuccess) + res + else + CloudClient::Error.new(res.body, res.code) end + end + + # ######################################################################### + # The Error Class represents a generic error in the Cloud Client + # library. It contains a readable representation of the error. + # ######################################################################### + class Error + attr_reader :message + attr_reader :code + + # +message+ a description of the error + def initialize(message=nil, code="500") + @message=message + @code=code + end + + def to_s() + @message + end + end + + # ######################################################################### + # Returns true if the object returned by a method of the OpenNebula + # library is an Error + # ######################################################################### + def self.is_error?(value) + value.class==CloudClient::Error + end end diff --git a/server/lib/deltacloud/drivers/opennebula/occi_client.rb b/server/lib/deltacloud/drivers/opennebula/occi_client.rb index 533eb94..3eab5d7 100644 --- a/server/lib/deltacloud/drivers/opennebula/occi_client.rb +++ b/server/lib/deltacloud/drivers/opennebula/occi_client.rb @@ -16,187 +16,330 @@ # require 'rubygems' -require 'uri' require 'rexml/document' +require 'uri' require 'deltacloud/drivers/opennebula/cloud_client' module OCCIClient - ##################################################################### - # Client Library to interface with the OpenNebula OCCI Service - ##################################################################### - class Client - - ###################################################################### - # Initialize client library - ###################################################################### - def initialize(endpoint_str=nil, user=nil, pass=nil, debug_flag=true) - @debug = debug_flag - - # Server location - if endpoint_str - @endpoint = endpoint_str - elsif ENV["OCCI_URL"] - @endpoint = ENV["OCCI_URL"] - 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 + ##################################################################### + # Client Library to interface with the OpenNebula OCCI Service + ##################################################################### + class Client + + attr_accessor :endpoint + + ###################################################################### + # Initialize client library + ###################################################################### + 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 + elsif ENV["OCCI_URL"] + @endpoint = ENV["OCCI_URL"] + 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 # - ################################# + ################################# + # Pool Resource Request Methods # + ################################# - ###################################################################### - # Post a new VM to the VM Pool - # :instance_type - # :xmlfile - ###################################################################### - def post_vms(xmlfile) - xml=File.read(xmlfile) + def get_root + get('/') + end + + ###################################################################### + # Retieves the available Instance types + ###################################################################### + def get_instance_types + get('/instance_type') + end - url = URI.parse(@endpoint+"/compute") + ###################################################################### + # Post a new VM to the VM Pool + # :xmlfile + ###################################################################### + def post_vms(xmlfile) + post('/compute', xmlfile) + end - req = Net::HTTP::Post.new(url.path) - req.body=xml + ###################################################################### + # Retieves the pool of Virtual Machines + ###################################################################### + def get_vms + get('/compute') + end - req.basic_auth @occiauth[0], @occiauth[1] + ###################################################################### + # Post a new Network to the VN Pool + # :xmlfile xml description of the Virtual Network + ###################################################################### + def post_network(xmlfile) + post('/network', xmlfile) + end - res = CloudClient::http_start(url) do |http| - http.request(req) - end + ###################################################################### + # Retieves the pool of Virtual Networks + ###################################################################### + def get_networks + get('/network') + end - 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) - ###################################################################### - # Retieves the pool of Virtual Machines - ###################################################################### - def get_vms - url = URI.parse(@endpoint+"/compute") - req = Net::HTTP::Get.new(url.path) + begin + image_info = REXML::Document.new(xml).root + rescue Exception => e + error = CloudClient::Error.new(e.message) + return error + end - req.basic_auth @occiauth[0], @occiauth[1] + if image_info.elements['URL'] + file_path = image_info.elements['URL'].text - res = CloudClient::http_start(url) {|http| - http.request(req) - } + m = file_path.match(/^\w+:\/\/(.*)$/) - if CloudClient::is_error?(res) - return res - else - return res.body - end + if m + file_path="/"+m[1] end + elsif !image_info.elements['TYPE'] == "DATABLOCK" + return CloudClient::Error.new("Can not find URL") + end + + if curb + if !CURL_LOADED + error_msg = "curb gem not loaded" + error = CloudClient::Error.new(error_msg) + return error + end + + curl=Curl::Easy.new(@endpoint+"/storage") - ###################################################################### - # Retieves the pool of Images owned by the user - ###################################################################### - def get_images - url = URI.parse(@endpoint+"/storage") - req = Net::HTTP::Get.new(url.path) + curl.http_auth_types = Curl::CURLAUTH_BASIC + curl.userpwd = "#{@occiauth[0]}:#{@occiauth[1]}" + curl.verbose = true if @debug + curl.multipart_form_post = true - req.basic_auth @occiauth[0], @occiauth[1] + begin + postfields = Array.new + postfields << Curl::PostField.content('occixml', xml) - res = CloudClient::http_start(url) {|http| - http.request(req) - } + if file_path + postfields << Curl::PostField.file('file', file_path) + end - if CloudClient::is_error?(res) - return res - else - return res.body - end + curl.http_post(*postfields) + rescue Exception => e + return CloudClient::Error.new(e.message) end - #################################### - # Entity Resource Request Methods # - #################################### + return curl.body_str + else + if !MULTIPART_LOADED + error_msg = "multipart-post gem not loaded" + error = CloudClient::Error.new(error_msg) + return error + end - ###################################################################### - # :id VM identifier - ###################################################################### - def get_vm(id) - url = URI.parse(@endpoint+"/compute/" + id.to_s) - req = Net::HTTP::Get.new(url.path) + params=Hash.new - req.basic_auth @occiauth[0], @occiauth[1] + if file_path + file=File.open(file_path) + params["file"]=UploadIO.new(file, + 'application/octet-stream', file_path) + end - res = CloudClient::http_start(url) {|http| - http.request(req) - } + params['occixml'] = xml - if CloudClient::is_error?(res) - return res - else - return res.body - end + 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 - ###################################################################### - # Puts a new Compute representation in order to change its state - # :xmlfile Compute OCCI xml representation - ###################################################################### - def put_vm(xmlfile) - xml=File.read(xmlfile) - vm_info=REXML::Document.new(xml).root.elements + file.close if file_path - url = URI.parse(@endpoint+'/compute/' + vm_info['ID'].text) + if CloudClient::is_error?(res) + return res + else + return res.body + end + end + end - req = Net::HTTP::Put.new(url.path) - req.body = xml + ###################################################################### + # Retieves the pool of Images owned by the user + ###################################################################### + def get_images + get('/storage') + end - req.basic_auth @occiauth[0], @occiauth[1] - res = CloudClient::http_start(url) do |http| - http.request(req) - end + #################################### + # Entity Resource Request Methods # + #################################### - if CloudClient::is_error?(res) - return res - else - return res.body - end - end + ###################################################################### + # :id VM identifier + ###################################################################### + def get_vm(id) + get('/compute/'+id.to_s) + end - ####################################################################### - # Retieves an Image - # :image_uuid Image identifier - ###################################################################### - 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) {|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 + ###################################################################### + def put_vm(xmlfile) + put('/compute/', xmlfile) + end + + #################################################################### + # :id Compute identifier + #################################################################### + def delete_vm(id) + delete('/compute/'+id.to_s) + end + + ###################################################################### + # Retrieves a Virtual Network + # :id Virtual Network identifier + ###################################################################### + def get_network(id) + get('/network/'+id.to_s) + end + + ###################################################################### + # Puts a new Network representation in order to change its state + # :xmlfile Network OCCI xml representation + ###################################################################### + def put_network(xmlfile) + put('/network/', xmlfile) + end + + ###################################################################### + # :id VM identifier + ###################################################################### + def delete_network(id) + delete('/network/'+id.to_s) + end + + ####################################################################### + # Retieves an Image + # :image_uuid Image identifier + ###################################################################### + def get_image(id) + get('/storage/'+id.to_s) + end + + ###################################################################### + # Puts a new Storage representation in order to change its state + # :xmlfile Storage OCCI xml representation + ###################################################################### + def put_image(xmlfile) + put('/storage/', xmlfile) + end + + ###################################################################### + # :id VM identifier + ###################################################################### + def delete_image(id) + delete('/storage/'+id.to_s) + end + + private + + def get(path) + url = URI.parse(@endpoint+path) + req = Net::HTTP::Get.new(url.path) + + do_request(url, req) + end + + def post(path, xmlfile) + url = URI.parse(@endpoint+path) + req = Net::HTTP::Post.new(url.path) + + req.body=File.read(xmlfile) + + do_request(url, req) + end + + def delete(path, xmlfile) + url = URI.parse(@endpoint+path) + req = Net::HTTP::Delete.new(url.path) + + do_request(url, req) + end + + def put(path, xmlfile) + xml = File.read(xmlfile) + + # Get ID from XML + begin + info = REXML::Document.new(xml).root + rescue Exception => e + error = CloudClient::Error.new(e.message) + return error + end + + if info.elements['ID'] == nil + return CloudClient::Error.new("Can not find RESOURCE ID") + end + + resource_id = info.elements['ID'].text + + url = URI.parse(@endpoint+path + resource_id) + req = Net::HTTP::Put.new(url.path) + + req.body = xml + + do_request(url, req) + end + + def do_request(url, req) + 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 + end end diff --git a/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb b/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb index e4f8f4d..81a1290 100644 --- a/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb +++ b/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb @@ -16,229 +16,294 @@ # require 'deltacloud/base_driver' +require 'deltacloud/drivers/opennebula/occi_client' require 'erb' +# TBD Nokogiri support require 'rexml/document' -path = File.dirname(__FILE__) -$: << path - -require 'occi_client' - module Deltacloud module Drivers module Opennebula class OpennebulaDriver < Deltacloud::BaseDriver - feature :instances, :user_name + def supported_collections + DEFAULT_COLLECTIONS - [:storage_volumes, :storage_snapshots] + end ###################################################################### # Hardware profiles - ###################################################################### - - define_hardware_profile 'small' - - define_hardware_profile 'medium' + ##################################################################### + def hardware_profiles(credentials, opts=nil) + occi_client = new_client(credentials) + xml = occi_client.get_instance_types + if CloudClient.is_error?(xml) + # OpenNebula 3.0 support + @hardware_profiles = ['small','medium','large'].map {|name| + ::Deltacloud::HardwareProfile.new(name) + } + else + # OpenNebula 3.2 support + @hardware_profiles = REXML::Document.new(xml).root.elements.map {|d| + elem = d.elements + ::Deltacloud::HardwareProfile.new(elem['NAME'].text) { + cpu elem['CPU'] + memory elem['MEMORY'] + storage elem['STORAGE'] + architecture elem['ARCHITECTURE'] + } + } + end - define_hardware_profile 'large' + filter_hardware_profiles(@hardware_profiles, opts) + end ###################################################################### # Realms ###################################################################### (REALMS = [ - Realm.new( { - :id=>'Any id', - :name=>'Any name', - :limit=>:unlimited, - :state=>'Any state', - } ), + Realm.new( { + :id=>'ONE', + :name=>'Opennebula', + :limit=>:unlimited, + :state=>'AVAILABLE', + } ), ] ) unless defined?( REALMS ) def realms(credentials, opts=nil) - return REALMS if ( opts.nil? ) - results = REALMS - results = filter_on( results, :id, opts ) - results + return REALMS if ( opts.nil? ) + results = REALMS + results = filter_on( results, :id, opts ) + results end ###################################################################### # Images ###################################################################### - def images(credentials, opts=nil) - occi_client = new_client(credentials) + occi_client = new_client(credentials) - images = [] - imagesxml = occi_client.get_images + xml = treat_response(occi_client.get_images) - storage = REXML::Document.new(imagesxml) - storage.root.elements.each do |d| - id = d.attributes['href'].split("/").last - - diskxml = occi_client.get_image(id) + # TBD Add extended info in the pool + images = REXML::Document.new(xml).root.elements.map do |d| + im_id = d.attributes['href'].split("/").last + storage = treat_response(occi_client.get_image(im_id)) + convert_image(storage, credentials) + end + end - images << convert_image(diskxml.to_s(), credentials) - end - images + def image(credentials, opts=nil) + occi_client = new_client(credentials) + xml = treat_response(occi_client.get_image(opts[:id])) + convert_image(xml, credentials) end + def destroy_image(credentials, id) + occi_client = new_client(credentials) + treat_response(occi_client.delete_image(opts[:id])) + end ###################################################################### # Instances ###################################################################### - define_instance_states do - start.to( :pending ) .on( :create ) - - pending.to( :running ) .automatically - - running.to( :stopped ) .on( :stop ) + feature :instances, :user_name + # TBD Add Context to the VMs + + OCCI_VM = %q{ + <COMPUTE> + <% if opts[:name] %> + <NAME><%=opts[:name]%></NAME> + <% end %> + <INSTANCE_TYPE><%= opts[:hwp_id] || 'small' %></INSTANCE_TYPE> + <DISK> + <STORAGE href="<%= storage_href %>" /> + </DISK> + </COMPUTE> + } + + OCCI_ACTION = %q{ + <COMPUTE> + <ID><%= id %></ID> + <STATE><%= strstate %></STATE> + </COMPUTE> + } + + VM_STATES = { + "INIT" => "START", + "PENDING" => "PENDING", + "HOLD" => "STOPPED", + "ACTIVE" => "RUNNING", + "STOPPED" => "STOPPED", + "SUSPENDED" => "STOPPED", + "DONE" => "FINISHED", + "FAILED" => "FINISHED" + } - stopped.to( :running ) .on( :start ) - stopped.to( :finish ) .on( :destroy ) + define_instance_states do + start.to(:pending) .on( :create ) + pending.to(:running) .automatically + stopped.to(:running) .on( :start ) + running.to(:running) .on( :reboot ) + running.to(:stopping) .on( :stop ) + stopping.to(:stopped) .automatically + running.to(:shutting_down) .on( :destroy ) + shutting_down.to(:finish) .automatically end - def instances(credentials, opts=nil) - occi_client = new_client(credentials) - - instances = [] - instancesxml = occi_client.get_vms + occi_client = new_client(credentials) - computes = REXML::Document.new(instancesxml) - computes.root.elements.each do |d| - vm_id = d.attributes['href'].split("/").last + xml = treat_response(occi_client.get_vms) - computexml = occi_client.get_vm(vm_id) + # TBD Add extended info in the pool + instances = REXML::Document.new(xml).root.elements.map do |d| + vm_id = d.attributes['href'].split("/").last + computexml = treat_response(occi_client.get_vm(vm_id)) + convert_instance(computexml, credentials) + end - instances << convert_instance(computexml.to_s(), credentials) - end - instances = filter_on( instances, :id, opts ) - instances = filter_on( instances, :state, opts ) - instances + instances = filter_on( instances, :state, opts ) end + def instance(credentials, opts=nil) + occi_client = new_client(credentials) + xml = treat_response(occi_client.get_vm(opts[:id])) + convert_instance(xml, credentials) + end def create_instance(credentials, image_id, opts=nil) - occi_client = new_client(credentials) + occi_client = new_client(credentials) - hwp_id = opts[:hwp_id] || 'small' + storage_href = "#{occi_client.endpoint}/storage/#{image_id}" - if not opts[:name] - opts[:name] = "#{Time.now.to_i.to_s}#{rand(9)}" - end + instancexml = ERB.new(OCCI_VM).result(binding) + instancefile = "|echo '#{instancexml}'" - instancexml = ERB.new(OCCI_VM).result(binding) - instancefile = "|echo '#{instancexml}'" + # TBD Specify VNET in the template. - xmlvm = occi_client.post_vms(instancefile) + xmlvm = treat_response(occi_client.post_vms(instancefile)) - convert_instance(xmlvm.to_s(), credentials) + convert_instance(xmlvm, credentials) end - def start_instance(credentials, id) - occi_action(credentials, id, 'RESUME') + occi_action(credentials, id, 'RESUME') end def stop_instance(credentials, id) - occi_action(credentials, id, 'STOPPED') + occi_action(credentials, id, 'STOPPED') end def destroy_instance(credentials, id) - occi_action(credentials, id, 'DONE') + occi_action(credentials, id, 'DONE') end - + def reboot_instance(credentials, id) + begin + occi_action(credentials, id, 'REBOOT') + rescue Exception => e + # TBD Check exception + # OpenNebula 3.0 support + raise "Reboot action not supported" + end + end private def new_client(credentials) - OCCIClient::Client.new(nil, credentials.user, credentials.password, false) + OCCIClient::Client.new(nil, credentials.user, credentials.password, false) end def convert_image(diskxml, credentials) - disk = REXML::Document.new(diskxml) - diskhash = disk.root.elements - - Image.new( { - :id=>diskhash['ID'].text, - :name=>diskhash['NAME'].text, - :description=>diskhash['NAME'].text, - :owner_id=>credentials.user, - :architecture=>'Any architecture', - } ) + storage = REXML::Document.new(diskxml).root.elements + + # TBD Add Image STATE, OWNER + Image.new( { + :id=>storage['ID'].text, + :name=>storage['NAME'].text, + :description=>storage['TYPE'].text, + :owner_id=>credentials.user, + :state=>"AVAILABLE", + :architecture=>storage['ARCH'], + } ) end def convert_instance(computexml, credentials) - compute = REXML::Document.new(computexml) - computehash = compute.root.elements - - imageid = computehash['STORAGE/DISK[@type="disk"]'].attributes['href'].split("/").last + compute = REXML::Document.new(computexml) + computehash = compute.root.elements - state = (computehash['STATE'].text == "ACTIVE") ? "RUNNING" : "STOPPED" + network = [] + computehash.each('NIC/IP') {|ip| network<<InstanceAddress.new(ip)} - hwp_name = computehash['INSTANCE_TYPE'] || 'small' - - networks = [] - (computehash['NETWORK'].each do |n| - networks << InstanceAddress.new(n.attributes['ip']) - end) unless computehash['NETWORK'].nil? + image_id = nil + if computehash['DISK/STORAGE'] + image_id = computehash['DISK/STORAGE'].attributes['href'].split("/").last + end - Instance.new( { - :id=>computehash['ID'].text, - :owner_id=>credentials.user, - :name=>computehash['NAME'].text, - :image_id=>imageid, - :instance_profile=>InstanceProfile.new(hwp_name), - :realm_id=>'Any realm', - :state=>state, - :public_addreses=>networks, - :private_addreses=>networks, - :actions=> instance_actions_for( state ) - } ) + Instance.new( { + :id=>computehash['ID'].text, + :owner_id=>credentials.user, + :name=>computehash['NAME'].text, + :image_id=>image_id, + :instance_profile=>InstanceProfile.new(computehash['INSTANCE_TYPE']||'small'), + :realm_id=>'ONE', + :state=>VM_STATES[computehash['STATE'].text], + :public_addreses=>network, + :private_addreses=>[], + :actions=> instance_actions_for( VM_STATES[computehash['STATE'].text] ) + } ) end def occi_action(credentials, id, strstate) - occi_client = new_client(credentials) + occi_client = new_client(credentials) - actionxml = ERB.new(OCCI_ACTION).result(binding) - actionfile = "|echo '#{actionxml}'" + actionxml = ERB.new(OCCI_ACTION).result(binding) + actionfile = "|echo '#{actionxml}'" - xmlvm = occi_client.put_vm(actionfile) + xmlvm = treat_response(occi_client.put_vm(actionfile)) - convert_instance(xmlvm.to_s(), credentials) + convert_instance(xmlvm, credentials) end - (OCCI_VM = %q{ - <COMPUTE> - <NAME><%=opts[:name]%></NAME> - <INSTANCE_TYPE><%= hwp_id %></INSTANCE_TYPE> - <STORAGE> - <DISK image="<%= image_id %>" dev="sda1" /> - </STORAGE> - </COMPUTE> - }.gsub(/^ /, '') ) unless defined?( OCCI_VM ) + def treat_response(res) + safely do + if CloudClient.is_error?(res) + raise case res.code + when "401" then "AuthenticationFailure" + when "404" then "ObjectNotFound" + else res.message + end + end + end + res + end + exceptions do + on /AuthenticationFailure/ do + status 401 + end - (OCCI_ACTION = %q{ - <COMPUTE> - <ID><%= id %></ID> - <STATE><%= strstate %></STATE> - </COMPUTE> - }.gsub(/^ /, '') ) unless defined?( OCCI_ACTION ) + on /ObjectNotFound/ do + status 404 + end - end + on // do + status 502 + end + end +end end end -- 1.7.6.5
