diff --git a/install.sh b/install.sh index 733ab6bb53..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" @@ -500,6 +498,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/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 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 7bfafe8fb5..10f49c93b9 100755 --- a/src/cli/onehost +++ b/src/cli/onehost @@ -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,8 +215,8 @@ def vms_in_host?(host_id) puts rc.message exit -1 end - - host['host_share/running_vms'].to_i + + host['HOST_SHARE/RUNNING_VMS'].to_i end @@ -234,59 +234,54 @@ 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) - #puts host.template_str - else - puts "Error: "+result.message - exit -1 - end - - if !ops[:xml] - str = "%-22s: %-20s" - str_h1 = "%-80s" - - print_header(str_h1, "HOST #{host_id} INFORMATION", true) + if !ops[:xml] + str = "%-22s: %-20s" + str_h1 = "%-80s" - 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, "HOST #{host_id} INFORMATION", true) - 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 + 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, "MONITORING INFORMATION", false) + print_header(str_h1, "HOST SHARES", false) - puts host.template_str - else - puts host.to_xml(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 + + print_header(str_h1, "MONITORING INFORMATION", false) + + puts host.template_str + else + puts host.to_xml(true) + end end when "delete" @@ -295,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 @@ -305,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 @@ -315,7 +310,7 @@ when "delete" end end end - + when "list" if !ops[:xml] hostlist=HostShow.new(get_one_client) @@ -331,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) @@ -361,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/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/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 b868b960e5..263ce30525 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 @@ -680,45 +680,47 @@ 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..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", @@ -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" diff --git a/src/cloud/common/CloudServer.rb b/src/cloud/common/CloudServer.rb index a76a6a5040..f4f70baaad 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' @@ -32,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 @@ -44,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,13 +54,8 @@ 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() @user_pool = UserPool.new(@one_client) end @@ -78,7 +72,7 @@ class CloudServer puts "--------------------------------------" puts " Registered Instance Types " puts "--------------------------------------" - pp @instance_types + pp @instance_types end ########################################################################### @@ -86,44 +80,22 @@ 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) + # user:: _Hash_ the user information + # [return] an OpenNebula client session + 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 - + 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 - end - + return @user_pool["USER[NAME=\"#{name}\"]/PASSWORD"] + end ########################################################################### # Repository Methods @@ -134,18 +106,52 @@ 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 - return image - 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 - # 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) + # ---------- Allocate the Image file ------------ + + rc = image.allocate(image.to_one_template) + if OpenNebula.is_error?(rc) + return rc + end + + # ---------- Copy the Image file ------------ + + image.info + + if file_path + rc = image.copy(file_path, image['SOURCE']) + file[:tempfile].unlink + 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']) + end + + if OpenNebula.is_error?(rc) + image.delete + return rc + end + + return nil end end 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/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] 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..8b6c46f3bc 100644 --- a/src/cloud/ec2/lib/EC2QueryServer.rb +++ b/src/cloud/ec2/lib/EC2QueryServer.rb @@ -19,11 +19,14 @@ 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 +# The EC2Query Server implements a EC2 compatible server based on the # OpenNebula Engine ############################################################################### class EC2QueryServer < CloudServer @@ -64,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 @@ -83,21 +86,165 @@ class EC2QueryServer < CloudServer # EC2 protocol authentication function # params:: of the request # [return] true if authenticated - def authenticate?(params,env) - user = 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 "2" then signature_version_2(params, - user[:password], + when "1" then signature_version_1(params.clone, password) + when "2" then signature_version_2(params, + password, env, false) end - return params['Signature']==signature + if params['Signature']==signature + return one_client_user(params['AWSAccessKeyId'], password) + else + return nil + end end + + ########################################################################### + # Repository Interface + ########################################################################### + + def upload_image(params, one_client) + 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, one_client) + # Get the Image ID + 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")) + return response.result(binding), 200 + end + + def describe_images(params, one_client) + user_flag=-1 + impool = ImagePool.new(one_client, user_flag) + impool.info + + erb_user_name = params['AWSAccessKeyId'] + erb_version = params['Version'] + + response = ERB.new(File.read(@config[:views]+"/describe_images.erb")) + return response.result(binding), 200 + end + + ########################################################################### + # Instance Interface + ########################################################################### + + def run_instances(params, one_client) + # Get the instance type and path + if params['InstanceType'] != nil + instance_type_name = params['InstanceType'] + instance_type = @instance_types[instance_type_name] + + if instance_type != nil + path = @config[:template_location] + "/#{instance_type['TEMPLATE']}" + end + end + + # Get the image + tmp, img=params['ImageId'].split('-') + + # 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) + + # 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 + + vm.info + + erb_vm_info[:vm_id]=vm.id + erb_vm_info[:vm]=vm + erb_user_name = params['AWSAccessKeyId'] + erb_version = params['Version'] + + response = ERB.new(File.read(@config[:views]+"/run_instances.erb")) + return response.result(binding), 200 + end + + + def describe_instances(params, one_client) + user_flag=-1 + 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, one_client) + # Get the VM ID + vmid=params['InstanceId.1'] + vmid=params['InstanceId.01'] if !vmid + + tmp, vmid=vmid.split('-') if vmid[0]==?i + + vm = VirtualMachine.new(VirtualMachine.build_xml(vmid),one_client) + rc = vm.info + + return OpenNebula::Error.new('Unsupported'),400 if OpenNebula::is_error?(rc) + + if vm.status == 'runn' + rc = vm.shutdown + else + rc = 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 + +private + # Calculates signature version 1 def signature_version_1(params, secret_key, digest='sha1') params.delete('Signature') @@ -110,197 +257,47 @@ 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"] + 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']) - 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 + sha_strength = case params['SignatureMethod'] + when "HmacSHA1" then 'sha1' + when "HmacSHA256" then 'sha256' + else 'sha1' + end - digest = OpenSSL::Digest::Digest.new(sha_strength) - b64hmac = + digest = OpenSSL::Digest::Digest.new(sha_strength) + b64hmac = Base64.encode64( - OpenSSL::HMAC.digest(digest, secret_key, canonical_str)).gsub("\n","") - - if urlencode + OpenSSL::HMAC.digest(digest, secret_key, canonical_str)).gsub("\n","") + + if urlencode return CGI::escape(b64hmac) - else + else return b64hmac end end - - ########################################################################### - # Repository Interface - ########################################################################### - - def upload_image(params) - user = get_user(params['AWSAccessKeyId']) - - image = add_image(user[:id],params["file"][:tempfile]) - erb_img_id = image.id - 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']) - - if !image - return OpenNebula::Error.new('InvalidAMIID.NotFound'), 400 - elsif user[:id] != image[:owner] - return OpenNebula::Error.new('AuthFailure'), 400 - end - - erb_img_id=image.id - erb_version = params['Version'] - - response = ERB.new(File.read(@config[:views]+"/register_image.erb")) - return response.result(binding), 200 - 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")) - - return response.result(binding), 200 - end - - ########################################################################### - # Instance Interface - ########################################################################### - - def run_instances(params) - # Get the instance type - instance_type_name = params['InstanceType'] - instance_type = @instance_types[instance_type_name] - - return OpenNebula::Error.new('Unsupported'),400 if !instance_type - - # 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[:instance_type] = instance_type_name - erb_vm_info[:template] = @config[:template_location] + - "/#{instance_type['TEMPLATE']}" - erb_vm_info[:user_data] = params['UserData'] - - template = ERB.new(File.read(erb_vm_info[:template])) - template_text = template.result(binding) - - #Start the VM. - vm = VirtualMachine.new(VirtualMachine.build_xml, one_client) - - rc = vm.allocate(template_text) - - 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_version = params['Version'] - - response = ERB.new(File.read(@config[:views]+"/run_instances.erb")) - return response.result(binding), 200 - end - - - def describe_instances(params) - # Get the user - user = get_user(params['AWSAccessKeyId']) - one_client = one_client_user(user) - - erb_user_name = user[:name] - - if user[:id]==0 - user_flag=-2 - else - user_flag=-1 - end - - erb_vmpool = VirtualMachinePool.new(one_client, user_flag) - 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) - - 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 - -private ########################################################################### # Helper functions ########################################################################### 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/rm/repo_manager.rb b/src/cloud/ec2/lib/ImageEC2.rb similarity index 54% rename from src/cloud/rm/repo_manager.rb rename to src/cloud/ec2/lib/ImageEC2.rb index fd3139f83f..4e5fa23e91 100644 --- a/src/cloud/rm/repo_manager.rb +++ b/src/cloud/ec2/lib/ImageEC2.rb @@ -14,53 +14,22 @@ # limitations under the License. # #--------------------------------------------------------------------------- # -require 'rubygems' -require 'fileutils' -require 'sequel' -require 'logger' +require 'uuid' +require 'OpenNebula' -module OpenNebula - class RepoManager - def initialize(rm_db=nil) - raise "DB not defined" if !rm_db - - @db=Sequel.sqlite(rm_db) +include OpenNebula - 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 +class ImageEC2 < Image -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 + 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 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 6d5156ba5a..05a84f57eb 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 %> - + + + <% impool.each do |im| %> + <% im.info %> + + ami-<%= sprintf('%08i', im.id) %> + <%= im['SOURCE'].split('/').last %> + <% if im['STATE'] == '4' %> + deregistered + <% elsif im['STATE'] == '2' %> + 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/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/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/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) %> diff --git a/src/cloud/occi/bin/occi-storage b/src/cloud/occi/bin/occi-storage index 3e6e2dbf0d..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,8 +81,8 @@ EOT require 'occi/OCCIClient' require 'CloudClient' require 'getoptlong' -require "rexml/document" - +require 'rexml/document' +require 'pp' include CloudCLI opts = GetoptLong.new( @@ -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,16 +158,22 @@ 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' - 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." @@ -176,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/occi-server.conf b/src/cloud/occi/etc/occi-server.conf index dfca56bb37..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,18 +8,10 @@ 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 -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] VM_TYPE=[NAME=large, TEMPLATE=large.erb] - diff --git a/src/cloud/occi/etc/templates/large.erb b/src/cloud/occi/etc/templates/large.erb index b88a916363..e6d1a94155 100644 --- a/src/cloud/occi/etc/templates/large.erb +++ b/src/cloud/occi/etc/templates/large.erb @@ -1,55 +1,40 @@ -NAME = <%= vm_info['NAME']%> +# +# 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 -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.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.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 diff --git a/src/cloud/occi/etc/templates/medium.erb b/src/cloud/occi/etc/templates/medium.erb index 1fa7f80b75..ab6bda21c7 100644 --- a/src/cloud/occi/etc/templates/medium.erb +++ b/src/cloud/occi/etc/templates/medium.erb @@ -1,55 +1,41 @@ -NAME = <%= vm_info['NAME']%> +# +# 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 -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.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.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']%> diff --git a/src/cloud/occi/etc/templates/small.erb b/src/cloud/occi/etc/templates/small.erb index 84ec3648c0..9c448bb7fd 100644 --- a/src/cloud/occi/etc/templates/small.erb +++ b/src/cloud/occi/etc/templates/small.erb @@ -1,55 +1,41 @@ -NAME = <%= vm_info['NAME']%> +# +# 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 -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.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.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']%> diff --git a/src/cloud/occi/lib/ImageOCCI.rb b/src/cloud/occi/lib/ImageOCCI.rb index 781423a5c9..478f868ff4 100755 --- a/src/cloud/occi/lib/ImageOCCI.rb +++ b/src/cloud/occi/lib/ImageOCCI.rb @@ -15,24 +15,85 @@ #--------------------------------------------------------------------------- # 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 self['TEMPLATE/TYPE'] != nil %> + <%= self['TEMPLATE/TYPE'] %> + <% end %> + <% if self['TEMPLATE/DESCRIPTION'] != nil %> + <%= self['TEMPLATE/DESCRIPTION'] %> + <% end %> + <% if size != nil %> + <%= size %> + <% end %> + } + ONE_IMAGE = %q{ + NAME = "<%= @image_info['NAME'] %>" + <% if @image_info['DESCRIPTION'] != nil %> + DESCRIPTION = "<%= @image_info['DESCRIPTION'] %>" + <% end %> + <% if @image_info['TYPE'] != nil %> + TYPE = <%= @image_info['TYPE'] %> + <% end %> + <% if @image_info['FSTYPE'] != nil %> + FSTYPE = <%= @image_info['FSTYPE'] %> + <% end %> + <% 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 + xmldoc = XMLElement.build_xml(xml_info, 'STORAGE') + @image_info = XMLElement.new(xmldoc) if xmldoc != nil + end + end + # Creates the OCCI representation of an Image - def to_occi() + def to_occi(base_url) + size = nil + + begin + 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 == nil + error_msg = "Missing STORAGE section in the XML body" + error = OpenNebula::Error.new(error_msg) + return error + end + + if @image_info['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 end diff --git a/src/cloud/occi/lib/ImagePoolOCCI.rb b/src/cloud/occi/lib/ImagePoolOCCI.rb index 596c139575..32b85351fe 100755 --- a/src/cloud/occi/lib/ImagePoolOCCI.rb +++ b/src/cloud/occi/lib/ImagePoolOCCI.rb @@ -16,25 +16,29 @@ require 'OpenNebula' - include OpenNebula -class ImagePoolOCCI +class ImagePoolOCCI < ImagePool OCCI_IMAGE_POOL = %q{ - <% - for image in @images do %> - <% - end %> - + + <% self.each{ |im| %> + + <% } %> + } - - 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*/,'') + 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..5ca53f22a1 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['DISK']['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,116 +192,46 @@ 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 file.close - + pp res if CloudClient::is_error?(res) return res 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 - ###################################################################### - 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 +242,83 @@ module OCCIClient 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 + ###################################################################### + def put_vm(xmlfile) + xml = File.read(xmlfile) + vm_info = REXML::Document.new(xml).root + + 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 + + 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) + } + + if CloudClient::is_error?(res) + return res + else + return res.body + end + end + ###################################################################### # Retrieves a Virtual Network # :id Virtual Network identifier @@ -316,9 +326,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 +339,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 +359,7 @@ module OCCIClient return res.body end end - + ####################################################################### # Retieves an Image # :image_uuid Image identifier @@ -357,9 +367,29 @@ 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) + } + + if CloudClient::is_error?(res) + return res + else + 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 4e46eef40c..a5b3abf2aa 100755 --- a/src/cloud/occi/lib/OCCIServer.rb +++ b/src/cloud/occi/lib/OCCIServer.rb @@ -31,473 +31,333 @@ require 'VirtualNetworkPoolOCCI' require 'ImageOCCI' require 'ImagePoolOCCI' -include ImageOCCI +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 - 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) - 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 - def post_compute(request) - # Get client with user credentials - client = get_client(request.env) - - if request.body - vm_info=Crack::XML.parse(request.body.read) - else - error = OpenNebula::Error.new( - "OCCI XML representation of VM not present") - return error, 400 - end + auth = Rack::Auth::Basic::Request.new(requestenv) - 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 - 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( - 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 + return one_client_user(auth.credentials[0], auth.credentials[1]) 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, code) + xml_response = resource.to_occi(@base_url) + return xml_response, 500 if OpenNebula.is_error?(xml_response) + + return xml_response, code + end + + ############################################################################ + ############################################################################ + # 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( + get_client(request.env), + user_flag) - # Just show resources from the user making the request - user_flag = -1 + # --- Prepare XML Response --- + rc = vmpool.info + return rc, 404 if OpenNebula.is_error?(rc) - 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 + return to_occi_xml(vmpool, 200) 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 User's VNETs --- + user_flag = -1 + 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) + + return to_occi_xml(network_pool, 200) + 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 User's Images --- + user_flag = -1 + image_pool = ImagePoolOCCI.new( + get_client(request.env), + user_flag) + + # --- Prepare XML Response --- + rc = image_pool.info + return rc, 404 if OpenNebula.is_error?(rc) + + return to_occi_xml(image_pool, 200) + end + + ############################################################################ + ############################################################################ + # ENTITY RESOURCE METHODS + ############################################################################ + ############################################################################ + + ############################################################################ + # COMPUTE 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 + def post_compute(request) + # --- Create the new Instance --- + vm = VirtualMachineOCCI.new( + VirtualMachine.build_xml, + 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 + 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 + return to_occi_xml(vm, 201) + end + + # Get the representation of a COMPUTE resource + # request:: _Hash_ hash containing the data of the request + # [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)) + + # --- Prepare XML Response --- + rc = vm.info + return rc, 404 if OpenNebula::is_error?(rc) + + return to_occi_xml(vm, 200) + end + + + # Deletes a COMPUTE resource + # request:: _Hash_ hash containing the data of the request + # [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)) + + # --- 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 + def put_compute(request, params) + xmldoc = XMLElement.build_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)) + + rc = vm.mk_action(vm_info['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 + + # --- Prepare XML Response --- + vm.info + return to_occi_xml(vm, 202) + 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) - - # Info retrieval from post params - if request.body - network_info=Crack::XML.parse(request.body.read) - else - error_msg = "OCCI XML representation of Virtual Network" + - " not present in the request" - error = OpenNebula::Error.new(error_msg) - return error, 400 - end - # Allocate the VirtualNetwork + # --- Create the new Instance --- network = VirtualNetworkOCCI.new( VirtualNetwork.build_xml, - client) + get_client(request.env), + request.body, + @config[:bridge]) - 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 + return to_occi_xml(network, 201) 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) - - # 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 - 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 - if request.params['occixml'] - image_info=Crack::XML.parse(request.params['occixml']) - else - error_msg = "OCCI XML representation of Image" + - " not present in the request" - error = OpenNebula::Error.new(error_msg) - return error, 400 - end - 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 - - return xml_response, 201 - 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) - # 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 - 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, - # status code - def get_compute(request, params) - # Get client with user credentials - client = get_client(request.env) - - vm = VirtualMachineOCCI.new( - VirtualMachine.build_xml(params[:id]), - client) - - result=vm.info - - 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 - end - - # Deletes a COMPUTE resource - # request:: _Hash_ hash containing the data of the request - # [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( - VirtualMachine.build_xml(params[:id]), - client) - - result = vm.finalize - - if OpenNebula::is_error?(result) - return result, 500 - else - return "", 204 - end - end - - # Updates a COMPUTE resource - # request:: _Hash_ hash containing the data of the request - # [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) - - if request.body - vm_info=Crack::XML.parse(request.body.read) - else - error_msg = "OCCI XML representation of VM not present" - 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) - 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 - 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) - - vn = VirtualNetworkOCCI.new( - VirtualNetwork.build_xml(params[:id]), - client) - - result=vn.info + # --- Get the VNET --- + network = VirtualNetworkOCCI.new( + VirtualNetwork.build_xml(params[:id]), + get_client(request.env)) - if OpenNebula::is_error?(result) - return result, 404 - end + # --- Prepare XML Response --- + rc = network.info + return rc, 404 if OpenNebula::is_error?(rc) - begin - return vn.to_occi, 200 - rescue Exception => e - error = OpenNebula::Error.new(e.message) - return error, 500 - end + return to_occi_xml(network, 200) 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( - VirtualNetwork.build_xml(params[:id]), - client) + # --- Get the VNET --- + network = VirtualNetworkOCCI.new( + VirtualNetwork.build_xml(params[:id]), + get_client(request.env)) - result = vn.delete - - if OpenNebula::is_error?(result) - return result, 500 - else - return "", 204 - end + # --- Delete the VNET --- + rc = network.delete + return rc, 500 if OpenNebula::is_error?(rc) + + 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) + # --- 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, + get_client(request.env), + 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, 201) + 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) - - image=get_image(params[:id]) + # --- Get the Image --- + image = ImageOCCI.new( + Image.build_xml(params[:id]), + get_client(request.env)) - 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 + rc = image.info + return rc, 404 if OpenNebula::is_error?(rc) + + # --- Prepare XML Response --- + return to_occi_xml(image, 200) 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) - error = OpenNebula::Error.new("Not yet implemented") - return error, 501 + # --- Get the Image --- + image = ImageOCCI.new( + Image.build_xml(params[:id]), + get_client(request.env)) + + # --- Delete the Image --- + rc = image.delete + return rc, 500 if OpenNebula::is_error?(rc) + + return "", 204 end end diff --git a/src/cloud/occi/lib/VirtualMachineOCCI.rb b/src/cloud/occi/lib/VirtualMachineOCCI.rb index 3b0923de50..06be235725 100755 --- a/src/cloud/occi/lib/VirtualMachineOCCI.rb +++ b/src/cloud/occi/lib/VirtualMachineOCCI.rb @@ -1,54 +1,139 @@ +# -------------------------------------------------------------------------- # +# 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 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 self['TEMPLATE/INSTANCE_TYPE'] %> + <%= self['TEMPLATE/INSTANCE_TYPE'] %> + <% end %> + <%= self.state_str %> + <% if self['TEMPLATE/DISK'] %> + <% self.each('TEMPLATE/DISK') do |disk| %> + + + <%= disk['TYPE'] %> + <%= disk['TARGET'] %> + <% if disk['CLONE']=='NO' %> + + <% end %> + <% if disk['SAVE_AS'] %> + <%= disk['SAVE_AS'] %> + <% end %> + + <% end %> + <% end %> + <% if self['TEMPLATE/NIC'] %> + <% self.each('TEMPLATE/NIC') do |nic| %> + + + <% if nic['IP'] %> + <%= nic['IP'] %> + <% end %> + <% if nic['MAC'] %> + <%= nic['MAC'] %> + <% end %> + + <% end %> + <% end %> + } - - + + # 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 = XMLElement.build_xml(xml_info, 'COMPUTE') + @vm_info = XMLElement.new(xmldoc) if xmldoc != nil + end + + if @vm_info != nil + itype = @vm_info['INSTANCE_TYPE'] + + if itype != nil and types[itype] != nil + @template = base + "/#{types[itype]['TEMPLATE']}" + end + end + + end + + def mk_action(action_str) + case action_str.downcase + when "stopped" + rc = self.stop + when "suspended" + rc = self.suspend + when "resume" + rc = self.resume + when "cancel" + rc = self.cancel + when "shutdown" + rc = self.shutdown + when "done" + rc = self.finalize + else + error_msg = "Invalid state" + error = OpenNebula::Error.new(error_msg) + return error + end + + return rc + end + + def to_one_template() + if @vm_info == nil + error_msg = "Missing COMPUTE section in the XML body" + return OpenNebula::Error.new(error_msg), 400 + end + + if @template == nil + return OpenNebula::Error.new("Bad instance type"), 500 + end + + begin + template = ERB.new(File.read(@template)) + 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'] - 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..0638cd4702 100755 --- a/src/cloud/occi/lib/VirtualMachinePoolOCCI.rb +++ b/src/cloud/occi/lib/VirtualMachinePoolOCCI.rb @@ -1,26 +1,44 @@ +# -------------------------------------------------------------------------- # +# 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 %> - + + <% self.each{ |vm| %> + + <% } %> + } # 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*/,'') + 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..541899349b 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 %> +
<%= self['TEMPLATE/NETWORK_ADDRESS'] %>
+ <% if self['TEMPLATE/NETWORK_SIZE'] %> + <%= self['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'] %> + <% if @bridge %> + BRIDGE = <%= @bridge %> + <% end %> + 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(xml, client, xml_info=nil, bridge=nil) + super(xml, client) + @bridge = bridge + @vnet_info = nil - occi = ERB.new(OCCI_NETWORK) - return occi.result(binding).gsub(/\n\s*/,'') + if xml_info != nil + xmldoc = XMLElement.build_xml(xml_info, 'NETWORK') + @vnet_info = XMLElement.new(xmldoc) if xmldoc != nil + end 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(base_url) + 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 == nil + 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 end diff --git a/src/cloud/occi/lib/VirtualNetworkPoolOCCI.rb b/src/cloud/occi/lib/VirtualNetworkPoolOCCI.rb index 3f640e100a..c8deffea37 100755 --- a/src/cloud/occi/lib/VirtualNetworkPoolOCCI.rb +++ b/src/cloud/occi/lib/VirtualNetworkPoolOCCI.rb @@ -1,25 +1,42 @@ +# -------------------------------------------------------------------------- # +# 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 %> - + + <% self.each{ |vn| %> + + <% } %> + } - # 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)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..3434824aac 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" @@ -61,22 +61,15 @@ 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) if OpenNebula::is_error?(result) halt rc, result.message end - + status rc - result + result end end @@ -88,12 +81,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 @@ -122,7 +115,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 @@ -134,20 +127,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 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 + 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/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 a3150d6953..a10ef34f7d 100644 --- a/src/oca/ruby/OpenNebula/Image.rb +++ b/src/oca/ruby/OpenNebula/Image.rb @@ -1,4 +1,5 @@ require 'OpenNebula/Pool' +require 'fileutils' module OpenNebula class Image < PoolElement @@ -14,7 +15,7 @@ module OpenNebula :publish => "image.publish", :delete => "image.delete" } - + IMAGE_STATES=%w{INIT LOCKED READY USED DISABLED} SHORT_IMAGE_STATES={ @@ -24,7 +25,7 @@ module OpenNebula "USED" => "used", "DISABLED" => "disa" } - + IMAGE_TYPES=%w{OS CDROM DATABLOCK} SHORT_IMAGE_TYPES={ @@ -47,7 +48,7 @@ module OpenNebula image_xml = "" end - XMLUtilsElement.initialize_xml(image_xml, 'IMAGE') + XMLElement.build_xml(image_xml,'IMAGE') end # Class constructor @@ -55,12 +56,13 @@ module OpenNebula super(xml,client) @client = client + @immanager = ImageManager.new end ####################################################################### # XML-RPC Methods for the Image Object ####################################################################### - + def info() super(IMAGE_METHODS[:info], 'IMAGE') end @@ -68,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 @@ -96,7 +98,19 @@ 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 + ####################################################################### # Helpers to get Image information ####################################################################### @@ -115,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 @@ -129,9 +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 @@ -140,7 +155,7 @@ module OpenNebula return rc end - + def set_publish(published) return Error.new('ID not defined') if !@pe_id @@ -149,15 +164,76 @@ 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 + # --------------------------------------------------------------------- + FS_UTILS = { + :dd => "/bin/dd", + :mkfs => "/bin/mkfs" + } + + def copy(path, source) + if source.nil? or path.nil? + return OpenNebula::Error.new("copy Image: missing parameters.") + end + + begin + FileUtils.copy(path, source) + rescue Exception => e + return OpenNebula::Error.new(e.message) + end + + return nil + end + + def dd(size, source) + 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("dd Image: in dd command.") + end + + return nil + end + + def mkfs(fstype, source) + 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("mkfs Image: in mkfs command.") + end + + return nil + end + end end diff --git a/src/oca/ruby/OpenNebula/Pool.rb b/src/oca/ruby/OpenNebula/Pool.rb index f2138abf2e..a271352232 100644 --- a/src/oca/ruby/OpenNebula/Pool.rb +++ b/src/oca/ruby/OpenNebula/Pool.rb @@ -2,9 +2,9 @@ module OpenNebula # The Pool class represents a generic OpenNebula Pool in XML format # and provides the basic functionality to handle the Pool elements - class Pool + + class Pool < XMLPool include Enumerable - include XMLUtilsPool protected @@ -12,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) @@ -37,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 = initialize_xml(rc) + initialize_xml(rc,@pool_name) rc = nil end - + return rc end @@ -63,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 @@ -96,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 @@ -114,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) @@ -129,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 @@ -146,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 @@ -159,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 @@ -183,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 6ee470d0f3..d1dbeb33ed 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,46 +17,109 @@ 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 + 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 - Nokogiri::XML(xml).xpath("/#{root_element}") + @xml = Nokogiri::XML(xml).xpath("/#{root_element}") + if @xml.size == 0 + @xml = nil + end else - REXML::Document.new(xml).root + @xml = REXML::Document.new(xml).root + if @xml.name != root_element + @xml = nil + end end 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 + # [return] _String_ the value of the element # Examples: # ['VID'] # gets VM id # ['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 + + if element element.text 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 - + def template_like_str(root_element, indent=true) if NOKOGIRI xml_template=@xml.xpath(root_element).to_s @@ -64,7 +127,7 @@ module OpenNebula else rexml=@xml.elements[root_element] end - + if indent ind_enter="\n" ind_tab=' ' @@ -72,7 +135,7 @@ module OpenNebula ind_enter='' ind_tab=' ' end - + str=rexml.collect {|n| if n.class==REXML::Element str_line="" @@ -93,13 +156,18 @@ module OpenNebula str_line end }.compact.join("\n") - + str end - - def to_hash + + 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 @@ -111,34 +179,26 @@ 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 - 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 + class XMLPool < XMLElement - #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 + def initialize(xml=nil) + super(xml) end - + #Executes the given block for each element of the Pool - #block:: _Block_ + #block:: _Block_ def each_element(block) if NOKOGIRI @xml.xpath( @@ -153,27 +213,14 @@ 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 + def to_hash if !@hash && @xml @hash=Crack::XML.parse(to_xml) end return @hash end end + end