From 25460dd9957069b67dff21b250643e6ea769c622 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Fri, 16 Mar 2012 17:22:29 +0100 Subject: [PATCH] feature #1112: Fix issues in VDC. Restores unique functionality. CloudServer has a static/class logger --- src/cli/one_helper/oneimage_helper.rb | 5 ++ src/cloud/common/CloudServer.rb | 16 +++- src/ozones/Client/bin/onevdc | 9 ++- .../lib/cli/ozones_helper/vdc_helper.rb | 3 + src/ozones/Client/lib/zona.rb | 30 ++++---- src/ozones/Server/models/OzonesServer.rb | 73 ++++++++++++++++--- 6 files changed, 105 insertions(+), 31 deletions(-) diff --git a/src/cli/one_helper/oneimage_helper.rb b/src/cli/one_helper/oneimage_helper.rb index b02ea356d9..e73866f1a3 100644 --- a/src/cli/one_helper/oneimage_helper.rb +++ b/src/cli/one_helper/oneimage_helper.rb @@ -67,6 +67,11 @@ class OneImageHelper < OpenNebulaHelper::OneHelper OneImageHelper.type_to_str(d["TYPE"]) end + column :REGTIME, "Registration time of the Image", + :size=>20 do |d| + OpenNebulaHelper.time_to_str(d["REGTIME"]) + end + column :PERSISTENT, "Whether the Image is persistent or not", :size=>3 do |d| OpenNebulaHelper.boolean_to_str(d["PERSISTENT"]) diff --git a/src/cloud/common/CloudServer.rb b/src/cloud/common/CloudServer.rb index d092e5c4fc..904e072ec0 100755 --- a/src/cloud/common/CloudServer.rb +++ b/src/cloud/common/CloudServer.rb @@ -110,15 +110,27 @@ module CloudLogger DATE_FORMAT = "%a %b %d %H:%M:%S %Y" # Patch logger class to be compatible with Rack::CommonLogger - class ::Logger + class CloudLogger < Logger + + def initialize(path) + super(path) + end + def write(msg) info msg.chop end + + def add(severity, message = nil, progname = nil, &block) + rc = super(severity, message, progname, &block) + @logdev.dev.flush + + rc + end end def enable_logging(path=nil, debug_level=3) path ||= $stdout - logger = ::Logger.new(path) + logger = CloudLogger.new(path) logger.level = DEBUG_LEVEL[debug_level] logger.formatter = proc do |severity, datetime, progname, msg| MSG_FORMAT % [ diff --git a/src/ozones/Client/bin/onevdc b/src/ozones/Client/bin/onevdc index 9820efff68..f6ff4ced27 100755 --- a/src/ozones/Client/bin/onevdc +++ b/src/ozones/Client/bin/onevdc @@ -43,6 +43,13 @@ cmd=CommandParser::CmdParser.new(ARGV) do ######################################################################## set :option, CommandParser::OPTIONS + FORCE={ + :name => "force", + :short => "-f", + :large => "--force", + :description => "Force the usage of Hosts in more than one VDC" + } + begin helper = VDCHelper.new "vdc" rescue Exception => e @@ -50,7 +57,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do exit -1 end - command :create, 'Create a new VDC', :file do + command :create, 'Create a new VDC', :file, :options=>[FORCE] do helper.create_resource(args[0], options) end diff --git a/src/ozones/Client/lib/cli/ozones_helper/vdc_helper.rb b/src/ozones/Client/lib/cli/ozones_helper/vdc_helper.rb index 44ae9e884f..8831ac7def 100644 --- a/src/ozones/Client/lib/cli/ozones_helper/vdc_helper.rb +++ b/src/ozones/Client/lib/cli/ozones_helper/vdc_helper.rb @@ -49,6 +49,9 @@ class VDCHelper < OZonesHelper::OZHelper tmpl_hash["RESOURCES"] = { "HOSTS" => eval("[#{hosts}]"), "DATASTORES" => eval("[#{ds}]"), "NETWORKS" => eval("[#{nets}]") } + if options[:force] + tmpl_hash["FORCE"] = "YES" + end vdc = { "#{@vdc_str.upcase}" => tmpl_hash } diff --git a/src/ozones/Client/lib/zona.rb b/src/ozones/Client/lib/zona.rb index fcec4978f3..e479e67d2d 100644 --- a/src/ozones/Client/lib/zona.rb +++ b/src/ozones/Client/lib/zona.rb @@ -270,26 +270,22 @@ EOT def self.parse_error(value, kind) if Zona.is_error?(value) return value - else - if Zona.is_http_error?(value) - str = "Operating with #{kind} failed with HTTP error" - str += " code: #{value.code}\n" - if value.body - # Try to extract error message - begin - str << "Body: " << - OZonesJSON.parse_json(value.body, - "error")["message"] - rescue - str.gsub!("\nBody:","") - end - end - return Error.new(str) - end end + + if Zona.is_http_error?(value) + str = "Operating with #{kind} failed with HTTP error" + str += " code: #{value.code}\n" + + if value.body + ehash = OZonesJSON.parse_json(value.body,"error") + str << ehash[:message] if !ehash.nil? + end + + return Error.new(str) + end + value # If it is not an error, return it as-is end - end # Parses a OpenNebula template string and turns it into a JSON string diff --git a/src/ozones/Server/models/OzonesServer.rb b/src/ozones/Server/models/OzonesServer.rb index 903a3bff4d..01e68d09bb 100644 --- a/src/ozones/Server/models/OzonesServer.rb +++ b/src/ozones/Server/models/OzonesServer.rb @@ -90,8 +90,11 @@ class OzonesServer < CloudServer "Reason: #{data.message}.").to_json] end + #----------------------------------------------------------------------- #Get the Zone that will host the VDC. And check resouces + #----------------------------------------------------------------------- zoneid = vdc_data.delete(:ZONE_ID) + force = vdc_data.delete(:FORCE) if !zoneid return [400, OZones::Error.new("Error: Couldn't create vdc. " \ @@ -104,7 +107,14 @@ class OzonesServer < CloudServer "Zone #{zoneid} not found.").to_json] end + if (!force or force.upcase != "YES") and !host_unique?(zone, vdc_data) + return [403, OZones::Error.new("Error: Couldn't create vdc. " \ + "Hosts are not unique, use force to override").to_json] + end + + #----------------------------------------------------------------------- # Create de VDC + #----------------------------------------------------------------------- vdc = OZones::OpenNebulaVdc.new(-1,zone) rc = vdc.create(vdc_data) @@ -113,7 +123,9 @@ class OzonesServer < CloudServer "Reason: #{rc.message}").to_json] end + #----------------------------------------------------------------------- #Update the zone and save the vdc + #----------------------------------------------------------------------- zone.raise_on_save_failure = true zone.vdcs << vdc.vdc @@ -160,17 +172,16 @@ class OzonesServer < CloudServer if OpenNebula.is_error?(vdc_data) return [400, OZones::Error.new("Error: Couldn't update vdc. " \ "Reason: #{data.message}.").to_json] - end - - rsrc = vdc_data.delete(:RESOURCES) - - # Check parameters - if !rsrc + end + + #----------------------------------------------------------------------- + # Check parameters & VDC + #----------------------------------------------------------------------- + if !vdc_data[:RESOURCES] return [400, OZones::Error.new("Error: Couldn't update vdc. " \ "Missing RESOURCES.").to_json] end - # Check if the referenced Vdc exists begin vdc = OZones::OpenNebulaVdc.new(vdc_id) rescue => e @@ -178,7 +189,17 @@ class OzonesServer < CloudServer "#{e.message}").to_json] end - rc = vdc.update(rsrc) + vdc_data[:CLUSTER_ID] = vdc.CLUSTER_ID + vdc_data[:ID] = vdc.ID + + force = vdc_data.delete(:FORCE) + + if (!force or force.upcase!="YES") and !host_unique?(vdc.zone, vdc_data) + return [403, OZones::Error.new("Error: Couldn't update vdc. " \ + "Hosts are not unique, use force to override").to_json] + end + + rc = vdc.update(vdc_data[:RESOURCES]) if !OpenNebula.is_error?(rc) return [200, rc] @@ -215,9 +236,8 @@ class OzonesServer < CloudServer if zone rc = zone.destroy else - return [404, - OZones::Error.new("Error: Cannot delete " \ - "zone. Reason: zone #{id} not found").to_json] + return [404, OZones::Error.new("Error: Cannot delete " \ + "zone. Reason: zone #{id} not found").to_json] end if !rc @@ -228,4 +248,35 @@ class OzonesServer < CloudServer return [200, OZones.str_to_json("Zone #{id} successfully deleted")] end end + + ############################################################################ + # Misc Helper Functions + ############################################################################ + private + + # Check if hosts are already include in any Vdc of the zone + def host_unique?(zone, vdc_data) + + hosts = vdc_data[:RESOURCES][:HOSTS] + c_id = vdc_data[:CLUSTER_ID] + + return true if hosts.empty? + + all_hosts = Array.new + + zone.vdcs.all(:CLUSTER_ID =>c_id).each{ |vdc| + + rsrc = vdc.resources + + if !rsrc[:HOSTS].empty? and vdc.ID != vdc_data[:ID] + all_hosts.concat(rsrc[:HOSTS]) + end + } + + hosts.each{|hid| + return false if all_hosts.include?(hid) + } + + return true + end end