1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-22 18:50:08 +03:00

feature #200: Better XML parsing for ImageOCCI

This commit is contained in:
Ruben S. Montero 2010-07-17 03:43:34 +02:00
parent e3b9eb63c0
commit 32e106858c
5 changed files with 267 additions and 251 deletions

View File

@ -156,25 +156,24 @@ class CloudServer
end
end
template = image.to_one_template
# ---------- Allocate the Image file ------------
rc = image.allocate(template)
rc = image.allocate(image.to_one_template)
if OpenNebula.is_error?(rc)
return rc
end
# Copy the Image file
# ---------- Copy the Image file ------------
image.info
template=image.to_hash
template=template['IMAGE']['TEMPLATE']
if file_path
rc = image.copy(file_path, image['SOURCE'])
file[:tempfile].unlink
elsif template['SIZE'] and template['FSTYPE']
elsif image['TEMPLATE/SIZE'] and image['TEMPLATE/FSTYPE']
rc = image.mk_datablock(
template['SIZE'],
template['FSTYPE'],
image['TEMPLATE/SIZE'],
image['TEMPLATE/FSTYPE'],
image['SOURCE'])
end
@ -185,12 +184,5 @@ class CloudServer
return nil
end
# Gets an image from the repository
# image_id:: _Integer_ Image identifier
# [return] _Image_ Image object
def get_image(image_id)
return nil
end
end

View File

@ -23,13 +23,13 @@ class ImageOCCI < Image
<STORAGE href="<%= base_url %>/storage/<%= self.id.to_s %>">
<ID><%= self.id.to_s %></ID>
<NAME><%= self.name %></NAME>
<% if template['TYPE'] %>
<TYPE><%= template['TYPE'] %></TYPE>
<% if self['TEMPLATE/TYPE'] != nil %>
<TYPE><%= self['TEMPLATE/TYPE'] %></TYPE>
<% end %>
<% if template['DESCRIPTION'] %>
<DESCRIPTION><%= template['DESCRIPTION'] %></DESCRIPTION>
<% if self['TEMPLATE/DESCRIPTION'] != nil %>
<DESCRIPTION><%= self['TEMPLATE/DESCRIPTION'] %></DESCRIPTION>
<% end %>
<% if size %>
<% if size != nil %>
<SIZE><%= size %></SIZE>
<% end %>
</STORAGE>
@ -37,59 +37,62 @@ class ImageOCCI < Image
ONE_IMAGE = %q{
NAME = "<%= image_info['NAME'] %>"
<% if image_info['DESCRIPTION'] %>
DESCRIPTION = "<%= image_info['DESCRIPTION'] %>"
NAME = "<%= @image_info.elements['NAME'].text %>"
<% if @image_info.elements['DESCRIPTION'] != nil %>
DESCRIPTION = "<%= @image_info.elements['DESCRIPTION'].text %>"
<% end %>
<% if image_info['TYPE'] %>
TYPE = <%= image_info['TYPE'] %>
<% if @image_info.elements['TYPE'] != nil %>
TYPE = <%= @image_info.elements['TYPE'].text %>
<% end %>
<% if image_info['FSTYPE'] %>
FSTYPE = <%= image_info['FSTYPE'] %>
<% if @image_info.elements['FSTYPE'] != nil %>
FSTYPE = <%= @image_info.elements['FSTYPE'].text %>
<% end %>
<% if image_info['SIZE'] %>
SIZE = <%= image_info['SIZE'] %>
<% if @image_info.elements['SIZE'] != nil %>
SIZE = <%= @image_info.elements['SIZE'].text %>
<% end %>
}.gsub(/^ /, '')
# Class constructor
def initialize(image_info, xml, client)
def initialize(xml, client, xml_info=nil)
super(xml, client)
@image_info = image_info
if xml_info != nil
@image_info = REXML::Document.new(xml_info).root
else
@image_info = nil
end
end
# Creates the OCCI representation of an Image
def to_occi(base_url)
image_hash = self.to_hash
return image_hash, 500 if OpenNebula.is_error?(image_hash)
template = image_hash['IMAGE']['TEMPLATE']
size = nil
begin
size = File.stat(template['SOURCE']).size if template['SOURCE']
if self['TEMPLATE/SOURCE'] != nil
size = File.stat(self['TEMPLATE/SOURCE']).size
end
rescue Exception => e
error = OpenNebula::Error.new(e.message)
return error
end
occi = ERB.new(OCCI_IMAGE)
return occi.result(binding).gsub(/\n\s*/,'')
end
def to_one_template()
if @image_info['STORAGE']
image_info = @image_info['STORAGE']
if !image_info['NAME']
error_msg = "Missing Image NAME in the XML DISK section"
error = OpenNebula::Error.new(error_msg)
return error
end
else
if @image_info.name != 'STORAGE'
error_msg = "Missing STORAGE section in the XML body"
error = OpenNebula::Error.new(error_msg)
return error
end
if @image_info.elements['NAME'] == nil
error_msg = "Missing Image NAME in the XML DISK section"
error = OpenNebula::Error.new(error_msg)
return error
end
one = ERB.new(ONE_IMAGE)
return one.result(binding)
end

