diff --git a/include/Image.h b/include/Image.h index 2109f6f03c..b4581311af 100644 --- a/include/Image.h +++ b/include/Image.h @@ -109,6 +109,15 @@ public: return (public_img == 1); }; + /** + * Returns true if the image is persistent + * @return true if the image is persistent + */ + bool isPersistent() + { + return (persistent_img == 1); + }; + /** * Set enum type * @return 0 on success, -1 otherwise @@ -183,16 +192,51 @@ public: * @param pub true to publish the image * @return 0 on success */ - void publish(bool pub) + bool publish(bool pub) { + bool success = false; + if (pub == true) { - public_img = 1; + if (!isPersistent()) + { + public_img = 1; + success = true; + } } else { public_img = 0; + success = true; } + + return success; + } + + /** + * Set/Unset an image as persistant + * @param persistent true to make an image persistant + * @return 0 on success + */ + bool persistent(bool persis) + { + bool success = false; + + if (persis == true) + { + if (!isPublic() && running_vms == 0) + { + persistent_img = 1; + success = true; + } + } + else + { + persistent_img = 0; + success = true; + } + + return success; } /** @@ -331,6 +375,11 @@ private: */ int public_img; + /** + * Persistency of the Image + */ + int persistent_img; + /** * Registration time */ @@ -421,13 +470,13 @@ protected: NAME = 2, /* Image name */ TYPE = 3, /* 0) OS 1) CDROM 2) DATABLOCK */ PUBLIC = 4, /* Public scope (YES OR NO) */ - REGTIME = 5, /* Time of registration */ - SOURCE = 6, /* Path to the image */ - STATE = 7, /* 0) INIT 1) ALLOCATED */ - /* 2) READY 3) USED */ - RUNNING_VMS = 8, /* Number of VMs using the img */ - TEMPLATE = 9, /* Image template xml data */ - LIMIT = 10 + PERSISTENT = 5, /* Peristency (YES OR NO) */ + REGTIME = 6, /* Time of registration */ + SOURCE = 7, /* Path to the image */ + STATE = 8, /* 0) INIT 1) ALLOCATED */ + RUNNING_VMS = 9, /* Number of VMs using the img */ + TEMPLATE = 10, /* Image template xml data */ + LIMIT = 11 }; static const char * db_names; diff --git a/include/Nebula.h b/include/Nebula.h index e44038cef8..44e41f503f 100644 --- a/include/Nebula.h +++ b/include/Nebula.h @@ -236,6 +236,7 @@ private: etc_location = "/etc/one/"; log_location = "/var/log/one/"; var_location = "/var/lib/one/"; + hook_location= "/usr/share/one/hooks/"; } else { @@ -250,6 +251,7 @@ private: etc_location = nebula_location + "etc/"; log_location = nebula_location + "var/"; var_location = nebula_location + "var/"; + hook_location= nebula_location + "share/hooks/"; } }; @@ -345,6 +347,7 @@ private: string etc_location; string log_location; string var_location; + string hook_location; string hostname; // --------------------------------------------------------------- diff --git a/include/PoolSQL.h b/include/PoolSQL.h index 74ffb85fe5..a7f57685aa 100644 --- a/include/PoolSQL.h +++ b/include/PoolSQL.h @@ -46,7 +46,7 @@ public: * @param table the name of the table supporting the pool (to set the oid * counter). If null the OID counter is not updated. */ - PoolSQL(SqlDB * _db, const char * table=0); + PoolSQL(SqlDB * _db, const char * table); virtual ~PoolSQL(); diff --git a/include/RequestManager.h b/include/RequestManager.h index 8035b90fe5..50c4d97fb8 100644 --- a/include/RequestManager.h +++ b/include/RequestManager.h @@ -1156,6 +1156,31 @@ private: /* ---------------------------------------------------------------------- */ + class ImagePersistent: public xmlrpc_c::method + { + public: + ImagePersistent(ImagePool * _ipool, + UserPool * _upool): + ipool(_ipool), + upool(_upool) + { + _signature="A:sib"; + _help="Make an Image (non)persistent"; + }; + + ~ImagePersistent(){}; + + void execute( + xmlrpc_c::paramList const& paramList, + xmlrpc_c::value * const retvalP); + + private: + ImagePool * ipool; + UserPool * upool; + }; + + /* ---------------------------------------------------------------------- */ + class ImageEnable: public xmlrpc_c::method { public: diff --git a/include/VirtualMachinePool.h b/include/VirtualMachinePool.h index 378f7460d0..a4aa1faa46 100644 --- a/include/VirtualMachinePool.h +++ b/include/VirtualMachinePool.h @@ -32,7 +32,9 @@ class VirtualMachinePool : public PoolSQL { public: - VirtualMachinePool(SqlDB * db, vector hook_mads); + VirtualMachinePool(SqlDB * db, + vector hook_mads, + const string& hook_location); ~VirtualMachinePool(){}; diff --git a/install.sh b/install.sh index a9172bdba4..92d6416afc 100755 --- a/install.sh +++ b/install.sh @@ -99,7 +99,7 @@ if [ -z "$ROOT" ] ; then RUN_LOCATION="/var/run/one" LOCK_LOCATION="/var/lock/one" INCLUDE_LOCATION="/usr/include" - SHARE_LOCATION="/usr/share/doc/opennebula" + SHARE_LOCATION="/usr/share/one" if [ "$CLIENT" = "no" ]; then MAKE_DIRS="$BIN_LOCATION $LIB_LOCATION $ETC_LOCATION $VAR_LOCATION \ @@ -306,6 +306,7 @@ RUBY_OPENNEBULA_LIB_FILES="src/oca/ruby/OpenNebula/Host.rb \ src/oca/ruby/OpenNebula/VirtualNetworkPool.rb \ src/oca/ruby/OpenNebula/Image.rb \ src/oca/ruby/OpenNebula/ImagePool.rb \ + src/oca/ruby/OpenNebula/ImageRepository.rb \ src/oca/ruby/OpenNebula/Cluster.rb \ src/oca/ruby/OpenNebula/ClusterPool.rb \ src/oca/ruby/OpenNebula/XMLUtils.rb" diff --git a/share/hooks/image.rb b/share/hooks/image.rb index 2d42ea53ca..8709a7d65f 100755 --- a/share/hooks/image.rb +++ b/share/hooks/image.rb @@ -37,6 +37,7 @@ end client = Client.new() +img_repo = ImageRepository.new vm = VirtualMachine.new( VirtualMachine.build_xml(vm_id), @@ -52,17 +53,8 @@ vm.each('TEMPLATE/DISK') do |disk| Image.build_xml(image_id), client) - result = image.info - exit -1 if OpenNebula.is_error?(result) - - # Disable the Image for a safe overwriting - # image.disable - - # Save the image file - result = image.move(source_path, image['SOURCE']) + result = img_repo.update_source(image, source_path) exit -1 if OpenNebula.is_error?(result) - - # image.enable end end diff --git a/src/cli/oneimage b/src/cli/oneimage index 41a17186a4..878f3e4a3d 100755 --- a/src/cli/oneimage +++ b/src/cli/oneimage @@ -78,6 +78,13 @@ ShowTableImage={ :proc => lambda {|d,e| if d["PUBLIC"].to_i == 1 then "Yes" else "No" end} }, + :persistent => { + :name => "PERSISTENT", + :desc => "Whether the Image is persistent or not", + :size => 3, + :proc => lambda {|d,e| + if d["PERSISTENT"].to_i == 1 then "Yes" else "No" end} + }, :state => { :name => "STAT", :desc => "State of the Image", @@ -94,7 +101,7 @@ ShowTableImage={ }, :default => [:id, :user, :name, :type, :regtime, - :public, :state, :runningvms] + :public, :persistent, :state, :runningvms] } @@ -217,6 +224,12 @@ Commands: * unpublish (Unpublish an Image) oneimage unpublish +* persistent (Makes an Image persistent) + oneimage persistent + +* nonpersistent (Makes an Image non persistent) + oneimage nonpersistent + * list (Shows Images in the pool) oneimage list @@ -251,6 +264,11 @@ EOT table.print_help end + def special_options(opts, options) + opts.on_tail("-n", "--no-cp", "Do not copy the source") do |o| + options[:no_cp]=true + end + end end @@ -300,58 +318,18 @@ result=[false, "Unknown error"] command=ARGV.shift +img_repo = OpenNebula::ImageRepository.new + case command -when "register", "create", "add" - # ---------- Get the Template ------------ - +when "register", "create", "add" check_parameters("register", 1) template = get_template(ARGV[0]) - - # ---------- Allocate the Image file ------------ - image = OpenNebula::Image.new( - OpenNebula::Image.build_xml, - get_one_client) - - result = image.allocate(template) - - if !is_successful?(result) - puts result.message - exit -1 - end + image = OpenNebula::Image.new(OpenNebula::Image.build_xml, get_one_client) - # ---------- Copy the Image file ------------ - - image.info - - 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 + result = img_repo.create(image, template, !ops[:no_cp]) + if is_successful?(result) puts "ID: " + image.id.to_s if ops[:verbose] - exit 0 - else - image.delete end @@ -421,6 +399,28 @@ when "unpublish" puts "Image unpublished" if ops[:verbose] end +when "persistent" + check_parameters("publish", 1) + image_id=get_image_id(ARGV[0]) + + image=OpenNebula::Image.new_with_id(image_id, get_one_client) + + result=image.persistent + if is_successful?(result) + puts "Image made persistent" if ops[:verbose] + end + +when "nonpersistent" + check_parameters("nonpersistent", 1) + image_id=get_image_id(ARGV[0]) + + image=OpenNebula::Image.new_with_id(image_id, get_one_client) + + result=image.nonpersistent + if is_successful?(result) + puts "Image made nonpersistent" if ops[:verbose] + end + when "list" ops.merge!(get_user_flags) if !ops[:xml] @@ -494,22 +494,14 @@ when "delete" args=expand_args(ARGV) args.each do |param| - image_id=get_image_id(param) - - image=OpenNebula::Image.new_with_id(image_id, get_one_client) - - result = image.info + image_id = get_image_id(param) + image = OpenNebula::Image.new( + OpenNebula::Image.build_xml(image_id), + get_one_client) + result = img_repo.delete(image) if is_successful?(result) - - file_path = image['SOURCE'] - - result=image.delete - - if is_successful?(result) - FileUtils.rm(file_path) if File.exists?(file_path) - puts "Image correctly deleted" if ops[:verbose] - end + puts "Image correctly deleted" if ops[:verbose] end end diff --git a/src/cloud/common/CloudServer.rb b/src/cloud/common/CloudServer.rb index f15acad711..157da9366c 100755 --- a/src/cloud/common/CloudServer.rb +++ b/src/cloud/common/CloudServer.rb @@ -58,6 +58,7 @@ class CloudServer @one_client = Client.new() @user_pool = UserPool.new(@one_client) + @img_repo = OpenNebula::ImageRepository.new end # @@ -110,47 +111,23 @@ class CloudServer if file if file[:tempfile] file_path = file[:tempfile].path + template = image.to_one_template + template << "\nPATH = #{file_path}" else error_msg = "Image not present, aborting." error = OpenNebula::Error.new(error_msg) return error 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 - # ---------- Allocate the Image file ------------ + rc = @img_repo.create(image, template) - rc = image.allocate(image.to_one_template) + file[:tempfile].unlink + 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 diff --git a/src/cloud/occi/lib/OCCIServer.rb b/src/cloud/occi/lib/OCCIServer.rb index a5b3abf2aa..0422213b9d 100755 --- a/src/cloud/occi/lib/OCCIServer.rb +++ b/src/cloud/occi/lib/OCCIServer.rb @@ -355,7 +355,7 @@ class OCCIServer < CloudServer get_client(request.env)) # --- Delete the Image --- - rc = image.delete + rc = @img_repo.delete(image) return rc, 500 if OpenNebula::is_error?(rc) return "", 204 diff --git a/src/image/Image.cc b/src/image/Image.cc index c7ce568b1a..891e936f66 100644 --- a/src/image/Image.cc +++ b/src/image/Image.cc @@ -66,12 +66,12 @@ Image::~Image() const char * Image::table = "image_pool"; -const char * Image::db_names = "(oid, uid, name, type, public, regtime, " +const char * Image::db_names = "(oid, uid, name, type, public, persistent, regtime, " "source, state, running_vms, template)"; const char * Image::db_bootstrap = "CREATE TABLE IF NOT EXISTS image_pool (" "oid INTEGER PRIMARY KEY, uid INTEGER, name VARCHAR(128), " - "type INTEGER, public INTEGER, regtime INTEGER, source TEXT, state INTEGER, " + "type INTEGER, public INTEGER, persistent INTEGER, regtime INTEGER, source TEXT, state INTEGER, " "running_vms INTEGER, template TEXT, UNIQUE(name) )"; /* ------------------------------------------------------------------------ */ @@ -84,6 +84,7 @@ int Image::select_cb(void * nil, int num, char **values, char ** names) (!values[NAME]) || (!values[TYPE]) || (!values[PUBLIC]) || + (!values[PERSISTENT]) || (!values[REGTIME]) || (!values[SOURCE]) || (!values[STATE]) || @@ -99,9 +100,10 @@ int Image::select_cb(void * nil, int num, char **values, char ** names) name = values[NAME]; - type = static_cast(atoi(values[TYPE])); - public_img = atoi(values[PUBLIC]); - regtime = static_cast(atoi(values[REGTIME])); + type = static_cast(atoi(values[TYPE])); + public_img = atoi(values[PUBLIC]); + persistent_img = atoi(values[PERSISTENT]); + regtime = static_cast(atoi(values[REGTIME])); source = values[SOURCE]; @@ -151,6 +153,7 @@ int Image::insert(SqlDB *db) string source_att; string type_att; string public_attr; + string persistent_attr; string dev_prefix; ostringstream tmp_hashstream; @@ -196,6 +199,23 @@ int Image::insert(SqlDB *db) public_img = (public_attr == "YES"); + // ------------ PERSISTENT -------------------- + + get_template_attribute("PERSISTENT", persistent_attr); + image_template->erase("PERSISTENT"); + + transform (persistent_attr.begin(), persistent_attr.end(), persistent_attr.begin(), + (int(*)(int))toupper); + + persistent_img = (persistent_attr == "YES"); + + // An image cannot be public and persistent simultaneously + + if ( public_img && persistent_img ) + { + goto error_public_and_persistent; + } + // ------------ PREFIX -------------------- get_template_attribute("DEV_PREFIX", dev_prefix); @@ -236,6 +256,10 @@ error_type: NebulaLog::log("IMG", Log::ERROR, "Incorrect TYPE in image template"); goto error_common; +error_public_and_persistent: + NebulaLog::log("IMG", Log::ERROR, "Image cannot be public and persistant"); + goto error_common; + error_common: return -1; } @@ -304,6 +328,7 @@ int Image::insert_replace(SqlDB *db, bool replace) << "'" << sql_name << "'," << type << "," << public_img << "," + << persistent_img << "," << regtime << "," << "'" << sql_source << "'," << state << "," @@ -336,6 +361,7 @@ int Image::dump(ostringstream& oss, int num, char **values, char **names) (!values[NAME]) || (!values[TYPE]) || (!values[PUBLIC]) || + (!values[PERSISTENT]) || (!values[REGTIME]) || (!values[SOURCE]) || (!values[STATE]) || @@ -354,6 +380,7 @@ int Image::dump(ostringstream& oss, int num, char **values, char **names) "" << values[NAME] << "" << "" << values[TYPE] << "" << "" << values[PUBLIC] << "" << + "" << values[PERSISTENT] << "" << "" << values[REGTIME] << "" << "" << values[SOURCE] << "" << "" << values[STATE] << "" << @@ -413,20 +440,19 @@ string& Image::to_xml(string& xml) const string template_xml; ostringstream oss; - - oss << "" << - "" << oid << "" << - "" << uid << "" << - "" << name << "" << - "" << type << "" << - "" << public_img << "" << - "" << regtime << "" << - "" << source << "" << - "" << state << "" << - "" << running_vms << "" << - image_template->to_xml(template_xml) << + "" << oid << "" << + "" << uid << "" << + "" << name << "" << + "" << type << "" << + "" << public_img << "" << + "" << persistent_img << "" << + "" << regtime << "" << + "" << source << "" << + "" << state << "" << + "" << running_vms << "" << + image_template->to_xml(template_xml) << ""; xml = oss.str(); @@ -444,15 +470,16 @@ string& Image::to_str(string& str) const ostringstream os; os << - "ID = " << oid << endl << - "UID = " << uid << endl << - "NAME = " << name << endl << - "TYPE = " << type << endl << - "PUBLIC = " << public_img << endl << - "REGTIME = " << regtime << endl << - "SOURCE = " << source << endl << - "STATE = " << state << endl << - "RUNNING_VMS = " << running_vms << endl << + "ID = " << oid << endl << + "UID = " << uid << endl << + "NAME = " << name << endl << + "TYPE = " << type << endl << + "PUBLIC = " << public_img << endl << + "PERSISTENT = " << persistent_img << endl << + "REGTIME = " << regtime << endl << + "SOURCE = " << source << endl << + "STATE = " << state << endl << + "RUNNING_VMS = " << running_vms << endl << "TEMPLATE" << endl << image_template->to_str(template_str) << endl; @@ -478,7 +505,14 @@ int Image::acquire_image() break; case USED: - running_vms++; + if (persistent_img) + { + rc = -1; + } + else + { + running_vms++; + } break; case DISABLED: @@ -527,17 +561,21 @@ int Image::disk_attribute( VectorAttribute * disk, ImageType* img_type) { string bus; + string target; ostringstream iid; *img_type = type; bus = disk->vector_value("BUS"); + target = disk->vector_value("TARGET"); iid << oid; string template_bus; + string template_target; string prefix; get_template_attribute("BUS", template_bus); + get_template_attribute("TARGET", template_target); get_template_attribute("DEV_PREFIX", prefix); //-------------------------------------------------------------------------- @@ -559,24 +597,31 @@ int Image::disk_attribute( VectorAttribute * disk, new_disk.insert(make_pair("IMAGE_ID", iid.str())); new_disk.insert(make_pair("SOURCE", source)); - if (bus.empty()) - { - if (!template_bus.empty()) - { - new_disk.insert(make_pair("BUS",template_bus)); - } - } - else + if (!bus.empty()) { new_disk.insert(make_pair("BUS",bus)); } + else if (!template_bus.empty()) + { + new_disk.insert(make_pair("BUS",template_bus)); + } //--------------------------------------------------------------------------- // TYPE, READONLY, CLONE, and SAVE attributes //--------------------------------------------------------------------------- - new_disk.insert(make_pair("CLONE","YES")); - new_disk.insert(make_pair("SAVE","NO")); + if ( persistent_img ) + { + new_disk.insert(make_pair("CLONE","NO")); + new_disk.insert(make_pair("SAVE","YES")); + + new_disk.insert(make_pair("SAVE_AS", iid.str())); // Tells the hook to overwrite + } + else + { + new_disk.insert(make_pair("CLONE","YES")); + new_disk.insert(make_pair("SAVE","NO")); + } switch(type) { @@ -596,23 +641,35 @@ int Image::disk_attribute( VectorAttribute * disk, // TARGET attribute //--------------------------------------------------------------------------- - switch(type) + if (!target.empty()) { - case OS: - prefix += "a"; - break; - - case CDROM: - prefix += "c"; // b is for context - break; - - case DATABLOCK: - prefix += static_cast(('e'+ *index)); - *index = *index + 1; - break; - + new_disk.insert(make_pair("TARGET", target)); + } + else if (!template_target.empty()) + { + new_disk.insert(make_pair("TARGET", template_target)); + } + else + { + switch(type) + { + case OS: + prefix += "a"; + break; + + case CDROM: + prefix += "c"; // b is for context + break; + + case DATABLOCK: + prefix += static_cast(('e'+ *index)); + *index = *index + 1; + break; + + } + + new_disk.insert(make_pair("TARGET", prefix)); } - new_disk.insert(make_pair("TARGET", prefix)); disk->replace(new_disk); diff --git a/src/nebula/Nebula.cc b/src/nebula/Nebula.cc index 8b28763267..a08b2b2e65 100644 --- a/src/nebula/Nebula.cc +++ b/src/nebula/Nebula.cc @@ -230,7 +230,7 @@ void Nebula::start() nebula_configuration->get("VM_HOOK", vm_hooks); - vmpool = new VirtualMachinePool(db, vm_hooks); + vmpool = new VirtualMachinePool(db, vm_hooks,hook_location); hpool = new HostPool(db); nebula_configuration->get("MAC_PREFIX", mac_prefix); diff --git a/src/oca/ruby/OpenNebula.rb b/src/oca/ruby/OpenNebula.rb index 1e8412b8be..975e4f6002 100644 --- a/src/oca/ruby/OpenNebula.rb +++ b/src/oca/ruby/OpenNebula.rb @@ -15,6 +15,7 @@ require 'OpenNebula/VirtualNetwork' require 'OpenNebula/VirtualNetworkPool' require 'OpenNebula/Image' require 'OpenNebula/ImagePool' +require 'OpenNebula/ImageRepository' require 'OpenNebula/User' require 'OpenNebula/UserPool' require 'OpenNebula/Host' diff --git a/src/oca/ruby/OpenNebula/Image.rb b/src/oca/ruby/OpenNebula/Image.rb index 74840da8ab..965f4d333f 100644 --- a/src/oca/ruby/OpenNebula/Image.rb +++ b/src/oca/ruby/OpenNebula/Image.rb @@ -7,13 +7,14 @@ module OpenNebula # Constants and Class Methods # --------------------------------------------------------------------- IMAGE_METHODS = { - :info => "image.info", - :allocate => "image.allocate", - :update => "image.update", - :rmattr => "image.rmattr", - :enable => "image.enable", - :publish => "image.publish", - :delete => "image.delete" + :info => "image.info", + :allocate => "image.allocate", + :update => "image.update", + :rmattr => "image.rmattr", + :enable => "image.enable", + :publish => "image.publish", + :persistent => "image.persistent", + :delete => "image.delete" } IMAGE_STATES=%w{INIT READY USED DISABLED} @@ -55,7 +56,6 @@ module OpenNebula super(xml,client) @client = client - @immanager = ImageManager.new end ####################################################################### @@ -109,27 +109,22 @@ module OpenNebula def unpublish set_publish(false) end + + # Makes the Image persistent + def persistent + set_persistent(true) + end + + # Makes the Image non persistent + def nonpersistent + set_persistent(false) + end # Deletes the Image def delete() super(IMAGE_METHODS[:delete]) end - - def copy(path, source) - @immanager.copy(path, source) - end - - def move(path, source) - @immanager.move(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 @@ -184,6 +179,15 @@ module OpenNebula return rc end + + def set_persistent(persistence) + return Error.new('ID not defined') if !@pe_id + + rc = @client.call(IMAGE_METHODS[:persistent], @pe_id, persistence) + rc = nil if !OpenNebula.is_error?(rc) + + return rc + end def do_rm_attr(name) return Error.new('ID not defined') if !@pe_id @@ -195,81 +199,4 @@ module OpenNebula end end - - class ImageManager - # --------------------------------------------------------------------- - # Constants and Class Methods - # --------------------------------------------------------------------- - FS_UTILS = { - :dd => "env dd", - :mkfs => "env 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) - FileUtils.chmod(0660, source) - rescue Exception => e - return OpenNebula::Error.new(e.message) - end - - return nil - end - - def move(path, source) - if source.nil? or path.nil? - return OpenNebula::Error.new("copy Image: missing parameters.") - end - - begin - FileUtils.move(path, source) - FileUtils.chmod(0660, 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 seek=#{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/ImageRepository.rb b/src/oca/ruby/OpenNebula/ImageRepository.rb new file mode 100644 index 0000000000..f80638cc83 --- /dev/null +++ b/src/oca/ruby/OpenNebula/ImageRepository.rb @@ -0,0 +1,185 @@ +require 'OpenNebula/Image' +require 'fileutils' + +module OpenNebula + class ImageRepository + + def create(image, template, copy=true) + if image.nil? + error_msg = "Image could not be found, aborting." + result = OpenNebula::Error.new(error_msg) + end + + # ------ Allocate the Image ------ + result = image.allocate(template) + + if OpenNebula.is_error?(result) + puts result.message + exit -1 + end + + + # ------ Copy the Image file ------ + image.info + + if image['TEMPLATE/PATH'] + if copy + # --- CDROM, DATABLOCK or OS based on a 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 = copy(file_path, image['SOURCE']) + end + elsif image['TEMPLATE/SIZE'] and image['TEMPLATE/FSTYPE'] and \ + image['TEMPLATE/TYPE'] == 'DATABLOCK' + # --- Empty DATABLOCK --- + result = dd(image['TEMPLATE/SIZE'], image['SOURCE']) + + if !OpenNebula.is_error?(result) + result = mkfs(image['TEMPLATE/FSTYPE'], image['SOURCE']) + end + else + error_msg = "Image not present, aborting." + result = OpenNebula::Error.new(error_msg) + end + + + # ------ Enable the Image ------ + if !OpenNebula.is_error?(result) + image.enable + else + image.delete + end + + return result + end + + def delete(image) + if image.nil? + error_msg = "Image could not be found, aborting." + result = OpenNebula::Error.new(error_msg) + end + + result = image.info + + if !OpenNebula.is_error?(result) + file_path = image['SOURCE'] + + result = image.delete + + if !OpenNebula.is_error?(result) + result = remove(file_path) + end + end + + return result + end + + def update_source(image, source) + if image.nil? + error_msg = "Image could not be found, aborting." + result = OpenNebula::Error.new(error_msg) + end + + result = image.info + + if !OpenNebula.is_error?(result) + result = move(source, image['SOURCE']) + + image.enable + end + + return result + end + + private + + FS_UTILS = { + :dd => "env dd", + :mkfs => "env 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) + FileUtils.chmod(0660, source) + rescue Exception => e + return OpenNebula::Error.new(e.message) + end + + return nil + end + + def move(path, source) + if source.nil? or path.nil? + return OpenNebula::Error.new("copy Image: missing parameters.") + end + + begin + FileUtils.move(path, source) + FileUtils.chmod(0660, 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 seek=#{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 + + def remove(source) + if File.exists?(source) + begin + FileUtils.rm(source) + rescue Exception => e + return OpenNebula::Error.new(e.message) + end + end + + return nil + end + end +end \ No newline at end of file diff --git a/src/rm/RequestManager.cc b/src/rm/RequestManager.cc index eef1d2cf52..46685c20c2 100644 --- a/src/rm/RequestManager.cc +++ b/src/rm/RequestManager.cc @@ -312,6 +312,9 @@ void RequestManager::register_xml_methods() xmlrpc_c::methodPtr image_publish(new RequestManager::ImagePublish(ipool, upool)); + xmlrpc_c::methodPtr image_persistent(new + RequestManager::ImagePersistent(ipool, upool)); + xmlrpc_c::methodPtr image_enable(new RequestManager::ImageEnable(ipool, upool)); @@ -368,15 +371,16 @@ void RequestManager::register_xml_methods() /* Image related methods*/ - RequestManagerRegistry.addMethod("one.image.allocate",image_allocate); - RequestManagerRegistry.addMethod("one.image.delete", image_delete); - RequestManagerRegistry.addMethod("one.image.info", image_info); - RequestManagerRegistry.addMethod("one.image.update", image_update); - RequestManagerRegistry.addMethod("one.image.rmattr", image_rm_attribute); - RequestManagerRegistry.addMethod("one.image.publish", image_publish); - RequestManagerRegistry.addMethod("one.image.enable", image_enable); + RequestManagerRegistry.addMethod("one.image.allocate", image_allocate); + RequestManagerRegistry.addMethod("one.image.delete", image_delete); + RequestManagerRegistry.addMethod("one.image.info", image_info); + RequestManagerRegistry.addMethod("one.image.update", image_update); + RequestManagerRegistry.addMethod("one.image.rmattr", image_rm_attribute); + RequestManagerRegistry.addMethod("one.image.publish", image_publish); + RequestManagerRegistry.addMethod("one.image.persistent", image_persistent); + RequestManagerRegistry.addMethod("one.image.enable", image_enable); - RequestManagerRegistry.addMethod("one.imagepool.info", imagepool_info); + RequestManagerRegistry.addMethod("one.imagepool.info", imagepool_info); }; diff --git a/src/rm/RequestManagerImagePersistent.cc b/src/rm/RequestManagerImagePersistent.cc new file mode 100644 index 0000000000..0c4c6322b4 --- /dev/null +++ b/src/rm/RequestManagerImagePersistent.cc @@ -0,0 +1,157 @@ +/* -------------------------------------------------------------------------- */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +#include "RequestManager.h" + +#include "NebulaLog.h" +#include "Nebula.h" + +#include "AuthManager.h" + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void RequestManager::ImagePersistent::execute( + xmlrpc_c::paramList const& paramList, + xmlrpc_c::value * const retval) +{ + string session; + + int iid; + bool persistent_flag; + int uid; + + int image_owner; + bool is_public; + + Image * image; + + ostringstream oss; + + bool response; + + const string method_name = "ImagePersistent"; + + vector arrayData; + xmlrpc_c::value_array * arrayresult; + + + NebulaLog::log("ReM",Log::DEBUG,"ImagePersistent invoked"); + + session = xmlrpc_c::value_string (paramList.getString(0)); + iid = xmlrpc_c::value_int (paramList.getInt(1)); + persistent_flag = xmlrpc_c::value_boolean(paramList.getBoolean(2)); + + // First, we need to authenticate the user + uid = ImagePersistent::upool->authenticate(session); + + if ( uid == -1 ) + { + goto error_authenticate; + } + + // Get image from the ImagePool + image = ImagePersistent::ipool->get(iid,true); + + if ( image == 0 ) + { + goto error_image_get; + } + + image_owner = image->get_uid(); + is_public = image->isPublic(); + + image->unlock(); + + //Authorize the operation + if ( uid != 0 ) // uid == 0 means oneadmin + { + AuthRequest ar(uid); + + ar.add_auth(AuthRequest::IMAGE, + iid, + AuthRequest::MANAGE, + image_owner, + is_public); + + if (UserPool::authorize(ar) == -1) + { + goto error_authorize; + } + } + + // Get the image locked again + image = ImagePersistent::ipool->get(iid,true); + + if ( image == 0 ) + { + goto error_image_get; + } + + response = image->persistent(persistent_flag); + + if (!response) + { + goto error_persistent; + } + + ImagePersistent::ipool->update(image); + + image->unlock(); + + arrayData.push_back(xmlrpc_c::value_boolean(true)); + arrayData.push_back(xmlrpc_c::value_int(iid)); + + // Copy arrayresult into retval mem space + arrayresult = new xmlrpc_c::value_array(arrayData); + *retval = *arrayresult; + + delete arrayresult; // and get rid of the original + + return; + +error_authenticate: + oss.str(authenticate_error(method_name)); + goto error_common; + +error_image_get: + oss.str(get_error(method_name, "IMAGE", iid)); + goto error_common; + +error_authorize: + oss.str(authorization_error(method_name, "MANAGE", "IMAGE", uid, iid)); + goto error_common; + +error_persistent: + oss << action_error(method_name, "MANAGE", "IMAGE", iid, NULL) + << " Is the image public? An Image cannot be public and persistent."; + goto error_common; + +error_common: + arrayData.push_back(xmlrpc_c::value_boolean(false)); // FAILURE + arrayData.push_back(xmlrpc_c::value_string(oss.str())); + + NebulaLog::log("ReM",Log::ERROR,oss); + + xmlrpc_c::value_array arrayresult_error(arrayData); + + *retval = arrayresult_error; + + return; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ diff --git a/src/rm/RequestManagerImagePublish.cc b/src/rm/RequestManagerImagePublish.cc index 9137766983..820b1961c3 100644 --- a/src/rm/RequestManagerImagePublish.cc +++ b/src/rm/RequestManagerImagePublish.cc @@ -38,6 +38,8 @@ void RequestManager::ImagePublish::execute( bool is_public; Image * image; + + bool response; ostringstream oss; @@ -99,7 +101,12 @@ void RequestManager::ImagePublish::execute( goto error_image_get; } - image->publish(publish_flag); + response = image->publish(publish_flag); + + if (!response) + { + goto error_publish; + } ImagePublish::ipool->update(image); @@ -128,6 +135,11 @@ error_authorize: oss.str(authorization_error(method_name, "MANAGE", "IMAGE", uid, iid)); goto error_common; +error_publish: + oss << action_error(method_name, "MANAGE", "IMAGE", iid, NULL) + << " Is the image persistent? An Image cannot be public and persistent."; + goto error_common; + error_common: arrayData.push_back(xmlrpc_c::value_boolean(false)); // FAILURE arrayData.push_back(xmlrpc_c::value_string(oss.str())); diff --git a/src/rm/SConstruct b/src/rm/SConstruct index 8bdf6dc050..42a9da1f83 100644 --- a/src/rm/SConstruct +++ b/src/rm/SConstruct @@ -41,6 +41,7 @@ source_files=[ 'RequestManagerImageUpdate.cc', 'RequestManagerImageRemoveAttribute.cc', 'RequestManagerImagePublish.cc', + 'RequestManagerImagePersistent.cc', 'RequestManagerImageEnable.cc', 'RequestManagerImagePoolInfo.cc', 'RequestManagerClusterAdd.cc', diff --git a/src/vm/VirtualMachine.cc b/src/vm/VirtualMachine.cc index 98bddcaffe..5849c49f70 100644 --- a/src/vm/VirtualMachine.cc +++ b/src/vm/VirtualMachine.cc @@ -815,8 +815,9 @@ int VirtualMachine::get_disk_images() ImagePool * ipool; VectorAttribute * disk; - int n_os = 0; - int n_cd = 0; + int n_os = 0; // Number of OS images + int n_cd = 0; // Number of CDROMS + int n_db = 0; // Number of DATABLOCKS string type; ostringstream oss; @@ -848,6 +849,9 @@ int VirtualMachine::get_disk_images() case Image::CDROM: n_cd++; break; + case Image::DATABLOCK: + n_db++; + break; default: break; } @@ -861,6 +865,11 @@ int VirtualMachine::get_disk_images() { goto error_max_cd; } + + if( n_db > 10 ) // Max. number of DATABLOCK images is 10 + { + goto error_max_db; + } } else if ( rc == -1 ) { @@ -879,6 +888,11 @@ error_max_cd: NebulaLog::log("ONE",Log::ERROR, "VM can not use more than one CDROM image."); goto error_common; + +error_max_db: + NebulaLog::log("ONE",Log::ERROR, + "VM can not use more than 10 DATABLOCK images."); + goto error_common; error_image: NebulaLog::log("ONE",Log::ERROR, "Could not get disk image for VM"); @@ -894,6 +908,7 @@ error_common: void VirtualMachine::release_disk_images() { string iid; + string saveas; int num_disks; vector disks; @@ -929,11 +944,17 @@ void VirtualMachine::release_disk_images() continue; } - if (img->release_image() == true) + img->release_image(); + + saveas = disk->vector_value("SAVE_AS"); + + if ( !saveas.empty() && saveas == iid ) { - ipool->update(img); + img->enable(false); } + ipool->update(img); + img->unlock(); } } diff --git a/src/vm/VirtualMachinePool.cc b/src/vm/VirtualMachinePool.cc index bc1a744c24..6d542ce0f3 100644 --- a/src/vm/VirtualMachinePool.cc +++ b/src/vm/VirtualMachinePool.cc @@ -25,7 +25,8 @@ /* -------------------------------------------------------------------------- */ VirtualMachinePool::VirtualMachinePool(SqlDB * db, - vector hook_mads) + vector hook_mads, + const string& hook_location) : PoolSQL(db,VirtualMachine::table) { const VectorAttribute * vattr; @@ -79,6 +80,11 @@ VirtualMachinePool::VirtualMachinePool(SqlDB * db, } } + if (cmd[0] != '/') + { + cmd = hook_location + cmd; + } + if ( on == "CREATE" ) { VirtualMachineAllocateHook * hook; diff --git a/src/vm/test/VirtualMachinePoolTest.cc b/src/vm/test/VirtualMachinePoolTest.cc index cd3e67e9cd..b46f573be5 100644 --- a/src/vm/test/VirtualMachinePoolTest.cc +++ b/src/vm/test/VirtualMachinePoolTest.cc @@ -88,7 +88,7 @@ class VirtualMachinePoolFriend : public VirtualMachinePool { public: VirtualMachinePoolFriend(SqlDB * db, vector hook_mads): - VirtualMachinePool(db, hook_mads) + VirtualMachinePool(db, hook_mads, "./") {};