mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-21 14:50:08 +03:00
feature #849: Improve OCCI PUT compute
This commit is contained in:
parent
faa3a8b8c6
commit
f1272b23d8
@ -253,56 +253,18 @@ class OCCIServer < CloudServer
|
||||
self.client)
|
||||
|
||||
rc = vm.info
|
||||
return rc, 400 if OpenNebula.is_error?(rc)
|
||||
|
||||
xmldoc = XMLElement.build_xml(request.body, 'COMPUTE')
|
||||
vm_info = XMLElement.new(xmldoc) if xmldoc != nil
|
||||
|
||||
# Check the number of changes in the request
|
||||
image_name = nil
|
||||
image_type = nil
|
||||
vm_info.each('DISK/SAVE_AS') { |disk|
|
||||
if image_name
|
||||
error_msg = "It is only allowed one save_as per request"
|
||||
return OpenNebula::Error.new(error_msg), 400
|
||||
end
|
||||
image_name = disk.attr('.', 'name')
|
||||
image_type = disk.attr('.', 'type')
|
||||
}
|
||||
state = vm_info['STATE']
|
||||
|
||||
if image_name && state
|
||||
error_msg = "It is not allowed to change the state and save_as" <<
|
||||
" a disk in the same request"
|
||||
return OpenNebula::Error.new(error_msg), 400
|
||||
elsif image_name
|
||||
# Get the disk id
|
||||
disk_id = vm_info.attr('DISK/SAVE_AS/..', 'id')
|
||||
if disk_id.nil?
|
||||
error_msg = "DISK id attribute not specified"
|
||||
return OpenNebula::Error.new(error_msg), 400
|
||||
end
|
||||
|
||||
disk_id = disk_id.to_i
|
||||
if vm["TEMPLATE/DISK[DISK_ID=\"#{disk_id}\"]/SAVE_AS"]
|
||||
error_msg = "The disk #{disk_id} is already" <<
|
||||
" suppossed to be saved"
|
||||
return OpenNebula::Error.new(error_msg), 400
|
||||
end
|
||||
|
||||
rc = vm.save_as(disk_id, image_name)
|
||||
if OpenNebula.is_error?(rc)
|
||||
image.delete
|
||||
return rc, 400
|
||||
end
|
||||
elsif state
|
||||
rc = vm.mk_action(state)
|
||||
return rc, 400 if OpenNebula.is_error?(rc)
|
||||
if OpenNebula.is_error?(rc)
|
||||
return rc, CloudServer::HTTP_ERROR_CODE[rc.errno]
|
||||
end
|
||||
|
||||
# --- Prepare XML Response ---
|
||||
vm.info
|
||||
return to_occi_xml(vm, 202)
|
||||
result, code = vm.update_from_xml(request.body)
|
||||
|
||||
if OpenNebula.is_error?(result)
|
||||
return result, code
|
||||
else
|
||||
vm.info
|
||||
return to_occi_xml(vm, code)
|
||||
end
|
||||
end
|
||||
|
||||
############################################################################
|
||||
|
@ -61,62 +61,48 @@ class VirtualMachineOCCI < VirtualMachine
|
||||
<% end %>
|
||||
</COMPUTE>
|
||||
}
|
||||
|
||||
|
||||
OCCI_ACTION = {
|
||||
"STOPPED" => { :from => ["ACTIVE"], :action => :stop},
|
||||
"SUSPENDED" => { :from => ["ACTIVE"], :action => :suspend},
|
||||
"RESUME" => { :from => ["STOPPED", "SUSPENDED"], :action => :resume},
|
||||
"CANCEL" => { :from => ["ACTIVE"], :action => :cancel},
|
||||
"SHUTDOWN" => { :from => ["ACTIVE"], :action => :shutdown},
|
||||
"DONE" => { :from => VM_STATE, :action => :finalize},
|
||||
}
|
||||
|
||||
# Class constructor
|
||||
def initialize(xml, client, xml_info=nil, types=nil, base=nil)
|
||||
super(xml, client)
|
||||
@vm_info = nil
|
||||
@template = nil
|
||||
@common_template = base + '/common.erb' if base
|
||||
|
||||
|
||||
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.to_sym] != nil
|
||||
@template = base + "/#{types[itype.to_sym][: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(@common_template)).result(binding)
|
||||
template << ERB.new(File.read(@template)).result(binding)
|
||||
@ -124,10 +110,10 @@ class VirtualMachineOCCI < VirtualMachine
|
||||
error = OpenNebula::Error.new(e.message)
|
||||
return error
|
||||
end
|
||||
|
||||
|
||||
return template
|
||||
end
|
||||
|
||||
|
||||
# Creates the VMI representation of a Virtual Machine
|
||||
def to_occi(base_url)
|
||||
begin
|
||||
@ -138,9 +124,90 @@ class VirtualMachineOCCI < VirtualMachine
|
||||
return error
|
||||
end
|
||||
|
||||
|
||||
return occi_vm_text.gsub(/\n\s*/,'')
|
||||
end
|
||||
|
||||
# Update de resource from an XML representation of the COMPUTE
|
||||
# @param [String] xml_compute XML representation of the COMPUTE
|
||||
# @return [[nil, OpenNebula::Error], HTTP_CODE] If there is no error
|
||||
# the first component is nil.
|
||||
def update_from_xml(xml_compute)
|
||||
xmldoc = XMLElement.build_xml(xml_compute, 'COMPUTE')
|
||||
vm_info = XMLElement.new(xmldoc) if xmldoc != nil
|
||||
|
||||
action = nil
|
||||
args = []
|
||||
|
||||
# Check if a state change is required
|
||||
occi_state = vm_info['STATE']
|
||||
|
||||
if occi_state
|
||||
# If a state is provided
|
||||
occi_state.upcase!
|
||||
if OCCI_ACTION.keys.include?(occi_state)
|
||||
# If the requested state is one the OCCI action states
|
||||
shash = OCCI_ACTION[occi_state]
|
||||
if shash[:from].include?(state_str)
|
||||
# Action to be performed
|
||||
action = shash[:action]
|
||||
elsif occi_state != state_str
|
||||
# If the requested state is different from the resource
|
||||
# state but it does not belong to the "from" state array
|
||||
error_msg = "The state of the resource cannot be changed" \
|
||||
" from #{state_str} to #{occi_state}."
|
||||
error = OpenNebula::Error.new(error_msg)
|
||||
return error, 403
|
||||
end
|
||||
elsif !VM_STATE.include?(occi_state)
|
||||
# The requested state is not one of the OCCI action states nor
|
||||
# a resource state
|
||||
error_msg = "Invalid state: \"#{occi_state}\""
|
||||
error = OpenNebula::Error.new(error_msg)
|
||||
return error, 400
|
||||
end
|
||||
end
|
||||
|
||||
# Check if a disk image save as is required
|
||||
image_name = nil
|
||||
vm_info.each('DISK/SAVE_AS') { |save_as|
|
||||
image_name = save_as.attr('.', 'name')
|
||||
if image_name
|
||||
if action
|
||||
# Return erro if an action has been defined before
|
||||
if action == :save_as
|
||||
error_msg = "Only one disk can be saved per request"
|
||||
else
|
||||
error_msg = "Changig the state of the resource and" \
|
||||
" saving a disk is not allowed in the same request"
|
||||
end
|
||||
error = OpenNebula::Error.new(error_msg)
|
||||
return error, 403
|
||||
else
|
||||
# if no action is defined yet and a save_as is requested
|
||||
action = :save_as
|
||||
disk_id = save_as.attr('..', 'id')
|
||||
|
||||
# Params for the save_as action:
|
||||
# save_as(disk_id, image_name)
|
||||
args << disk_id.to_i
|
||||
args << image_name
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
# Perform the requested action
|
||||
if action
|
||||
rc = self.send(action, *args)
|
||||
if OpenNebula.is_error?(rc)
|
||||
return rc, CloudServer::HTTP_ERROR_CODE[rc.errno]
|
||||
else
|
||||
return nil, 202
|
||||
end
|
||||
else
|
||||
# There is no change requested
|
||||
return nil, 200
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user