From 7ae228c7120b36771d6aecd260da1323b70631af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Constantino=20V=C3=A1zquez=20Blanco?= Date: Mon, 19 Oct 2009 17:35:50 +0000 Subject: [PATCH] OCCI Server refactoring git-svn-id: http://svn.opennebula.org/one/trunk@868 3034c82b-c49b-4eb3-8279-a7acafdc01c0 --- install.sh | 15 +- src/cloud/common/CloudServer.rb | 8 +- src/cloud/ec2/lib/econe-server.rb | 12 +- src/cloud/occi/bin/occi-compute | 4 +- src/cloud/occi/bin/occi-network | 4 +- src/cloud/occi/bin/occi-server | 4 +- src/cloud/occi/bin/occi-storage | 4 +- src/cloud/occi/lib/OCCI.rb | 17 + .../lib/{ONEOCCIClient.rb => OCCIClient.rb} | 22 +- src/cloud/occi/lib/OCCIConfiguration.rb | 16 + src/cloud/occi/lib/OCCIServer.rb | 918 +++++++++--------- src/cloud/occi/lib/occi-server.rb | 159 +++ src/rm/RequestManagerInfo.cc | 2 +- 13 files changed, 700 insertions(+), 485 deletions(-) rename src/cloud/occi/lib/{ONEOCCIClient.rb => OCCIClient.rb} (89%) mode change 100755 => 100644 src/cloud/occi/lib/OCCIServer.rb create mode 100755 src/cloud/occi/lib/occi-server.rb diff --git a/install.sh b/install.sh index b94a68c17b..a15867752c 100755 --- a/install.sh +++ b/install.sh @@ -483,14 +483,15 @@ ECO_ETC_FILES="src/cloud/ec2/etc/econe.conf" ECO_ETC_TEMPLATE_FILES="src/cloud/ec2/etc/templates/m1.small.erb" -#------------------------------------------------------------------------------- +#----------------------------------------------------------------------------- # OCCI files -#------------------------------------------------------------------------------- +#----------------------------------------------------------------------------- OCCI_LIB_FILES="src/cloud/occi/lib/OCCI.rb \ src/cloud/occi/lib/OCCIServer.rb \ + src/cloud/occi/lib/occi-server.rb \ src/cloud/occi/lib/OCCIConfiguration.rb \ - src/cloud/occi/lib/ONEOCCIClient.rb \ + src/cloud/occi/lib/OCCIClient.rb \ src/cloud/occi/lib/VirtualMachineOCCI.rb \ src/cloud/occi/lib/VirtualMachinePoolOCCI.rb \ src/cloud/occi/lib/VirtualNetworkOCCI.rb \ @@ -509,11 +510,11 @@ OCCI_ETC_TEMPLATE_FILES="src/cloud/occi/etc/templates/small.erb \ src/cloud/occi/etc/templates/medium.erb \ src/cloud/occi/etc/templates/large.erb" -#------------------------------------------------------------------------------- -#------------------------------------------------------------------------------- +#----------------------------------------------------------------------------- +#----------------------------------------------------------------------------- # INSTALL.SH SCRIPT -#------------------------------------------------------------------------------- -#------------------------------------------------------------------------------- +#----------------------------------------------------------------------------- +#----------------------------------------------------------------------------- # --- Create OpenNebula directories --- diff --git a/src/cloud/common/CloudServer.rb b/src/cloud/common/CloudServer.rb index 57b25ecb81..e785e44b22 100644 --- a/src/cloud/common/CloudServer.rb +++ b/src/cloud/common/CloudServer.rb @@ -20,15 +20,15 @@ require 'Configuration' require 'OpenNebula' require 'pp' -############################################################################### +############################################################################## # This class represents a generic Cloud Server using the OpenNebula Cloud # API (OCA). Any cloud implementation should derive from this class -############################################################################### +############################################################################## class CloudServer - ########################################################################### + ########################################################################## # Public attributes - ########################################################################### + ########################################################################## attr_reader :config attr_reader :one_client diff --git a/src/cloud/ec2/lib/econe-server.rb b/src/cloud/ec2/lib/econe-server.rb index 42e37cb655..74ea0a4fde 100644 --- a/src/cloud/ec2/lib/econe-server.rb +++ b/src/cloud/ec2/lib/econe-server.rb @@ -15,9 +15,9 @@ # limitations under the License. # #--------------------------------------------------------------------------- # -############################################################################### +############################################################################## # Environment Configuration for the Cloud Server -############################################################################### +############################################################################## ONE_LOCATION=ENV["ONE_LOCATION"] if !ONE_LOCATION @@ -49,15 +49,15 @@ include OpenNebula $econe_server = EC2QueryServer.new(CONFIGURATION_FILE, TEMPLATE_LOCATION, VIEWS_LOCATION) -############################################################################### +############################################################################## # Sinatra Configuration -############################################################################### +############################################################################## set :host, $econe_server.config[:server] set :port, $econe_server.config[:port] -############################################################################### +############################################################################## # Actions -############################################################################### +############################################################################## before do if !$econe_server.authenticate?(params) diff --git a/src/cloud/occi/bin/occi-compute b/src/cloud/occi/bin/occi-compute index d75449e401..915d33aeca 100755 --- a/src/cloud/occi/bin/occi-compute +++ b/src/cloud/occi/bin/occi-compute @@ -79,7 +79,7 @@ end $: << RUBY_LIB_LOCATION $: << RUBY_LIB_LOCATION+"/cloud/occi" -require 'ONEOCCIClient' +require 'OCCIClient' require 'getoptlong' require 'rdoc/usage' require 'pp' @@ -118,7 +118,7 @@ rescue Exception => e end begin - occi_client = ONEOCCIClient::Client.new(url,username,password,debug) + occi_client = OCCIClient::Client.new(url,username,password,debug) rescue Exception => e puts "#{$0}: #{e.message}" exit -1 diff --git a/src/cloud/occi/bin/occi-network b/src/cloud/occi/bin/occi-network index f741e8181d..76d6f2bec1 100755 --- a/src/cloud/occi/bin/occi-network +++ b/src/cloud/occi/bin/occi-network @@ -78,7 +78,7 @@ end $: << RUBY_LIB_LOCATION $: << RUBY_LIB_LOCATION+"/cloud/occi" -require 'ONEOCCIClient' +require 'OCCIClient' require 'getoptlong' require 'rdoc/usage' require 'pp' @@ -119,7 +119,7 @@ end begin - occi_client = ONEOCCIClient::Client.new(url,username,password,debug) + occi_client = OCCIClient::Client.new(url,username,password,debug) rescue Exception => e puts "#{$0}: #{e.message}" exit -1 diff --git a/src/cloud/occi/bin/occi-server b/src/cloud/occi/bin/occi-server index e65b936c70..2d8586ee52 100755 --- a/src/cloud/occi/bin/occi-server +++ b/src/cloud/occi/bin/occi-server @@ -19,12 +19,12 @@ if [ -z "$ONE_LOCATION" ]; then OCCI_PID=/var/run/one/occi-server.pid - OCCI_SERVER=/usr/lib/ruby/cloud/occi/OCCIServer.rb + OCCI_SERVER=/usr/lib/ruby/cloud/occi/occi-server.rb OCCI_LOCK_FILE=/var/lock/.occi.lock OCCI_LOG=/var/log/one/occi-server.log else OCCI_PID=$ONE_LOCATION/var/occi-server.pid - OCCI_SERVER=$ONE_LOCATION/lib/ruby/cloud/occi/OCCIServer.rb + OCCI_SERVER=$ONE_LOCATION/lib/ruby/cloud/occi/occi-server.rb OCCI_LOCK_FILE=$ONE_LOCATION/var/.occi.lock OCCI_LOG=$ONE_LOCATION/var/occi-server.log fi diff --git a/src/cloud/occi/bin/occi-storage b/src/cloud/occi/bin/occi-storage index e5a910ed33..6130194821 100755 --- a/src/cloud/occi/bin/occi-storage +++ b/src/cloud/occi/bin/occi-storage @@ -76,7 +76,7 @@ end $: << RUBY_LIB_LOCATION $: << RUBY_LIB_LOCATION+"/cloud/occi" -require 'ONEOCCIClient' +require 'OCCIClient' require 'getoptlong' require 'rdoc/usage' require 'pp' @@ -127,7 +127,7 @@ end begin - occi_client = ONEOCCIClient::Client.new(url,username,password,debug) + occi_client = OCCIClient::Client.new(url,username,password,debug) rescue Exception => e puts "#{$0}: #{e.message}" exit -1 diff --git a/src/cloud/occi/lib/OCCI.rb b/src/cloud/occi/lib/OCCI.rb index 1aead29eba..ee6f996373 100644 --- a/src/cloud/occi/lib/OCCI.rb +++ b/src/cloud/occi/lib/OCCI.rb @@ -1,3 +1,20 @@ +# -------------------------------------------------------------------------- # +# 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 # +# 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 'VirtualMachineOCCI' require 'VirtualMachinePoolOCCI' require 'VirtualNetworkOCCI' diff --git a/src/cloud/occi/lib/ONEOCCIClient.rb b/src/cloud/occi/lib/OCCIClient.rb similarity index 89% rename from src/cloud/occi/lib/ONEOCCIClient.rb rename to src/cloud/occi/lib/OCCIClient.rb index 11cb3f3139..2339681365 100755 --- a/src/cloud/occi/lib/ONEOCCIClient.rb +++ b/src/cloud/occi/lib/OCCIClient.rb @@ -1,5 +1,22 @@ #!/usr/bin/ruby +# -------------------------------------------------------------------------- # +# 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 # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#--------------------------------------------------------------------------- # + require 'rubygems' require 'uri' require 'OpenNebula' @@ -20,7 +37,7 @@ end -module ONEOCCIClient +module OCCIClient ##################################################################### # Client Library to interface with the OpenNebula OCCI Service @@ -44,7 +61,8 @@ module ONEOCCIClient # Autentication if user && pass - @occiauth = user + ":" + Digest::SHA1.hexdigest(pass) + @occiauth = user + ":" + pass + one_auth=@occiauth elsif ENV["ONE_AUTH"] and !ENV["ONE_AUTH"].empty? and File.file?(ENV["ONE_AUTH"]) one_auth=File.read(ENV["ONE_AUTH"]) elsif File.file?(ENV["HOME"]+"/.one/one_auth") diff --git a/src/cloud/occi/lib/OCCIConfiguration.rb b/src/cloud/occi/lib/OCCIConfiguration.rb index 453743ba72..93279d4618 100644 --- a/src/cloud/occi/lib/OCCIConfiguration.rb +++ b/src/cloud/occi/lib/OCCIConfiguration.rb @@ -1,3 +1,19 @@ +# -------------------------------------------------------------------------- # +# 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 # +# 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. # +#--------------------------------------------------------------------------- # class OCCIConfiguration diff --git a/src/cloud/occi/lib/OCCIServer.rb b/src/cloud/occi/lib/OCCIServer.rb old mode 100755 new mode 100644 index 0390d8fea9..0db30c4f59 --- a/src/cloud/occi/lib/OCCIServer.rb +++ b/src/cloud/occi/lib/OCCIServer.rb @@ -1,478 +1,482 @@ -################################################ -# Find out where the needed ruby libraries are -################################################ -ONE_LOCATION=ENV["ONE_LOCATION"] +# -------------------------------------------------------------------------- # +# 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 # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#--------------------------------------------------------------------------- # -if !ONE_LOCATION - RUBY_LIB_LOCATION="/usr/lib/one/ruby" -else - RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby" - TEMPLATES_LOCATION=ONE_LOCATION+"/etc/occi_templates" - CONF_LOCATION=ONE_LOCATION+"/etc" -end - -$: << RUBY_LIB_LOCATION -$: << RUBY_LIB_LOCATION+"/cloud/occi" -$: << RUBY_LIB_LOCATION+"/cloud" # For the Repository Manager - -################################################ -# Required libraries -################################################ require 'rubygems' require 'sinatra' -require 'time' -require 'pp' +require 'CloudServer' require 'OpenNebula' require 'cloud/occi/OCCI' - include OpenNebula -CONFIG=OCCIConfiguration.new(CONF_LOCATION+'/occi-server.conf') -AUTH="#{CONFIG[:user]}:#{CONFIG[:password]}" -ONE_RM_DATABASE=CONFIG[:database] - -# Load Repository Manager here to use ONE_RM_DATABASE from the configuration file -require 'repo_manager' - -INSTANCE_TYPES=Hash.new - -puts "######################################" -puts " OCCI Server configuration " -puts "######################################" -puts "---------8<---------------------" -pp CONFIG -puts "------>8------------------------" - -if CONFIG[:vm_type].kind_of?(Array) - # Multiple instance types - CONFIG[:vm_type].each {|type| - INSTANCE_TYPES[type['NAME']]=type - } -else - # When only one instance type is defined - INSTANCE_TYPES[CONFIG[:vm_type]['NAME']]=CONFIG[:vm_type] -end - -puts "######################################" -puts " OCCI Available Instances Types " -puts "######################################" -puts "---------8<---------------------" -pp INSTANCE_TYPES -puts "------>8------------------------" - -set :host, CONFIG[:server] -set :port, CONFIG[:port] - -# Start repository manager -begin - $repoman=RepoManager.new(CONFIG[:database]) -rescue Exception => e - puts "Error initializing Repository Manager. Reason: " + e - exit -1 -end -Image.image_dir=CONFIG[:image_dir] - -################################################ -# Client builders for ONE communication -################################################ - -def get_one_client - Client.new(AUTH) -end - -def get_one_client_user(user_name) - user=get_user(user_name) +############################################################################## +# The OCCI Server provides an OCCI implementation based on the +# OpenNebula Engine +############################################################################## +class OCCIServer < CloudServer - - auth="#{user[:name]}:#{user[:password]}" - - client=Client.new("dummy:dummy") - client.one_auth=auth - client -end - -def get_user(name) - user=nil - - user_pool=UserPool.new(get_one_client) - 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 - } - - user -end - -################################################### -# Helpers to manage authentication & authorization -################################################### - - -helpers do - - def protected! - response['WWW-Authenticate'] = %(Basic realm="Testing HTTP Auth") and \ - throw(:halt, [401, "Not authorized\n"]) and \ - return unless authorized? - end - - def authorized? - - @auth ||= Rack::Auth::Basic::Request.new(request.env) - - if !(@auth.provided? && @auth.basic? && @auth.credentials) - return false - end - - user = get_user(@auth.credentials.first) + # Server initializer + # config_file:: _String_ path of the config file + # template:: _String_ path to the location of the templates + def initialize(config_file,template) + super(config_file) - if user - if user[:password] == @auth.credentials[1] - return true - end - else - return false - end - end - -end - -################################################### -# Helper functions -################################################### - - -def submit_vm(request) - - if request.body - @vm_info=Crack::XML.parse(request.body.read) - else - halt 400, "OCCI XML representation of VM not present" + @config.add_configuration_value("TEMPLATE_LOCATION",template) + print_configuration end - @vm_info=@vm_info['COMPUTE'] - - disks=@vm_info['STORAGE'] - - disks['DISK'].each{|disk| - next if disk==nil - image=$repoman.get(disk['image']) - halt 400, "Invalid image (#{disk['image']}) referred" if !image - disk['source']=image.path - } if disks and disks['DISK'] - - @vm_info['STORAGE']=disks - - 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']), get_one_client) - vn.info - vn_xml=Crack::XML.parse(vn.to_xml) - halt 400, "Invalid network referred" if !vn_xml['VNET']['NAME'] - - nic['network_id']=nic['network'] - nic['network']=vn_xml['VNET']['NAME'].strip - } - - @vm_info['NETWORK']['NIC']=nics - - instance_type_name=@vm_info['INSTANCE_TYPE'] - instance_type=INSTANCE_TYPES[instance_type_name] - - halt 400, "Bad instance type" if !instance_type - - @vm_info[:instance_type]=instance_type_name - - template=ERB.new(File.read( - TEMPLATES_LOCATION+"/#{instance_type['TEMPLATE']}")) - template_text=template.result(binding) - - vm=VirtualMachineOCCI.new( - VirtualMachine.build_xml, get_one_client_user(@auth.credentials[0])) - response=vm.allocate(template_text) - - if OpenNebula.is_error?(response) - status 400 - response.to_str - else - vm.info - vm.to_occi(CONFIG[:server]) - end -end - -def change_state(request) - if request.body - vm_info=Crack::XML.parse(request.body.read) - else - halt 400, "OCCI XML representation of VM not present" - end - - vm=VirtualMachineOCCI.new( - VirtualMachine.build_xml(params[:id]), get_one_client_user(@auth.credentials[0])) - - halt 400, "State not defined in the OCCI XML, cannot change state" if !vm_info['COMPUTE']['STATE'] - - case vm_info['COMPUTE']['STATE'] - when "stopped" - rc = vm.stop - when "suspended" - rc = vm.suspend - when "resume" - rc = vm.resume - when "cancel" - rc = vm.cancel - when "done" - rc = vm.finalize - else - halt 400, "Invalid state" - end - - if OpenNebula.is_error?(rc) - status 400 - response.to_str - else - status 202 - response_text = "Changing state of VM " + params[:id] + " to " + vm_info['COMPUTE']['STATE'] - end -end - -################################################### -# Pool Resources methods -################################################### - -post '/compute' do - # Auth check - protected! - - submit_vm(request) -end - -get '/compute' do - # Auth check - protected! - # Info retrieval - user = get_user(@auth.credentials.first) - - if user[:id] == 0 - user_flag=-2 - else - user_flag=-1 - end - - vmpool = VirtualMachinePoolOCCI.new(get_one_client,user_flag) - vmpool.info - - # OCCI conversion - begin - vmpool.to_occi(CONFIG[:server]+":"+CONFIG[:port]) - rescue Exception => e - status 500 - error = OpenNebula::Error.new(e.message) - return error - end -end - -post '/network' do - # Auth check - protected! - # Info retrieval from post params - if request.body - network_info=Crack::XML.parse(request.body.read) - else - halt 400, "OCCI XML representation of Virtual Network not present in the request" - end - # Allocate the VirtualNetwork - network = VirtualNetworkOCCI.new( - VirtualNetwork.build_xml, - get_one_client_user(@auth.credentials[0])) - - begin - vntemplate = network.to_one_template(network_info['NIC'],CONFIG[:bridge]) - rc = network.allocate(vntemplate) - rescue Exception => e - rc = "XML malformed?." - end - - # Return status 201 XML if correct, status 500 otherwise - if rc - halt 500, "Error creating the Virtual Network: " + rc - else - network.info - status 201 - network.to_occi - end -end - -get '/network' do - # Auth check - protected! - # Info retrieval - network_pool = VirtualNetworkPoolOCCI.new(get_one_client) - network_pool.info - # OCCI conversion - begin - network_pool.to_occi(CONFIG[:server]+":"+CONFIG[:port]) - rescue Exception => e - status 500 - error = OpenNebula::Error.new(e.message) - return error - end -end - -post '/storage' do - # Auth check - protected! - # Info retrieval from post params - if params['occixml'] - image_info=Crack::XML.parse(params['occixml']) - else - halt 400, "OCCI XML representation of Image not present in the request" - end - - if params['file'] - file=params["file"] - else - halt 400, "File not present in the request" - end - - user = get_user(@auth.credentials[0]) - - # tmpfile where the file is stored - f_tmp=file[:tempfile] - img=$repoman.add(user[:id], f_tmp.path) - f_tmp.unlink - - img.get_image_info - img.change_metadata(:name=>image_info['DISK']['NAME']) - img.change_metadata(:description=>image_info['DISK']['URL']) - - img.extend(ImageOCCI) - xml_response = img.to_occi - - status 201 - xml_response -end - -get '/storage' do - # Auth check - protected! - # Retrieve images owned by this user - user = get_user(@auth.credentials[0]) - - image_pool = ImagePoolOCCI.new(user[:id]) - image_pool.to_occi -end - -################################################### -# Entity Resources Methods -################################################### - -get '/compute/:id' do - protected! - vm = VirtualMachineOCCI.new(VirtualMachine.build_xml(params[:id]),get_one_client_user(@auth.credentials[0])) - - result=vm.info - - if OpenNebula::is_error?(result) - status 404 - return "Error: "+result.message - end - - begin - vm.to_occi(CONFIG[:server]) - rescue Exception => e - status 500 - error = OpenNebula::Error.new(e.message) - return error - end -end - -delete '/compute/:id' do - protected! - vm = VirtualMachineOCCI.new(VirtualMachine.build_xml(params[:id]),get_one_client_user(@auth.credentials[0])) - result = vm.finalize - if OpenNebula::is_error?(result) - status 500 - "Error: " + result.message - else - "The Compute resource has been successfully deleted" - end -end - -put '/compute/:id' do - protected! - - change_state(request) -end - -get '/network/:id' do - protected! - vn = VirtualNetworkOCCI.new(VirtualNetwork.build_xml(params[:id]),get_one_client_user(@auth.credentials[0])) - result=vn.info - - if OpenNebula::is_error?(result) - status 404 - return "Error: "+result.message - end - - begin - vn.to_occi() - rescue Exception => e - status 500 - error = OpenNebula::Error.new(e.message) - return error - end -end - -delete '/network/:id' do - protected! - vn = VirtualNetworkOCCI.new(VirtualNetwork.build_xml(params[:id]),get_one_client_user(@auth.credentials[0])) - - result = vn.delete - - if OpenNebula::is_error?(result) - status 500 - "Error: " + result.message - else - "The Virtual Network has been successfully deleted" - end -end - -get '/storage/:id' do - protected! - image=$repoman.get(params[:id]) - - if image - image.get_image_info + # 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) - image.extend(ImageOCCI) - image.to_occi - else - status 404 - "Disk with id = \"" + params[:id] + "\" not found" + pp auth + return + + if !(auth.provided? && auth.basic? && auth.credentials) + return false + end + + user = get_user(auth.credentials.first) + + if user + if user[:password] == auth.credentials[1] + return true + end + else + return false + end end -end -delete '/storage/:id' do - protected! - status 501 - "Not yet implemented" -end + # Retrieve the user crendentials + # requestenv:: _Hash_ Hash containing the environment of the request + # [return] _User_ User structure + def get_user(requestenv) + auth = Rack::Auth::Basic::Request.new(requestenv) + 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 + @vm_info=@vm_info['COMPUTE'] + + disks=@vm_info['STORAGE'] + + disks['DISK'].each{|disk| + next if disk==nil + image=$repoman.get(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']['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 + } + + @vm_info['NETWORK']['NIC']=nics + + 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( + TEMPLATES_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(CONFIG[:server]), 201 + end + end + + # Gets the pool representation of COMPUTES + # request:: _Hash_ hash containing the data of the request + # [return] _String_,_Integer_ Pool Representation or error, status code + def get_computes(request) + # Get client with user credentials + client = get_client(request.env) + # Just show resources from the user making the request + user_flag = -1 + vmpool = VirtualMachinePoolOCCI.new(client,user_flag) + vmpool.info + # OCCI conversion + begin + compute_xml = vmpool.to_occi(@config[:server]+":"+@config[:port]) + return compute_xml, 200 + rescue Exception => e + error = OpenNebula::Error.new(e.message) + return error, 500 + end + end + + # Post a new network to the NETWORK pool + # request:: _Hash_ hash containing the data of the request + # [return] _String_,_Integer_ Network Representation or error, status code + def post_network(request) + # Get client with user credentials + client = get_client(request.env) + + # 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 + network = VirtualNetworkOCCI.new( + VirtualNetwork.build_xml, + client) + begin + vntemplate = network.to_one_template( + network_info['NIC'], + @config[:bridge]) + rc = network.allocate(vntemplate) + 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 + 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(@config[:server]+":"+@config[:port]) + rescue Exception => e + status 500 + 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=$repoman.add(user[:id], f_tmp.path) + f_tmp.unlink + + img.get_image_info + img.change_metadata(:name=>image_info['DISK']['NAME']) + img.change_metadata(: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, 200 + 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) + # Get client with user credentials + client = get_client(request.env) + + vm = VirtualMachineOCCI.new( + VirtualMachine.build_xml(request.params[:id]), + client) + + result=vm.info + + if OpenNebula::is_error?(result) + return "Error: "+result.message, 404 + end + + begin + return vm.to_occi(CONFIG[:server]), 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) + # Get client with user credentials + client = get_client(request.env) + + vm = VirtualMachineOCCI.new( + VirtualMachine.build_xml(request.params[:id]), + client) + + result = vm.finalize + if OpenNebula::is_error?(result) + error_msg = "Deletion failed. Reason: " + e.message + error = OpenNebula::Error.new(error_msg) + return error, 500 + else + return "The Compute resource has been successfully deleted", 200 + 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) + # 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(request.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'] + when "stopped" + rc = vm.stop + when "suspended" + rc = vm.suspend + when "resume" + rc = vm.resume + when "cancel" + rc = vm.cancel + 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 + response_text = "Changing state of VM " + + params[:id] + " to " + vm_info['COMPUTE']['STATE'] + 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 + def get_network(request) + # Get client with user credentials + client = get_client(request.env) + + vn = VirtualNetworkOCCI.new( + VirtualNetwork.build_xml(params[:id]), + client) + + result=vn.info + + if OpenNebula::is_error?(result) + error = OpenNebula::Error.new("Error: "+result.message) + return error, 404 + end + + begin + return vn.to_occi(), 200 + rescue Exception => e + error = OpenNebula::Error.new(e.message) + return error, 500 + end + end + + # Deletes a NETWORK resource + # request:: _Hash_ hash containing the data of the request + # [return] _String_,_Integer_ Delete confirmation msg or error, + # status code + def delete_network(request) + # Get client with user credentials + client = get_client(request.env) + + vn = VirtualNetworkOCCI.new( + VirtualNetwork.build_xml(request.params[:id]), + client) + + result = vn.delete + + if OpenNebula::is_error?(result) + error = OpenNebula::Error.new("Error: " + result.message) + return error, 500 + else + return "The Virtual Network has been successfully deleted", 200 + end + end + + # Get a STORAGE resource + # request:: _Hash_ hash containing the data of the request + # [return] _String_,_Integer_ STORAGE occi representation or error, + # status code + def get_storage(request) + # Get client with user credentials + client = get_client(request.env) + + image=$repoman.get(request.params[:id]) + + if image + image.get_image_info + + image.extend(ImageOCCI) + return image.to_occi, 200 + else + msg="Disk with id = \"" + request.params[:id] + "\" not found" + error = OpenNebula::Error.new(msg) + return error, 404 + end + 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 + def delete_network(request) + error = OpenNebula::Error.new("Not yet implemented") + return error, 501 + 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 new file mode 100755 index 0000000000..e22721dfda --- /dev/null +++ b/src/cloud/occi/lib/occi-server.rb @@ -0,0 +1,159 @@ +# -------------------------------------------------------------------------- # +# 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 # +# 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. # +#--------------------------------------------------------------------------- # + +############################################################################## +# The OCCI Server provides compatible server based on the +# OpenNebula Engine +############################################################################## + +############################################################################## +# Environment Configuration for the Cloud Server +############################################################################## +ONE_LOCATION=ENV["ONE_LOCATION"] + +if !ONE_LOCATION + RUBY_LIB_LOCATION="/usr/lib/one/ruby" + TEMPLATE_LOCATION="/etc/one/occi_templates" + CONFIGURATION_FILE = "/etc/one/occi-server.conf" +else + RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby" + TEMPLATE_LOCATION=ONE_LOCATION+"/etc/occi_templates" + CONFIGURATION_FILE = ONE_LOCATION+"/etc/occi-server.conf" +end + +$: << RUBY_LIB_LOCATION +$: << RUBY_LIB_LOCATION+"/cloud/occi" +$: << RUBY_LIB_LOCATION+"/cloud" # For the Repository Manager + +################################################ +# Required libraries +################################################ +require 'rubygems' +require 'sinatra' +require 'OCCIServer' + +require 'OpenNebula' + +include OpenNebula + +$occi_server = OCCIServer.new(CONFIGURATION_FILE, TEMPLATE_LOCATION) + +############################################################################## +# Sinatra Configuration +############################################################################## +set :host, $occi_server.config[:server] +set :port, $occi_server.config[:port] + +############################################################################## +# Helpers +############################################################################## + +# Authentication +before do + if !$occi_server.authenticate?(params) + halt 401, 'Invalid credentials' + end +end + +# Response treatment +helpers do + def treat_response + if OpenNebula::is_error?(result) + halt rc, result.message + end + + status rc + result + end +end + +############################################################################## +# Actions +############################################################################## + +################################################### +# Pool Resources methods +################################################### + +post '/compute' do + result,rc = $occi_server.post_compute(request) + treat_response +end + +get '/compute' do + result,rc = $occi_server.get_compute(request) + treat_response +end + +post '/network' do + result,rc = $occi_server.get_compute(request) + treat_response +end + +get '/network' do + result,rc = $occi_server.get_network(request) + treat_response +end + +post '/storage' do + result,rc = $occi_server.post_storage(request) + treat_response +end + +get '/storage' do + result,rc = $occi_server.get_storages(request) + treat_response +end + +################################################### +# Entity Resources Methods +################################################### + +get '/compute/:id' do + result,rc = $occi_server.get_compute(request) + treat_response +end + +delete '/compute/:id' do + result,rc = $occi_server.delete_compute(request) + treat_response +end + +put '/compute/:id' do + result,rc = $occi_server.put_compute(request) + treat_response +end + +get '/network/:id' do + result,rc = $occi_server.get_network(request) + treat_response +end + +delete '/network/:id' do + result,rc = $occi_server.delete_network(request) + treat_response +end + +get '/storage/:id' do + result,rc = $occi_server.get_storage(request) + treat_response +end + +delete '/storage/:id' do + result,rc = $occi_server.delete_storage(request) + treat_response +end \ No newline at end of file diff --git a/src/rm/RequestManagerInfo.cc b/src/rm/RequestManagerInfo.cc index 1859f5a0b1..514376611a 100644 --- a/src/rm/RequestManagerInfo.cc +++ b/src/rm/RequestManagerInfo.cc @@ -42,7 +42,7 @@ void RequestManager::VirtualMachineInfo::execute( session = xmlrpc_c::value_string(paramList.getString(0)); vid = xmlrpc_c::value_int (paramList.getInt(1)); - // Perform the allocation in the vmpool + // Get the details of the virtual machine vm = VirtualMachineInfo::vmpool->get(vid,true); if ( vm == 0 )