View File

@ -17,27 +17,27 @@
#--------------------------------------------------------------------------- #
require 'rubygems'
require 'crack'
require 'rexml/document'
require 'uri'
require 'CloudClient'
module OCCIClient
#####################################################################
# Client Library to interface with the OpenNebula OCCI Service
#####################################################################
class Client
class Client
######################################################################
# Initialize client library
######################################################################
def initialize(endpoint_str=nil, user=nil, pass=nil,
def initialize(endpoint_str=nil, user=nil, pass=nil,
timeout=nil, debug_flag=true)
@debug = debug_flag
@timeout = timeout
# Server location
if endpoint_str
@endpoint = endpoint_str
@ -46,25 +46,25 @@ module OCCIClient
else
@endpoint = "http://localhost:4567"
end
# Autentication
if user && pass
@occiauth = [user, pass]
else
@occiauth = CloudClient::get_one_auth
end
if !@occiauth
raise "No authorization data present"
end
@occiauth[1] = Digest::SHA1.hexdigest(@occiauth[1])
end
#################################
# Pool Resource Request Methods #
#################################
######################################################################
# Post a new VM to the VM Pool
# :instance_type
@ -72,14 +72,14 @@ module OCCIClient
######################################################################
def post_vms(xmlfile)
xml=File.read(xmlfile)
url = URI.parse(@endpoint+"/compute")
req = Net::HTTP::Post.new(url.path)
req.body=xml
req.basic_auth @occiauth[0], @occiauth[1]
res = CloudClient::http_start(url, @timeout) do |http|
http.request(req)
end
@ -90,88 +90,92 @@ module OCCIClient
return res.body
end
end
######################################################################
# Retieves the pool of Virtual Machines
######################################################################
def get_vms
url = URI.parse(@endpoint+"/compute")
req = Net::HTTP::Get.new(url.path)
req.basic_auth @occiauth[0], @occiauth[1]
res = CloudClient::http_start(url, @timeout) {|http|
http.request(req)
}
if CloudClient::is_error?(res)
return res
else
return res.body
end
end
######################################################################
# Post a new Network to the VN Pool
# :xmlfile xml description of the Virtual Network
######################################################################
def post_network(xmlfile)
xml=File.read(xmlfile)
url = URI.parse(@endpoint+"/network")
req = Net::HTTP::Post.new(url.path)
req.body=xml
req.basic_auth @occiauth[0], @occiauth[1]
res = CloudClient::http_start(url, @timeout) do |http|
http.request(req)
end
if CloudClient::is_error?(res)
return res
else
return res.body
end
end
######################################################################
# Retieves the pool of Virtual Networks
######################################################################
def get_networks
url = URI.parse(@endpoint+"/network")
req = Net::HTTP::Get.new(url.path)
req.basic_auth @occiauth[0], @occiauth[1]
res = CloudClient::http_start(url, @timeout) {|http|
http.request(req)
}
if CloudClient::is_error?(res)
return res
else
return res.body
end
end
######################################################################
# Post a new Image to the Image Pool
# :xmlfile
######################################################################
def post_image(xmlfile, curb=true)
xml=File.read(xmlfile)
image_info=Crack::XML.parse(xml)
file_path = image_info['STORAGE']['URL']
m=file_path.match(/^\w+:\/\/(.*)$/)
if m
xml = File.read(xmlfile)
image_info = REXML::Document.new(xml).root
if image_info.elements['URL'] == nil
return CloudClient::Error.new("Can not find URL")
end
file_path = image_info.elements['URL'].text
m = file_path.match(/^\w+:\/\/(.*)$/)
if m
file_path="/"+m[1]
end
if curb and CURL_LOADED
curl=Curl::Easy.new(@endpoint+"/storage")
@ -179,7 +183,7 @@ module OCCIClient
curl.userpwd = "#{@occiauth[0]}:#{@occiauth[1]}"
curl.verbose = true if @debug
curl.multipart_form_post = true
begin
curl.http_post(
Curl::PostField.content('occixml', xml),
@ -188,23 +192,23 @@ module OCCIClient
rescue Exception => e
return CloudClient::Error.new(e.message)
end
return curl.body_str
else
file=File.open(file_path)
params=Hash.new
params["file"]=UploadIO.new(file,
'application/octet-stream', file_path)
params['occixml'] = xml
url = URI.parse(@endpoint+"/storage")
req = Net::HTTP::Post::Multipart.new(url.path, params)
req.basic_auth @occiauth[0], @occiauth[1]
res = CloudClient::http_start(url, @timeout) do |http|
http.request(req)
end
@ -216,53 +220,53 @@ module OCCIClient
else
return res.body
end
end
end
end
######################################################################
# Retieves the pool of Images owned by the user
######################################################################
def get_images
url = URI.parse(@endpoint+"/storage")
req = Net::HTTP::Get.new(url.path)
req.basic_auth @occiauth[0], @occiauth[1]
res = CloudClient::http_start(url, @timeout) {|http|
http.request(req)
}
if CloudClient::is_error?(res)
return res
else
return res.body
end
end
####################################
# Entity Resource Request Methods #
####################################
######################################################################
# :id VM identifier
######################################################################
def get_vm(id)
url = URI.parse(@endpoint+"/compute/" + id.to_s)
req = Net::HTTP::Get.new(url.path)
req.basic_auth @occiauth[0], @occiauth[1]
res = CloudClient::http_start(url, @timeout) {|http|
http.request(req)
}
if CloudClient::is_error?(res)
return res
else
return res.body
end
end
######################################################################
# Puts a new Compute representation in order to change its state
# :xmlfile Compute OCCI xml representation
@ -270,34 +274,34 @@ module OCCIClient
def put_vm(xmlfile)
xml=File.read(xmlfile)
vm_info=Crack::XML.parse(xml)
url = URI.parse(@endpoint+'/compute/' + vm_info['COMPUTE']['ID'])
req = Net::HTTP::Put.new(url.path)
req.body = xml
req.basic_auth @occiauth[0], @occiauth[1]
res = CloudClient::http_start(url, @timeout) do |http|
http.request(req)
end
if CloudClient::is_error?(res)
return res
else
return res.body
end
end
####################################################################
# :id Compute identifier
####################################################################
def delete_vm(id)
url = URI.parse(@endpoint+"/compute/" + id.to_s)
req = Net::HTTP::Delete.new(url.path)
req.basic_auth @occiauth[0], @occiauth[1]
res = CloudClient::http_start(url, @timeout) {|http|
http.request(req)
}
@ -308,7 +312,7 @@ module OCCIClient
return res.body
end
end
######################################################################
# Retrieves a Virtual Network
# :id Virtual Network identifier
@ -316,9 +320,9 @@ module OCCIClient
def get_network(id)
url = URI.parse(@endpoint+"/network/" + id.to_s)
req = Net::HTTP::Get.new(url.path)
req.basic_auth @occiauth[0], @occiauth[1]
res = CloudClient::http_start(url, @timeout) {|http|
http.request(req)
}
@ -329,16 +333,16 @@ module OCCIClient
return res.body
end
end
######################################################################
# :id VM identifier
######################################################################
def delete_network(id)
url = URI.parse(@endpoint+"/network/" + id.to_s)
req = Net::HTTP::Delete.new(url.path)
req.basic_auth @occiauth[0], @occiauth[1]
res = CloudClient::http_start(url, @timeout) {|http|
http.request(req)
}
@ -349,7 +353,7 @@ module OCCIClient
return res.body
end
end
#######################################################################
# Retieves an Image
# :image_uuid Image identifier
@ -357,9 +361,9 @@ module OCCIClient
def get_image(image_uuid)
url = URI.parse(@endpoint+"/storage/"+image_uuid)
req = Net::HTTP::Get.new(url.path)
req.basic_auth @occiauth[0], @occiauth[1]
res = CloudClient::http_start(url, @timeout) {|http|
http.request(req)
}
@ -370,16 +374,16 @@ module OCCIClient
return res.body
end
end
######################################################################
# :id VM identifier
######################################################################
def delete_image(id)
url = URI.parse(@endpoint+"/storage/" + id.to_s)
req = Net::HTTP::Delete.new(url.path)
req.basic_auth @occiauth[0], @occiauth[1]
res = CloudClient::http_start(url, @timeout) {|http|
http.request(req)
}

View File

@ -115,9 +115,78 @@ class OCCIServer < CloudServer
end
end
###################################################
# Pool Resources methods
###################################################
############################################################################
############################################################################
# POOL RESOURCE METHODS
############################################################################
############################################################################
# Gets the pool representation of COMPUTES
# request:: _Hash_ hash containing the data of the request
# [return] _String_,_Integer_ Pool Representation or error, status code
def get_computes(request)
# --- Get client with user credentials ---
client = get_client(request.env)
# --- Get User's VMs ---
user_flag = -1
vmpool = VirtualMachinePoolOCCI.new(client, user_flag)
# --- Prepare XML Response ---
rc = vmpool.info
return rc, 404 if OpenNebula.is_error?(rc)
return to_occi_xml(vmpool)
end
# Gets the pool representation of NETWORKS
# request:: _Hash_ hash containing the data of the request
# [return] _String_,_Integer_ Network pool representation or error,
# => status code
def get_networks(request)
# --- Get client with user credentials ---
client = get_client(request.env)
# --- Get User's VNETs ---
user_flag = -1
network_pool = VirtualNetworkPoolOCCI.new(client, user_flag)
rc = network_pool.info
return rc, 404 if OpenNebula.is_error?(rc)
# --- Prepare XML Response ---
return to_occi_xml(network_pool)
end
# Gets the pool representation of STORAGES
# request:: _Hash_ hash containing the data of the request
# [return] _String_,_Integer_ Image pool representation or error,
# status code
def get_storages(request)
# --- Get client with user credentials ---
client = get_client(request.env)
# --- Get User's Images ---
user_flag = -1
image_pool = ImagePoolOCCI.new(client, user_flag)
result = image_pool.info
return result, 404 if OpenNebula.is_error?(result)
# --- Prepare XML Response ---
return to_occi_xml(image_pool)
end
############################################################################
############################################################################
# ENTITY RESOURCE METHODS
############################################################################
############################################################################
############################################################################
# COMPUTE Methods
############################################################################
# Post a new compute to the COMPUTE pool
# request:: _Hash_ hash containing the data of the request
@ -156,124 +225,6 @@ class OCCIServer < CloudServer
return to_occi_xml(vm)
end
# Gets the pool representation of COMPUTES
# request:: _Hash_ hash containing the data of the request
# [return] _String_,_Integer_ Pool Representation or error, status code
def get_computes(request)
# --- Get client with user credentials ---
client = get_client(request.env)
# --- Get User's VMs ---
user_flag = -1
vmpool = VirtualMachinePoolOCCI.new(client, user_flag)
# --- Prepare XML Response ---
rc = vmpool.info
return rc, 404 if OpenNebula.is_error?(rc)
return to_occi_xml(vmpool)
end
# Post a new network to the NETWORK pool
# request:: _Hash_ hash containing the data of the request
# [return] _String_,_Integer_ Network Representation or error, status code
def post_network(request)
# --- Get client with user credentials ---
client = get_client(request.env)
# --- Create the new Instance ---
network = VirtualNetworkOCCI.new(
VirtualNetwork.build_xml,
client,
request.body,
@config[:bridge])
# --- Generate the template and Allocate the new Instance ---
template = network.to_one_template
return template, 500 if OpenNebula.is_error?(template)
rc = network.allocate(template)
return rc, 500 if OpenNebula.is_error?(rc)
# --- Prepare XML Response ---
network.info
return to_occi_xml(network)
end
# Gets the pool representation of NETWORKS
# request:: _Hash_ hash containing the data of the request
# [return] _String_,_Integer_ Network pool representation or error,
# => status code
def get_networks(request)
# --- Get client with user credentials ---
client = get_client(request.env)
# --- Get User's VNETs ---
user_flag = -1
network_pool = VirtualNetworkPoolOCCI.new(client, user_flag)
rc = network_pool.info
return rc, 404 if OpenNebula.is_error?(rc)
# --- Prepare XML Response ---
return to_occi_xml(network_pool)
end
# Post a new image to the STORAGE pool
# request:: _Hash_ hash containing the data of the request
# [return] _String_,_Integer_ Image representation or error, status code
def post_storage(request)
# Get client with user credentials
client = get_client(request.env)
# --- Check OCCI XML from POST ---
if request.params['occixml']
image_info = XMLUtilsElement::xml_to_hash(request.params['occixml'])
return image_info, 400 if OpenNebula.is_error?(image_info)
else
error_msg = "OCCI XML representation of Image" +
" not present in the request"
error = OpenNebula::Error.new(error_msg)
return error, 400
end
# --- Create and Add the new Image ---
image = ImageOCCI.new(image_info, Image.build_xml, client)
rc = add_image(image, request.params['file'])
return rc, 500 if OpenNebula.is_error?(rc)
# --- Enable the new Image ---
rc = image.enable
return rc, 500 if OpenNebula.is_error?(rc)
# --- Prepare XML Response ---
return to_occi_xml(image)
end
# Gets the pool representation of STORAGES
# request:: _Hash_ hash containing the data of the request
# [return] _String_,_Integer_ Image pool representation or error,
# status code
def get_storages(request)
# --- Get client with user credentials ---
client = get_client(request.env)
# --- Get User's Images ---
user_flag = -1
image_pool = ImagePoolOCCI.new(client, user_flag)
result = image_pool.info
return result, 404 if OpenNebula.is_error?(result)
# --- Prepare XML Response ---
return to_occi_xml(image_pool)
end
###################################################
# Entity Resources methods
###################################################
# Get the representation of a COMPUTE resource
# request:: _Hash_ hash containing the data of the request
# [return] _String_,_Integer_ COMPUTE representation or error,
@ -295,6 +246,7 @@ class OCCIServer < CloudServer
return to_occi_xml(vm)
end
# Deletes a COMPUTE resource
# request:: _Hash_ hash containing the data of the request
# [return] _String_,_Integer_ Delete confirmation msg or error,
@ -347,6 +299,36 @@ class OCCIServer < CloudServer
return to_occi_xml(vm)
end
############################################################################
# NETWORK Methods
############################################################################
# Post a new network to the NETWORK pool
# request:: _Hash_ hash containing the data of the request
# [return] _String_,_Integer_ Network Representation or error, status code
def post_network(request)
# --- Get client with user credentials ---
client = get_client(request.env)
# --- Create the new Instance ---
network = VirtualNetworkOCCI.new(
VirtualNetwork.build_xml,
client,
request.body,
@config[:bridge])
# --- Generate the template and Allocate the new Instance ---
template = network.to_one_template
return template, 500 if OpenNebula.is_error?(template)
rc = network.allocate(template)
return rc, 500 if OpenNebula.is_error?(rc)
# --- Prepare XML Response ---
network.info
return to_occi_xml(network)
end
# Retrieves a NETWORK resource
# request:: _Hash_ hash containing the data of the request
# [return] _String_,_Integer_ NETWORK occi representation or error,
@ -386,6 +368,39 @@ class OCCIServer < CloudServer
return "", 204
end
############################################################################
# STORAGE Methods
############################################################################
# Post a new image to the STORAGE pool
# request:: _Hash_ hash containing the data of the request
# [return] _String_,_Integer_ Image representation or error, status code
def post_storage(request)
# Get client with user credentials
client = get_client(request.env)
# --- Check OCCI XML from POST ---
if request.params['occixml'] == nil
error_msg = "OCCI XML representation of Image" +
" not present in the request"
error = OpenNebula::Error.new(error_msg)
return error, 400
end
# --- Create and Add the new Image ---
image = ImageOCCI.new(Image.build_xml,client, request.params['occixml'])
rc = add_image(image, request.params['file'])
return rc, 500 if OpenNebula.is_error?(rc)
# --- Enable the new Image ---
rc = image.enable
return rc, 500 if OpenNebula.is_error?(rc)
# --- Prepare XML Response ---
return to_occi_xml(image)
end
# Get a STORAGE resource
# request:: _Hash_ hash containing the data of the request
# [return] _String_,_Integer_ STORAGE occi representation or error,
@ -395,7 +410,7 @@ class OCCIServer < CloudServer
client = get_client(request.env)
# --- Get the Image ---
image = ImageOCCI.new(nil, Image.build_xml(params[:id]), client)
image = ImageOCCI.new(Image.build_xml(params[:id]), client)
result = image.info
return result, 404 if OpenNebula::is_error?(result)
@ -412,7 +427,7 @@ class OCCIServer < CloudServer
# --- Get client with user credentials ---
client = get_client(request.env)
image = ImageOCCI.new(nil, Image.build_xml(params[:id]), client)
image = ImageOCCI.new(Image.build_xml(params[:id]), client)
# --- Delete the Image ---
result = image.delete

View File

@ -190,8 +190,10 @@ module OpenNebula
return OpenNebula::Error.new("copy Image: missing parameters.")
end
if !FileUtils.copy(path, source)
return OpenNebula::Error.new("copy Image: in File.copy")
begin
FileUtils.copy(path, source)
rescue Exception => e
return OpenNebula::Error.new(e.message)
end
return nil