diff --git a/include/DispatchManager.h b/include/DispatchManager.h index 482c89cffd..35df649ab4 100644 --- a/include/DispatchManager.h +++ b/include/DispatchManager.h @@ -363,6 +363,56 @@ public: int snap_id, string& error_str); + /** + * Starts the disk snapshot create action + * + * @param vid VirtualMachine identification + * @param did DISK identification + * @param tag Description for the new snapshot + * @param snap_id Will contain the new snapshot ID + * @param error_str Error reason, if any + * + * @return 0 on success, -1 otherwise + */ + int disk_snapshot_create( + int vid, + int did, + const string& tag, + int& snap_id, + string& error_str); + + /** + * Reverts the disk state to a previous snapshot + * + * @param vid VirtualMachine identification + * @param did DISK identification + * @param snap_id Snapshot to be restored + * @param error_str Error reason, if any + * + * @return 0 on success, -1 otherwise + */ + int disk_snapshot_revert( + int vid, + int did, + int snap_id, + string& error_str); + + /** + * Deletes a disk snapshot + * + * @param vid VirtualMachine identification + * @param did DISK identification + * @param snap_id Snapshot to be restored + * @param error_str Error reason, if any + * + * @return 0 on success, -1 otherwise + */ + int disk_snapshot_delete( + int vid, + int did, + int snap_id, + string& error_str); + private: /** * Thread id for the Dispatch Manager diff --git a/include/Image.h b/include/Image.h index 6fb6b977b2..b12f7eac9e 100644 --- a/include/Image.h +++ b/include/Image.h @@ -21,6 +21,7 @@ #include "ImageTemplate.h" #include "NebulaLog.h" #include "ObjectCollection.h" +#include "Snapshots.h" using namespace std; @@ -96,16 +97,16 @@ public: { switch (ob) { - case FILE: return "FILE" ; break; - case CD_ROM: return "CDROM" ; break; - case BLOCK: return "BLOCK" ; break; - case RBD: return "RBD" ; break; - case RBD_CDROM: return "RBD_CDROM" ; break; - case GLUSTER: return "GLUSTER" ; break; - case GLUSTER_CDROM: return "GLUSTER_CDROM" ; break; - case SHEEPDOG: return "SHEEPDOG" ; break; - case SHEEPDOG_CDROM: return "SHEEPDOG_CDROM" ; break; - default: return ""; + case FILE: return "FILE" ; break; + case CD_ROM: return "CDROM" ; break; + case BLOCK: return "BLOCK" ; break; + case RBD: return "RBD" ; break; + case RBD_CDROM: return "RBD_CDROM" ; break; + case GLUSTER: return "GLUSTER" ; break; + case GLUSTER_CDROM: return "GLUSTER_CDROM" ; break; + case SHEEPDOG: return "SHEEPDOG" ; break; + case SHEEPDOG_CDROM: return "SHEEPDOG_CDROM" ; break; + default: return ""; } }; @@ -177,7 +178,7 @@ public: * Returns true if the image is persistent * @return true if the image is persistent */ - bool isPersistent() const + bool is_persistent() const { return (persistent_img == 1); }; @@ -218,6 +219,7 @@ public: return size_mb; } + /** * Sets the source path of the image */ @@ -344,37 +346,15 @@ public: * @param _type the new type. It will be transformed to upper case * @return 0 on success, -1 otherwise */ - int set_type(string& _type); - - /** - * Check if the image can be used by other users - * @return true if group or others can access the image - */ - bool isPublic() - { - return (group_u == 1 || other_u == 1); - } + int set_type(string& _type, string& error); /** * Check if the image is used for saving_as a current one * @return true if the image will be used to save an existing image. */ - bool isSaving() + bool is_saving() { - ImageTemplate * it = static_cast(obj_template); - - return it->is_saving(); - } - - /** - * Check if the image is a hot snapshot - * @return true if image is a hot snapshot - */ - bool isHot() - { - ImageTemplate * it = static_cast(obj_template); - - return it->is_saving_hot(); + return (static_cast(obj_template))->is_saving(); } /** @@ -388,13 +368,20 @@ public: { ostringstream oss; + if ((snapshots.size() > 0) && !persis) + { + error_str = "Image has snapshots."; + return -1; + } + switch(state) { case USED: case CLONE: case USED_PERS: - goto error_state; - break; + oss << "Image cannot be in state " << state_to_str(state) <<"."; + error_str = oss.str(); + return -1; case INIT: case READY: @@ -415,16 +402,6 @@ public: } return 0; - - error_state: - oss << "Image cannot be in state " << state_to_str(state) << "."; - error_str = oss.str(); - - goto error_common; - - error_common: - return -1; - } /** @@ -486,6 +463,60 @@ public: */ ImageTemplate * clone_template(const string& new_name) const; + /* ---------------------------------------------------------------------- */ + /* Snapshots functions */ + /* ---------------------------------------------------------------------- */ + /** + * Return the snapshot list of this image + */ + const Snapshots& get_snapshots() const + { + return snapshots; + }; + + /** + * Clear all the snapshots in the list + */ + void clear_snapshots() + { + snapshots.clear(); + } + + /** + * Set the snapshots for this image + * @param snapshot list + */ + void set_snapshots(const Snapshots& s) + { + snapshots = s; + snapshots.clear_disk_id(); + }; + + void delete_snapshot(int snap_id) + { + snapshots.delete_snapshot(snap_id); + }; + + void revert_snapshot(int snap_id) + { + snapshots.active_snapshot(snap_id); + }; + + void set_target_snapshot(int snap_id) + { + target_snapshot = snap_id; + }; + + int get_target_snapshot() + { + return target_snapshot; + }; + + void clear_target_snapshot() + { + target_snapshot = -1; + }; + private: // ------------------------------------------------------------------------- @@ -579,6 +610,16 @@ private: */ ObjectCollection img_clone_collection; + /** + * Snapshot list for this image + */ + Snapshots snapshots; + + /** + * ID of the snapshot being processed (if any) + */ + int target_snapshot; + // ************************************************************************* // DataBase implementation (Private) // ************************************************************************* diff --git a/include/ImageManager.h b/include/ImageManager.h index 57d4c27060..a12ece2ed1 100644 --- a/include/ImageManager.h +++ b/include/ImageManager.h @@ -26,6 +26,7 @@ using namespace std; extern "C" void * image_action_loop(void *arg); class Image; +class Snapshots; class Template; class ImageManager : public MadManager, public ActionListener @@ -189,6 +190,42 @@ public: */ void monitor_datastore(int ds_id); + /** + * Set the snapshots for the given image. The image MUST be persistent + * and of type OS or DATABLOCK. + * @param iid id of image + * @param s snapshot list + * @param failed the associated VM releasing the images is FAILED + */ + void set_image_snapshots(int iid, const Snapshots& s, bool failed); + + /** + * Deletes the snapshot of an image + * @param iid id of image + * @param sid id of the snapshot + * @param error_str Error reason, if any + * @return 0 on success + */ + int delete_snapshot(int iid, int sid, string& error); + + /** + * Reverts image state to a previous snapshot + * @param iid id of image + * @param sid id of the snapshot + * @param error_str Error reason, if any + * @return 0 on success + */ + int revert_snapshot(int iid, int sid, string& error); + + /** + * Flattens ths snapshot by commiting changes to base image. + * @param iid id of image + * @param sid id of the snapshot + * @param error_str Error reason, if any + * @return 0 on success + */ + int flatten_snapshot(int iid, int sid, string& error); + private: /** * Generic name for the Image driver diff --git a/include/ImageManagerDriver.h b/include/ImageManagerDriver.h index b1cd750741..2e00397cbf 100644 --- a/include/ImageManagerDriver.h +++ b/include/ImageManagerDriver.h @@ -114,6 +114,27 @@ private: * @param drv_msg xml data for the mad operation. */ void monitor(int oid, const string& drv_msg) const; + + /** + * Sends a delete snapshot command: "SNAP_DELETE DS_ID DS_XML" + * @param oid the datastore id. + * @param drv_msg xml data for the mad operation. + */ + void snapshot_delete(int oid, const string& drv_msg) const; + + /** + * Sends a revert snapshot command: "SNAP_REVERT DS_ID DS_XML" + * @param oid the datastore id. + * @param drv_msg xml data for the mad operation. + */ + void snapshot_revert(int oid, const string& drv_msg) const; + + /** + * Sends a flatten snapshot command: "SNAP_FLATTEN DS_ID DS_XML" + * @param oid the datastore id. + * @param drv_msg xml data for the mad operation. + */ + void snapshot_flatten(int oid, const string& drv_msg) const; }; /* -------------------------------------------------------------------------- */ diff --git a/include/ImagePool.h b/include/ImagePool.h index 52d932d86b..5c35b0842d 100644 --- a/include/ImagePool.h +++ b/include/ImagePool.h @@ -29,6 +29,7 @@ #include class AuthRequest; +class Snapshots; using namespace std; @@ -158,6 +159,7 @@ public: * or the default one * @param uid of VM owner (to look for the image id within its images) * @param image_id on success returns the acquired image id + * @param snaps list of snapshots associated to this image * @param error_str string describing the error * * @return 0 on success, -1 otherwise @@ -169,6 +171,7 @@ public: string& dev_prefix, int uid, int& image_id, + Snapshots ** snaps, string& error_str); /** * Generates an Authorization token for the DISK attribute diff --git a/include/ImageTemplate.h b/include/ImageTemplate.h index fc117061b3..6391161c67 100644 --- a/include/ImageTemplate.h +++ b/include/ImageTemplate.h @@ -61,43 +61,16 @@ public: bool is_saving() { - string saving; + bool save_as_hot; - get(saving_attribute, saving); + get("SAVE_AS_HOT", save_as_hot); - return (saving.empty() == false); - } - - bool is_saving_hot() - { - string save_as_hot; - - get(saving_hot_attribute, save_as_hot); - - return (save_as_hot.empty() == false); + return save_as_hot; } void set_saving() { - SingleAttribute * attr= new SingleAttribute(saving_attribute, "YES"); - - erase(saving_attribute); - - set(attr); - } - - void set_saving_hot() - { - SingleAttribute * attr = new SingleAttribute(saving_hot_attribute,"YES"); - - erase(saving_hot_attribute); - - set(attr); - } - - void unset_saving() - { - erase(saving_attribute); + replace("SAVE_AS_HOT", "YES"); } private: @@ -105,9 +78,6 @@ private: static vector restricted_attributes; - static string saving_attribute; - static string saving_hot_attribute; - bool has_restricted() { return restricted_attributes.size() > 0; diff --git a/include/LifeCycleManager.h b/include/LifeCycleManager.h index a310a598c4..a98f925986 100644 --- a/include/LifeCycleManager.h +++ b/include/LifeCycleManager.h @@ -75,14 +75,16 @@ public: DETACH_NIC_FAILURE,/**< Sent by the VMM when a detach nic action fails */ CLEANUP_SUCCESS, /**< Sent by the VMM when a cleanup action succeeds */ CLEANUP_FAILURE, /**< Sent by the VMM when a cleanup action fails */ - SAVEAS_HOT_SUCCESS,/**< Sent by the VMM when hot saveas succeeds */ - SAVEAS_HOT_FAILURE,/**< Sent by the VMM when hot saveas fails */ + SAVEAS_SUCCESS, /**< Sent by the VMM when saveas succeeds */ + SAVEAS_FAILURE, /**< Sent by the VMM when saveas fails */ SNAPSHOT_CREATE_SUCCESS, /**< Sent by the VMM on snap. create success */ SNAPSHOT_CREATE_FAILURE, /**< Sent by the VMM on snap. create failure */ SNAPSHOT_REVERT_SUCCESS, /**< Sent by the VMM on snap. revert success */ SNAPSHOT_REVERT_FAILURE, /**< Sent by the VMM on snap. revert failure */ SNAPSHOT_DELETE_SUCCESS, /**< Sent by the VMM on snap. revert success */ SNAPSHOT_DELETE_FAILURE, /**< Sent by the VMM on snap. revert failure */ + DISK_SNAPSHOT_SUCCESS, /** +#include +#include + +#include + +#include "Template.h" + +using namespace std; + +class VectorAttribute; + +/** + * This class represents a list of Snapshots associated to an image or Virtual + * Machine Disk. The list is in the form: + * + * : of the disk the snapshots are taken from (the initial backing) + * : the current snapshot in use by the VM. 0 for the original DISK + * + * + * : Description + * : the snapshot was taken + * : backing for this snapshot, -1 for the original image + * : comma separated list of children snapshots + */ +class Snapshots +{ +public: + Snapshots(int _disk_id); + + Snapshots(const Snapshots& s); + + Snapshots& operator= (const Snapshots& s); + + virtual ~Snapshots(); + + // ************************************************************************* + // Inititalization functions + // ************************************************************************* + + /** + * Builds the snapshot list from its XML representation. This function + * is used when importing it from the DB. + * @param node xmlNode for the template + * @return 0 on success + */ + int from_xml_node(const xmlNodePtr node); + + /** + * XML Representation of the Snapshots + */ + string& to_xml(string& xml) const + { + return snapshot_template.to_xml(xml); + }; + + /** + * Creates a new (empty) snapshot of the active disk + * @param tag description of this snapshot (optional) + * @return id of the new snapshot + */ + int create_snapshot(const string& tag); + + /** + * Check if an snapshot can be deleted (no children, no active) + * @param id of the snapshot + * @param error if any + * @return true if can be deleted, false otherwise + */ + bool test_delete(unsigned int id, string& error) const; + + /** + * Removes the snapshot from the list + * @param id of the snapshot + */ + void delete_snapshot(unsigned int id); + + /** + * Set the given snapshot as active. Updates the values of the current + * snapshot + */ + int active_snapshot(unsigned int id); + + /** + * Clear all the snapshots in the list + */ + void clear() + { + next_snapshot = 0; + active = -1; + disk_id = -1; + + snapshot_template.clear(); + snapshot_pool.clear(); + } + + /** + * Return the disk_id of the snapshot list + */ + int get_disk_id() const + { + return disk_id; + } + + /** + * Return the active snapshot id + */ + int get_active_id() const + { + return active; + } + + /** + * Removes the DISK_ID attribute to link the list to an Image + */ + void clear_disk_id() + { + disk_id = -1; + snapshot_template.erase("DISK_ID"); + }; + + /** + * Sets the disk id for this snapshot list + * @param did the id + */ + void set_disk_id(int did) + { + disk_id = did; + snapshot_template.replace("DISK_ID", did); + }; + + /** + * @return number of snapshots in the list + */ + unsigned int size() const + { + return snapshot_pool.size(); + }; + + /** + * Check if snapshot exists + * @param snap_id of the snapshot + * @return true if the snapshot with snap_id exisits + */ + bool exists(int snap_id) const + { + const VectorAttribute * snap = get_snapshot(snap_id); + + return (snap != 0); + } + + /** + * Get Attribute from the given snapshot + * @param id of the snapshot + * @param name of the attribute + * + * @return value or empty if not found + */ + string get_snapshot_attribute(unsigned int id, const char* name); + +private: + + /** + * Get a snapshot from the pool + * @param id of the snapshot + * @return pointer to the snapshot (VectorAttribute) or null + */ + const VectorAttribute * get_snapshot(unsigned int id) const; + + VectorAttribute * get_snapshot(unsigned int id) + { + return const_cast( + static_cast(*this).get_snapshot(id)); + }; + + /** + * Build the object internal representation from an initialized + * template + */ + void init(); + + /** + * Text representation of the snapshot pool. To be stored as part of the + * VM or Image Templates + */ + Template snapshot_template; + + /** + * Next id + */ + unsigned int next_snapshot; + + /** + * Id of the active (current) snapshot, 0 represents the base image + */ + int active; + + /** + * Id of the disk associated with this snapshot list + */ + unsigned int disk_id; + + /** + * Snapshot pointer map + */ + map snapshot_pool; +}; + +#endif /*SNAPSHOTS_H_*/ diff --git a/include/Template.h b/include/Template.h index d368d41fcf..ae07a846b2 100644 --- a/include/Template.h +++ b/include/Template.h @@ -55,12 +55,35 @@ public: separator = t.separator; xml_root = t.xml_root; + attributes.clear(); + for (it = t.attributes.begin() ; it != t.attributes.end() ; it++) { attributes.insert(make_pair(it->first,(it->second)->clone())); } } + Template& operator=(const Template& t) + { + multimap::const_iterator it; + + if (this != &t) + { + replace_mode = t.replace_mode; + separator = t.separator; + xml_root = t.xml_root; + + attributes.clear(); + + for (it = t.attributes.begin() ; it != t.attributes.end() ; it++) + { + attributes.insert(make_pair(it->first,(it->second)->clone())); + } + } + + return *this; + } + /** * The class destructor frees all the attributes conforming the template */ @@ -127,6 +150,11 @@ public: */ string& to_str(string& str) const; + /** + * Clears all the attributes from the template + */ + void clear(); + /** * Sets a new attribute, the attribute MUST BE ALLOCATED IN THE HEAP, and * will be freed when the template destructor is called. diff --git a/include/TransferManager.h b/include/TransferManager.h index 7fbf7a3ffd..aa3255f6ce 100644 --- a/include/TransferManager.h +++ b/include/TransferManager.h @@ -60,6 +60,9 @@ public: CHECKPOINT, DRIVER_CANCEL, SAVEAS_HOT, + SNAPSHOT_CREATE, + SNAPSHOT_REVERT, + SNAPSHOT_DELETE, FINALIZE }; @@ -325,6 +328,26 @@ private: * This function starts the saveas of the given disk */ void saveas_hot_action(int vid); + + /** + * This function performs a generic snapshot action + */ + void do_snapshot_action(int vid, const char * action); + + /** + * This function takes an snapshot of a disk + */ + void snapshot_create_action(int vid); + + /** + * This function takes an snapshot of a disk + */ + void snapshot_revert_action(int vid); + + /** + * This function deletes an snapshot of a disk + */ + void snapshot_delete_action(int vid); }; #endif /*TRANSFER_MANAGER_H*/ diff --git a/include/UserPool.h b/include/UserPool.h index b94682c336..484f030b3d 100644 --- a/include/UserPool.h +++ b/include/UserPool.h @@ -187,11 +187,6 @@ public: */ static const char * PUBLIC_AUTH; - /** - * Name for the default auth driver to be used for not registered users - */ - static const char * DEFAULT_AUTH; - /** * Name for the default Sunstone server user */ diff --git a/include/VirtualMachine.h b/include/VirtualMachine.h index 37ece6f3cc..2ca85bfa57 100644 --- a/include/VirtualMachine.h +++ b/include/VirtualMachine.h @@ -32,6 +32,7 @@ using namespace std; class AuthRequest; +class Snapshots; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ @@ -154,7 +155,10 @@ public: BOOT_UNDEPLOY_FAILURE = 47, BOOT_STOPPED_FAILURE = 48, PROLOG_RESUME_FAILURE = 49, - PROLOG_UNDEPLOY_FAILURE = 50 + PROLOG_UNDEPLOY_FAILURE = 50, + DISK_SNAPSHOT_POWEROFF = 51, + DISK_SNAPSHOT_REVERT_POWEROFF = 52, + DISK_SNAPSHOT_DELETE_POWEROFF = 53 }; static int lcm_state_from_str(string& st, LcmState& state) @@ -210,6 +214,9 @@ public: else if ( st == "BOOT_UNDEPLOY_FAILURE") { state = BOOT_UNDEPLOY_FAILURE; } else if ( st == "PROLOG_RESUME_FAILURE") { state = PROLOG_RESUME_FAILURE; } else if ( st == "PROLOG_UNDEPLOY_FAILURE") { state = PROLOG_UNDEPLOY_FAILURE; } + else if ( st == "DISK_SNAPSHOT_POWEROFF") { state = DISK_SNAPSHOT_POWEROFF; } + else if ( st == "DISK_SNAPSHOT_REVERT_POWEROFF") { state = DISK_SNAPSHOT_REVERT_POWEROFF; } + else if ( st == "DISK_SNAPSHOT_DELETE_POWEROFF") { state = DISK_SNAPSHOT_DELETE_POWEROFF; } else {return -1;} return 0; @@ -268,6 +275,9 @@ public: case BOOT_UNDEPLOY_FAILURE: st = "BOOT_UNDEPLOY_FAILURE"; break; case PROLOG_RESUME_FAILURE: st = "PROLOG_RESUME_FAILURE"; break; case PROLOG_UNDEPLOY_FAILURE: st = "PROLOG_UNDEPLOY_FAILURE"; break; + case DISK_SNAPSHOT_POWEROFF: st = "DISK_SNAPSHOT_POWEROFF"; break; + case DISK_SNAPSHOT_REVERT_POWEROFF: st = "DISK_SNAPSHOT_REVERT_POWEROFF"; break; + case DISK_SNAPSHOT_DELETE_POWEROFF: st = "DISK_SNAPSHOT_DELETE_POWEROFF"; break; } return st; @@ -1260,82 +1270,56 @@ public: int generate_context(string &files, int &disk_id, string& token_password); // ------------------------------------------------------------------------- - // Datastore related functions + // "Save as" Disk related functions (save_as hot) // ------------------------------------------------------------------------- /** - * Gest the associated image to the given disk_id + * Mark the disk that is going to be "save as" * @param disk_id of the VM - * @param hot is this a save_as hot operation + * @param snap_id of the disk to save, -1 to select the active snapshot * @param err_str describing the error - * @return -1 if the image cannot saveas + * @return -1 if the image cannot saveas or image_id of current disk */ - int get_image_from_disk(int disk_id, bool hot, string& err_str); + int set_saveas_disk(int disk_id, int snap_id, string& err_str); /** - * Sets the corresponding SAVE_AS state. + * Set save attributes for the disk * @param disk_id Index of the disk to save - * @param hot is this a save_as hot operation - * @return 0 if the VM can be saved as + * @param source to save the disk + * @param img_id ID of the image this disk will be saved to */ - int set_saveas_state(int disk_id, bool hot); + int set_saveas_disk(int disk_id, const string& source, int img_id); /** - * Clears the SAVE_AS state, moving the VM to the original state. - * @param disk_id Index of the disk to save - * @param hot is this a save_as hot operation - * @return 0 if the VM was in a SAVE_AS state + * Sets the corresponding state to save the disk. + * @return 0 if the VM can be saved */ - int clear_saveas_state(int disk_id, bool hot); + int set_saveas_state(); /** - * Set the SAVE_AS attribute for the "disk_id"th disk. - * @param disk_id Index of the disk to save - * @param source to save the disk (SAVE_AS_SOURCE) - * @param img_id ID of the image this disk will be saved to (SAVE_AS). + * Clears the save state, moving the VM to the original state. + * @return 0 if the VM was in an saveas state */ - int save_disk(int disk_id, - const string& source, - int img_id); - /** - * Clears the SAVE_AS attribute for the "disk_id"th disk. - * @param disk_id Index of the disk to save - * @return 0 on success, -1 if the disk does not exist - */ - int clear_save_disk(int disk_id); + int clear_saveas_state(); /** - * Returns the image ID to be saved-as. - * @param disk_id Index of the disk to save - * @return The image ID, or -1 if the disk is not going to be saved-as + * Clears the SAVE_AS_* attributes of the disk being saved as + * @return the ID of the image this disk will be saved to or -1 if it + * is not found. */ - int get_save_disk_image(int disk_id); + int clear_saveas_disk(); - /** - * Set the SAVE_AS attribute for the "disk_id"th disk. - * @param disk_id Index of the disk to save - * @param source to save the disk (SAVE_AS_SOURCE) - * @param img_id ID of the image this disk will be saved to (SAVE_AS). - */ - int save_disk_hot(int disk_id, - const string& source, - int img_id); /** * Get the original image id of the disk. It also checks that the disk can * be saved_as. * @param disk_id Index of the disk to save - * @param error_str describes the error + * @param source of the image to save the disk to + * @param image_id of the image to save the disk to + * @param tm_mad in use by the disk + * @param ds_id of the datastore in use by the disk * @return -1 if failure */ - int get_saveas_disk_hot(int& disk_id, string& source, int& image_id); - - /** - * Clears the save_as attributes of the disk being (hot) saved as - * - * @param img_id ID of the image this disk will be saved to. Can be - * -1 if it is not found - * @return 0 if a disk with (HOTPLUG_)SAVE_AS was cleaned - */ - int cancel_saveas_disk(int& image_id); + int get_saveas_disk(int& disk_id, string& source, int& image_id, + string& snap_id, string& tm_mad, string& ds_id); // ------------------------------------------------------------------------ // Authorization related functions @@ -1388,6 +1372,7 @@ public: int max_disk_id, int uid, int& image_id, + Snapshots ** snap, string& error_str); /** * Returns the disk that is waiting for an attachment action @@ -1406,18 +1391,27 @@ public: * * @return the DISK or 0 if no disk was deleted */ - VectorAttribute * delete_attach_disk(); + VectorAttribute * delete_attach_disk(Snapshots **snap); /** * Adds a new disk to the virtual machine template. The disk should be * generated by the build_attach_disk * @param new_disk must be allocated in the heap + * @param snap list of snapshots associated to the disk */ - void set_attach_disk(VectorAttribute * new_disk) + void set_attach_disk(VectorAttribute * new_disk, Snapshots * snap) { new_disk->replace("ATTACH", "YES"); obj_template->set(new_disk); + + if (snap != 0) + { + int disk_id; + + new_disk->vector_value("DISK_ID", disk_id); + snapshots.insert(pair(disk_id, snap)); + } } /** @@ -1495,6 +1489,64 @@ public: */ int set_attach_nic(int nic_id); + // ------------------------------------------------------------------------ + // Snapshot related functions + // ------------------------------------------------------------------------ + + /** + * Return the snapshot list for the disk + * @param disk_id of the disk + * @param error if any + * @return pointer to Snapshots or 0 if not found + */ + const Snapshots * get_disk_snapshots(int did, string& err) const; + + /** + * Creates a new snapshot of the given disk + * @param disk_id of the disk + * @param tag a description for this snapshot + * @param error if any + * @return the id of the new snapshot or -1 if error + */ + int new_disk_snapshot(int disk_id, const string& tag, string& error); + + /** + * Sets the snap_id as active, the VM will boot from it next time + * @param disk_id of the disk + * @param snap_id of the snapshot + * @param error if any + * @return -1 if error + */ + int revert_disk_snapshot(int disk_id, int snap_id); + + /** + * Deletes the snap_id from the list, test_delete_disk_snapshot *MUST* be + * called before actually deleting the snapshot. + * @param disk_id of the disk + * @param snap_id of the snapshot + */ + void delete_disk_snapshot(int disk_id, int snap_id); + + /** + * Get information about the disk to take the snapshot from + * @param ds_id id of the datastore + * @param tm_mad used by the datastore + * @param disk_id of the disk + * @param snap_id of the snapshot + */ + int get_snapshot_disk(string& ds_id, string& tm_mad, string& disk_id, + string& snap_id); + /** + * Unset the current disk being snapshotted (reverted...) + */ + void clear_snapshot_disk(); + + /** + * Set the disk as being snapshotted (reverted...) + * @param disk_id of the disk + * @param snap_id of the target snap_id + */ + int set_snapshot_disk(int disk_id, int snap_id); // ------------------------------------------------------------------------ // Snapshot related functions @@ -1651,6 +1703,11 @@ private: */ vector history_records; + /** + * Snapshots for each disk + */ + map snapshots; + // ------------------------------------------------------------------------- // Logging & Dirs // ------------------------------------------------------------------------- @@ -1797,12 +1854,12 @@ private: */ int parse_defaults(string& error_str); - /** + /** * Known attributes for network contextualization rendered as: * ETH__ = $NETWORK[context[1], vnet_name] * - * The context[1] values in the map are searched in the NIC and - * if not found in the AR and VNET. They can be also set in the + * The context[1] values in the map are searched in the NIC and + * if not found in the AR and VNET. They can be also set in the * CONTEXT section it self using full name (ETH_). * * IPv4 context variables: @@ -1924,6 +1981,19 @@ private: */ int get_disk_images(string &error_str); + /** + * Return the VectorAttribute representation of a disk + * @param disk_id of the disk + * @return pointer to the VectorAttribute + */ + VectorAttribute* get_disk(int disk_id) + { + return const_cast( + static_cast(*this).get_disk(disk_id)); + }; + + const VectorAttribute* get_disk(int disk_id) const; + protected: //************************************************************************** @@ -1998,11 +2068,6 @@ protected: return -1; } - // ************************************************************************* - // Helpers - // ************************************************************************* - - VectorAttribute* get_disk(int disk_id); }; #endif /*VIRTUAL_MACHINE_H_*/ diff --git a/include/VirtualMachinePool.h b/include/VirtualMachinePool.h index 5b260a3424..a819020292 100644 --- a/include/VirtualMachinePool.h +++ b/include/VirtualMachinePool.h @@ -344,10 +344,8 @@ public: * Images and updates usage quotas * * @param vid VM id - * @param release_save_as true to release non-persistent images - * in the detach event */ - void delete_attach_disk(int vid, bool release_save_as); + void delete_attach_disk(int vid); /** * Deletes the NIC that was in the process of being attached diff --git a/install.sh b/install.sh index d29e734f5f..982a871b3e 100755 --- a/install.sh +++ b/install.sh @@ -1018,7 +1018,11 @@ TM_SHARED_FILES="src/tm_mad/shared/clone \ src/tm_mad/shared/context \ src/tm_mad/shared/premigrate \ src/tm_mad/shared/postmigrate \ + src/tm_mad/shared/failmigrate \ src/tm_mad/shared/mvds \ + src/tm_mad/shared/snap_create \ + src/tm_mad/shared/snap_delete \ + src/tm_mad/shared/snap_revert \ src/tm_mad/shared/cpds" TM_FS_LVM_FILES="src/tm_mad/fs_lvm/clone \ @@ -1028,6 +1032,10 @@ TM_FS_LVM_FILES="src/tm_mad/fs_lvm/clone \ src/tm_mad/fs_lvm/cpds \ src/tm_mad/fs_lvm/premigrate \ src/tm_mad/fs_lvm/postmigrate \ + src/tm_mad/fs_lvm/snap_create \ + src/tm_mad/fs_lvm/snap_delete \ + src/tm_mad/fs_lvm/snap_revert \ + src/tm_mad/fs_lvm/failmigrate \ src/tm_mad/fs_lvm/delete" TM_QCOW2_FILES="src/tm_mad/qcow2/clone \ @@ -1039,7 +1047,11 @@ TM_QCOW2_FILES="src/tm_mad/qcow2/clone \ src/tm_mad/qcow2/context \ src/tm_mad/qcow2/premigrate \ src/tm_mad/qcow2/postmigrate \ + src/tm_mad/qcow2/failmigrate \ src/tm_mad/qcow2/mvds \ + src/tm_mad/qcow2/snap_create \ + src/tm_mad/qcow2/snap_delete \ + src/tm_mad/qcow2/snap_revert \ src/tm_mad/qcow2/cpds" TM_SSH_FILES="src/tm_mad/ssh/clone \ @@ -1051,7 +1063,11 @@ TM_SSH_FILES="src/tm_mad/ssh/clone \ src/tm_mad/ssh/context \ src/tm_mad/ssh/premigrate \ src/tm_mad/ssh/postmigrate \ + src/tm_mad/ssh/failmigrate \ src/tm_mad/ssh/mvds \ + src/tm_mad/ssh/snap_create \ + src/tm_mad/ssh/snap_delete \ + src/tm_mad/ssh/snap_revert \ src/tm_mad/ssh/cpds" TM_DUMMY_FILES="src/tm_mad/dummy/clone \ @@ -1063,7 +1079,11 @@ TM_DUMMY_FILES="src/tm_mad/dummy/clone \ src/tm_mad/dummy/context \ src/tm_mad/dummy/premigrate \ src/tm_mad/dummy/postmigrate \ + src/tm_mad/dummy/failmigrate \ src/tm_mad/dummy/mvds \ + src/tm_mad/dummy/snap_create \ + src/tm_mad/dummy/snap_delete \ + src/tm_mad/dummy/snap_revert \ src/tm_mad/dummy/cpds" TM_VMFS_FILES="src/tm_mad/vmfs/clone \ @@ -1076,6 +1096,10 @@ TM_VMFS_FILES="src/tm_mad/vmfs/clone \ src/tm_mad/vmfs/mvds \ src/tm_mad/vmfs/cpds \ src/tm_mad/vmfs/postmigrate \ + src/tm_mad/vmfs/snap_create \ + src/tm_mad/vmfs/snap_delete \ + src/tm_mad/vmfs/snap_revert \ + src/tm_mad/vmfs/failmigrate \ src/tm_mad/vmfs/premigrate" TM_LVM_FILES="src/tm_mad/lvm/clone \ @@ -1085,6 +1109,10 @@ TM_LVM_FILES="src/tm_mad/lvm/clone \ src/tm_mad/lvm/cpds \ src/tm_mad/lvm/premigrate \ src/tm_mad/lvm/postmigrate \ + src/tm_mad/lvm/snap_create \ + src/tm_mad/lvm/snap_delete \ + src/tm_mad/lvm/snap_revert \ + src/tm_mad/lvm/failmigrate \ src/tm_mad/lvm/delete" TM_CEPH_FILES="src/tm_mad/ceph/clone \ @@ -1094,6 +1122,10 @@ TM_CEPH_FILES="src/tm_mad/ceph/clone \ src/tm_mad/ceph/cpds \ src/tm_mad/ceph/premigrate \ src/tm_mad/ceph/postmigrate \ + src/tm_mad/ceph/snap_create \ + src/tm_mad/ceph/snap_delete \ + src/tm_mad/ceph/snap_revert \ + src/tm_mad/ceph/failmigrate \ src/tm_mad/ceph/delete" TM_DEV_FILES="src/tm_mad/dev/clone \ @@ -1103,6 +1135,10 @@ TM_DEV_FILES="src/tm_mad/dev/clone \ src/tm_mad/dev/cpds \ src/tm_mad/dev/premigrate \ src/tm_mad/dev/postmigrate \ + src/tm_mad/dev/snap_create \ + src/tm_mad/dev/snap_delete \ + src/tm_mad/dev/snap_revert \ + src/tm_mad/dev/failmigrate \ src/tm_mad/dev/delete" #------------------------------------------------------------------------------- @@ -1122,6 +1158,9 @@ DATASTORE_DRIVER_DUMMY_SCRIPTS="src/datastore_mad/remotes/dummy/cp \ src/datastore_mad/remotes/dummy/stat \ src/datastore_mad/remotes/dummy/clone \ src/datastore_mad/remotes/dummy/monitor \ + src/datastore_mad/remotes/dummy/snap_delete \ + src/datastore_mad/remotes/dummy/snap_revert \ + src/datastore_mad/remotes/dummy/snap_flatten \ src/datastore_mad/remotes/dummy/rm" DATASTORE_DRIVER_FS_SCRIPTS="src/datastore_mad/remotes/fs/cp \ @@ -1129,6 +1168,9 @@ DATASTORE_DRIVER_FS_SCRIPTS="src/datastore_mad/remotes/fs/cp \ src/datastore_mad/remotes/fs/stat \ src/datastore_mad/remotes/fs/clone \ src/datastore_mad/remotes/fs/monitor \ + src/datastore_mad/remotes/fs/snap_delete \ + src/datastore_mad/remotes/fs/snap_revert \ + src/datastore_mad/remotes/fs/snap_flatten \ src/datastore_mad/remotes/fs/rm" DATASTORE_DRIVER_VMFS_SCRIPTS="src/datastore_mad/remotes/vmfs/cp \ @@ -1137,6 +1179,9 @@ DATASTORE_DRIVER_VMFS_SCRIPTS="src/datastore_mad/remotes/vmfs/cp \ src/datastore_mad/remotes/vmfs/clone \ src/datastore_mad/remotes/vmfs/monitor \ src/datastore_mad/remotes/vmfs/rm \ + src/datastore_mad/remotes/vmfs/snap_delete \ + src/datastore_mad/remotes/vmfs/snap_revert \ + src/datastore_mad/remotes/vmfs/snap_flatten \ src/datastore_mad/remotes/vmfs/vmfs.conf" DATASTORE_DRIVER_LVM_SCRIPTS="src/datastore_mad/remotes/lvm/cp \ @@ -1145,6 +1190,9 @@ DATASTORE_DRIVER_LVM_SCRIPTS="src/datastore_mad/remotes/lvm/cp \ src/datastore_mad/remotes/lvm/rm \ src/datastore_mad/remotes/lvm/monitor \ src/datastore_mad/remotes/lvm/clone \ + src/datastore_mad/remotes/lvm/snap_delete \ + src/datastore_mad/remotes/lvm/snap_revert \ + src/datastore_mad/remotes/lvm/snap_flatten \ src/datastore_mad/remotes/lvm/lvm.conf" DATASTORE_DRIVER_CEPH_SCRIPTS="src/datastore_mad/remotes/ceph/cp \ @@ -1153,6 +1201,9 @@ DATASTORE_DRIVER_CEPH_SCRIPTS="src/datastore_mad/remotes/ceph/cp \ src/datastore_mad/remotes/ceph/rm \ src/datastore_mad/remotes/ceph/monitor \ src/datastore_mad/remotes/ceph/clone \ + src/datastore_mad/remotes/ceph/snap_delete \ + src/datastore_mad/remotes/ceph/snap_revert \ + src/datastore_mad/remotes/ceph/snap_flatten \ src/datastore_mad/remotes/ceph/ceph.conf" DATASTORE_DRIVER_DEV_SCRIPTS="src/datastore_mad/remotes/dev/cp \ @@ -1160,6 +1211,9 @@ DATASTORE_DRIVER_DEV_SCRIPTS="src/datastore_mad/remotes/dev/cp \ src/datastore_mad/remotes/dev/stat \ src/datastore_mad/remotes/dev/rm \ src/datastore_mad/remotes/dev/monitor \ + src/datastore_mad/remotes/dev/snap_delete \ + src/datastore_mad/remotes/dev/snap_revert \ + src/datastore_mad/remotes/dev/snap_flatten \ src/datastore_mad/remotes/dev/clone" #------------------------------------------------------------------------------- diff --git a/share/doc/xsd/acct.xsd b/share/doc/xsd/acct.xsd index 3df22ebf4a..9b1b9d1870 100644 --- a/share/doc/xsd/acct.xsd +++ b/share/doc/xsd/acct.xsd @@ -163,7 +163,10 @@ BOOT_UNDEPLOY_FAILURE = 47, BOOT_STOPPED_FAILURE = 48, PROLOG_RESUME_FAILURE = 49, - PROLOG_UNDEPLOY_FAILURE = 50 + PROLOG_UNDEPLOY_FAILURE = 50, + DISK_SNAPSHOT_POWEROFF = 51, + DISK_SNAPSHOT_REVERT_POWEROFF = 52, + DISK_SNAPSHOT_DELETE_POWEROFF = 53 --> diff --git a/share/doc/xsd/vm.xsd b/share/doc/xsd/vm.xsd index f201a1e7ea..fb37186bf9 100644 --- a/share/doc/xsd/vm.xsd +++ b/share/doc/xsd/vm.xsd @@ -96,7 +96,10 @@ BOOT_UNDEPLOY_FAILURE = 47, BOOT_STOPPED_FAILURE = 48, PROLOG_RESUME_FAILURE = 49, - PROLOG_UNDEPLOY_FAILURE = 50 + PROLOG_UNDEPLOY_FAILURE = 50, + DISK_SNAPSHOT_POWEROFF = 51, + DISK_SNAPSHOT_REVERT_POWEROFF = 52, + DISK_SNAPSHOT_DELETE_POWEROFF = 53 --> diff --git a/share/etc/oned.conf b/share/etc/oned.conf index d32b5578a8..b942dc390d 100644 --- a/share/etc/oned.conf +++ b/share/etc/oned.conf @@ -703,6 +703,13 @@ HM_MAD = [ # defined all the modules available will be enabled # authz : list of authentication modules separated by commas # +# DEFAULT_AUTH: The default authentication driver to use when OpenNebula does +# not know the user and needs to authenticate it externally. If you want to +# use "default" (not recommended, but supported for backwards compatibility +# reasons) make sure you create a symlink pointing to the actual authentication +# driver in /var/lib/one/remotes/auth, and add "default" to the 'auth' +# parameter in the 'AUTH_MAD' section. +# # SESSION_EXPIRATION_TIME: Time in seconds to keep an authenticated token as # valid. During this time, the driver is not used. Use 0 to disable session # caching @@ -721,6 +728,8 @@ AUTH_MAD = [ authn = "ssh,x509,ldap,server_cipher,server_x509" ] +#DEFAULT_AUTH = "default" + SESSION_EXPIRATION_TIME = 900 #ENABLE_OTHER_PERMISSIONS = "YES" diff --git a/share/pkgs/Debian/opennebula b/share/pkgs/Debian7/opennebula similarity index 100% rename from share/pkgs/Debian/opennebula rename to share/pkgs/Debian7/opennebula diff --git a/share/pkgs/Debian/opennebula-econe b/share/pkgs/Debian7/opennebula-econe similarity index 100% rename from share/pkgs/Debian/opennebula-econe rename to share/pkgs/Debian7/opennebula-econe diff --git a/share/pkgs/Debian/opennebula-flow b/share/pkgs/Debian7/opennebula-flow similarity index 100% rename from share/pkgs/Debian/opennebula-flow rename to share/pkgs/Debian7/opennebula-flow diff --git a/share/pkgs/Debian/opennebula-gate b/share/pkgs/Debian7/opennebula-gate similarity index 100% rename from share/pkgs/Debian/opennebula-gate rename to share/pkgs/Debian7/opennebula-gate diff --git a/share/pkgs/Debian/opennebula-novnc b/share/pkgs/Debian7/opennebula-novnc similarity index 100% rename from share/pkgs/Debian/opennebula-novnc rename to share/pkgs/Debian7/opennebula-novnc diff --git a/share/pkgs/Debian/opennebula-sunstone b/share/pkgs/Debian7/opennebula-sunstone similarity index 100% rename from share/pkgs/Debian/opennebula-sunstone rename to share/pkgs/Debian7/opennebula-sunstone diff --git a/share/pkgs/Debian7/opennebula.sudoers b/share/pkgs/Debian7/opennebula.sudoers new file mode 100644 index 0000000000..4f75c3eec7 --- /dev/null +++ b/share/pkgs/Debian7/opennebula.sudoers @@ -0,0 +1,11 @@ +Defaults:oneadmin !requiretty +Defaults:oneadmin secure_path = /sbin:/bin:/usr/sbin:/usr/bin + +Cmnd_Alias ONE_MISC = /bin/dd, /sbin/mkfs, /bin/sync +Cmnd_Alias ONE_NET = /sbin/brctl, /sbin/ebtables, /sbin/iptables, /sbin/ip, /usr/sbin/ipset +Cmnd_Alias ONE_LVM = /sbin/lvcreate, /sbin/lvremove, /sbin/lvrename, /sbin/lvs, /sbin/vgdisplay +Cmnd_Alias ONE_ISCSI = /usr/bin/iscsiadm, /usr/sbin/tgt-admin, /usr/sbin/tgtadm +Cmnd_Alias ONE_OVS = /usr/bin/ovs-ofctl, /usr/bin/ovs-vsctl +Cmnd_Alias ONE_XEN = /usr/sbin/xentop, /usr/sbin/xl, /usr/sbin/xm + +oneadmin ALL=(ALL) NOPASSWD: ONE_MISC, ONE_NET, ONE_LVM, ONE_ISCSI, ONE_OVS, ONE_XEN diff --git a/share/pkgs/Debian8/opennebula b/share/pkgs/Debian8/opennebula new file mode 100755 index 0000000000..9d923565b4 --- /dev/null +++ b/share/pkgs/Debian8/opennebula @@ -0,0 +1,128 @@ +#! /bin/sh +### BEGIN INIT INFO +# Provides: opennebula +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Should-Start: mysql +# Should-Stop: mysql +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: OpenNebula init script +# Description: OpenNebula cloud initialisation script +### END INIT INFO + +# Author: Soren Hansen + +PATH=/sbin:/usr/sbin:/bin:/usr/bin +DESC="OpenNebula cloud" +NAME=one +DAEMON=/usr/bin/$NAME +DAEMON_ARGS="" +PIDFILE=/var/run/$NAME.pid +SCRIPTNAME=/etc/init.d/$NAME + +# Exit if the package is not installed +[ -x "$DAEMON" ] || exit 0 + +# Load the VERBOSE setting and other rcS variables +. /lib/init/vars.sh + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.0-6) to ensure that this file is present. +. /lib/lsb/init-functions + +# +# Function that starts the daemon/service +# +do_start() +{ + mkdir -p /var/run/one /var/lock/one + chown oneadmin /var/run/one /var/lock/one + su oneadmin -s /bin/sh -c 'one start' +} + +# +# Function that stops the daemon/service +# +do_stop() +{ + su oneadmin -s /bin/sh -c 'one stop' +} + +do_start_sched() +{ + su oneadmin -s /bin/sh -c 'one start-sched' +} + +do_stop_sched() +{ + su oneadmin -s /bin/sh -c 'one stop-sched' +} + +case "$1" in + start) + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" + do_start + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + status) + status_of_proc "oned" "$NAME" && exit 0 || exit $? + ;; + restart|force-reload) + # + # If the "reload" option is implemented then remove the + # 'force-reload' alias + # + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + restart-sched) + log_daemon_msg "Restarting scheduler" + do_stop_sched + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload|status}" >&2 + exit 3 + ;; +esac + +: diff --git a/share/pkgs/Debian8/opennebula-econe b/share/pkgs/Debian8/opennebula-econe new file mode 100755 index 0000000000..31003b2b0d --- /dev/null +++ b/share/pkgs/Debian8/opennebula-econe @@ -0,0 +1,106 @@ +#! /bin/sh +### BEGIN INIT INFO +# Provides: opennebula-econe +# Required-Start: $remote_fs +# Required-Stop: $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: ECONE Server init script +# Description: OpenNebula ECONE service initialisation script +### END INIT INFO + +# Author: Tino Vázquez + +PATH=/sbin:/usr/sbin:/bin:/usr/bin +DESC="ECONE Service" +NAME=econe-server +DAEMON=/usr/bin/$NAME +DAEMON_ARGS="" +SCRIPTNAME=/etc/init.d/$NAME +PID_FILE=/var/run/one/econe-server.pid + +# Exit if the package is not installed +[ -x "$DAEMON" ] || exit 0 + +# Load the VERBOSE setting and other rcS variables +. /lib/init/vars.sh + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.0-6) to ensure that this file is present. +. /lib/lsb/init-functions + +# +# Function that starts the daemon/service +# +do_start() +{ + mkdir -p /var/run/one /var/lock/one /var/log/one + chown oneadmin /var/run/one /var/lock/one /var/log/one + su oneadmin -s /bin/sh -c "$DAEMON start" +} + +# +# Function that stops the daemon/service +# +do_stop() +{ + su oneadmin -s /bin/sh -c "$DAEMON stop" +} + +case "$1" in + start) + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" + do_start + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + status) + ECONE_PID=`cat $PID_FILE` + kill -0 $ECONE_PID > /dev/null 2>&1 + if [ "$?" -eq "0" ]; then + log_daemon_msg "$NAME is running" + log_end_msg 0 + else + log_daemon_msg "$NAME is not running" + log_end_msg 1 + fi + ;; + restart|force-reload) + # + # If the "reload" option is implemented then remove the + # 'force-reload' alias + # + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 + exit 3 + ;; +esac + +: diff --git a/share/pkgs/Debian8/opennebula-flow b/share/pkgs/Debian8/opennebula-flow new file mode 100755 index 0000000000..6467dd9476 --- /dev/null +++ b/share/pkgs/Debian8/opennebula-flow @@ -0,0 +1,94 @@ +#! /bin/sh +### BEGIN INIT INFO +# Provides: opennebula-flow +# Required-Start: $remote_fs +# Required-Stop: $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: OneFlow init script +# Description: OpenNebula OneFlow service initialisation script +### END INIT INFO + +# Author: Tino Vázquez + +PATH=/sbin:/usr/sbin:/bin:/usr/bin +DESC="OneFlow Service" +NAME=oneflow-server +DAEMON=/usr/bin/$NAME +DAEMON_ARGS="" +SCRIPTNAME=/etc/init.d/$NAME + +# Exit if the package is not installed +[ -x "$DAEMON" ] || exit 0 + +# Load the VERBOSE setting and other rcS variables +. /lib/init/vars.sh + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.0-6) to ensure that this file is present. +. /lib/lsb/init-functions + +# +# Function that starts the daemon/service +# +do_start() +{ + mkdir -p /var/run/one /var/lock/one /var/log/one + chown oneadmin /var/run/one /var/lock/one /var/log/one + su oneadmin -s /bin/sh -c "$DAEMON start" +} + +# +# Function that stops the daemon/service +# +do_stop() +{ + su oneadmin -s /bin/sh -c "$DAEMON stop" +} + +case "$1" in + start) + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" + do_start + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + restart|force-reload) + # + # If the "reload" option is implemented then remove the + # 'force-reload' alias + # + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2 + exit 3 + ;; +esac + +: diff --git a/share/pkgs/Debian8/opennebula-gate b/share/pkgs/Debian8/opennebula-gate new file mode 100755 index 0000000000..613f2614ef --- /dev/null +++ b/share/pkgs/Debian8/opennebula-gate @@ -0,0 +1,94 @@ +#! /bin/sh +### BEGIN INIT INFO +# Provides: opennebula-gate +# Required-Start: $remote_fs +# Required-Stop: $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: OneGate init script +# Description: OpenNebula OneGate service initialisation script +### END INIT INFO + +# Author: Tino Vázquez + +PATH=/sbin:/usr/sbin:/bin:/usr/bin +DESC="OneGate Service" +NAME=onegate-server +DAEMON=/usr/bin/$NAME +DAEMON_ARGS="" +SCRIPTNAME=/etc/init.d/$NAME + +# Exit if the package is not installed +[ -x "$DAEMON" ] || exit 0 + +# Load the VERBOSE setting and other rcS variables +. /lib/init/vars.sh + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.0-6) to ensure that this file is present. +. /lib/lsb/init-functions + +# +# Function that starts the daemon/service +# +do_start() +{ + mkdir -p /var/run/one /var/lock/one /var/log/one + chown oneadmin /var/run/one /var/lock/one /var/log/one + su oneadmin -s /bin/sh -c "$DAEMON start" +} + +# +# Function that stops the daemon/service +# +do_stop() +{ + su oneadmin -s /bin/sh -c "$DAEMON stop" +} + +case "$1" in + start) + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" + do_start + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + restart|force-reload) + # + # If the "reload" option is implemented then remove the + # 'force-reload' alias + # + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2 + exit 3 + ;; +esac + +: diff --git a/share/pkgs/Debian8/opennebula-novnc b/share/pkgs/Debian8/opennebula-novnc new file mode 100755 index 0000000000..f583a5fe1c --- /dev/null +++ b/share/pkgs/Debian8/opennebula-novnc @@ -0,0 +1,105 @@ +#! /bin/sh +### BEGIN INIT INFO +# Provides: opennebula-novnc +# Required-Start: $remote_fs +# Required-Stop: $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: novnc init script +# Description: OpenNebula novnc server +### END INIT INFO + +# Author: Arnold Bechtoldt + +PATH=/sbin:/usr/sbin:/bin:/usr/bin +DESC="OpenNebula novnc server" +NAME=novnc-server +DAEMON=/usr/bin/$NAME +DAEMON_ARGS="" +SCRIPTNAME=/etc/init.d/opennebula-novnc + +# Exit if the package is not installed +[ -x "$DAEMON" ] || exit 0 + +# Load the VERBOSE setting and other rcS variables +. /lib/init/vars.sh + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.0-6) to ensure that this file is present. +. /lib/lsb/init-functions + +# +# Function that starts the daemon/service +# +do_start() +{ + mkdir -p /var/lock/one /var/log/one + chown oneadmin /var/lock/one /var/log/one + su oneadmin -s /bin/sh -c "$DAEMON start" +} + +# +# Function that retrives the status of the daemon/service +# +do_status() +{ + su oneadmin -s /bin/sh -c "$DAEMON status" +} + +# +# Function that stops the daemon/service +# +do_stop() +{ + su oneadmin -s /bin/sh -c "$DAEMON stop" +} + +case "$1" in + start) + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" + do_start + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + status) + do_status && exit 0 || exit $? + ;; + stop) + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + restart|force-reload) + # + # If the "reload" option is implemented then remove the + # 'force-reload' alias + # + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 + exit 3 + ;; +esac + +: diff --git a/share/pkgs/Debian8/opennebula-sunstone b/share/pkgs/Debian8/opennebula-sunstone new file mode 100755 index 0000000000..34e9e1fbfb --- /dev/null +++ b/share/pkgs/Debian8/opennebula-sunstone @@ -0,0 +1,108 @@ +#! /bin/sh +### BEGIN INIT INFO +# Provides: opennebula-sunstone +# Required-Start: $remote_fs +# Required-Stop: $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Sunstone init script +# Description: OpenNebula Sunstone web interface cloud initialisation script +### END INIT INFO + +# Author: Jaime Melis + +PATH=/sbin:/usr/sbin:/bin:/usr/bin +DESC="Sunstone Web interface" +NAME=sunstone-server +DAEMON=/usr/bin/$NAME +DAEMON_ARGS="" +SCRIPTNAME=/etc/init.d/opennebula-sunstone +PID_FILE=/var/run/one/sunstone.pid + +# Exit if the package is not installed +[ -x "$DAEMON" ] || exit 0 + +# Load the VERBOSE setting and other rcS variables +. /lib/init/vars.sh + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.0-6) to ensure that this file is present. +. /lib/lsb/init-functions + +# +# Function that starts the daemon/service +# +do_start() +{ + service opennebula-novnc start + mkdir -p /var/run/one /var/lock/one /var/log/one + chown oneadmin /var/run/one /var/lock/one /var/log/one + su oneadmin -s /bin/sh -c "$DAEMON start-sunstone" +} + +# +# Function that stops the daemon/service +# +do_stop() +{ + su oneadmin -s /bin/sh -c "$DAEMON stop-sunstone" + service opennebula-novnc stop +} + +case "$1" in + start) + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" + do_start + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + status) + SUNSTONE_PID=`cat $PID_FILE` + kill -0 $SUNSTONE_PID > /dev/null 2>&1 + if [ "$?" -eq "0" ]; then + log_daemon_msg "$NAME is running" + log_end_msg 0 + else + log_daemon_msg "$NAME is not running" + log_end_msg 1 + fi + ;; + restart|force-reload) + # + # If the "reload" option is implemented then remove the + # 'force-reload' alias + # + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 + exit 3 + ;; +esac + +: diff --git a/share/pkgs/Debian/opennebula.sudoers b/share/pkgs/Debian8/opennebula.sudoers similarity index 100% rename from share/pkgs/Debian/opennebula.sudoers rename to share/pkgs/Debian8/opennebula.sudoers diff --git a/src/cli/one_helper/onehost_helper.rb b/src/cli/one_helper/onehost_helper.rb index a9ed75ea51..44f262daa4 100644 --- a/src/cli/one_helper/onehost_helper.rb +++ b/src/cli/one_helper/onehost_helper.rb @@ -167,6 +167,11 @@ class OneHostHelper < OpenNebulaHelper::OneHelper NUM_THREADS = 15 def sync(host_ids, options) + if `id -u`.to_i == 0 || `id -G`.split.collect{|e| e.to_i}.include?(0) + STDERR.puts("Cannot run 'onehost sync' as root") + exit -1 + end + begin current_version = File.read(REMOTES_LOCATION+'/VERSION').strip rescue diff --git a/src/cli/one_helper/oneimage_helper.rb b/src/cli/one_helper/oneimage_helper.rb index 068a417a85..72799b8d50 100644 --- a/src/cli/one_helper/oneimage_helper.rb +++ b/src/cli/one_helper/oneimage_helper.rb @@ -292,6 +292,13 @@ class OneImageHelper < OpenNebulaHelper::OneHelper puts str % [e, mask] } + + if image.has_elements?("/IMAGE/SNAPSHOTS") + puts + CLIHelper.print_header(str_h1 % "IMAGE SNAPSHOTS",false) + format_snapshots(image) + end + puts CLIHelper.print_header(str_h1 % "IMAGE TEMPLATE",false) @@ -311,6 +318,44 @@ class OneImageHelper < OpenNebulaHelper::OneHelper end end + def format_snapshots(image) + table=CLIHelper::ShowTable.new(nil, self) do + column :AC , "Is active", :left, :size => 2 do |d| + if d["ACTIVE"] == "YES" + "=>" + else + "" + end + end + column :ID, "Snapshot ID", :size=>3 do |d| + d["ID"] + end + + column :PARENT, "Snapshot Parent ID", :size=>6 do |d| + d["PARENT"] + end + + column :CHILDREN, "Snapshot Children IDs", :size=>10 do |d| + d["CHILDREN"] + end + + column :TAG, "Snapshot Tag", :left, :size=>45 do |d| + d["TAG"] + end + + column :DATE, "Snapshot creation date", :size=>15 do |d| + OpenNebulaHelper.time_to_str(d["DATE"]) + end + + default :AC, :ID, :PARENT, :DATE, :CHILDREN, :TAG + end + + # Convert snapshot data to an array + image_hash = image.to_hash + image_snapshots = [image_hash['IMAGE']['SNAPSHOTS']].flatten.first + table.show(image_snapshots) + end + def self.create_image_variables(options, name) if Array===name names=name diff --git a/src/cli/one_helper/onevm_helper.rb b/src/cli/one_helper/onevm_helper.rb index 81c8d1c58f..22e4d6e3da 100644 --- a/src/cli/one_helper/onevm_helper.rb +++ b/src/cli/one_helper/onevm_helper.rb @@ -601,13 +601,8 @@ class OneVMHelper < OpenNebulaHelper::OneHelper d["CLONE"] end - column :"SAVE_AS", "", :size=>7 do |d| - d["SAVE_AS"] || "-" - end - - default :ID, :TARGET, :IMAGE, :TYPE, - :SAVE, :SAVE_AS + :SAVE end.show(vm_disks, {}) while vm.has_elements?("/VM/TEMPLATE/DISK") @@ -615,6 +610,12 @@ class OneVMHelper < OpenNebulaHelper::OneHelper end if !options[:all] end + if vm.has_elements?("/VM/SNAPSHOTS") + puts + CLIHelper.print_header(str_h1 % "VM DISK SNAPSHOTS",false) + format_snapshots(vm) + end + sg_nics = [] if (vm.has_elements?("/VM/TEMPLATE/NIC/SECURITY_GROUPS")) @@ -941,4 +942,59 @@ class OneVMHelper < OpenNebulaHelper::OneHelper table.show(history) end + + def format_snapshots(vm) + table=CLIHelper::ShowTable.new(nil, self) do + column :AC , "Is active", :left, :size => 2 do |d| + if d["ACTIVE"] == "YES" + "=>" + else + "" + end + end + column :ID, "Snapshot ID", :size=>3 do |d| + d["ID"] + end + + column :DISK, "Disk ID", :size=>4 do |d| + d["DISK_ID"] + end + + column :PARENT, "Snapshot Parent ID", :size=>6 do |d| + d["PARENT"] + end + + column :CHILDREN, "Snapshot Children IDs", :size=>10 do |d| + d["CHILDREN"] + end + + column :TAG, "Snapshot Tag", :left, :size=>45 do |d| + d["TAG"] + end + + column :DATE, "Snapshot creation date", :size=>15 do |d| + OpenNebulaHelper.time_to_str(d["DATE"]) + end + + default :AC, :ID, :DISK, :PARENT, :DATE, :CHILDREN, :TAG + end + + # Convert snapshot data to an array + vm_hash = vm.to_hash + vm_snapshots = [vm_hash['VM']['SNAPSHOTS']].flatten + + snapshots = [] + + vm_snapshots.each do |disk| + disk_id = disk['DISK_ID'] + + sshots = [disk['SNAPSHOT']].flatten + sshots.each do |snapshot| + data = snapshot.merge({ 'DISK_ID' => disk_id }) + snapshots << data + end + end + + table.show(snapshots) + end end diff --git a/src/cli/oneimage b/src/cli/oneimage index b0ce67d352..431f764a1b 100755 --- a/src/cli/oneimage +++ b/src/cli/oneimage @@ -301,6 +301,36 @@ cmd=CommandParser::CmdParser.new(ARGV) do end end + snapshot_delete_desc = <<-EOT.unindent + Deletes a snapshot from the image + EOT + + command :"snapshot-delete", snapshot_delete_desc, :imageid, :snapshot_id do + helper.perform_action(args[0], options, "snapshot deleted") do |o| + o.snapshot_delete(args[1].to_i) + end + end + + snapshot_revert_desc = <<-EOT.unindent + Reverts image state to a snapshot + EOT + + command :"snapshot-revert", snapshot_revert_desc, :imageid, :snapshot_id do + helper.perform_action(args[0], options, "image state reverted") do |o| + o.snapshot_revert(args[1].to_i) + end + end + + snapshot_flatten_desc = <<-EOT.unindent + Flattens the snapshot and removes all other snapshots in the image + EOT + + command :"snapshot-flatten", snapshot_flatten_desc, :imageid, :snapshot_id do + helper.perform_action(args[0], options, "snapshot flattened") do |o| + o.snapshot_flatten(args[1].to_i) + end + end + list_desc = <<-EOT.unindent Lists Images in the pool EOT diff --git a/src/cli/onevcenter b/src/cli/onevcenter index 87f11bc617..00bbc98944 100755 --- a/src/cli/onevcenter +++ b/src/cli/onevcenter @@ -216,84 +216,14 @@ cmd=CommandParser::CmdParser.new(ARGV) do end vms_desc = <<-EOT.unindent - Import vCenter running Virtual Machines into OpenNebula + Deprecated action in onevcenter, please use onehost importvm instead EOT command :vms, vms_desc, :options=>[ VCENTER, USER, PASS ] do - if options[:vuser].nil? || - options[:vpass].nil? || - options[:vcenter].nil? - STDERR.puts "vCenter connection parameters are mandatory to import"\ - " VM templates:\n"\ - "\t --vcenter vCenter hostname\n"\ - "\t --vuser username to login in vcenter\n"\ - "\t --vpass password for the user" - exit -1 - end + STDERR.puts "Deprecated action in onevcenter, please use onehost "\ + "importvm instead" - begin - STDOUT.print "\nConnecting to vCenter: #{options[:vcenter]}..." - - vc = VCenterDriver::VIClient.new_connection( - :user => options[:vuser], - :password => options[:vpass], - :host => options[:vcenter]) - - STDOUT.print "done!\n\n" - - STDOUT.print "Looking for running Virtual Machines..." - - rs = vc.running_vms - - STDOUT.print "done!\n" - - rs.each {|dc, tmps| - STDOUT.print "\nDo you want to process datacenter #{dc} [y/n]? " - - next if STDIN.gets.strip.downcase != 'y' - - if tmps.empty? - STDOUT.print " No new running Virtual Machines found in"\ - " #{dc}...\n\n" - next - end - - tmps.each{ |v| - STDOUT.print "\n * Running Virtual Machine found:\n"\ - " - Name : #{v[:name]}\n"\ - " - UUID : #{v[:uuid]}\n"\ - " - Cluster: #{v[:host]}\n"\ - " Import this Virtual Machine [y/n]? " - - next if STDIN.gets.strip.downcase != 'y' - - one_v = ::OpenNebula::VirtualMachine.new( - ::OpenNebula::VirtualMachine.build_xml, vc.one) - - rc = one_v.allocate(v[:one]) - - if ::OpenNebula.is_error?(rc) - STDOUT.puts " Error creating Virtual Machine: "\ - "#{rc.message}\n" - end - - rc = one_v.deploy v[:host_id] - - if ::OpenNebula.is_error?(rc) - STDOUT.puts " Error creating Virtual Machine: "\ - "#{rc.message}\n" - else - STDOUT.puts " OpenNebula VM #{one_v.id} "\ - "created!\n" - end - } - } - rescue Exception => e - STDOUT.puts "error: #{e.message}" - exit -1 - end - - exit 0 + exit -1 end network_desc = <<-EOT.unindent diff --git a/src/cli/onevm b/src/cli/onevm index 714a1d8d10..7a8e380577 100755 --- a/src/cli/onevm +++ b/src/cli/onevm @@ -104,6 +104,14 @@ cmd=CommandParser::CmdParser.new(ARGV) do " the --retry option." } + SNAP={ + :name => "snapshot", + :short => "-s snapshot", + :large => "--snapshot snapshot", + :format => String, + :description => "ID of the Snapshot to save." + } + ######################################################################## # Global Options ######################################################################## @@ -298,29 +306,36 @@ cmd=CommandParser::CmdParser.new(ARGV) do end end - disk_snapshot_desc = <<-EOT.unindent - Sets the specified VM disk to be saved in a new Image. The Image is - created immediately, but the contents are saved only after the VM is - shut down gracefully (i.e., using 'onevm shutdown' and not - 'onevm delete') - - If '--live' is specified, the Image will be saved immediately. + disk_saveas_desc = <<-EOT.unindent + Saves the specified VM disk as a new Image. The Image is + created immediately, and the contents of the VM disk will be saved to + it. States: ANY EOT - command :"disk-snapshot", disk_snapshot_desc, :vmid, :diskid, :img_name, - :options=>[TYPE, OneVMHelper::LIVE] do - disk_id = args[1].to_i - image_name = args[2] - image_type = options[:type] || "" + command :"disk-saveas", disk_saveas_desc, :vmid, :diskid, :img_name, + :options=>[TYPE, SNAP] do - verbose = "disk #{disk_id} prepared to be saved in " << - "the image #{image_name}" + disk_id = args[1].to_i + image_name = args[2] + image_type = options[:type] || "" + snapshot_id = options[:snapshot] + + if snapshot_id.nil? || snapshot_id.empty? + snapshot_id = -1 + + verbose = "disk #{disk_id} prepared to be saved in " << + "the image #{image_name}" + else + snapshot_id = snapshot_id.to_i + + verbose = "disk #{disk_id} snapshot #{snapshot_id} prepared to " << + "be saved in the image #{image_name}" + end helper.perform_action(args[0],options,verbose) do |vm| - res = vm.disk_snapshot(disk_id, image_name, image_type, - options[:live]==true) + res = vm.disk_saveas(disk_id, image_name, image_type, snapshot_id) if !OpenNebula.is_error?(res) puts "Image ID: #{res}" @@ -330,19 +345,6 @@ cmd=CommandParser::CmdParser.new(ARGV) do end end - disk_snapshot_cancel_desc = <<-EOT.unindent - Cancels a deferred disk snapshot that has been set by disk-snapshot. - The target image is also deleted. - - States: ANY - EOT - - command :"disk-snapshot-cancel", disk_snapshot_cancel_desc, :vmid, :diskid do - helper.perform_action(args[0],options,"disk snapshot canceled") do |vm| - vm.disk_snapshot_cancel(args[1].to_i) - end - end - shutdown_desc = <<-EOT.unindent Shuts down the given VM. The VM life cycle will end. @@ -785,6 +787,45 @@ cmd=CommandParser::CmdParser.new(ARGV) do end end + disk_snapshot_create_desc = <<-EOT.unindent + Takes a new snapshot of the given disk. This operation needs support + from the Datastore drivers: QCOW2 or Ceph. + + States: POWEROFF + EOT + + command :"disk-snapshot-create", disk_snapshot_create_desc, + :vmid, :diskid, :tag do + helper.perform_action(args[0],options,"disk snapshot created") do |o| + o.disk_snapshot_create(args[1].to_i, args[2]) + end + end + + disk_snapshot_revert_desc = <<-EOT.unindent + Reverts disk state to a previously taken snapshot. + + States: POWEROFF + EOT + + command :"disk-snapshot-revert", disk_snapshot_revert_desc, + :vmid, :diskid, :snapshot_id do + helper.perform_action(args[0],options,"disk snapshot reverted") do |o| + o.disk_snapshot_revert(args[1].to_i, args[2].to_i) + end + end + + disk_snapshot_delete_desc = <<-EOT.unindent + Deletes a disk snapshot. + + States: POWEROFF + EOT + command :"disk-snapshot-delete", disk_snapshot_delete_desc, + :vmid, :diskid, :snapshot_id do + helper.perform_action(args[0],options,"disk snapshot deleted") do |o| + o.disk_snapshot_delete(args[1].to_i, args[2].to_i) + end + end + list_desc = <<-EOT.unindent Lists VMs in the pool EOT diff --git a/src/cloud/ec2/lib/EC2QueryServer.rb b/src/cloud/ec2/lib/EC2QueryServer.rb index c5c5ed0519..37b58bd15a 100644 --- a/src/cloud/ec2/lib/EC2QueryServer.rb +++ b/src/cloud/ec2/lib/EC2QueryServer.rb @@ -218,10 +218,9 @@ class EC2QueryServer < CloudServer return rc end - image_id = vm.disk_snapshot(1, - params["Name"], - OpenNebula::Image::IMAGE_TYPES[0], - true) + image_id = vm.disk_saveas(1, + params["Name"], + OpenNebula::Image::IMAGE_TYPES[0]) # TODO Add AMI Tags # TODO A new persistent image should be created for each instance diff --git a/src/cloud/ec2/lib/ebs.rb b/src/cloud/ec2/lib/ebs.rb index c09e7ccc5c..eff3b3575e 100644 --- a/src/cloud/ec2/lib/ebs.rb +++ b/src/cloud/ec2/lib/ebs.rb @@ -302,10 +302,9 @@ module EBS disk_id = vm["TEMPLATE/DISK[IMAGE_ID=#{image_id}]/DISK_ID"] if !disk_id.nil? - snapshot_id = vm.disk_snapshot(disk_id.to_i, + snapshot_id = vm.disk_saveas(disk_id.to_i, params["Description"]||ImageEC2.generate_uuid, - OpenNebula::Image::IMAGE_TYPES[image["TYPE"].to_i], - true) + OpenNebula::Image::IMAGE_TYPES[image["TYPE"].to_i]) if OpenNebula::is_error?(snapshot_id) return snapshot_id diff --git a/src/datastore_mad/one_datastore.rb b/src/datastore_mad/one_datastore.rb index eeaceb4bd5..a0680c01db 100755 --- a/src/datastore_mad/one_datastore.rb +++ b/src/datastore_mad/one_datastore.rb @@ -50,7 +50,10 @@ class DatastoreDriver < OpenNebulaDriver :log => "LOG", :stat => "STAT", :clone => "CLONE", - :monitor => "MONITOR" + :monitor => "MONITOR", + :snap_delete => "SNAP_DELETE", + :snap_revert => "SNAP_REVERT", + :snap_flatten=> "SNAP_FLATTEN" } # Register default actions for the protocol @@ -65,7 +68,10 @@ class DatastoreDriver < OpenNebulaDriver ACTION[:rm] => nil, ACTION[:mkfs] => nil, ACTION[:clone] => nil, - ACTION[:monitor] => nil + ACTION[:monitor] => nil, + ACTION[:snap_delete] => nil, + ACTION[:snap_revert] => nil, + ACTION[:snap_flatten] => nil } }.merge!(options) @@ -87,6 +93,9 @@ class DatastoreDriver < OpenNebulaDriver register_action(ACTION[:stat].to_sym, method("stat")) register_action(ACTION[:clone].to_sym, method("clone")) register_action(ACTION[:monitor].to_sym, method("monitor")) + register_action(ACTION[:snap_delete].to_sym, method("snap_delete")) + register_action(ACTION[:snap_revert].to_sym, method("snap_revert")) + register_action(ACTION[:snap_flatten].to_sym, method("snap_flatten")) end ############################################################################ @@ -123,6 +132,21 @@ class DatastoreDriver < OpenNebulaDriver do_image_action(id, ds, :monitor, "#{drv_message} #{id}", true) end + def snap_delete(id, drv_message) + ds = get_ds_type(drv_message) + do_image_action(id, ds, :snap_delete, "#{drv_message} #{id}") + end + + def snap_revert(id, drv_message) + ds = get_ds_type(drv_message) + do_image_action(id, ds, :snap_revert, "#{drv_message} #{id}") + end + + def snap_flatten(id, drv_message) + ds = get_ds_type(drv_message) + do_image_action(id, ds, :snap_flatten, "#{drv_message} #{id}") + end + private def is_available?(ds, id, action) diff --git a/src/datastore_mad/remotes/ceph/rm b/src/datastore_mad/remotes/ceph/rm index 6300c4dd2b..324d6f7ca1 100755 --- a/src/datastore_mad/remotes/ceph/rm +++ b/src/datastore_mad/remotes/ceph/rm @@ -17,7 +17,7 @@ #--------------------------------------------------------------------------- # ############################################################################### -# This script is used to remove a VM image (SRC) from the image repository +# This script is used to remove a VM image (RBD_SRC) from the image repository ############################################################################### # ------------ Set up the environment to source common tools ------------ @@ -48,7 +48,7 @@ done < <($XPATH /DS_DRIVER_ACTION_DATA/IMAGE/SOURCE \ /DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/BRIDGE_LIST \ /DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/CEPH_USER) -SRC="${XPATH_ELEMENTS[j++]}" +RBD_SRC="${XPATH_ELEMENTS[j++]}" BRIDGE_LIST="${XPATH_ELEMENTS[j++]}" CEPH_USER="${XPATH_ELEMENTS[j++]}" @@ -63,11 +63,52 @@ if [ -n "$CEPH_USER" ]; then RBD="$RBD --id ${CEPH_USER}" fi - # -------- Remove Image from Datastore ------------ -log "Removing $SRC from the rbd image repository in $DST_HOST" +log "Removing $RBD_SRC from the rbd image repository in $DST_HOST" -ssh_exec_and_log "$DST_HOST" "$RBD rm $SRC" "Error removing $SRC in $DST_HOST" +DELETE_CMD=$(cat </dev/null) + + for child in \$CHILDREN; do + snap_id=\${child##*-} + child=\$child@\$snap_id + rm_children \$child + done + + $RBD snap unprotect \$rbd_snap + $RBD snap rm \$rbd_snap + fi + + $RBD rm \$rbd + } + + RBD_FORMAT=\$($RBD info $RBD_SRC | sed -n 's/.*format: // p') + + if [ "\$RBD_FORMAT" = "2" ]; then + has_snap_shots=\$($RBD info $RBD_SRC-0@0 2>/dev/null) + + if [ -n "\$has_snap_shots" ]; then + rm_children $RBD_SRC-0@0 + else + $RBD rm $RBD_SRC + fi + else + $RBD rm $RBD_SRC + fi +EOF +) + +ssh_exec_and_log "$DST_HOST" "$DELETE_CMD" \ + "Error deleting $RBD_SRC in $DST_HOST" exit 0 diff --git a/src/datastore_mad/remotes/ceph/snap_delete b/src/datastore_mad/remotes/ceph/snap_delete new file mode 100755 index 0000000000..57724fc6ed --- /dev/null +++ b/src/datastore_mad/remotes/ceph/snap_delete @@ -0,0 +1,90 @@ +#!/bin/bash + +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project (OpenNebula.org), C12G Labs # +# # +# 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. # +#--------------------------------------------------------------------------- # + +############################################################################### +# This script is used to delete a snapshot of an image +############################################################################### + +# -------- Set up the environment to source common tools & conf ------------ + +if [ -z "${ONE_LOCATION}" ]; then + LIB_LOCATION=/usr/lib/one +else + LIB_LOCATION=$ONE_LOCATION/lib +fi + +. $LIB_LOCATION/sh/scripts_common.sh + +DRIVER_PATH=$(dirname $0) +source ${DRIVER_PATH}/../libfs.sh +source ${DRIVER_PATH}/ceph.conf + +# -------- Get image and datastore arguments from OpenNebula core ------------ + +DRV_ACTION=$1 +ID=$2 + +XPATH="${DRIVER_PATH}/../xpath.rb -b $DRV_ACTION" + +unset i XPATH_ELEMENTS + +while IFS= read -r -d '' element; do + XPATH_ELEMENTS[i++]="$element" +done < <($XPATH /DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/BRIDGE_LIST \ + /DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/POOL_NAME \ + /DS_DRIVER_ACTION_DATA/IMAGE/SOURCE \ + /DS_DRIVER_ACTION_DATA/IMAGE/TARGET_SNAPSHOT \ + /DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/CEPH_USER) + +unset i + +BRIDGE_LIST="${XPATH_ELEMENTS[i++]}" +POOL_NAME="${XPATH_ELEMENTS[i++]:-$POOL_NAME}" +RBD_SRC="${XPATH_ELEMENTS[i++]}" +SNAP_ID="${XPATH_ELEMENTS[i++]}" +CEPH_USER="${XPATH_ELEMENTS[i++]}" + +DST_HOST=`get_destination_host $ID` + +if [ -z "$DST_HOST" ]; then + error_message "Datastore template missing 'BRIDGE_LIST' attribute." + exit -1 +fi + +if [ -n "$CEPH_USER" ]; then + RBD="$RBD --id ${CEPH_USER}" +fi + +SNAP_DELETE_CMD=$(cat <&2 + exit 1 + fi + + $RBD snap unprotect $RBD_SRC-$SNAP_ID@$SNAP_ID + $RBD snap rm $RBD_SRC-$SNAP_ID@$SNAP_ID + $RBD rm $RBD_SRC-$SNAP_ID +EOF +) + +ssh_exec_and_log "$DST_HOST" "$SNAP_DELETE_CMD" \ + "Error deleting snapshot $RBD_SRC-$SNAP_ID@$SNAP_ID" diff --git a/src/datastore_mad/remotes/ceph/snap_flatten b/src/datastore_mad/remotes/ceph/snap_flatten new file mode 100755 index 0000000000..3b6a7fb2d4 --- /dev/null +++ b/src/datastore_mad/remotes/ceph/snap_flatten @@ -0,0 +1,115 @@ +#!/bin/bash + +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project (OpenNebula.org), C12G Labs # +# # +# 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. # +#--------------------------------------------------------------------------- # + +############################################################################### +# This script is used to flatten a snapshot of a persistent image +############################################################################### + +# -------- Set up the environment to source common tools & conf ------------ + +if [ -z "${ONE_LOCATION}" ]; then + LIB_LOCATION=/usr/lib/one +else + LIB_LOCATION=$ONE_LOCATION/lib +fi + +. $LIB_LOCATION/sh/scripts_common.sh + +DRIVER_PATH=$(dirname $0) +source ${DRIVER_PATH}/../libfs.sh +source ${DRIVER_PATH}/ceph.conf + +# -------- Get image and datastore arguments from OpenNebula core ------------ + +DRV_ACTION=$1 +ID=$2 + +XPATH="${DRIVER_PATH}/../xpath.rb -b $DRV_ACTION" + +unset i XPATH_ELEMENTS + +while IFS= read -r -d '' element; do + XPATH_ELEMENTS[i++]="$element" +done < <($XPATH /DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/BRIDGE_LIST \ + /DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/POOL_NAME \ + /DS_DRIVER_ACTION_DATA/IMAGE/SOURCE \ + /DS_DRIVER_ACTION_DATA/IMAGE/TARGET_SNAPSHOT \ + /DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/CEPH_USER) + +unset i + +BRIDGE_LIST="${XPATH_ELEMENTS[i++]}" +POOL_NAME="${XPATH_ELEMENTS[i++]:-$POOL_NAME}" +RBD_SRC="${XPATH_ELEMENTS[i++]}" +SNAP_ID="${XPATH_ELEMENTS[i++]}" +CEPH_USER="${XPATH_ELEMENTS[i++]}" + +DST_HOST=`get_destination_host $ID` + +if [ -z "$DST_HOST" ]; then + error_message "Datastore template missing 'BRIDGE_LIST' attribute." + exit -1 +fi + +if [ -n "$CEPH_USER" ]; then + RBD="$RBD --id ${CEPH_USER}" +fi + +SNAP_FLATTEN_CMD=$(cat </dev/null) + + for child in \$CHILDREN; do + snap_id=\${child##*-} + child=\$child@\$snap_id + rm_children \$child + done + + $RBD snap unprotect \$rbd_snap + $RBD snap rm \$rbd_snap + fi + + $RBD rm \$rbd + } + + RBD_FORMAT=\$($RBD info $RBD_SRC | sed -n 's/.*format: // p') + + if [ "\${RBD_FORMAT}" != "2" ]; then + echo "Only RBD Format 2 is supported for this operation" >&2 + exit 1 + fi + + $RBD clone $RBD_SRC-$SNAP_ID@$SNAP_ID $RBD_SRC.flatten + $RBD flatten $RBD_SRC.flatten + + rm_children $RBD_SRC-0@0 + + $RBD rename $RBD_SRC.flatten $RBD_SRC +EOF +) + +ssh_exec_and_log "$DST_HOST" "$SNAP_FLATTEN_CMD" \ + "Error flattening snapshot $RBD_SRC-$SNAP_ID@$SNAP_ID" diff --git a/src/datastore_mad/remotes/ceph/snap_revert b/src/datastore_mad/remotes/ceph/snap_revert new file mode 100755 index 0000000000..1a552c7191 --- /dev/null +++ b/src/datastore_mad/remotes/ceph/snap_revert @@ -0,0 +1,89 @@ +#!/bin/bash + +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project (OpenNebula.org), C12G Labs # +# # +# 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. # +#--------------------------------------------------------------------------- # + +############################################################################### +# This script is used to revert a snapshot of an image +############################################################################### + +# -------- Set up the environment to source common tools & conf ------------ + +if [ -z "${ONE_LOCATION}" ]; then + LIB_LOCATION=/usr/lib/one +else + LIB_LOCATION=$ONE_LOCATION/lib +fi + +. $LIB_LOCATION/sh/scripts_common.sh + +DRIVER_PATH=$(dirname $0) +source ${DRIVER_PATH}/../libfs.sh +source ${DRIVER_PATH}/ceph.conf + +# -------- Get image and datastore arguments from OpenNebula core ------------ + +DRV_ACTION=$1 +ID=$2 + +XPATH="${DRIVER_PATH}/../xpath.rb -b $DRV_ACTION" + +unset i XPATH_ELEMENTS + +while IFS= read -r -d '' element; do + XPATH_ELEMENTS[i++]="$element" +done < <($XPATH /DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/BRIDGE_LIST \ + /DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/POOL_NAME \ + /DS_DRIVER_ACTION_DATA/IMAGE/SOURCE \ + /DS_DRIVER_ACTION_DATA/IMAGE/TARGET_SNAPSHOT \ + /DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/CEPH_USER) + +unset i + +BRIDGE_LIST="${XPATH_ELEMENTS[i++]}" +POOL_NAME="${XPATH_ELEMENTS[i++]:-$POOL_NAME}" +RBD_SRC="${XPATH_ELEMENTS[i++]}" +SNAP_ID="${XPATH_ELEMENTS[i++]}" +CEPH_USER="${XPATH_ELEMENTS[i++]}" + +DST_HOST=`get_destination_host $ID` + +if [ -z "$DST_HOST" ]; then + error_message "Datastore template missing 'BRIDGE_LIST' attribute." + exit -1 +fi + +if [ -n "$CEPH_USER" ]; then + RBD="$RBD --id ${CEPH_USER}" +fi + +SNAP_REVERT_CMD=$(cat <&2 + exit 1 + fi + + $RBD rm $RBD_SRC + $RBD clone $RBD_SRC-$SNAP_ID@$SNAP_ID $RBD_SRC +EOF +) + +ssh_exec_and_log "$DST_HOST" "$SNAP_REVERT_CMD" \ + "Error reverting snapshot $RBD_SRC-$SNAP_ID@$SNAP_ID" diff --git a/src/datastore_mad/remotes/dev/snap_delete b/src/datastore_mad/remotes/dev/snap_delete new file mode 120000 index 0000000000..9c454e8cd4 --- /dev/null +++ b/src/datastore_mad/remotes/dev/snap_delete @@ -0,0 +1 @@ +../common/not_supported.sh \ No newline at end of file diff --git a/src/datastore_mad/remotes/dev/snap_flatten b/src/datastore_mad/remotes/dev/snap_flatten new file mode 120000 index 0000000000..9c454e8cd4 --- /dev/null +++ b/src/datastore_mad/remotes/dev/snap_flatten @@ -0,0 +1 @@ +../common/not_supported.sh \ No newline at end of file diff --git a/src/datastore_mad/remotes/dev/snap_revert b/src/datastore_mad/remotes/dev/snap_revert new file mode 120000 index 0000000000..9c454e8cd4 --- /dev/null +++ b/src/datastore_mad/remotes/dev/snap_revert @@ -0,0 +1 @@ +../common/not_supported.sh \ No newline at end of file diff --git a/src/datastore_mad/remotes/dummy/snap_delete b/src/datastore_mad/remotes/dummy/snap_delete new file mode 100755 index 0000000000..49b0cbefb2 --- /dev/null +++ b/src/datastore_mad/remotes/dummy/snap_delete @@ -0,0 +1,19 @@ +#!/bin/sh + +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project (OpenNebula.org), C12G Labs # +# # +# 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. # +#--------------------------------------------------------------------------- # + +exit 0 diff --git a/src/datastore_mad/remotes/dummy/snap_flatten b/src/datastore_mad/remotes/dummy/snap_flatten new file mode 100755 index 0000000000..49b0cbefb2 --- /dev/null +++ b/src/datastore_mad/remotes/dummy/snap_flatten @@ -0,0 +1,19 @@ +#!/bin/sh + +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project (OpenNebula.org), C12G Labs # +# # +# 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. # +#--------------------------------------------------------------------------- # + +exit 0 diff --git a/src/datastore_mad/remotes/dummy/snap_revert b/src/datastore_mad/remotes/dummy/snap_revert new file mode 100755 index 0000000000..49b0cbefb2 --- /dev/null +++ b/src/datastore_mad/remotes/dummy/snap_revert @@ -0,0 +1,19 @@ +#!/bin/sh + +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project (OpenNebula.org), C12G Labs # +# # +# 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. # +#--------------------------------------------------------------------------- # + +exit 0 diff --git a/src/datastore_mad/remotes/fs/cp b/src/datastore_mad/remotes/fs/cp index e65991a68e..cfd9560d8c 100755 --- a/src/datastore_mad/remotes/fs/cp +++ b/src/datastore_mad/remotes/fs/cp @@ -52,6 +52,7 @@ done < <($XPATH /DS_DRIVER_ACTION_DATA/DATASTORE/BASE_PATH \ /DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/SAFE_DIRS \ /DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/BRIDGE_LIST \ /DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/STAGING_DIR \ + /DS_DRIVER_ACTION_DATA/DATASTORE/TYPE \ /DS_DRIVER_ACTION_DATA/IMAGE/PATH \ /DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/MD5 \ /DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/SHA1 \ @@ -65,6 +66,7 @@ RESTRICTED_DIRS="${XPATH_ELEMENTS[i++]}" SAFE_DIRS="${XPATH_ELEMENTS[i++]}" BRIDGE_LIST="${XPATH_ELEMENTS[i++]}" STAGING_DIR="${XPATH_ELEMENTS[i++]:-/var/tmp}" +TYPE="${XPATH_ELEMENTS[i++]}" SRC="${XPATH_ELEMENTS[i++]}" MD5="${XPATH_ELEMENTS[i++]}" SHA1="${XPATH_ELEMENTS[i++]}" @@ -76,6 +78,11 @@ IMAGE_HASH=`basename $DST` set_up_datastore "$BASE_PATH" "$RESTRICTED_DIRS" "$SAFE_DIRS" +# Disable auto-decompress for the 'files' datastores (type 2) +if [ "$TYPE" = "2" ]; then + NO_DECOMPRESS="${NO_DECOMPRESS:-yes}" +fi + if [ -n "$BRIDGE_LIST" ]; then DOWNLOADER_ARGS=`set_downloader_args "$MD5" "$SHA1" "$NO_DECOMPRESS" "$LIMIT_TRANSFER_BW" "$SRC" -` else diff --git a/src/datastore_mad/remotes/fs/snap_delete b/src/datastore_mad/remotes/fs/snap_delete new file mode 120000 index 0000000000..9c454e8cd4 --- /dev/null +++ b/src/datastore_mad/remotes/fs/snap_delete @@ -0,0 +1 @@ +../common/not_supported.sh \ No newline at end of file diff --git a/src/datastore_mad/remotes/fs/snap_flatten b/src/datastore_mad/remotes/fs/snap_flatten new file mode 120000 index 0000000000..9c454e8cd4 --- /dev/null +++ b/src/datastore_mad/remotes/fs/snap_flatten @@ -0,0 +1 @@ +../common/not_supported.sh \ No newline at end of file diff --git a/src/datastore_mad/remotes/fs/snap_revert b/src/datastore_mad/remotes/fs/snap_revert new file mode 120000 index 0000000000..9c454e8cd4 --- /dev/null +++ b/src/datastore_mad/remotes/fs/snap_revert @@ -0,0 +1 @@ +../common/not_supported.sh \ No newline at end of file diff --git a/src/datastore_mad/remotes/lvm/snap_delete b/src/datastore_mad/remotes/lvm/snap_delete new file mode 120000 index 0000000000..9c454e8cd4 --- /dev/null +++ b/src/datastore_mad/remotes/lvm/snap_delete @@ -0,0 +1 @@ +../common/not_supported.sh \ No newline at end of file diff --git a/src/datastore_mad/remotes/lvm/snap_flatten b/src/datastore_mad/remotes/lvm/snap_flatten new file mode 120000 index 0000000000..9c454e8cd4 --- /dev/null +++ b/src/datastore_mad/remotes/lvm/snap_flatten @@ -0,0 +1 @@ +../common/not_supported.sh \ No newline at end of file diff --git a/src/datastore_mad/remotes/lvm/snap_revert b/src/datastore_mad/remotes/lvm/snap_revert new file mode 120000 index 0000000000..9c454e8cd4 --- /dev/null +++ b/src/datastore_mad/remotes/lvm/snap_revert @@ -0,0 +1 @@ +../common/not_supported.sh \ No newline at end of file diff --git a/src/datastore_mad/remotes/vmfs/snap_delete b/src/datastore_mad/remotes/vmfs/snap_delete new file mode 120000 index 0000000000..9c454e8cd4 --- /dev/null +++ b/src/datastore_mad/remotes/vmfs/snap_delete @@ -0,0 +1 @@ +../common/not_supported.sh \ No newline at end of file diff --git a/src/datastore_mad/remotes/vmfs/snap_flatten b/src/datastore_mad/remotes/vmfs/snap_flatten new file mode 120000 index 0000000000..9c454e8cd4 --- /dev/null +++ b/src/datastore_mad/remotes/vmfs/snap_flatten @@ -0,0 +1 @@ +../common/not_supported.sh \ No newline at end of file diff --git a/src/datastore_mad/remotes/vmfs/snap_revert b/src/datastore_mad/remotes/vmfs/snap_revert new file mode 120000 index 0000000000..9c454e8cd4 --- /dev/null +++ b/src/datastore_mad/remotes/vmfs/snap_revert @@ -0,0 +1 @@ +../common/not_supported.sh \ No newline at end of file diff --git a/src/dm/DispatchManagerActions.cc b/src/dm/DispatchManagerActions.cc index 6899515335..ad4a3b7bf7 100644 --- a/src/dm/DispatchManagerActions.cc +++ b/src/dm/DispatchManagerActions.cc @@ -905,6 +905,7 @@ int DispatchManager::attach(int vid, set used_targets; VectorAttribute * disk; + Snapshots * snap; VirtualMachine * vm = vmpool->get(vid, true); @@ -958,6 +959,7 @@ int DispatchManager::attach(int vid, max_disk_id, uid, image_id, + &snap, error_str); vm = vmpool->get(vid, true); @@ -968,6 +970,9 @@ int DispatchManager::attach(int vid, imagem->release_image(oid, image_id, false); } + delete snap; + delete disk; + oss << "Could not attach a new disk to VM " << vid << ", VM does not exist after setting its state to HOTPLUG." ; error_str = oss.str(); @@ -1001,7 +1006,7 @@ int DispatchManager::attach(int vid, // VM template vm->set_vm_info(); - vm->set_attach_disk(disk); + vm->set_attach_disk(disk, snap); if ( vm->get_lcm_state() == VirtualMachine::HOTPLUG ) { @@ -1146,10 +1151,10 @@ int DispatchManager::detach( /* -------------------------------------------------------------------------- */ int DispatchManager::snapshot_create( - int vid, - string& name, - int& snap_id, - string& error_str) + int vid, + string& name, + int& snap_id, + string& error_str) { ostringstream oss; @@ -1606,3 +1611,200 @@ int DispatchManager::detach_nic( /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ + +int DispatchManager::disk_snapshot_create( + int vid, + int did, + const string& tag, + int& snap_id, + string& error_str) +{ + ostringstream oss; + + VirtualMachine * vm = vmpool->get(vid, true); + + if ( vm == 0 ) + { + oss << "Could not create a new disk snapshot for VM " << vid + << ", VM does not exist" ; + error_str = oss.str(); + + NebulaLog::log("DiM", Log::ERROR, error_str); + + return -1; + } + + if ( vm->get_state() != VirtualMachine::POWEROFF || + vm->get_lcm_state() != VirtualMachine::LCM_INIT ) + { + oss << "Could not create a new snapshot for VM " << vid + << ", wrong state " << vm->state_str() << "."; + error_str = oss.str(); + + NebulaLog::log("DiM", Log::ERROR, error_str); + + vm->unlock(); + + return -1; + } + + snap_id = vm->new_disk_snapshot(did, tag, error_str); + + if (snap_id == -1) + { + vm->unlock(); + return -1; + } + + vm->set_state(VirtualMachine::ACTIVE); + vm->set_state(VirtualMachine::DISK_SNAPSHOT_POWEROFF); + + vmpool->update(vm); + + vm->unlock(); + + tm->trigger(TransferManager::SNAPSHOT_CREATE,vid); + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int DispatchManager::disk_snapshot_revert( + int vid, + int did, + int snap_id, + string& error_str) +{ + ostringstream oss; + + VirtualMachine * vm = vmpool->get(vid, true); + + if ( vm == 0 ) + { + oss << "Could not revert to disk snapshot for VM " << vid + << ", VM does not exist" ; + error_str = oss.str(); + + NebulaLog::log("DiM", Log::ERROR, error_str); + + return -1; + } + + if ( vm->get_state() != VirtualMachine::POWEROFF || + vm->get_lcm_state() != VirtualMachine::LCM_INIT ) + { + oss << "Could not revert to disk snapshot for VM " << vid + << ", wrong state " << vm->state_str() << "."; + error_str = oss.str(); + + NebulaLog::log("DiM", Log::ERROR, error_str); + + vm->unlock(); + return -1; + } + + const Snapshots * snaps = vm->get_disk_snapshots(did, error_str); + + if (snaps == 0) + { + vm->unlock(); + return -1; + } + + if (snaps->get_active_id() == snap_id) + { + error_str = "Snapshot is already the active one"; + + vm->unlock(); + return -1; + } + + if (vm->set_snapshot_disk(did, snap_id) == -1) + { + vm->unlock(); + return -1; + } + + vm->set_state(VirtualMachine::ACTIVE); + vm->set_state(VirtualMachine::DISK_SNAPSHOT_REVERT_POWEROFF); + + vmpool->update(vm); + + vm->unlock(); + + tm->trigger(TransferManager::SNAPSHOT_REVERT, vid); + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int DispatchManager::disk_snapshot_delete( + int vid, + int did, + int snap_id, + string& error_str) +{ + ostringstream oss; + + VirtualMachine * vm = vmpool->get(vid, true); + + if ( vm == 0 ) + { + oss << "Could not delete disk snapshot from VM " << vid + << ", VM does not exist" ; + error_str = oss.str(); + + NebulaLog::log("DiM", Log::ERROR, error_str); + + return -1; + } + + if ( vm->get_state() != VirtualMachine::POWEROFF || + vm->get_lcm_state() != VirtualMachine::LCM_INIT ) + { + oss << "Could not delete disk snapshot from VM " << vid + << ", wrong state " << vm->state_str() << "."; + error_str = oss.str(); + + NebulaLog::log("DiM", Log::ERROR, error_str); + + vm->unlock(); + return -1; + } + + const Snapshots * snaps = vm->get_disk_snapshots(did, error_str); + + if (snaps == 0) + { + vm->unlock(); + return -1; + } + + if (!snaps->test_delete(snap_id, error_str)) + { + vm->unlock(); + return -1; + } + + if (vm->set_snapshot_disk(did, snap_id) == -1) + { + vm->unlock(); + return -1; + } + + vm->set_state(VirtualMachine::ACTIVE); + vm->set_state(VirtualMachine::DISK_SNAPSHOT_DELETE_POWEROFF); + + vmpool->update(vm); + + vm->unlock(); + + tm->trigger(TransferManager::SNAPSHOT_DELETE, vid); + + return 0; +} + diff --git a/src/dm/DispatchManagerStates.cc b/src/dm/DispatchManagerStates.cc index b58add4521..a7728b2490 100644 --- a/src/dm/DispatchManagerStates.cc +++ b/src/dm/DispatchManagerStates.cc @@ -166,6 +166,9 @@ void DispatchManager::poweroff_success_action(int vid) vm->get_lcm_state() == VirtualMachine::HOTPLUG_PROLOG_POWEROFF || vm->get_lcm_state() == VirtualMachine::HOTPLUG_EPILOG_POWEROFF || vm->get_lcm_state() == VirtualMachine::PROLOG_MIGRATE_POWEROFF || + vm->get_lcm_state() == VirtualMachine::DISK_SNAPSHOT_POWEROFF || + vm->get_lcm_state() == VirtualMachine::DISK_SNAPSHOT_REVERT_POWEROFF || + vm->get_lcm_state() == VirtualMachine::DISK_SNAPSHOT_DELETE_POWEROFF || vm->get_lcm_state() == VirtualMachine::PROLOG_MIGRATE_POWEROFF_FAILURE)) { vm->set_state(VirtualMachine::POWEROFF); diff --git a/src/im_mad/remotes/kvm-probes.d/kvm.rb b/src/im_mad/remotes/kvm-probes.d/kvm.rb index 7209dd67b5..32db20488f 100755 --- a/src/im_mad/remotes/kvm-probes.d/kvm.rb +++ b/src/im_mad/remotes/kvm-probes.d/kvm.rb @@ -26,6 +26,8 @@ end # TODO : use virsh freecell when available ###### +ENV['LANG'] = 'C' + nodeinfo_text = `virsh -c qemu:///system nodeinfo` exit(-1) if $?.exitstatus != 0 @@ -40,36 +42,31 @@ nodeinfo_text.split(/\n/).each{|line| } ###### -# for everything else, top & proc -##### +# CPU +###### +vmstat = `vmstat 1 2` +$free_cpu = $total_cpu * ((vmstat.split("\n").to_a.last.split)[14].to_i)/100 +$used_cpu = $total_cpu - $free_cpu -NETINTERFACE = "eth|bond|em|p[0-9]+p[0-9]+" +###### +# MEMORY +###### +memory = `cat /proc/meminfo` +meminfo = Hash.new() +memory.each_line do |line| + key, value = line.split(':') + meminfo[key] = /\d+/.match(value)[0].to_i +end -top_text=`top -bin2` -exit(-1) if $?.exitstatus != 0 +$total_memory = meminfo['MemTotal'] -top_text.gsub!(/^top.*^top.*?$/m, "") # Strip first top output +$used_memory = meminfo['MemTotal'] - meminfo['MemFree'] - meminfo['Buffers'] - meminfo['Cached'] +$free_memory = $total_memory - $used_memory -top_text.split(/\n/).each{|line| - if line.match('^%?Cpu') - line[7..-1].split(",").each{|elemento| - temp = elemento.strip.split(/[% ]/) - if temp[1]=="id" - idle = temp[0] - $free_cpu = idle.to_f * $total_cpu.to_f / 100 - $used_cpu = $total_cpu.to_f - $free_cpu - break - end - - } - end -} - -$total_memory = `free -k|grep "Mem:" | awk '{print $2}'` -tmp=`free -k|grep "buffers\/cache"|awk '{print $3 " " $4}'`.split - -$used_memory=tmp[0] -$free_memory=tmp[1] +###### +# INTERFACE +###### +NETINTERFACE = "eth|bond|em|enp|p[0-9]+p[0-9]+" net_text=`cat /proc/net/dev` exit(-1) if $?.exitstatus != 0 diff --git a/src/image/Image.cc b/src/image/Image.cc index de2c9fd543..2ff499e3b1 100644 --- a/src/image/Image.cc +++ b/src/image/Image.cc @@ -56,7 +56,9 @@ Image::Image(int _uid, ds_id(-1), ds_name(""), vm_collection("VMS"), - img_clone_collection("CLONES") + img_clone_collection("CLONES"), + snapshots(-1), + target_snapshot(-1) { if (_image_template != 0) { @@ -124,9 +126,9 @@ int Image::insert(SqlDB *db, string& error_str) type_att = ImagePool::default_type(); } - if (set_type(type_att) != 0) + if (set_type(type_att, error_str) != 0) { - goto error_type; + goto error_common; } // ------------ PERSISTENT & PREFIX -------------------- @@ -181,7 +183,7 @@ int Image::insert(SqlDB *db, string& error_str) erase_template_attribute("PATH", path); erase_template_attribute("SOURCE", source); - if (!isSaving()) //Not a saving image + if (!is_saving()) //Not a saving image { if ( source.empty() && path.empty() ) { @@ -218,10 +220,6 @@ int Image::insert(SqlDB *db, string& error_str) return rc; -error_type: - error_str = "Incorrect TYPE in template."; - goto error_common; - error_no_path: error_str = "No PATH in template."; goto error_common; @@ -334,11 +332,12 @@ error_common: string& Image::to_xml(string& xml) const { - string template_xml; - string perms_xml; - ostringstream oss; - string vm_collection_xml; - string clone_collection_xml; + string template_xml; + string perms_xml; + ostringstream oss; + string vm_collection_xml; + string clone_collection_xml; + string snapshots_xml; oss << "" << @@ -361,11 +360,13 @@ string& Image::to_xml(string& xml) const "" << running_vms << "" << "" << cloning_ops << "" << "" << cloning_id << "" << + ""<< target_snapshot << ""<< "" << ds_id << ""<< "" << ds_name << "" << vm_collection.to_xml(vm_collection_xml) << img_clone_collection.to_xml(clone_collection_xml) << obj_template->to_xml(template_xml) << + snapshots.to_xml(snapshots_xml) << ""; xml = oss.str(); @@ -410,6 +411,8 @@ int Image::from_xml(const string& xml) rc += xpath(cloning_ops, "/IMAGE/CLONING_OPS", -1); rc += xpath(cloning_id, "/IMAGE/CLONING_ID", -1); + xpath(target_snapshot, "/IMAGE/TARGET_SNAPSHOT", -1); + rc += xpath(ds_id, "/IMAGE/DATASTORE_ID", -1); rc += xpath(ds_name, "/IMAGE/DATASTORE", "not_found"); @@ -462,6 +465,17 @@ int Image::from_xml(const string& xml) ObjectXML::free_nodes(content); + content.clear(); + + ObjectXML::get_nodes("/IMAGE/SNAPSHOTS", content); + + if (!content.empty()) + { + rc += snapshots.from_xml_node(content[0]); + + ObjectXML::free_nodes(content); + content.clear(); + } if (rc != 0) { @@ -610,9 +624,9 @@ int Image::disk_attribute( VectorAttribute * disk, new_disk_type = RBD_CDROM; break; - case SHEEPDOG: - new_disk_type = SHEEPDOG_CDROM; - break; + case SHEEPDOG: + new_disk_type = SHEEPDOG_CDROM; + break; case GLUSTER: new_disk_type = GLUSTER_CDROM; @@ -656,12 +670,18 @@ int Image::disk_attribute( VectorAttribute * disk, /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ -int Image::set_type(string& _type) +int Image::set_type(string& _type, string& error) { int rc = 0; TO_UPPER(_type); + if ((_type != "OS" && _type != "DATABLOCK") && (snapshots.size() > 0)) + { + error = "Image with snapshots can be only of type OS or DATABLOCK"; + return -1; + } + if ( _type == "OS" ) { type = OS; @@ -688,6 +708,7 @@ int Image::set_type(string& _type) } else { + error = "Unknown type " + type; rc = -1; } @@ -709,7 +730,7 @@ ImageTemplate * Image::clone_template(const string& new_name) const tmpl->replace("FSTYPE", fs_type); tmpl->replace("SIZE", size_mb); - if ( isPersistent() ) + if ( is_persistent() ) { tmpl->replace("PERSISTENT", "YES"); } diff --git a/src/image/ImageManagerActions.cc b/src/image/ImageManagerActions.cc index a4651ab0af..6846353ac8 100644 --- a/src/image/ImageManagerActions.cc +++ b/src/image/ImageManagerActions.cc @@ -113,7 +113,7 @@ int ImageManager::acquire_image(int vm_id, Image *img, string& error) case Image::READY: img->inc_running(vm_id); - if ( img->isPersistent() ) + if ( img->is_persistent() ) { img->set_state(Image::USED_PERS); } @@ -160,11 +160,9 @@ int ImageManager::acquire_image(int vm_id, Image *img, string& error) void ImageManager::release_image(int vm_id, int iid, bool failed) { - Image * img; + ostringstream oss; - ostringstream disk_file; - - img = ipool->get(iid,true); + Image * img = ipool->get(iid,true); if ( img == 0 ) { @@ -218,27 +216,10 @@ void ImageManager::release_image(int vm_id, int iid, bool failed) break; case Image::LOCKED: - if ( img->isSaving() ) //SAVE_AS images are LOCKED till released - { - if (failed == true) - { - img->set_state(Image::ERROR); - } - else - { - img->set_state(Image::READY); - } + oss << "Releasing image in wrong state: " + << Image::state_to_str(img->get_state()); - ipool->update(img); - } - else - { - stringstream oss; - oss << "Releasing image in wrong state: " - << Image::state_to_str(img->get_state()); - - NebulaLog::log("ImM", Log::ERROR, oss.str()); - } + NebulaLog::log("ImM", Log::ERROR, oss.str()); img->unlock(); break; @@ -249,7 +230,6 @@ void ImageManager::release_image(int vm_id, int iid, bool failed) case Image::DISABLED: case Image::READY: case Image::ERROR: - ostringstream oss; oss << "Releasing image in wrong state: " << Image::state_to_str(img->get_state()); @@ -265,11 +245,7 @@ void ImageManager::release_image(int vm_id, int iid, bool failed) void ImageManager::release_cloning_image(int iid, int clone_img_id) { - Image * img; - - ostringstream disk_file; - - img = ipool->get(iid,true); + Image * img = ipool->get(iid,true); if ( img == 0 ) { @@ -296,15 +272,13 @@ void ImageManager::release_cloning_image(int iid, int clone_img_id) { case Image::USED: case Image::CLONE: - if (img->dec_cloning(clone_img_id) == 0 && img->get_running() == 0) { img->set_state(Image::READY); } ipool->update(img); - - break; + break; case Image::DELETE: case Image::INIT: @@ -313,14 +287,13 @@ void ImageManager::release_cloning_image(int iid, int clone_img_id) case Image::ERROR: case Image::USED_PERS: case Image::LOCKED: + ostringstream oss; - ostringstream oss; - oss << "Releasing image in wrong state: " - << Image::state_to_str(img->get_state()); + oss << "Releasing image in wrong state: " + << Image::state_to_str(img->get_state()); - NebulaLog::log("ImM", Log::ERROR, oss.str()); - - break; + NebulaLog::log("ImM", Log::ERROR, oss.str()); + break; } img->unlock(); @@ -639,7 +612,7 @@ int ImageManager::clone_image(int new_id, case Image::READY: img->inc_cloning(new_id); - if (img->isPersistent()) + if (img->is_persistent()) { img->set_state(Image::CLONE); } @@ -738,12 +711,11 @@ int ImageManager::register_image(int iid, const string& ds_data, string& error) { string source = img->get_source(); - if ( img->isSaving() || img->get_type() == Image::DATABLOCK ) + if ( img->is_saving() || img->get_type() == Image::DATABLOCK ) { imd->mkfs(img->get_oid(), *drv_msg); - oss << "Creating disk at " << source - << " of "<< img->get_size() + oss << "Creating disk at " << source << " of "<< img->get_size() << "Mb (type: " << img->get_fstype() << ")"; } else if ( !source.empty() ) //Source in Template @@ -895,3 +867,333 @@ string * ImageManager::format_message( /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +void ImageManager::set_image_snapshots(int iid, const Snapshots& s, bool failed) +{ + Image * img = ipool->get(iid,true); + + if ( img == 0 ) + { + return; + } + + switch(img->get_type()) + { + case Image::OS: + case Image::DATABLOCK: + break; + + case Image::KERNEL: + case Image::RAMDISK: + case Image::CONTEXT: + case Image::CDROM: + img->unlock(); + return; + } + + if (img->get_state() != Image::USED_PERS) + { + img->unlock(); + return; + } + + img->set_snapshots(s); + + ipool->update(img); + + img->unlock(); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int ImageManager::delete_snapshot(int iid, int sid, string& error) +{ + const ImageManagerDriver* imd = get(); + + if ( imd == 0 ) + { + error = "Could not get datastore driver"; + NebulaLog::log("ImM",Log::ERROR, error); + + return -1; + } + + /* ---------------------------------------------------------------------- */ + /* Check action consistency: */ + /* state is READY */ + /* snapshot can be deleted (not active, no childs, exists) */ + /* ---------------------------------------------------------------------- */ + Image * img = ipool->get(iid,true); + + if ( img == 0 ) + { + error = "Image does not exist"; + return -1; + } + + if (img->get_state() != Image::READY) + { + error = "Cannot delete snapshot in state " + Image::state_to_str(img->get_state()); + img->unlock(); + return -1; + } + + const Snapshots& snaps = img->get_snapshots(); + + if (!snaps.test_delete(sid, error)) + { + img->unlock(); + return -1; + } + + /* ---------------------------------------------------------------------- */ + /* Get DS data for driver */ + /* ---------------------------------------------------------------------- */ + int ds_id = img->get_ds_id(); + + img->unlock(); + + string ds_data; + + Datastore * ds = dspool->get(ds_id, true); + + if ( ds == 0 ) + { + error = "Datastore no longer exists"; + return -1; + } + + ds->to_xml(ds_data); + + ds->unlock(); + + img = ipool->get(iid,true); + + /* ---------------------------------------------------------------------- */ + /* Format message and send action to driver */ + /* ---------------------------------------------------------------------- */ + if ( img == 0 ) + { + error = "Image does not exist"; + return -1; + } + + img->set_target_snapshot(sid); + + string img_tmpl; + string * drv_msg = format_message(img->to_xml(img_tmpl), ds_data); + + imd->snapshot_delete(iid, *drv_msg); + + img->set_state(Image::LOCKED); + + ipool->update(img); + + img->unlock(); + + delete drv_msg; + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int ImageManager::revert_snapshot(int iid, int sid, string& error) +{ + const ImageManagerDriver* imd = get(); + + if ( imd == 0 ) + { + error = "Could not get datastore driver"; + NebulaLog::log("ImM",Log::ERROR, error); + + return -1; + } + + /* ---------------------------------------------------------------------- */ + /* Check action consistency: */ + /* state is READY */ + /* snapshot exists */ + /* snapshot is not the active one */ + /* ---------------------------------------------------------------------- */ + + Image * img = ipool->get(iid,true); + + if ( img == 0 ) + { + error = "Image does not exist"; + return -1; + } + + if (img->get_state() != Image::READY) + { + error = "Cannot revert to snapshot in state " + Image::state_to_str(img->get_state()); + img->unlock(); + return -1; + } + + const Snapshots& snaps = img->get_snapshots(); + + if (!snaps.exists(sid)) + { + error = "Snapshot does not exist"; + + img->unlock(); + return -1; + } + + if (snaps.get_active_id() == sid) + { + error = "Snapshot is already the active one"; + + img->unlock(); + return -1; + } + + /* ---------------------------------------------------------------------- */ + /* Get DS data for driver */ + /* ---------------------------------------------------------------------- */ + int ds_id = img->get_ds_id(); + + img->unlock(); + + string ds_data; + + Datastore * ds = dspool->get(ds_id, true); + + if ( ds == 0 ) + { + error = "Datastore no longer exists"; + return -1; + } + + ds->to_xml(ds_data); + + ds->unlock(); + + /* ---------------------------------------------------------------------- */ + /* Format message and send action to driver */ + /* ---------------------------------------------------------------------- */ + img = ipool->get(iid,true); + + if ( img == 0 ) + { + error = "Image does not exist"; + return -1; + } + + img->set_target_snapshot(sid); + + string img_tmpl; + string * drv_msg = format_message(img->to_xml(img_tmpl), ds_data); + + imd->snapshot_revert(iid, *drv_msg); + + img->set_state(Image::LOCKED); + + ipool->update(img); + + img->unlock(); + + delete drv_msg; + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int ImageManager::flatten_snapshot(int iid, int sid, string& error) +{ + const ImageManagerDriver* imd = get(); + + if ( imd == 0 ) + { + error = "Could not get datastore driver"; + NebulaLog::log("ImM",Log::ERROR, error); + + return -1; + } + + /* ---------------------------------------------------------------------- */ + /* Check action consistency: */ + /* state is READY */ + /* snapshot exists */ + /* ---------------------------------------------------------------------- */ + + Image * img = ipool->get(iid,true); + + if ( img == 0 ) + { + error = "Image does not exist"; + return -1; + } + + if (img->get_state() != Image::READY) + { + error = "Cannot flatten snapshot in state " + Image::state_to_str(img->get_state()); + img->unlock(); + return -1; + } + + const Snapshots& snaps = img->get_snapshots(); + + if (!snaps.exists(sid)) + { + error = "Snapshot does not exist"; + + img->unlock(); + return -1; + } + + /* ---------------------------------------------------------------------- */ + /* Get DS data for driver */ + /* ---------------------------------------------------------------------- */ + int ds_id = img->get_ds_id(); + + img->unlock(); + + string ds_data; + + Datastore * ds = dspool->get(ds_id, true); + + if ( ds == 0 ) + { + error = "Datastore no longer exists"; + return -1; + } + + ds->to_xml(ds_data); + + ds->unlock(); + + /* ---------------------------------------------------------------------- */ + /* Format message and send action to driver */ + /* ---------------------------------------------------------------------- */ + img = ipool->get(iid,true); + + if ( img == 0 ) + { + error = "Image does not exist"; + return -1; + } + + img->set_target_snapshot(sid); + + string img_tmpl; + string * drv_msg = format_message(img->to_xml(img_tmpl), ds_data); + + imd->snapshot_flatten(iid, *drv_msg); + + img->set_state(Image::LOCKED); + + ipool->update(img); + + img->unlock(); + + delete drv_msg; + + return 0; +} + diff --git a/src/image/ImageManagerDriver.cc b/src/image/ImageManagerDriver.cc index 407c7efae0..6bb6fa1aac 100644 --- a/src/image/ImageManagerDriver.cc +++ b/src/image/ImageManagerDriver.cc @@ -93,6 +93,39 @@ void ImageManagerDriver::monitor(int oid, const string& drv_msg) const write(os); } +/* -------------------------------------------------------------------------- */ + +void ImageManagerDriver::snapshot_delete(int oid, const string& drv_msg) const +{ + ostringstream os; + + os << "SNAP_DELETE " << oid << " " << drv_msg << endl; + + write(os); +} + +/* -------------------------------------------------------------------------- */ + +void ImageManagerDriver::snapshot_revert(int oid, const string& drv_msg) const +{ + ostringstream os; + + os << "SNAP_REVERT " << oid << " " << drv_msg << endl; + + write(os); +} + +/* -------------------------------------------------------------------------- */ + +void ImageManagerDriver::snapshot_flatten(int oid, const string& drv_msg) const +{ + ostringstream os; + + os << "SNAP_FLATTEN " << oid << " " << drv_msg << endl; + + write(os); +} + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ @@ -336,15 +369,12 @@ static int mkfs_action(istringstream& is, string source; Image * image; bool is_saving = false; - bool is_hot = false; string info; - int rc; - int vm_id = -1; - int ds_id = -1; - - int disk_id; + int vm_id = -1; + int ds_id = -1; + int disk_id = -1; VirtualMachine * vm; ostringstream oss; @@ -378,14 +408,13 @@ static int mkfs_action(istringstream& is, return ds_id; } - is_saving = image->isSaving(); - is_hot = image->isHot(); + is_saving = image->is_saving(); ds_id = image->get_ds_id(); if ( is_saving ) { - image->get_template_attribute("SAVED_VM_ID", vm_id); image->get_template_attribute("SAVED_DISK_ID", disk_id); + image->get_template_attribute("SAVED_VM_ID", vm_id); } if ( result == "FAILURE" ) @@ -426,28 +455,12 @@ static int mkfs_action(istringstream& is, goto error_save_get; } - if ( is_hot ) //Saveas hot, trigger disk copy + if ( vm->set_saveas_disk(disk_id, source, id) == -1 ) { - rc = vm->save_disk_hot(disk_id, source, id); - - if ( rc == -1 ) - { - goto error_save_state; - } - - tm->trigger(TransferManager::SAVEAS_HOT, vm_id); + goto error_save_state; } - else //setup disk information - { - rc = vm->save_disk(disk_id, source, id); - if ( rc == -1 ) - { - goto error_save_state; - } - - vm->clear_saveas_state(disk_id, is_hot); - } + tm->trigger(TransferManager::SAVEAS_HOT, vm_id); vmpool->update(vm); @@ -460,12 +473,12 @@ error_img: goto error; error_save_get: - oss << "Image created for SAVE_AS, but the associated VM does not exist."; + oss << "Image created to save as a disk but VM does not exist."; goto error_save; error_save_state: vm->unlock(); - oss << "Image created for SAVE_AS, but VM is no longer running"; + oss << "Image created to save as disk but VM is no longer running"; error_save: image = ipool->get(id, true); @@ -497,7 +510,10 @@ error: { if ((vm = vmpool->get(vm_id, true)) != 0) { - vm->clear_saveas_state(disk_id, is_hot); + vm->clear_saveas_state(); + + vm->clear_saveas_disk(); + vmpool->update(vm); vm->unlock(); @@ -666,6 +682,168 @@ static void monitor_action(istringstream& is, return; } +/* -------------------------------------------------------------------------- */ + +static void snap_delete_action(istringstream& is, + ImagePool* ipool, + int id, + const string& result) +{ + ostringstream oss; + string info; + + Image * image = ipool->get(id, true); + + if ( image == 0 ) + { + return; + } + + image->set_state(Image::READY); + + int snap_id = image->get_target_snapshot(); + + if (snap_id == -1) + { + NebulaLog::log("ImM", Log::ERROR, "No target snapshot in callback"); + + ipool->update(image); + + image->unlock(); + return; + } + + if ( result == "SUCCESS") + { + image->delete_snapshot(snap_id); + } + else + { + oss << "Error removing snapshot " << snap_id << " from image " << id; + + getline(is, info); + + if (!info.empty() && (info[0] != '-')) + { + oss << ": " << info; + } + + image->set_template_error_message(oss.str()); + + NebulaLog::log("ImM", Log::ERROR, oss); + } + + image->clear_target_snapshot(); + + ipool->update(image); + + image->unlock(); +} + +/* -------------------------------------------------------------------------- */ + +static void snap_revert_action(istringstream& is, + ImagePool* ipool, + int id, + const string& result) +{ + ostringstream oss; + string info; + + Image * image = ipool->get(id, true); + + if ( image == 0 ) + { + return; + } + + int snap_id = image->get_target_snapshot(); + + image->set_state(Image::READY); + + if (snap_id == -1) + { + NebulaLog::log("ImM", Log::ERROR, "No target snapshot in callback"); + + ipool->update(image); + + image->unlock(); + return; + } + + if ( result == "SUCCESS") + { + image->revert_snapshot(snap_id); + } + else + { + oss << "Error reverting image " << id << " to snapshot " << snap_id; + + getline(is, info); + + if (!info.empty() && (info[0] != '-')) + { + oss << ": " << info; + } + + image->set_template_error_message(oss.str()); + + NebulaLog::log("ImM", Log::ERROR, oss); + } + + image->clear_target_snapshot(); + + ipool->update(image); + + image->unlock(); +} + +/* -------------------------------------------------------------------------- */ + +static void snap_flatten_action(istringstream& is, + ImagePool* ipool, + int id, + const string& result) +{ + ostringstream oss; + string info; + + Image * image = ipool->get(id, true); + + if ( image == 0 ) + { + return; + } + + if ( result == "SUCCESS") + { + image->clear_snapshots(); + } + else + { + oss << "Error flattening image snapshot"; + + getline(is, info); + + if (!info.empty() && (info[0] != '-')) + { + oss << ": " << info; + } + + image->set_template_error_message(oss.str()); + + NebulaLog::log("ImM", Log::ERROR, oss); + } + + image->set_state(Image::READY); + + image->clear_target_snapshot(); + + ipool->update(image); + + image->unlock(); +} + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ @@ -717,30 +895,42 @@ void ImageManagerDriver::protocol(const string& message) const else return; - if ( action == "STAT" ) + if (action == "STAT") { stat_action(is, id, result); } - else if ( action == "CP" ) + else if (action == "CP") { ds_id = cp_action(is, ipool, id, result); } - else if ( action == "CLONE" ) + else if (action == "CLONE") { ds_id = clone_action(is, ipool, id, result); } - else if ( action == "MKFS" ) + else if (action == "MKFS") { ds_id = mkfs_action(is, ipool, id, result); } - else if ( action == "RM" ) + else if (action == "RM") { ds_id = rm_action(is, ipool, id, result); } - else if ( action == "MONITOR" ) + else if (action == "MONITOR") { monitor_action(is, dspool, id, result); } + else if (action == "SNAP_DELETE") + { + snap_delete_action(is, ipool, id, result); + } + else if (action == "SNAP_REVERT") + { + snap_revert_action(is, ipool, id, result); + } + else if (action == "SNAP_FLATTEN") + { + snap_flatten_action(is, ipool, id, result); + } else if (action == "LOG") { getline(is,info); diff --git a/src/image/ImagePool.cc b/src/image/ImagePool.cc index 9a174d3d91..0f897e539e 100644 --- a/src/image/ImagePool.cc +++ b/src/image/ImagePool.cc @@ -19,6 +19,7 @@ /* ************************************************************************** */ #include "ImagePool.h" +#include "Snapshots.h" #include "AuthManager.h" #include "Nebula.h" #include "PoolObjectAuth.h" @@ -313,6 +314,7 @@ int ImagePool::disk_attribute(int vm_id, string& dev_prefix, int uid, int& image_id, + Snapshots ** snap, string& error_str) { string source; @@ -326,6 +328,8 @@ int ImagePool::disk_attribute(int vm_id, Nebula& nd = Nebula::instance(); ImageManager * imagem = nd.get_imagem(); + *snap = 0; + if (!(source = disk->vector_value("IMAGE")).empty()) { int uiid = get_disk_uid(disk,uid); @@ -412,6 +416,12 @@ int ImagePool::disk_attribute(int vm_id, image_id = img->get_oid(); datastore_id = img->get_ds_id(); + if (img->snapshots.size() > 0) + { + *snap = new Snapshots(img->snapshots); + (*snap)->set_disk_id(disk_id); + } + img->unlock(); if (rc == -1) @@ -419,6 +429,9 @@ int ImagePool::disk_attribute(int vm_id, imagem->release_image(vm_id, iid, false); error_str = "Unknown internal error"; + delete *snap; + *snap = 0; + return -1; } @@ -429,6 +442,9 @@ int ImagePool::disk_attribute(int vm_id, imagem->release_image(vm_id, iid, false); error_str = "Associated datastore for the image does not exist"; + delete *snap; + *snap = 0; + return -1; } diff --git a/src/image/ImageTemplate.cc b/src/image/ImageTemplate.cc index 9db95e66fc..599cfd4c78 100644 --- a/src/image/ImageTemplate.cc +++ b/src/image/ImageTemplate.cc @@ -21,8 +21,5 @@ vector ImageTemplate::restricted_attributes; -string ImageTemplate::saving_attribute = "SAVE_AS"; -string ImageTemplate::saving_hot_attribute = "SAVE_AS_HOT"; - /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ diff --git a/src/lcm/LifeCycleActions.cc b/src/lcm/LifeCycleActions.cc index a24c1c77e3..81a3ec4e08 100644 --- a/src/lcm/LifeCycleActions.cc +++ b/src/lcm/LifeCycleActions.cc @@ -917,6 +917,7 @@ void LifeCycleManager::clean_up_vm(VirtualMachine * vm, bool dispose, int& imag case VirtualMachine::HOTPLUG: vm->clear_attach_disk(); + vmpool->update(vm); vm->set_running_etime(the_time); vmpool->update_history(vm); @@ -927,6 +928,7 @@ void LifeCycleManager::clean_up_vm(VirtualMachine * vm, bool dispose, int& imag case VirtualMachine::HOTPLUG_NIC: vm->clear_attach_nic(); + vmpool->update(vm); vm->set_running_etime(the_time); vmpool->update_history(vm); @@ -936,11 +938,8 @@ void LifeCycleManager::clean_up_vm(VirtualMachine * vm, bool dispose, int& imag break; case VirtualMachine::HOTPLUG_SAVEAS: - case VirtualMachine::HOTPLUG_SAVEAS_POWEROFF: - case VirtualMachine::HOTPLUG_SAVEAS_SUSPENDED: - tm->trigger(TransferManager::DRIVER_CANCEL, vid); - - vm->cancel_saveas_disk(image_id); + image_id = vm->clear_saveas_disk(); + vmpool->update(vm); vm->set_running_etime(the_time); vmpool->update_history(vm); @@ -949,14 +948,36 @@ void LifeCycleManager::clean_up_vm(VirtualMachine * vm, bool dispose, int& imag vmm->trigger(VirtualMachineManager::CLEANUP,vid); break; + case VirtualMachine::HOTPLUG_SAVEAS_POWEROFF: + case VirtualMachine::HOTPLUG_SAVEAS_SUSPENDED: + tm->trigger(TransferManager::DRIVER_CANCEL, vid); + + image_id = vm->clear_saveas_disk(); + vmpool->update(vm); + + vm->set_running_etime(the_time); + vmpool->update_history(vm); + break; + case VirtualMachine::HOTPLUG_PROLOG_POWEROFF: case VirtualMachine::HOTPLUG_EPILOG_POWEROFF: vm->clear_attach_disk(); + vmpool->update(vm); tm->trigger(TransferManager::DRIVER_CANCEL,vid); tm->trigger(TransferManager::EPILOG_DELETE,vid); break; + case VirtualMachine::DISK_SNAPSHOT_POWEROFF: + case VirtualMachine::DISK_SNAPSHOT_REVERT_POWEROFF: + case VirtualMachine::DISK_SNAPSHOT_DELETE_POWEROFF: + vm->clear_snapshot_disk(); + vmpool->update(vm); + + tm->trigger(TransferManager::DRIVER_CANCEL, vid); + tm->trigger(TransferManager::EPILOG_DELETE,vid); + break; + case VirtualMachine::MIGRATE: vm->set_running_etime(the_time); vmpool->update_history(vm); @@ -967,7 +988,8 @@ void LifeCycleManager::clean_up_vm(VirtualMachine * vm, bool dispose, int& imag vm->set_previous_reason(History::USER); vmpool->update_previous_history(vm); - hpool->del_capacity(vm->get_previous_hid(), vm->get_oid(), cpu, mem, disk); + hpool->del_capacity(vm->get_previous_hid(), vm->get_oid(), cpu, + mem, disk); vmm->trigger(VirtualMachineManager::DRIVER_CANCEL,vid); vmm->trigger(VirtualMachineManager::CLEANUP_BOTH,vid); @@ -992,7 +1014,8 @@ void LifeCycleManager::clean_up_vm(VirtualMachine * vm, bool dispose, int& imag vm->set_previous_reason(History::USER); vmpool->update_previous_history(vm); - hpool->del_capacity(vm->get_previous_hid(), vm->get_oid(), cpu, mem, disk); + hpool->del_capacity(vm->get_previous_hid(), vm->get_oid(), cpu, + mem, disk); vmm->trigger(VirtualMachineManager::DRIVER_CANCEL,vid); vmm->trigger(VirtualMachineManager::CLEANUP_PREVIOUS,vid); @@ -1106,11 +1129,11 @@ void LifeCycleManager::recover(VirtualMachine * vm, bool success) case VirtualMachine::HOTPLUG_SAVEAS_SUSPENDED: if (success) { - lcm_action = LifeCycleManager::SAVEAS_HOT_SUCCESS; + lcm_action = LifeCycleManager::SAVEAS_SUCCESS; } else { - lcm_action = LifeCycleManager::SAVEAS_HOT_FAILURE; + lcm_action = LifeCycleManager::SAVEAS_FAILURE; } break; @@ -1220,6 +1243,12 @@ void LifeCycleManager::recover(VirtualMachine * vm, bool success) case VirtualMachine::HOTPLUG_SNAPSHOT: lcm_action = LifeCycleManager::SNAPSHOT_CREATE_FAILURE; break; + + case VirtualMachine::DISK_SNAPSHOT_POWEROFF: + case VirtualMachine::DISK_SNAPSHOT_REVERT_POWEROFF: + case VirtualMachine::DISK_SNAPSHOT_DELETE_POWEROFF: + lcm_action = LifeCycleManager::DISK_SNAPSHOT_FAILURE; + break; } if (lcm_action != LifeCycleManager::FINALIZE) @@ -1420,6 +1449,9 @@ void LifeCycleManager::retry(VirtualMachine * vm) case VirtualMachine::HOTPLUG_SAVEAS_SUSPENDED: case VirtualMachine::HOTPLUG_PROLOG_POWEROFF: case VirtualMachine::HOTPLUG_EPILOG_POWEROFF: + case VirtualMachine::DISK_SNAPSHOT_POWEROFF: + case VirtualMachine::DISK_SNAPSHOT_REVERT_POWEROFF: + case VirtualMachine::DISK_SNAPSHOT_DELETE_POWEROFF: case VirtualMachine::RUNNING: case VirtualMachine::UNKNOWN: break; diff --git a/src/lcm/LifeCycleManager.cc b/src/lcm/LifeCycleManager.cc index 0604f7f58a..1f98cb806f 100644 --- a/src/lcm/LifeCycleManager.cc +++ b/src/lcm/LifeCycleManager.cc @@ -166,12 +166,12 @@ void LifeCycleManager::trigger(Actions action, int _vid) aname = "DETACH_FAILURE"; break; - case SAVEAS_HOT_SUCCESS: - aname = "SAVEAS_HOT_SUCCESS"; + case SAVEAS_SUCCESS: + aname = "SAVEAS_SUCCESS"; break; - case SAVEAS_HOT_FAILURE: - aname = "SAVEAS_HOT_FAILURE"; + case SAVEAS_FAILURE: + aname = "SAVEAS_FAILURE"; break; case ATTACH_NIC_SUCCESS: @@ -222,6 +222,14 @@ void LifeCycleManager::trigger(Actions action, int _vid) aname = "SNAPSHOT_DELETE_FAILURE"; break; + case DISK_SNAPSHOT_SUCCESS: + aname = "DISK_SNAPSHOT_SUCCESS"; + break; + + case DISK_SNAPSHOT_FAILURE: + aname = "DISK_SNAPSHOT_FAILURE"; + break; + case DEPLOY: aname = "DEPLOY"; break; @@ -391,13 +399,13 @@ void LifeCycleManager::do_action(const string &action, void * arg) { detach_failure_action(vid); } - else if (action == "SAVEAS_HOT_SUCCESS") + else if (action == "SAVEAS_SUCCESS") { - saveas_hot_success_action(vid); + saveas_success_action(vid); } - else if (action == "SAVEAS_HOT_FAILURE") + else if (action == "SAVEAS_FAILURE") { - saveas_hot_failure_action(vid); + saveas_failure_action(vid); } else if (action == "ATTACH_NIC_SUCCESS") { @@ -447,6 +455,14 @@ void LifeCycleManager::do_action(const string &action, void * arg) { snapshot_delete_failure(vid); } + else if (action == "DISK_SNAPSHOT_SUCCESS") + { + disk_snapshot_success(vid); + } + else if (action == "DISK_SNAPSHOT_FAILURE") + { + disk_snapshot_failure(vid); + } else if (action == "DEPLOY") { deploy_action(vid); diff --git a/src/lcm/LifeCycleStates.cc b/src/lcm/LifeCycleStates.cc index 952b01113d..76954ab173 100644 --- a/src/lcm/LifeCycleStates.cc +++ b/src/lcm/LifeCycleStates.cc @@ -1232,7 +1232,7 @@ void LifeCycleManager::attach_failure_action(int vid) { vm->unlock(); - vmpool->delete_attach_disk(vid, false); + vmpool->delete_attach_disk(vid); vm = vmpool->get(vid,true); @@ -1282,7 +1282,7 @@ void LifeCycleManager::detach_success_action(int vid) { vm->unlock(); - vmpool->delete_attach_disk(vid, true); + vmpool->delete_attach_disk(vid); vm = vmpool->get(vid,true); @@ -1604,27 +1604,32 @@ void LifeCycleManager::detach_nic_failure_action(int vid) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -void LifeCycleManager::saveas_hot_success_action(int vid) +void LifeCycleManager::saveas_success_action(int vid) { - VirtualMachine * vm; - Image * image; - int image_id; int disk_id; - string source; + string tm_mad; + string snap; + string ds_id; + string src; - vm = vmpool->get(vid,true); + VirtualMachine * vm = vmpool->get(vid,true); if ( vm == 0 ) { return; } - int rc = vm->get_saveas_disk_hot(disk_id, source, image_id); + int rc = vm->get_saveas_disk(disk_id, src, image_id, snap, tm_mad, ds_id); - if (vm->clear_saveas_state(disk_id, true) == -1) + vm->clear_saveas_disk(); + + if (vm->clear_saveas_state() == -1) { - vm->log("LCM", Log::ERROR, "saveas_hot_success_action, VM in a wrong state"); + vm->log("LCM",Log::ERROR, "saveas_success_action, VM in a wrong state"); + + vmpool->update(vm); + vm->unlock(); return; @@ -1634,14 +1639,14 @@ void LifeCycleManager::saveas_hot_success_action(int vid) vm->unlock(); - if ( rc != 0 ) + if (rc != 0) { return; } - image = ipool->get(image_id, true); + Image * image = ipool->get(image_id, true); - if ( image == 0 ) + if (image == 0) { return; } @@ -1656,27 +1661,32 @@ void LifeCycleManager::saveas_hot_success_action(int vid) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -void LifeCycleManager::saveas_hot_failure_action(int vid) +void LifeCycleManager::saveas_failure_action(int vid) { - VirtualMachine * vm; - Image * image; - int image_id; int disk_id; - string source; + string tm_mad; + string snap; + string ds_id; + string src; - vm = vmpool->get(vid,true); + VirtualMachine * vm = vmpool->get(vid,true); if ( vm == 0 ) { return; } - int rc = vm->get_saveas_disk_hot(disk_id, source, image_id); + int rc = vm->get_saveas_disk(disk_id, src, image_id, snap, tm_mad, ds_id); - if (vm->clear_saveas_state(disk_id, true) == -1) + vm->clear_saveas_disk(); + + if (vm->clear_saveas_state() == -1) { - vm->log("LCM", Log::ERROR, "saveas_hot_success_action, VM in a wrong state"); + vm->log("LCM",Log::ERROR, "saveas_failure_action, VM in a wrong state"); + + vmpool->update(vm); + vm->unlock(); return; @@ -1686,14 +1696,14 @@ void LifeCycleManager::saveas_hot_failure_action(int vid) vm->unlock(); - if ( rc != 0 ) + if (rc != 0) { return; } - image = ipool->get(image_id, true); + Image * image = ipool->get(image_id, true); - if ( image == 0 ) + if (image == 0) { return; } @@ -1707,3 +1717,116 @@ void LifeCycleManager::saveas_hot_failure_action(int vid) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ + +void LifeCycleManager::disk_snapshot_success(int vid) +{ + string disk_id, tm_mad, ds_id, snap_id; + + VirtualMachine * vm = vmpool->get(vid,true); + + if ( vm == 0 ) + { + return; + } + + if (vm->get_snapshot_disk(ds_id, tm_mad, disk_id, snap_id) == -1) + { + vm->log("LCM", Log::ERROR, "Snapshot DISK could not be found"); + + dm->trigger(DispatchManager::POWEROFF_SUCCESS, vid); + + vm->unlock(); + + return; + } + + int isnap_id = strtol(snap_id.c_str(),NULL,0); + int idisk_id = strtol(disk_id.c_str(),NULL,0); + + switch (vm->get_lcm_state()) + { + case VirtualMachine::DISK_SNAPSHOT_POWEROFF: + case VirtualMachine::DISK_SNAPSHOT_REVERT_POWEROFF: + vm->log("LCM", Log::INFO, "VM disk snapshot operation completed."); + vm->revert_disk_snapshot(idisk_id, isnap_id); + break; + + case VirtualMachine::DISK_SNAPSHOT_DELETE_POWEROFF: + vm->log("LCM", Log::INFO, "VM disk snapshot deleted."); + vm->delete_disk_snapshot(idisk_id, isnap_id); + break; + + default: + vm->log("LCM",Log::ERROR,"disk_snapshot_success, VM in a wrong state"); + vm->unlock(); + return; + } + + vm->clear_snapshot_disk(); + + vmpool->update(vm); + + dm->trigger(DispatchManager::POWEROFF_SUCCESS, vid); + + vm->unlock(); + + return; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void LifeCycleManager::disk_snapshot_failure(int vid) +{ + string disk_id, tm_mad, ds_id, snap_id; + + VirtualMachine * vm = vmpool->get(vid,true); + + if ( vm == 0 ) + { + return; + } + + if (vm->get_snapshot_disk(ds_id, tm_mad, disk_id, snap_id) == -1) + { + vm->log("LCM", Log::ERROR, "Snapshot DISK could not be found"); + + dm->trigger(DispatchManager::POWEROFF_SUCCESS, vid); + + vm->unlock(); + + return; + } + + int isnap_id = strtol(snap_id.c_str(),NULL,0); + int idisk_id = strtol(disk_id.c_str(),NULL,0); + + switch (vm->get_lcm_state()) + { + case VirtualMachine::DISK_SNAPSHOT_POWEROFF: + vm->log("LCM", Log::ERROR, "Could not take disk snapshot."); + vm->delete_disk_snapshot(idisk_id, isnap_id); + break; + + case VirtualMachine::DISK_SNAPSHOT_DELETE_POWEROFF: + case VirtualMachine::DISK_SNAPSHOT_REVERT_POWEROFF: + vm->log("LCM", Log::ERROR, "VM disk snapshot operation failed."); + break; + + default: + vm->log("LCM",Log::ERROR,"disk_snapshot_failure, VM in a wrong state"); + vm->unlock(); + return; + } + + vm->clear_snapshot_disk(); + + vmpool->update(vm); + + dm->trigger(DispatchManager::POWEROFF_SUCCESS, vid); + + vm->unlock(); + + return; +} + diff --git a/src/mad/sh/scripts_common.sh b/src/mad/sh/scripts_common.sh index 343e869186..43317bce2f 100644 --- a/src/mad/sh/scripts_common.sh +++ b/src/mad/sh/scripts_common.sh @@ -320,7 +320,7 @@ function mkfs_command { OPTS="-F" ;; - "reiserfs") + "reiserfs"|"xfs") OPTS="-f -q" ;; @@ -355,7 +355,9 @@ function mkfs_command { return 0 ;; *) - OPTS="" + echo "" + echo "Filesystem '$FSTYPE' not valid." 1>&2 + return 1 ;; esac diff --git a/src/nebula/NebulaTemplate.cc b/src/nebula/NebulaTemplate.cc index 1741404ae2..876310daf0 100644 --- a/src/nebula/NebulaTemplate.cc +++ b/src/nebula/NebulaTemplate.cc @@ -356,11 +356,18 @@ void OpenNebulaTemplate::set_conf_default() #******************************************************************************* # Auth Manager Configuration #******************************************************************************* +# DEFAULT_AUTH # SESSION_EXPIRATION_TIME # ENABLE_OTHER_PERMISSIONS # DEFAULT_UMASK #******************************************************************************* */ + // DEFAULT_AUTH + value = "default"; + + attribute = new SingleAttribute("DEFAULT_AUTH",value); + conf_default.insert(make_pair(attribute->name(),attribute)); + // SESSION_EXPIRATION_TIME value = "0"; diff --git a/src/oca/java/src/org/opennebula/client/vm/VirtualMachine.java b/src/oca/java/src/org/opennebula/client/vm/VirtualMachine.java index c26c02cd66..d7e70bea57 100644 --- a/src/oca/java/src/org/opennebula/client/vm/VirtualMachine.java +++ b/src/oca/java/src/org/opennebula/client/vm/VirtualMachine.java @@ -127,7 +127,10 @@ public class VirtualMachine extends PoolElement{ "BOOT_UNDEPLOY_FAILURE", "BOOT_STOPPED_FAILURE", "PROLOG_RESUME_FAILURE", - "PROLOG_UNDEPLOY_FAILURE" + "PROLOG_UNDEPLOY_FAILURE", + "DISK_SNAPSHOT_POWEROFF", + "DISK_SNAPSHOT_REVERT_POWEROFF", + "DISK_SNAPSHOT_DELETE_POWEROFF" }; private static final String[] SHORT_LCM_STATES = @@ -182,7 +185,10 @@ public class VirtualMachine extends PoolElement{ "fail", // BOOT_UNDEPLOY_FAILURE "fail", // BOOT_STOPPED_FAILURE "fail", // PROLOG_RESUME_FAILURE - "fail" // PROLOG_UNDEPLOY_FAILURE + "fail", // PROLOG_UNDEPLOY_FAILURE + "snap", // DISK_SNAPSHOT_POWEROFF + "snap", // DISK_SNAPSHOT_REVERT_POWEROFF + "snap" // DISK_SNAPSHOT_DELETE_POWEROFF }; /** diff --git a/src/oca/ruby/opennebula/client.rb b/src/oca/ruby/opennebula/client.rb index d649f36e8f..a733dd5269 100644 --- a/src/oca/ruby/opennebula/client.rb +++ b/src/oca/ruby/opennebula/client.rb @@ -130,7 +130,7 @@ module OpenNebula raise "ONE_AUTH file not present" end - @one_auth.rstrip! + @one_auth = @one_auth.rstrip if endpoint @one_endpoint = endpoint @@ -144,6 +144,8 @@ module OpenNebula @one_endpoint = "http://localhost:2633/RPC2" end + @one_endpoint= @one_endpoint.rstrip + @async = !options[:sync] timeout=nil diff --git a/src/oca/ruby/opennebula/image.rb b/src/oca/ruby/opennebula/image.rb index c090a865c6..3940989487 100644 --- a/src/oca/ruby/opennebula/image.rb +++ b/src/oca/ruby/opennebula/image.rb @@ -24,7 +24,6 @@ module OpenNebula # Constants and Class Methods ####################################################################### - IMAGE_METHODS = { :info => "image.info", :allocate => "image.allocate", @@ -36,7 +35,10 @@ module OpenNebula :chmod => "image.chmod", :chtype => "image.chtype", :clone => "image.clone", - :rename => "image.rename" + :rename => "image.rename", + :snapshotdelete => "image.snapshotdelete", + :snapshotrevert => "image.snapshotrevert", + :snapshotflatten=> "image.snapshotflatten" } IMAGE_STATES=%w{INIT READY USED DISABLED LOCKED ERROR CLONE DELETE USED_PERS} @@ -224,6 +226,32 @@ module OpenNebula return call(IMAGE_METHODS[:rename], @pe_id, name) end + # Deletes Image from snapshot + # + # @param snap_id [Integet] ID of the snapshot to delete + # + # @return [nil, OpenNebula::Error] nil in case of success or Error + def snapshot_delete(snap_id) + return call(IMAGE_METHODS[:snapshotdelete], @pe_id, snap_id) + end + + # Reverts Image state to a previous snapshot + # + # @param snap_id [Integet] ID of the snapshot to delete + # + # @return [nil, OpenNebula::Error] nil in case of success or Error + def snapshot_revert(snap_id) + return call(IMAGE_METHODS[:snapshotrevert], @pe_id, snap_id) + end + + # Flattens an image snapshot + # + # @param snap_id [Integet] ID of the snapshot to flatten + # + # @return [nil, OpenNebula::Error] nil in case of success or Error + def snapshot_flatten(snap_id) + return call(IMAGE_METHODS[:snapshotflatten], @pe_id, snap_id) + end ####################################################################### # Helpers to get Image information ####################################################################### diff --git a/src/oca/ruby/opennebula/virtual_machine.rb b/src/oca/ruby/opennebula/virtual_machine.rb index e9612749f5..cb686f1f4e 100644 --- a/src/oca/ruby/opennebula/virtual_machine.rb +++ b/src/oca/ruby/opennebula/virtual_machine.rb @@ -29,8 +29,6 @@ module OpenNebula :action => "vm.action", :migrate => "vm.migrate", :deploy => "vm.deploy", - :savedisk => "vm.savedisk", - :savediskcancel => "vm.savediskcancel", :chown => "vm.chown", :chmod => "vm.chmod", :monitoring => "vm.monitoring", @@ -44,7 +42,11 @@ module OpenNebula :snapshotdelete => "vm.snapshotdelete", :attachnic => "vm.attachnic", :detachnic => "vm.detachnic", - :recover => "vm.recover" + :recover => "vm.recover", + :disksaveas => "vm.disksaveas", + :disksnapshotcreate => "vm.disksnapshotcreate", + :disksnapshotrevert => "vm.disksnapshotrevert", + :disksnapshotdelete => "vm.disksnapshotdelete" } VM_STATE=%w{INIT PENDING HOLD ACTIVE STOPPED SUSPENDED DONE FAILED @@ -102,6 +104,9 @@ module OpenNebula BOOT_STOPPED_FAILURE PROLOG_RESUME_FAILURE PROLOG_UNDEPLOY_FAILURE + DISK_SNAPSHOT_POWEROFF + DISK_SNAPSHOT_REVERT_POWEROFF + DISK_SNAPSHOT_DELETE_POWEROFF } SHORT_VM_STATES={ @@ -167,7 +172,10 @@ module OpenNebula "BOOT_UNDEPLOY_FAILURE" => "fail", "BOOT_STOPPED_FAILURE" => "fail", "PROLOG_RESUME_FAILURE" => "fail", - "PROLOG_UNDEPLOY_FAILURE" => "fail" + "PROLOG_UNDEPLOY_FAILURE" => "fail", + "DISK_SNAPSHOT_POWEROFF" => "snap", + "DISK_SNAPSHOT_REVERT_POWEROFF" => "snap", + "DISK_SNAPSHOT_DELETE_POWEROFF" => "snap" } MIGRATE_REASON=%w{NONE ERROR USER} @@ -451,7 +459,7 @@ module OpenNebula migrate(host_id, true, enforce) end - # Set the specified vm's disk to be saved in a new image + # Set the specified vm's disk to be saved as a new image # when the VirtualMachine shutdowns # # @param disk_id [Integer] ID of the disk to be saved @@ -459,36 +467,23 @@ module OpenNebula # disk will be saved # @param image_type [String] Type of the new image. Set to empty string # to use the default type - # @param hot [true|false] True to save the disk immediately, false will - # perform the operation when the VM shuts down + # @param snap_id [Integer] ID of the snapshot to save, -1 to use the + # current disk image state # # @return [Integer, OpenNebula::Error] the new Image ID in case of # success, error otherwise - def disk_snapshot(disk_id, image_name, image_type="", hot=false) + def disk_saveas(disk_id, image_name, image_type="", snap_id=-1) return Error.new('ID not defined') if !@pe_id - rc = @client.call(VM_METHODS[:savedisk], + rc = @client.call(VM_METHODS[:disksaveas], @pe_id, disk_id, image_name, image_type, - hot) + snap_id) return rc end - # @deprecated use {#disk_snapshot} - def save_as(disk_id, image_name, image_type="", hot=false) - return disk_snapshot(disk_id, image_name, image_type, hot) - end - - # Cancels a deferred snapshot that has been set by disk_snapshot. - # The target image is also deleted. - def disk_snapshot_cancel(disk_id) - return call(VM_METHODS[:savediskcancel], - @pe_id, - disk_id) - end - # Resize the VM # # @param capacity_template [String] Template containing the new capacity @@ -610,6 +605,38 @@ module OpenNebula return call(VM_METHODS[:snapshotdelete], @pe_id, snap_id) end + # Takes a new snapshot of a disk + # + # @param disk_id [Integer] Id of the disk + # @param tag [String] description for the snapshot + # + # @return [Integer, OpenNebula::Error] The new snapshot ID or error + def disk_snapshot_create(disk_id, tag) + return call(VM_METHODS[:disksnapshotcreate], @pe_id, disk_id, tag) + end + + # Reverts disk state to a previously taken snapshot + # + # @param disk_id [Integer] Id of the disk + # @param snap_id [Integer] Id of the snapshot + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def disk_snapshot_revert(disk_id, snap_id) + return call(VM_METHODS[:disksnapshotrevert], @pe_id, disk_id, snap_id) + end + + # Deletes a disk snapshot + # + # @param disk_id [Integer] Id of the disk + # @param snap_id [Integer] Id of the snapshot + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def disk_snapshot_delete(disk_id, snap_id) + return call(VM_METHODS[:disksnapshotdelete], @pe_id, disk_id, snap_id) + end + # Recovers an ACTIVE VM # # @param result [Integer] Recover with failure (0), success (1) or @@ -743,8 +770,7 @@ module OpenNebula image_id = disk["IMAGE_ID"] if !image_id.nil? && !image_id.empty? - rc = disk_snapshot(disk_id.to_i, "#{name}-disk-#{disk_id}", - "", true) + rc = disk_saveas(disk_id.to_i,"#{name}-disk-#{disk_id}","",-1) return rc if OpenNebula.is_error?(rc) diff --git a/src/pool/PoolObjectSQL.cc b/src/pool/PoolObjectSQL.cc index cd2a898e72..f430f4b741 100644 --- a/src/pool/PoolObjectSQL.cc +++ b/src/pool/PoolObjectSQL.cc @@ -225,6 +225,8 @@ int PoolObjectSQL::replace_template( return -1; } + delete old_tmpl; + return 0; } @@ -282,6 +284,8 @@ int PoolObjectSQL::append_template( return -1; } + delete old_tmpl; + return 0; } diff --git a/src/rm/RequestManager.cc b/src/rm/RequestManager.cc index c2fb8892a2..78ed77a113 100644 --- a/src/rm/RequestManager.cc +++ b/src/rm/RequestManager.cc @@ -293,8 +293,6 @@ void RequestManager::register_xml_methods() xmlrpc_c::methodPtr vm_deploy(new VirtualMachineDeploy()); xmlrpc_c::methodPtr vm_migrate(new VirtualMachineMigrate()); xmlrpc_c::methodPtr vm_action(new VirtualMachineAction()); - xmlrpc_c::methodPtr vm_savedisk(new VirtualMachineSaveDisk()); - xmlrpc_c::methodPtr vm_savedisk_cancel(new VirtualMachineSaveDiskCancel()); xmlrpc_c::methodPtr vm_monitoring(new VirtualMachineMonitoring()); xmlrpc_c::methodPtr vm_attach(new VirtualMachineAttach()); xmlrpc_c::methodPtr vm_detach(new VirtualMachineDetach()); @@ -304,6 +302,10 @@ void RequestManager::register_xml_methods() xmlrpc_c::methodPtr vm_snap_create(new VirtualMachineSnapshotCreate()); xmlrpc_c::methodPtr vm_snap_revert(new VirtualMachineSnapshotRevert()); xmlrpc_c::methodPtr vm_snap_delete(new VirtualMachineSnapshotDelete()); + xmlrpc_c::methodPtr vm_dsaveas(new VirtualMachineDiskSaveas()); + xmlrpc_c::methodPtr vm_dsnap_create(new VirtualMachineDiskSnapshotCreate()); + xmlrpc_c::methodPtr vm_dsnap_revert(new VirtualMachineDiskSnapshotRevert()); + xmlrpc_c::methodPtr vm_dsnap_delete(new VirtualMachineDiskSnapshotDelete()); xmlrpc_c::methodPtr vm_recover(new VirtualMachineRecover()); xmlrpc_c::methodPtr vm_pool_acct(new VirtualMachinePoolAccounting()); @@ -394,6 +396,9 @@ void RequestManager::register_xml_methods() xmlrpc_c::methodPtr image_enable(new ImageEnable()); xmlrpc_c::methodPtr image_chtype(new ImageChangeType()); xmlrpc_c::methodPtr image_clone(new ImageClone()); + xmlrpc_c::methodPtr image_snap_delete(new ImageSnapshotDelete()); + xmlrpc_c::methodPtr image_snap_revert(new ImageSnapshotRevert()); + xmlrpc_c::methodPtr image_snap_flatten(new ImageSnapshotFlatten()); // Datastore Methods xmlrpc_c::methodPtr datastore_enable(new DatastoreEnable()); @@ -443,8 +448,6 @@ void RequestManager::register_xml_methods() RequestManagerRegistry.addMethod("one.vm.deploy", vm_deploy); RequestManagerRegistry.addMethod("one.vm.action", vm_action); RequestManagerRegistry.addMethod("one.vm.migrate", vm_migrate); - RequestManagerRegistry.addMethod("one.vm.savedisk", vm_savedisk); - RequestManagerRegistry.addMethod("one.vm.savediskcancel", vm_savedisk_cancel); RequestManagerRegistry.addMethod("one.vm.allocate", vm_allocate); RequestManagerRegistry.addMethod("one.vm.info", vm_info); RequestManagerRegistry.addMethod("one.vm.chown", vm_chown); @@ -460,6 +463,10 @@ void RequestManager::register_xml_methods() RequestManagerRegistry.addMethod("one.vm.snapshotcreate", vm_snap_create); RequestManagerRegistry.addMethod("one.vm.snapshotrevert", vm_snap_revert); RequestManagerRegistry.addMethod("one.vm.snapshotdelete", vm_snap_delete); + RequestManagerRegistry.addMethod("one.vm.disksaveas", vm_dsaveas); + RequestManagerRegistry.addMethod("one.vm.disksnapshotcreate", vm_dsnap_create); + RequestManagerRegistry.addMethod("one.vm.disksnapshotrevert", vm_dsnap_revert); + RequestManagerRegistry.addMethod("one.vm.disksnapshotdelete", vm_dsnap_delete); RequestManagerRegistry.addMethod("one.vm.recover", vm_recover); RequestManagerRegistry.addMethod("one.vmpool.info", vm_pool_info); @@ -647,6 +654,9 @@ void RequestManager::register_xml_methods() RequestManagerRegistry.addMethod("one.image.chtype", image_chtype); RequestManagerRegistry.addMethod("one.image.clone", image_clone); RequestManagerRegistry.addMethod("one.image.rename", image_rename); + RequestManagerRegistry.addMethod("one.image.snapshotdelete", image_snap_delete); + RequestManagerRegistry.addMethod("one.image.snapshotrevert", image_snap_revert); + RequestManagerRegistry.addMethod("one.image.snapshotflatten", image_snap_flatten); RequestManagerRegistry.addMethod("one.imagepool.info", imagepool_info); diff --git a/src/rm/RequestManagerDelete.cc b/src/rm/RequestManagerDelete.cc index 5c193e19c7..f9e81085eb 100644 --- a/src/rm/RequestManagerDelete.cc +++ b/src/rm/RequestManagerDelete.cc @@ -179,55 +179,12 @@ int HostDelete::drop(int oid, PoolObjectSQL * object, string& error_msg) int ImageDelete::drop(int oid, PoolObjectSQL * object, string& error_msg) { - Nebula& nd = Nebula::instance(); - ImageManager * imagem = nd.get_imagem(); - VirtualMachinePool * vmpool = nd.get_vmpool(); - - VirtualMachine * vm; - - bool save_as; - int rc, img_id, vm_id, disk_id; - - object->get_template_attribute("SAVE_AS", save_as); - - save_as &= object->get_template_attribute("SAVED_VM_ID", vm_id) & - object->get_template_attribute("SAVED_DISK_ID", disk_id); + Nebula& nd = Nebula::instance(); + ImageManager * imagem = nd.get_imagem(); object->unlock(); - rc = imagem->delete_image(oid, error_msg); - - // ------------------------------------------------------------------------- - // Cancel the disk snapshot - // ------------------------------------------------------------------------- - - if (rc == 0 && save_as) - { - vm = vmpool->get(vm_id, true); - - if (vm == 0) - { - return rc; - } - - if (vm->get_state() == VirtualMachine::DONE) - { - vm->unlock(); - return rc; - } - - img_id = vm->get_save_disk_image(disk_id); - - if ( img_id == oid ) - { - vm->clear_save_disk(disk_id); - vmpool->update(vm); - } - - vm->unlock(); - } - - return rc; + return imagem->delete_image(oid, error_msg); } /* ------------------------------------------------------------------------- */ diff --git a/src/rm/RequestManagerImage.cc b/src/rm/RequestManagerImage.cc index 9a044fdcae..958804f420 100644 --- a/src/rm/RequestManagerImage.cc +++ b/src/rm/RequestManagerImage.cc @@ -200,12 +200,10 @@ void ImageChangeType::request_execute(xmlrpc_c::paramList const& paramList, break; } - rc = image->set_type(type); + rc = image->set_type(type, err_msg); if ( rc != 0 ) { - err_msg = "Unknown type " + type; - failure_response(INTERNAL,request_error(err_msg,""), att); image->unlock(); @@ -282,6 +280,16 @@ void ImageClone::request_execute( return; } + const Snapshots& snaps = img->get_snapshots(); + + if (snaps.size () > 0) + { + failure_response(ACTION, + request_error("Cannot clone images with snapshots",""), att); + img->unlock(); + return; + } + tmpl = img->clone_template(name); img->get_permissions(perms); @@ -461,4 +469,90 @@ void ImageClone::request_execute( success_response(new_id, att); } +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +void ImageSnapshotDelete::request_execute(xmlrpc_c::paramList const& paramList, + RequestAttributes& att) +{ + int id = xmlrpc_c::value_int(paramList.getInt(1)); + int snap_id = xmlrpc_c::value_int(paramList.getInt(2)); + + Nebula& nd = Nebula::instance(); + ImageManager * imagem = nd.get_imagem(); + + if ( basic_authorization(id, att) == false ) + { + return; + } + + string err_msg; + int rc = imagem->delete_snapshot(id, snap_id, err_msg); + + if ( rc < 0 ) + { + failure_response(ACTION, request_error(err_msg, ""), att); + return; + } + + success_response(snap_id, att); +} + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +void ImageSnapshotRevert::request_execute(xmlrpc_c::paramList const& paramList, + RequestAttributes& att) +{ + int id = xmlrpc_c::value_int(paramList.getInt(1)); + int snap_id = xmlrpc_c::value_int(paramList.getInt(2)); + + Nebula& nd = Nebula::instance(); + ImageManager * imagem = nd.get_imagem(); + + if ( basic_authorization(id, att) == false ) + { + return; + } + + string err_msg; + int rc = imagem->revert_snapshot(id, snap_id, err_msg); + + if ( rc < 0 ) + { + failure_response(ACTION, request_error(err_msg, ""), att); + return; + } + + success_response(snap_id, att); +} + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +void ImageSnapshotFlatten::request_execute(xmlrpc_c::paramList const& paramList, + RequestAttributes& att) +{ + int id = xmlrpc_c::value_int(paramList.getInt(1)); + int snap_id = xmlrpc_c::value_int(paramList.getInt(2)); + + Nebula& nd = Nebula::instance(); + ImageManager * imagem = nd.get_imagem(); + + if ( basic_authorization(id, att) == false ) + { + return; + } + + string err_msg; + int rc = imagem->flatten_snapshot(id, snap_id, err_msg); + + if ( rc < 0 ) + { + failure_response(ACTION, request_error(err_msg, ""), att); + return; + } + + success_response(snap_id, att); +} diff --git a/src/rm/RequestManagerVirtualMachine.cc b/src/rm/RequestManagerVirtualMachine.cc index bb96166dde..b29f0f13f5 100644 --- a/src/rm/RequestManagerVirtualMachine.cc +++ b/src/rm/RequestManagerVirtualMachine.cc @@ -1176,66 +1176,72 @@ void VirtualMachineMigrate::request_execute(xmlrpc_c::paramList const& paramList /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -void VirtualMachineSaveDisk::request_execute(xmlrpc_c::paramList const& paramList, - RequestAttributes& att) +void VirtualMachineDiskSaveas::request_execute( + xmlrpc_c::paramList const& paramList, RequestAttributes& att) { - Nebula& nd = Nebula::instance(); + Nebula& nd = Nebula::instance(); ImagePool * ipool = nd.get_ipool(); DatastorePool * dspool = nd.get_dspool(); - int id = xmlrpc_c::value_int(paramList.getInt(1)); - int disk_id = xmlrpc_c::value_int(paramList.getInt(2)); - string img_name = xmlrpc_c::value_string(paramList.getString(3)); - string img_type = xmlrpc_c::value_string(paramList.getString(4)); - bool is_hot = false; //Optional XML-RPC argument - - if ( paramList.size() > 5 ) - { - is_hot = xmlrpc_c::value_boolean(paramList.getBoolean(5)); - } + int id = xmlrpc_c::value_int(paramList.getInt(1)); + int disk_id = xmlrpc_c::value_int(paramList.getInt(2)); + string img_name = xmlrpc_c::value_string(paramList.getString(3)); + string img_type = xmlrpc_c::value_string(paramList.getString(4)); + int snap_id = xmlrpc_c::value_int(paramList.getInt(5)); VirtualMachinePool * vmpool = static_cast(pool); + VirtualMachine * vm; Datastore * ds; - int iid; + Image * img; + int iid; + int iid_orig; - string error_str; + string ds_data; + PoolObjectAuth ds_perms; + long long avail; + bool ds_check; string driver; string target; string dev_prefix; + int ds_id; + string ds_name; + long long size; + + string iname_orig; + string iuname_orig; + + Image::ImageType type; + Image::DiskType ds_disk_type; + + ImageTemplate * itemplate; + Template img_usage; + + int rc; + bool rc_auth; + string error; + // ------------------------------------------------------------------------- - // Prepare and check the VM/DISK to be saved_as + // Prepare and check the VM/DISK to be saved as // ------------------------------------------------------------------------- if ((vm = get_vm(id, att)) == 0) { return; } - if ( vm->set_saveas_state(disk_id, is_hot) != 0 ) + if (vm->set_saveas_state() != 0) { - vm->unlock(); - - failure_response(INTERNAL, - request_error("VM has to be RUNNING, POWEROFF or" - " SUSPENDED to snapshot disks.",""), att); - return; + goto error_state; } - int iid_orig = vm->get_image_from_disk(disk_id, is_hot, error_str); + iid_orig = vm->set_saveas_disk(disk_id, snap_id, error); - if ( iid_orig == -1 ) + if (iid_orig == -1) { - vm->clear_saveas_state(disk_id, is_hot); - - vm->unlock(); - - failure_response(INTERNAL, - request_error("Cannot use selected DISK", error_str), - att); - return; + goto error_disk; } vmpool->update(vm); @@ -1245,32 +1251,21 @@ void VirtualMachineSaveDisk::request_execute(xmlrpc_c::paramList const& paramLis // ------------------------------------------------------------------------- // Get the data of the Image to be saved // ------------------------------------------------------------------------- - Image * img = ipool->get(iid_orig, true); + img = ipool->get(iid_orig, true); if ( img == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(PoolObjectSQL::IMAGE), iid_orig), - att); - - if ((vm = vmpool->get(id, true)) != 0) - { - vm->clear_saveas_state(disk_id, is_hot); - - vmpool->update(vm); - vm->unlock(); - } - - return; + goto error_image; } - int ds_id = img->get_ds_id(); - string ds_name = img->get_ds_name(); - long long size = img->get_size(); + ds_id = img->get_ds_id(); + ds_name = img->get_ds_name(); - string iname_orig = img->get_name(); - string iuname_orig = img->get_uname(); - Image::ImageType type = img->get_type(); + size = img->get_size(); + type = img->get_type(); + + iname_orig = img->get_name(); + iuname_orig = img->get_uname(); img->get_template_attribute("DRIVER", driver); img->get_template_attribute("TARGET", target); @@ -1283,74 +1278,39 @@ void VirtualMachineSaveDisk::request_execute(xmlrpc_c::paramList const& paramLis case Image::OS: case Image::DATABLOCK: case Image::CDROM: - break; + break; case Image::KERNEL: case Image::RAMDISK: case Image::CONTEXT: - failure_response(INTERNAL, - request_error("Cannot save_as image of type " + - Image::type_to_str(type), ""), att); - return; + goto error_image_type; } // ------------------------------------------------------------------------- - // Get the data of the DataStore for the new image + // Get the data of the DataStore for the new image & size // ------------------------------------------------------------------------- if ((ds = dspool->get(ds_id, true)) == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(PoolObjectSQL::DATASTORE), ds_id), - att); - - if ((vm = vmpool->get(id, true)) != 0) - { - vm->clear_saveas_state(disk_id, is_hot); - - vmpool->update(vm); - vm->unlock(); - } - - return; + goto error_ds; } - string ds_data; - PoolObjectAuth ds_perms; - long long avail; - bool ds_check; - ds->get_permissions(ds_perms); ds->to_xml(ds_data); - ds_check = ds->get_avail_mb(avail); - - Image::DiskType ds_disk_type = ds->get_disk_type(); + ds_check = ds->get_avail_mb(avail); + ds_disk_type = ds->get_disk_type(); ds->unlock(); - // ------------------------------------------------------------------------- - // Check Datastore Capacity - // ------------------------------------------------------------------------- if (ds_check && (size > avail)) { - failure_response(ACTION, "Not enough space in datastore", att); - - if ((vm = vmpool->get(id, true)) != 0) - { - vm->clear_saveas_state(disk_id, is_hot); - - vmpool->update(vm); - vm->unlock(); - } - - return; + goto error_size; } // ------------------------------------------------------------------------- // Create a template for the new Image // ------------------------------------------------------------------------- - ImageTemplate * itemplate = new ImageTemplate; - Template img_usage; + itemplate = new ImageTemplate; itemplate->add("NAME", img_name); itemplate->add("SIZE", size); @@ -1358,15 +1318,9 @@ void VirtualMachineSaveDisk::request_execute(xmlrpc_c::paramList const& paramLis itemplate->add("SAVED_IMAGE_ID",iid_orig); itemplate->add("SAVED_DISK_ID",disk_id); itemplate->add("SAVED_VM_ID", id); - itemplate->set_saving(); - if ( is_hot ) - { - itemplate->set_saving_hot(); - } - - if ( img_type.empty() ) + if (img_type.empty()) { itemplate->add("TYPE", Image::type_to_str(type)); } @@ -1375,17 +1329,17 @@ void VirtualMachineSaveDisk::request_execute(xmlrpc_c::paramList const& paramLis itemplate->add("TYPE", img_type); } - if ( driver.empty() == false ) + if (!driver.empty()) { itemplate->add("DRIVER", driver); } - if ( target.empty() == false ) + if (!target.empty()) { itemplate->add("TARGET", target); } - if ( dev_prefix.empty() == false ) + if (!dev_prefix.empty()) { itemplate->add("DEV_PREFIX", dev_prefix); } @@ -1396,7 +1350,7 @@ void VirtualMachineSaveDisk::request_execute(xmlrpc_c::paramList const& paramLis // ------------------------------------------------------------------------- // Authorize the operation & check quotas // ------------------------------------------------------------------------- - bool rc_auth = vm_authorization(id, itemplate, 0, att, 0,&ds_perms,auth_op); + rc_auth = vm_authorization(id, itemplate, 0, att, 0,&ds_perms,auth_op); if ( rc_auth == true ) { @@ -1405,216 +1359,111 @@ void VirtualMachineSaveDisk::request_execute(xmlrpc_c::paramList const& paramLis if ( rc_auth == false) { - delete itemplate; - - if ((vm = vmpool->get(id, true)) != 0) - { - vm->clear_saveas_state(disk_id, is_hot); - - vmpool->update(vm); - vm->unlock(); - } - - return; + goto error_auth; } // ------------------------------------------------------------------------- // Create the image // ------------------------------------------------------------------------- - int rc = ipool->allocate(att.uid, - att.gid, - att.uname, - att.gname, - att.umask, - itemplate, - ds_id, - ds_name, - ds_disk_type, - ds_data, - Datastore::IMAGE_DS, - -1, - &iid, - error_str); + rc = ipool->allocate(att.uid, + att.gid, + att.uname, + att.gname, + att.umask, + itemplate, + ds_id, + ds_name, + ds_disk_type, + ds_data, + Datastore::IMAGE_DS, + -1, + &iid, + error); if (rc < 0) { - quota_rollback(&img_usage, Quotas::DATASTORE, att); - - if ((vm = vmpool->get(id, true)) != 0) - { - vm->clear_saveas_state(disk_id, is_hot); - - vmpool->update(vm); - vm->unlock(); - } - - failure_response(INTERNAL, - allocate_error(PoolObjectSQL::IMAGE, error_str), att); - return; + goto error_allocate; } ds = dspool->get(ds_id, true); - if ( ds != 0 ) // TODO: error otherwise or leave image in ERROR? + if (ds == 0) { - ds->add_image(iid); - - dspool->update(ds); - - ds->unlock(); + goto error_ds_removed; } + ds->add_image(iid); + + dspool->update(ds); + + ds->unlock(); + success_response(iid, att); -} -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ + return; -void VirtualMachineSaveDiskCancel::request_execute( - xmlrpc_c::paramList const& paramList, - RequestAttributes& att) -{ - Nebula& nd = Nebula::instance(); +error_state: + vm->unlock(); - AclManager * aclm = nd.get_aclm(); - ImageManager * imagem = nd.get_imagem(); - ImagePool * ipool = nd.get_ipool(); - Image * img; - int img_id; + failure_response(INTERNAL,request_error("VM has to be RUNNING, POWEROFF or " + "SUSPENDED to save disks.",""), att); + return; - VirtualMachinePool * vmpool = static_cast(pool); - VirtualMachine * vm; +error_disk: + vm->clear_saveas_state(); - string error_str; - - int id = xmlrpc_c::value_int(paramList.getInt(1)); - int disk_id = xmlrpc_c::value_int(paramList.getInt(2)); - - // ------------------------------------------------------------------------- - // Authorize the VM operation - // ------------------------------------------------------------------------- - - if (att.uid != UserPool::ONEADMIN_ID) - { - PoolObjectAuth vm_perms; - PoolObjectAuth img_perms; - - if ((vm = get_vm(id, att)) == 0) - { - return; - } - - vm->get_permissions(vm_perms); - - img_id = vm->get_save_disk_image(disk_id); - - vm->unlock(); - - AuthRequest ar(att.uid, att.group_ids); - - ar.add_auth(auth_op, vm_perms); // MANAGE VM - - img = ipool->get(img_id, true); - - if ( img != 0 ) - { - img->get_permissions(img_perms); - - img->unlock(); - - ar.add_auth(AuthRequest::MANAGE, img_perms); // MANAGE IMAGE - } - - if (UserPool::authorize(ar) == -1) - { - failure_response(AUTHORIZATION, - authorization_error(ar.message, att), - att); - - return; - } - } - - // ------------------------------------------------------------------------- - // Check the VM state - // ------------------------------------------------------------------------- - - if ((vm = get_vm(id, att)) == 0) - { - return; - } - - if ((vm->get_state() != VirtualMachine::ACTIVE || - (vm->get_lcm_state() != VirtualMachine::RUNNING && - vm->get_lcm_state() != VirtualMachine::UNKNOWN) ) && - vm->get_state() != VirtualMachine::POWEROFF && - vm->get_state() != VirtualMachine::SUSPENDED) - { - failure_response(ACTION, - request_error("Wrong state to perform action",""), - att); - - vm->unlock(); - return; - } - - // ------------------------------------------------------------------------- - // Cancel the disk snapshot - // ------------------------------------------------------------------------- - - img_id = vm->get_save_disk_image(disk_id); - - if ( img_id == -1 ) - { - ostringstream oss; - oss << "Disk with ID [" << disk_id << "] is not going to be saved"; - - failure_response(ACTION, - request_error(oss.str(), ""), - att); - - vm->unlock(); - - return; - } - - vm->clear_save_disk(disk_id); - - vmpool->update(vm); + vm->clear_saveas_disk(); vm->unlock(); - // ------------------------------------------------------------------------- - // Delete the target Image - // ------------------------------------------------------------------------- + failure_response(INTERNAL,request_error("Cannot use DISK", error), att); + return; - img = ipool->get(img_id, true); +error_image: + failure_response(NO_EXISTS, get_error(object_name(PoolObjectSQL::IMAGE), + iid_orig), att); + goto error_common; - if ( img != 0 ) +error_image_type: + failure_response(INTERNAL, request_error("Cannot save_as image of type " + + Image::type_to_str(type), ""), att); + goto error_common; + +error_ds: + failure_response(NO_EXISTS, get_error(object_name(PoolObjectSQL::DATASTORE), + ds_id), att); + goto error_common; + +error_size: + failure_response(ACTION, "Not enough space in datastore", att); + goto error_common; + +error_auth: + delete itemplate; + goto error_common; + +error_allocate: + quota_rollback(&img_usage, Quotas::DATASTORE, att); + failure_response(INTERNAL, allocate_error(PoolObjectSQL::IMAGE, error),att); + goto error_common; + +error_ds_removed: + failure_response(NO_EXISTS,get_error(object_name(PoolObjectSQL::DATASTORE), + ds_id), att); + goto error_common; + +error_common: + if ((vm = vmpool->get(id, true)) != 0) { - img->unlock(); + vm->clear_saveas_state(); - int rc = imagem->delete_image(img_id, error_str); + vm->clear_saveas_disk(); - if (rc != 0) - { - ostringstream oss; - oss << "The snapshot was canceled, but " - << object_name(PoolObjectSQL::IMAGE) << " [" << img_id - << "] could not be deleted: " << error_str; + vmpool->update(vm); - failure_response(INTERNAL, - request_error(oss.str(), ""), - att); - - return; - } - - aclm->del_resource_rules(img_id, PoolObjectSQL::IMAGE); + vm->unlock(); } - // TODO: Delete the cloned template - - success_response(id, att); + return; } /* -------------------------------------------------------------------------- */ @@ -2483,3 +2332,120 @@ void VirtualMachinePoolCalculateShowback::request_execute( return; } + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void VirtualMachineDiskSnapshotCreate::request_execute( + xmlrpc_c::paramList const& paramList, + RequestAttributes& att) +{ + Nebula& nd = Nebula::instance(); + DispatchManager * dm = nd.get_dm(); + + int rc; + int snap_id; + string error_str; + + int id = xmlrpc_c::value_int(paramList.getInt(1)); + int did = xmlrpc_c::value_int(paramList.getInt(2)); + string tag = xmlrpc_c::value_string(paramList.getString(3)); + + if ( vm_authorization(id, 0, 0, att, 0, 0, auth_op) == false ) + { + return; + } + + rc = dm->disk_snapshot_create(id, did, tag, snap_id, error_str); + + if ( rc != 0 ) + { + failure_response(ACTION, + request_error(error_str, ""), + att); + } + else + { + success_response(snap_id, att); + } + + return; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void VirtualMachineDiskSnapshotRevert::request_execute( + xmlrpc_c::paramList const& paramList, + RequestAttributes& att) +{ + Nebula& nd = Nebula::instance(); + DispatchManager * dm = nd.get_dm(); + + int rc; + string error_str; + + int id = xmlrpc_c::value_int(paramList.getInt(1)); + int did = xmlrpc_c::value_int(paramList.getInt(2)); + int snap_id = xmlrpc_c::value_int(paramList.getInt(3)); + + if ( vm_authorization(id, 0, 0, att, 0, 0, auth_op) == false ) + { + return; + } + + rc = dm->disk_snapshot_revert(id, did, snap_id, error_str); + + if ( rc != 0 ) + { + failure_response(ACTION, + request_error(error_str, ""), + att); + } + else + { + success_response(snap_id, att); + } + + return; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + + +void VirtualMachineDiskSnapshotDelete::request_execute( + xmlrpc_c::paramList const& paramList, + RequestAttributes& att) +{ + Nebula& nd = Nebula::instance(); + DispatchManager * dm = nd.get_dm(); + + int rc; + string error_str; + + int id = xmlrpc_c::value_int(paramList.getInt(1)); + int did = xmlrpc_c::value_int(paramList.getInt(2)); + int snap_id = xmlrpc_c::value_int(paramList.getInt(3)); + + if ( vm_authorization(id, 0, 0, att, 0, 0, auth_op) == false ) + { + return; + } + + rc = dm->disk_snapshot_delete(id, did, snap_id, error_str); + + if ( rc != 0 ) + { + failure_response(ACTION, + request_error(error_str, ""), + att); + } + else + { + success_response(snap_id, att); + } + + return; +} + diff --git a/src/sunstone/OpenNebulaVNC.rb b/src/sunstone/OpenNebulaVNC.rb index 077976f553..457d7a0609 100644 --- a/src/sunstone/OpenNebulaVNC.rb +++ b/src/sunstone/OpenNebulaVNC.rb @@ -83,6 +83,9 @@ VNC_STATES = [ #48, #BOOT_STOPPED_FAILURE #49, #PROLOG_RESUME_FAILURE #50, #PROLOG_UNDEPLOY_FAILURE + #51, #DISK_SNAPSHOT_POWEROFF + #52, #DISK_SNAPSHOT_REVERT_POWEROFF + #53, #DISK_SNAPSHOT_DELETE_POWEROFF ] class OpenNebulaVNC diff --git a/src/sunstone/models/OpenNebulaJSON/VirtualMachineJSON.rb b/src/sunstone/models/OpenNebulaJSON/VirtualMachineJSON.rb index 987d780f78..295b10e1ca 100644 --- a/src/sunstone/models/OpenNebulaJSON/VirtualMachineJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/VirtualMachineJSON.rb @@ -55,7 +55,6 @@ module OpenNebulaJSON when "suspend" then self.suspend when "reset" then self.reset when "saveas" then self.save_as(action_hash['params']) - when "disk_snapshot_cancel" then self.disk_snapshot_cancel(action_hash['params']) when "snapshot_create" then self.snapshot_create(action_hash['params']) when "snapshot_revert" then self.snapshot_revert(action_hash['params']) when "snapshot_delete" then self.snapshot_delete(action_hash['params']) @@ -105,14 +104,7 @@ module OpenNebulaJSON end def save_as(params=Hash.new) - clone = params['clonetemplate'] - clone = false if clone.nil? - - disk_snapshot(params['disk_id'].to_i, params['image_name'], params['type'], params['hot'], clone) - end - - def disk_snapshot_cancel(params=Hash.new) - super(params['disk_id'].to_i) + disk_saveas(params['disk_id'].to_i, params['image_name'], params['type']) end def snapshot_create(params=Hash.new) diff --git a/src/sunstone/routes/vcenter.rb b/src/sunstone/routes/vcenter.rb index 74d09b03bb..ac7c125e18 100644 --- a/src/sunstone/routes/vcenter.rb +++ b/src/sunstone/routes/vcenter.rb @@ -87,26 +87,6 @@ get '/vcenter/templates' do end end - -get '/vcenter/vms' do - begin - vms = vcenter_client.running_vms( - $cloud_auth.client(session[:user], session[:active_zone_endpoint])) - if vms.nil? - msg = "No datacenter found" - logger.error("[vCenter] " + msg) - error = Error.new(msg) - error 404, error.to_json - end - - [200, vms.to_json] - rescue Exception => e - logger.error("[vCenter] " + e.message) - error = Error.new(e.message) - error 403, error.to_json - end -end - get '/vcenter/networks' do begin networks = vcenter_client.vcenter_networks( diff --git a/src/template/Template.cc b/src/template/Template.cc index afab0f1f98..27c5d7f22a 100644 --- a/src/template/Template.cc +++ b/src/template/Template.cc @@ -16,14 +16,13 @@ #include "Template.h" #include "template_syntax.h" +#include "NebulaUtil.h" #include #include #include #include -#define TO_UPPER(S) transform(S.begin(),S.end(),S.begin(),(int(*)(int))toupper) - /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ @@ -524,7 +523,7 @@ bool Template::get( return false; } - TO_UPPER(sval); + one_util::toupper(sval); if ( sval == "YES" ) { @@ -747,18 +746,7 @@ void Template::rebuild_attributes(const xmlNode * root_element) Attribute * attr; - //Clear the template if not empty - if (!attributes.empty()) - { - multimap::iterator it; - - for ( it = attributes.begin(); it != attributes.end(); it++) - { - delete it->second; - } - - attributes.clear(); - } + clear(); // Get the root's children and try to build attributes. for (cur_node = root_element->children; @@ -976,17 +964,31 @@ void Template::remove_all_except_restricted(const vector &restricted_att remove(*res_it); } - multimap::iterator att_it; - - for ( att_it = attributes.begin(); att_it != attributes.end(); att_it++) - { - delete att_it->second; - } - - attributes.clear(); + clear(); for (res_it = restricted.begin(); res_it != restricted.end(); res_it++) { set(*res_it); } } + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void Template::clear() +{ + if (attributes.empty()) + { + return; + } + + multimap::iterator it; + + for ( it = attributes.begin(); it != attributes.end(); it++) + { + delete it->second; + } + + attributes.clear(); +} + diff --git a/src/tm/TransferManager.cc b/src/tm/TransferManager.cc index f9e6d0cfb8..c4d95f34fd 100644 --- a/src/tm/TransferManager.cc +++ b/src/tm/TransferManager.cc @@ -139,6 +139,18 @@ void TransferManager::trigger(Actions action, int _vid) aname = "DRIVER_CANCEL"; break; + case SNAPSHOT_CREATE: + aname = "SNAPSHOT_CREATE"; + break; + + case SNAPSHOT_REVERT: + aname = "SNAPSHOT_REVERT"; + break; + + case SNAPSHOT_DELETE: + aname = "SNAPSHOT_DELETE"; + break; + case FINALIZE: aname = ACTION_FINALIZE; break; @@ -378,6 +390,18 @@ void TransferManager::do_action(const string &action, void * arg) { driver_cancel_action(vid); } + else if (action == "SNAPSHOT_CREATE") + { + snapshot_create_action(vid); + } + else if (action == "SNAPSHOT_REVERT") + { + snapshot_revert_action(vid); + } + else if (action == "SNAPSHOT_DELETE") + { + snapshot_delete_action(vid); + } else { ostringstream oss; @@ -1209,27 +1233,20 @@ void TransferManager::epilog_transfer_command( const VectorAttribute * disk, ostream& xfr) { - string save; - string tm_mad; int disk_id; - disk->vector_value("DISK_ID", disk_id); - save = disk->vector_value("SAVE"); + string save = disk->vector_value("SAVE"); + + disk->vector_value("DISK_ID", disk_id); transform(save.begin(),save.end(),save.begin(),(int(*)(int))toupper); if ( save == "YES" ) { - string source; - string save_source; - string ds_id; - - source = disk->vector_value("SOURCE"); - save_source = disk->vector_value("SAVE_AS_SOURCE"); - - tm_mad = disk->vector_value("TM_MAD"); - ds_id = disk->vector_value("DATASTORE_ID"); + string source = disk->vector_value("SOURCE"); + string tm_mad = disk->vector_value("TM_MAD"); + string ds_id = disk->vector_value("DATASTORE_ID"); if ( ds_id.empty() || tm_mad.empty() ) { @@ -1237,17 +1254,12 @@ void TransferManager::epilog_transfer_command( return; } - if (source.empty() && save_source.empty()) + if (source.empty()) { vm->log("TM", Log::ERROR, "No SOURCE to save disk image"); return; } - if (!save_source.empty())//Use the save_as_source instead - { - source = save_source; - } - //MVDS tm_mad hostname:remote_system_dir/disk.0 vmid dsid xfr << "MVDS " << tm_mad << " " @@ -1260,6 +1272,8 @@ void TransferManager::epilog_transfer_command( } else //No saving disk { + string tm_mad; + int ds_id_i; int vv_rc = 0; @@ -2039,30 +2053,21 @@ void TransferManager::saveas_hot_action(int vid) { int disk_id; int image_id; - string save_source; - - string save; + string src; + string snap_id; string tm_mad; string ds_id; - int num; - int disk_id_iter; - ostringstream os; ofstream xfr; string xfr_name; - string source; - - const VectorAttribute * disk; - vector attrs; - VirtualMachine * vm; - Nebula& nd = Nebula::instance(); - const TransferManagerDriver * tm_md; + Nebula& nd = Nebula::instance(); + // ------------------------------------------------------------------------ // Setup & Transfer script // ------------------------------------------------------------------------ @@ -2080,9 +2085,9 @@ void TransferManager::saveas_hot_action(int vid) goto error_common; } - if (vm->get_saveas_disk_hot(disk_id, save_source, image_id) == -1) + if (vm->get_saveas_disk(disk_id, src, image_id, snap_id, tm_mad, ds_id)!= 0) { - vm->log("TM", Log::ERROR, "Could not get disk information to saveas it"); + vm->log("TM", Log::ERROR,"Could not get disk information to export it"); goto error_common; } @@ -2093,41 +2098,7 @@ void TransferManager::saveas_hot_action(int vid) goto error_driver; } - num = vm->get_template_attribute("DISK",attrs); - - for (int i=0 ; i < num ; i++) - { - disk = dynamic_cast(attrs[i]); - - if ( disk == 0 ) - { - continue; - } - - disk->vector_value("DISK_ID", disk_id_iter); - - if (disk_id == disk_id_iter) - { - tm_mad = disk->vector_value("TM_MAD"); - ds_id = disk->vector_value("DATASTORE_ID"); - - break; - } - } - - if ( ds_id.empty() || tm_mad.empty() ) - { - vm->log("TM", Log::ERROR, "No DS_ID or TM_MAD to save disk image"); - goto error_common; - } - - if (save_source.empty()) - { - vm->log("TM", Log::ERROR, "No SOURCE to save disk image"); - goto error_common; - } - - xfr_name = vm->get_transfer_file() + ".saveas_hot"; + xfr_name = vm->get_transfer_file() + ".disk_saveas"; xfr.open(xfr_name.c_str(),ios::out | ios::trunc); if (xfr.fail() == true) @@ -2135,12 +2106,13 @@ void TransferManager::saveas_hot_action(int vid) goto error_file; } - //MVDS tm_mad hostname:remote_system_dir/disk.0 vmid dsid + //CPDS tm_mad hostname:remote_system_dir/disk.0 source snapid vmid dsid xfr << "CPDS " << tm_mad << " " << vm->get_hostname() << ":" << vm->get_remote_system_dir() << "/disk." << disk_id << " " - << save_source << " " + << src << " " + << snap_id << " " << vm->get_oid() << " " << ds_id << endl; @@ -2165,7 +2137,7 @@ error_file: error_common: vm->log("TM", Log::ERROR, os); - (nd.get_lcm())->trigger(LifeCycleManager::SAVEAS_HOT_FAILURE, vid); + (nd.get_lcm())->trigger(LifeCycleManager::SAVEAS_FAILURE, vid); vm->unlock(); return; @@ -2190,6 +2162,117 @@ void TransferManager::migrate_transfer_command( << endl; } +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void TransferManager::do_snapshot_action(int vid, const char * snap_action) +{ + string tm_mad; + string ds_id; + string disk_id; + string parent_id; + string snap_id; + + ostringstream os; + + ofstream xfr; + string xfr_name; + + VirtualMachine * vm; + + const TransferManagerDriver * tm_md; + + Nebula& nd = Nebula::instance(); + + // ------------------------------------------------------------------------ + // Setup & Transfer script + // ------------------------------------------------------------------------ + vm = vmpool->get(vid,true); + + if (vm == 0) + { + vm->log("TM", Log::ERROR, "Could not obtain the VM"); + goto error_common; + } + + if (!vm->hasHistory()) + { + vm->log("TM", Log::ERROR, "The VM has no history"); + goto error_common; + } + + if (vm->get_snapshot_disk(ds_id, tm_mad, disk_id, snap_id) == -1) + { + vm->log("TM", Log::ERROR, "Could not get disk information to" + "take snapshot"); + goto error_common; + } + + tm_md = get(); + + if (tm_md == 0) + { + goto error_driver; + } + + xfr_name = vm->get_transfer_file() + ".disk_snapshot"; + xfr.open(xfr_name.c_str(),ios::out | ios::trunc); + + if (xfr.fail() == true) + { + goto error_file; + } + + //SNAP_CREATE tm_mad host:remote_system_dir/disk.0 snapid vmid dsid + xfr << snap_action << " " + << tm_mad << " " + << vm->get_hostname() << ":" + << vm->get_remote_system_dir() << "/disk." << disk_id << " " + << snap_id << " " + << vm->get_oid() << " " + << ds_id + << endl; + + xfr.close(); + + tm_md->transfer(vid, xfr_name); + + vm->unlock(); + + return; + +error_driver: + os << "saveas_hot_transfer, error getting TM driver."; + goto error_common; + +error_file: + os << "disk_snapshot_create, could not open file: " << xfr_name; + goto error_common; + +error_common: + vm->log("TM", Log::ERROR, os); + + (nd.get_lcm())->trigger(LifeCycleManager::DISK_SNAPSHOT_FAILURE, vid); + + vm->unlock(); + return; +} + +void TransferManager::snapshot_create_action(int vid) +{ + return do_snapshot_action(vid, "SNAP_CREATE"); +}; + +void TransferManager::snapshot_revert_action(int vid) +{ + return do_snapshot_action(vid, "SNAP_REVERT"); +}; + +void TransferManager::snapshot_delete_action(int vid) +{ + return do_snapshot_action(vid, "SNAP_DELETE"); +}; + /* ************************************************************************** */ /* MAD Loading */ /* ************************************************************************** */ diff --git a/src/tm/TransferManagerDriver.cc b/src/tm/TransferManagerDriver.cc index 9ab120ca64..79ae4a7556 100644 --- a/src/tm/TransferManagerDriver.cc +++ b/src/tm/TransferManagerDriver.cc @@ -136,7 +136,7 @@ void TransferManagerDriver::protocol(const string& message) const case VirtualMachine::HOTPLUG_SAVEAS: case VirtualMachine::HOTPLUG_SAVEAS_POWEROFF: case VirtualMachine::HOTPLUG_SAVEAS_SUSPENDED: - lcm_action = LifeCycleManager::SAVEAS_HOT_SUCCESS; + lcm_action = LifeCycleManager::SAVEAS_SUCCESS; break; case VirtualMachine::HOTPLUG_PROLOG_POWEROFF: @@ -147,6 +147,12 @@ void TransferManagerDriver::protocol(const string& message) const lcm_action = LifeCycleManager::DETACH_SUCCESS; break; + case VirtualMachine::DISK_SNAPSHOT_POWEROFF: + case VirtualMachine::DISK_SNAPSHOT_REVERT_POWEROFF: + case VirtualMachine::DISK_SNAPSHOT_DELETE_POWEROFF: + lcm_action = LifeCycleManager::DISK_SNAPSHOT_SUCCESS; + break; + default: goto error_state; } @@ -191,7 +197,7 @@ void TransferManagerDriver::protocol(const string& message) const case VirtualMachine::HOTPLUG_SAVEAS: case VirtualMachine::HOTPLUG_SAVEAS_POWEROFF: case VirtualMachine::HOTPLUG_SAVEAS_SUSPENDED: - lcm_action = LifeCycleManager::SAVEAS_HOT_FAILURE; + lcm_action = LifeCycleManager::SAVEAS_FAILURE; break; case VirtualMachine::HOTPLUG_PROLOG_POWEROFF: @@ -202,6 +208,12 @@ void TransferManagerDriver::protocol(const string& message) const lcm_action = LifeCycleManager::DETACH_FAILURE; break; + case VirtualMachine::DISK_SNAPSHOT_POWEROFF: + case VirtualMachine::DISK_SNAPSHOT_REVERT_POWEROFF: + case VirtualMachine::DISK_SNAPSHOT_DELETE_POWEROFF: + lcm_action = LifeCycleManager::DISK_SNAPSHOT_FAILURE; + break; + default: goto error_state; } diff --git a/src/tm_mad/ceph/cpds b/src/tm_mad/ceph/cpds index ba800ec6bd..32c8b5146c 100755 --- a/src/tm_mad/ceph/cpds +++ b/src/tm_mad/ceph/cpds @@ -16,16 +16,18 @@ # limitations under the License. # #--------------------------------------------------------------------------- # -# mvds host:remote_system_ds/disk.i fe:SOURCE +# cpds host:remote_system_ds/disk.i fe:SOURCE snapid vmid dsid # - fe is the front-end hostname # - SOURCE is the path of the disk image in the form DS_BASE_PATH/disk # - host is the target host to deploy the VM # - remote_system_ds is the path for the system datastore in the host +# - snapid is the snapshot id. "-1" for none SRC=$1 DST=$2 -VM_ID=$3 -DS_ID=$4 +SNAP_ID=$3 +VM_ID=$4 +DS_ID=$5 if [ -z "${ONE_LOCATION}" ]; then TMCOMMON=/var/lib/one/remotes/tm/tm_common.sh @@ -43,13 +45,13 @@ source ${DRIVER_PATH}/../../datastore/ceph/ceph.conf #------------------------------------------------------------------------------- SRC_HOST=`arg_host $SRC` -SRC_PATH=`arg_path $SRC` +RBD_SRC=`arg_path $SRC` #------------------------------------------------------------------------------- # Get Image information #------------------------------------------------------------------------------- -DISK_ID=$(echo "$SRC_PATH" | $AWK -F. '{print $NF}') +DISK_ID=$(echo "$RBD_SRC" | $AWK -F. '{print $NF}') XPATH="${DRIVER_PATH}/../../datastore/xpath.rb --stdin" @@ -76,11 +78,14 @@ else RBD_DST="${RBD_SRC}-${VM_ID}-${DISK_ID}" fi +if [ "$SNAP_ID" != "-1" ]; then + RBD_DST="${RBD_DST}-${SNAP_ID}@${SNAP_ID}" +fi + if [ -n "$CEPH_USER" ]; then RBD="$RBD --id ${CEPH_USER}" fi - ssh_exec_and_log "$SRC_HOST" "$RBD copy $RBD_DST $DST" \ "Error cloning $RBD_DST to $DST in $SRC_HOST" diff --git a/src/tm_mad/ceph/delete b/src/tm_mad/ceph/delete index ea0c7b1b99..5be934284f 100755 --- a/src/tm_mad/ceph/delete +++ b/src/tm_mad/ceph/delete @@ -97,12 +97,45 @@ log "Deleting $DST_PATH" # drivers, is executed in the worker node and not in the CEPH frontend. DELETE_CMD=$(cat </dev/null) + + for child in \$CHILDREN; do + snap_id=\${child##*-} + child=\$child@\$snap_id + rm_children \$child + done + + $RBD snap unprotect \$rbd_snap + $RBD snap rm \$rbd_snap + fi + + $RBD rm \$rbd + } RBD_FORMAT=\$($RBD info $RBD_SRC | sed -n 's/.*format: // p') - $RBD rm $RBD_SRC + if [ "\$RBD_FORMAT" = "2" ]; then + has_snap_shots=\$($RBD info $RBD_SRC-0@0 2>/dev/null) + if [ -n "\$has_snap_shots" ]; then + rm_children $RBD_SRC-0@0 + else + $RBD rm $RBD_SRC + fi + else + $RBD rm $RBD_SRC + fi + + # Remove the snapshot of the original image used to create a CLONE if [ "\$RBD_FORMAT" = "2" ]; then $RBD snap unprotect $SRC@$RBD_SNAP $RBD snap rm $SRC@$RBD_SNAP diff --git a/src/tm_mad/ceph/failmigrate b/src/tm_mad/ceph/failmigrate new file mode 120000 index 0000000000..5928a42794 --- /dev/null +++ b/src/tm_mad/ceph/failmigrate @@ -0,0 +1 @@ +../common/failmigrate \ No newline at end of file diff --git a/src/tm_mad/ceph/mvds b/src/tm_mad/ceph/mvds index f64234933d..8c976fe703 100755 --- a/src/tm_mad/ceph/mvds +++ b/src/tm_mad/ceph/mvds @@ -16,91 +16,4 @@ # limitations under the License. # #--------------------------------------------------------------------------- # -# mvds host:remote_system_ds/disk.i fe:SOURCE -# - fe is the front-end hostname -# - SOURCE is the path of the disk image in the form DS_BASE_PATH/disk -# - host is the target host to deploy the VM -# - remote_system_ds is the path for the system datastore in the host - -SRC=$1 -DST=$2 -VM_ID=$3 -DS_ID=$4 - -if [ -z "${ONE_LOCATION}" ]; then - TMCOMMON=/var/lib/one/remotes/tm/tm_common.sh -else - TMCOMMON=$ONE_LOCATION/var/remotes/tm/tm_common.sh -fi - -DRIVER_PATH=$(dirname $0) - -source $TMCOMMON -source ${DRIVER_PATH}/../../datastore/ceph/ceph.conf - -#------------------------------------------------------------------------------- -# Set dst path and dir -#------------------------------------------------------------------------------- - -SRC_HOST=`arg_host $SRC` -SRC_PATH=`arg_path $SRC` - -#------------------------------------------------------------------------------- -# Get Image information -#------------------------------------------------------------------------------- - -DISK_ID=$(echo "$SRC_PATH" | $AWK -F. '{print $NF}') - -XPATH="${DRIVER_PATH}/../../datastore/xpath.rb --stdin" - -unset i j XPATH_ELEMENTS - -while IFS= read -r -d '' element; do - XPATH_ELEMENTS[i++]="$element" -done < <(onevm show -x $VM_ID| $XPATH \ - /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/SOURCE \ - /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CLONE \ - /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_USER) - -RBD_SRC="${XPATH_ELEMENTS[j++]}" -CLONE="${XPATH_ELEMENTS[j++]}" -CEPH_USER="${XPATH_ELEMENTS[j++]}" - -# No need to copy back to datastore no cloned images -if [ "$CLONE" = "NO" ]; then - exit 0 -fi - -if [ -n "$CEPH_USER" ]; then - RBD="$RBD --id ${CEPH_USER}" -fi - -# cloned, so the name will be "/one---" -RBD_DST="${RBD_SRC}-${VM_ID}-${DISK_ID}" -RBD_SNAP="${VM_ID}-${DISK_ID}" - -#------------------------------------------------------------------------------- -# Move the image back to the datastore -#------------------------------------------------------------------------------- - -log "Dumping $RBD_DST to $DST" - -DUMP_CMD=$(cat <&2 + exit 1 + fi + + $RBD snap create $RBD_DST@$SNAP_ID + $RBD snap protect $RBD_DST@$SNAP_ID + $RBD rename $RBD_DST $RBD_DST-$SNAP_ID + $RBD clone $RBD_DST-$SNAP_ID@$SNAP_ID $RBD_DST +EOF +) + +ssh_exec_and_log "$SRC_HOST" "$SNAP_CREATE_CMD" \ + "Error creating snapshot $RBD_DST@$SNAP_ID" + +exit 0 diff --git a/src/tm_mad/ceph/snap_delete b/src/tm_mad/ceph/snap_delete new file mode 100755 index 0000000000..60f4c27f39 --- /dev/null +++ b/src/tm_mad/ceph/snap_delete @@ -0,0 +1,98 @@ +#!/bin/bash + +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project (OpenNebula.org), C12G Labs # +# # +# 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. # +#--------------------------------------------------------------------------- # + +# snap_delete host:parent_image snap_id vmid ds_id + +SRC=$1 +SNAP_ID=$2 +VM_ID=$3 +DS_ID=$4 + +if [ -z "${ONE_LOCATION}" ]; then + TMCOMMON=/var/lib/one/remotes/tm/tm_common.sh +else + TMCOMMON=$ONE_LOCATION/var/remotes/tm/tm_common.sh +fi + +DRIVER_PATH=$(dirname $0) + +source $TMCOMMON +source ${DRIVER_PATH}/../../datastore/ceph/ceph.conf + +#------------------------------------------------------------------------------- +# Set dst path and dir +#------------------------------------------------------------------------------- + +SRC_HOST=`arg_host $SRC` +SRC_PATH=`arg_path $SRC` + +#------------------------------------------------------------------------------- +# Get Image information +#------------------------------------------------------------------------------- + +DISK_ID=$(echo "$SRC_PATH" | $AWK -F. '{print $NF}') + +XPATH="${DRIVER_PATH}/../../datastore/xpath.rb --stdin" + +unset i j XPATH_ELEMENTS + +while IFS= read -r -d '' element; do + XPATH_ELEMENTS[i++]="$element" +done < <(onevm show -x $VM_ID| $XPATH \ + /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/SOURCE \ + /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CLONE \ + /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_USER) + +RBD_SRC="${XPATH_ELEMENTS[j++]}" +CLONE="${XPATH_ELEMENTS[j++]}" +CEPH_USER="${XPATH_ELEMENTS[j++]}" + +if [ "$CLONE" = "NO" ]; then + RBD_DST="${RBD_SRC}" +else + RBD_DST="${RBD_SRC}-${VM_ID}-${DISK_ID}" +fi + +#------------------------------------------------------------------------------- +# Delete snapshots +#------------------------------------------------------------------------------- + +if [ -n "$CEPH_USER" ]; then + RBD="$RBD --id ${CEPH_USER}" +fi + +SNAP_DELETE_CMD=$(cat <&2 + exit 1 + fi + + $RBD snap unprotect $RBD_DST-$SNAP_ID@$SNAP_ID + $RBD snap rm $RBD_DST-$SNAP_ID@$SNAP_ID + $RBD rm $RBD_DST-$SNAP_ID +EOF +) + +ssh_exec_and_log "$SRC_HOST" "$SNAP_DELETE_CMD" \ + "Error deleting snapshot $RBD_DST-$SNAP_ID@$SNAP_ID" + +exit 0 diff --git a/src/tm_mad/ceph/snap_revert b/src/tm_mad/ceph/snap_revert new file mode 100755 index 0000000000..63f8366563 --- /dev/null +++ b/src/tm_mad/ceph/snap_revert @@ -0,0 +1,97 @@ +#!/bin/bash + +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project (OpenNebula.org), C12G Labs # +# # +# 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. # +#--------------------------------------------------------------------------- # + +# snap_revert host:parent_image snap_id vmid ds_id + +SRC=$1 +SNAP_ID=$2 +VM_ID=$3 +DS_ID=$4 + +if [ -z "${ONE_LOCATION}" ]; then + TMCOMMON=/var/lib/one/remotes/tm/tm_common.sh +else + TMCOMMON=$ONE_LOCATION/var/remotes/tm/tm_common.sh +fi + +DRIVER_PATH=$(dirname $0) + +source $TMCOMMON +source ${DRIVER_PATH}/../../datastore/ceph/ceph.conf + +#------------------------------------------------------------------------------- +# Set dst path and dir +#------------------------------------------------------------------------------- + +SRC_HOST=`arg_host $SRC` +SRC_PATH=`arg_path $SRC` + +#------------------------------------------------------------------------------- +# Get Image information +#------------------------------------------------------------------------------- + +DISK_ID=$(echo "$SRC_PATH" | $AWK -F. '{print $NF}') + +XPATH="${DRIVER_PATH}/../../datastore/xpath.rb --stdin" + +unset i j XPATH_ELEMENTS + +while IFS= read -r -d '' element; do + XPATH_ELEMENTS[i++]="$element" +done < <(onevm show -x $VM_ID| $XPATH \ + /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/SOURCE \ + /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CLONE \ + /VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CEPH_USER) + +RBD_SRC="${XPATH_ELEMENTS[j++]}" +CLONE="${XPATH_ELEMENTS[j++]}" +CEPH_USER="${XPATH_ELEMENTS[j++]}" + +if [ "$CLONE" = "NO" ]; then + RBD_DST="${RBD_SRC}" +else + RBD_DST="${RBD_SRC}-${VM_ID}-${DISK_ID}" +fi + +#------------------------------------------------------------------------------- +# Create snapshots +#------------------------------------------------------------------------------- + +if [ -n "$CEPH_USER" ]; then + RBD="$RBD --id ${CEPH_USER}" +fi + +SNAP_REVERT_CMD=$(cat <&2 + exit 1 + fi + + $RBD rm $RBD_DST + $RBD clone $RBD_DST-$SNAP_ID@$SNAP_ID $RBD_DST +EOF +) + +ssh_exec_and_log "$SRC_HOST" "$SNAP_REVERT_CMD" \ + "Error reverting snapshot $RBD_DST-$SNAP_ID@$SNAP_ID" + +exit 0 diff --git a/src/tm_mad/common/failmigrate b/src/tm_mad/common/failmigrate new file mode 100755 index 0000000000..49ab4a881d --- /dev/null +++ b/src/tm_mad/common/failmigrate @@ -0,0 +1,29 @@ +#!/bin/bash + +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project (OpenNebula.org), C12G Labs # +# # +# 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. # +#--------------------------------------------------------------------------- # +# FAILMIGRATE SOURCE DST remote_system_dir vmid dsid template +# - SOURCE is the host where the VM is running +# - DST is the host where the VM failed to be migrated +# - remote_system_dir is the path for the VM home in the system datastore +# - vmid is the id of the VM +# - dsid is the target datastore +# - template is the template of the VM in XML and base64 encoded + +# To access the vm_template you can use the xpath.rb utility. Check the +# datastore drivers for an example. + +exit 0 diff --git a/src/tm_mad/dev/failmigrate b/src/tm_mad/dev/failmigrate new file mode 120000 index 0000000000..5928a42794 --- /dev/null +++ b/src/tm_mad/dev/failmigrate @@ -0,0 +1 @@ +../common/failmigrate \ No newline at end of file diff --git a/src/tm_mad/dev/snap_create b/src/tm_mad/dev/snap_create new file mode 120000 index 0000000000..9c454e8cd4 --- /dev/null +++ b/src/tm_mad/dev/snap_create @@ -0,0 +1 @@ +../common/not_supported.sh \ No newline at end of file diff --git a/src/tm_mad/dev/snap_delete b/src/tm_mad/dev/snap_delete new file mode 120000 index 0000000000..9c454e8cd4 --- /dev/null +++ b/src/tm_mad/dev/snap_delete @@ -0,0 +1 @@ +../common/not_supported.sh \ No newline at end of file diff --git a/src/tm_mad/dev/snap_revert b/src/tm_mad/dev/snap_revert new file mode 120000 index 0000000000..9c454e8cd4 --- /dev/null +++ b/src/tm_mad/dev/snap_revert @@ -0,0 +1 @@ +../common/not_supported.sh \ No newline at end of file diff --git a/src/tm_mad/dummy/failmigrate b/src/tm_mad/dummy/failmigrate new file mode 120000 index 0000000000..5928a42794 --- /dev/null +++ b/src/tm_mad/dummy/failmigrate @@ -0,0 +1 @@ +../common/failmigrate \ No newline at end of file diff --git a/src/tm_mad/dummy/snap_create b/src/tm_mad/dummy/snap_create new file mode 120000 index 0000000000..9c454e8cd4 --- /dev/null +++ b/src/tm_mad/dummy/snap_create @@ -0,0 +1 @@ +../common/not_supported.sh \ No newline at end of file diff --git a/src/tm_mad/dummy/snap_delete b/src/tm_mad/dummy/snap_delete new file mode 120000 index 0000000000..9c454e8cd4 --- /dev/null +++ b/src/tm_mad/dummy/snap_delete @@ -0,0 +1 @@ +../common/not_supported.sh \ No newline at end of file diff --git a/src/tm_mad/dummy/snap_revert b/src/tm_mad/dummy/snap_revert new file mode 120000 index 0000000000..9c454e8cd4 --- /dev/null +++ b/src/tm_mad/dummy/snap_revert @@ -0,0 +1 @@ +../common/not_supported.sh \ No newline at end of file diff --git a/src/tm_mad/fs_lvm/cpds b/src/tm_mad/fs_lvm/cpds index f4df668072..6e88b772da 100755 --- a/src/tm_mad/fs_lvm/cpds +++ b/src/tm_mad/fs_lvm/cpds @@ -16,16 +16,18 @@ # limitations under the License. # #--------------------------------------------------------------------------- # -# mvds host:remote_system_ds/disk.i fe:SOURCE +# cpds host:remote_system_ds/disk.i fe:SOURCE snapid vmid dsid # - fe is the front-end hostname # - SOURCE is the path of the disk image in the form DS_BASE_PATH/disk # - host is the target host to deploy the VM # - remote_system_ds is the path for the system datastore in the host +# - snapid is the snapshot id. "-1" for none SRC=$1 DST=$2 -VM_ID=$3 -DS_ID=$4 +SNAP_ID=$3 +VM_ID=$4 +DS_ID=$5 if [ -z "${ONE_LOCATION}" ]; then TMCOMMON=/var/lib/one/remotes/tm/tm_common.sh diff --git a/src/tm_mad/fs_lvm/failmigrate b/src/tm_mad/fs_lvm/failmigrate new file mode 120000 index 0000000000..5928a42794 --- /dev/null +++ b/src/tm_mad/fs_lvm/failmigrate @@ -0,0 +1 @@ +../common/failmigrate \ No newline at end of file diff --git a/src/tm_mad/fs_lvm/snap_create b/src/tm_mad/fs_lvm/snap_create new file mode 120000 index 0000000000..9c454e8cd4 --- /dev/null +++ b/src/tm_mad/fs_lvm/snap_create @@ -0,0 +1 @@ +../common/not_supported.sh \ No newline at end of file diff --git a/src/tm_mad/fs_lvm/snap_delete b/src/tm_mad/fs_lvm/snap_delete new file mode 120000 index 0000000000..9c454e8cd4 --- /dev/null +++ b/src/tm_mad/fs_lvm/snap_delete @@ -0,0 +1 @@ +../common/not_supported.sh \ No newline at end of file diff --git a/src/tm_mad/fs_lvm/snap_revert b/src/tm_mad/fs_lvm/snap_revert new file mode 120000 index 0000000000..9c454e8cd4 --- /dev/null +++ b/src/tm_mad/fs_lvm/snap_revert @@ -0,0 +1 @@ +../common/not_supported.sh \ No newline at end of file diff --git a/src/tm_mad/lvm/cpds b/src/tm_mad/lvm/cpds index 8532363507..c97379f250 100755 --- a/src/tm_mad/lvm/cpds +++ b/src/tm_mad/lvm/cpds @@ -16,16 +16,18 @@ # limitations under the License. # #--------------------------------------------------------------------------- # -# mvds host:remote_system_ds/disk.i fe:SOURCE +# cpds host:remote_system_ds/disk.i fe:SOURCE snapid vmid dsid # - fe is the front-end hostname # - SOURCE is the path of the disk image in the form DS_BASE_PATH/disk # - host is the target host to deploy the VM # - remote_system_ds is the path for the system datastore in the host +# - snapid is the snapshot id. "-1" for none SRC=$1 DST=$2 -VM_ID=$3 -DS_ID=$4 +SNAP_ID=$3 +VM_ID=$4 +DS_ID=$5 if [ -z "${ONE_LOCATION}" ]; then TMCOMMON=/var/lib/one/remotes/tm/tm_common.sh diff --git a/src/tm_mad/lvm/failmigrate b/src/tm_mad/lvm/failmigrate new file mode 120000 index 0000000000..5928a42794 --- /dev/null +++ b/src/tm_mad/lvm/failmigrate @@ -0,0 +1 @@ +../common/failmigrate \ No newline at end of file diff --git a/src/tm_mad/lvm/mvds b/src/tm_mad/lvm/mvds index 1d80718a1b..55e35ec3a4 100755 --- a/src/tm_mad/lvm/mvds +++ b/src/tm_mad/lvm/mvds @@ -22,52 +22,4 @@ # - host is the target host to deploy the VM # - remote_system_ds is the path for the system datastore in the host -SRC=$1 -DST=$2 -VM_ID=$3 -DS_ID=$4 - -if [ -z "${ONE_LOCATION}" ]; then - TMCOMMON=/var/lib/one/remotes/tm/tm_common.sh -else - TMCOMMON=$ONE_LOCATION/var/remotes/tm/tm_common.sh -fi - -DRIVER_PATH=$(dirname $0) - -source $TMCOMMON -source ${DRIVER_PATH}/../../datastore/lvm/lvm.conf - -#------------------------------------------------------------------------------- -# Set dst path and dir -#------------------------------------------------------------------------------- -SRC_PATH=`arg_path $SRC` -SRC_HOST=`arg_host $SRC` - -DST_PATH=`arg_path $DST` -DST_HOST=`arg_host $DST` - -VG_NAME=$(echo $DST_PATH|cut -d. -f1) -LV_NAME=$(echo $DST_PATH|cut -d. -f2) - -TARGET_DEV=/dev/$VG_NAME/$LV_NAME - -DUMP_CMD=$(cat <trigger(AuthManager::AUTHENTICATE, &ar); ar.wait(); diff --git a/src/vm/SConstruct b/src/vm/SConstruct index 957aaa163a..1c29aa6180 100644 --- a/src/vm/SConstruct +++ b/src/vm/SConstruct @@ -47,7 +47,8 @@ source_files=[ 'vm_file_var_syntax.cc', 'VirtualMachinePool.cc', 'VirtualMachineHook.cc', - 'VirtualMachineTemplate.cc' + 'VirtualMachineTemplate.cc', + 'Snapshots.cc' ] # Build library diff --git a/src/vm/Snapshots.cc b/src/vm/Snapshots.cc new file mode 100644 index 0000000000..2cee81882b --- /dev/null +++ b/src/vm/Snapshots.cc @@ -0,0 +1,319 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project (OpenNebula.org), C12G Labs */ +/* */ +/* 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 "Snapshots.h" +#include "NebulaUtil.h" + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +Snapshots::Snapshots(int _disk_id): + snapshot_template(false,'=',"SNAPSHOTS"), + next_snapshot(0), + active(-1), + disk_id(_disk_id) +{ + if (_disk_id != -1) + { + snapshot_template.add("DISK_ID",_disk_id); + } +}; + +Snapshots::Snapshots(const Snapshots& s): + snapshot_template(s.snapshot_template), + next_snapshot(0), + active(-1), + disk_id(-1) +{ + init(); +} + + +Snapshots& Snapshots::operator= (const Snapshots& s) +{ + if (this != &s) + { + next_snapshot = s.next_snapshot; + active = s.active; + disk_id = s.disk_id; + + snapshot_template = s.snapshot_template; + + snapshot_pool.clear(); + + init(); + } + + return *this; +} + +Snapshots::~Snapshots(){}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int Snapshots::from_xml_node(const xmlNodePtr node) +{ + int rc = snapshot_template.from_xml_node(node); + + if (rc != 0) + { + return -1; + } + + init(); + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +void Snapshots::init() +{ + vector vsnap; + + unsigned int id; + bool current; + + int num_snap = snapshot_template.get("SNAPSHOT", vsnap); + + for (int i=0; i < num_snap; i++) + { + VectorAttribute * snap = static_cast(vsnap[i]); + + snap->vector_value("ID", id); + + snap->vector_value("ACTIVE", current); + + if (current) + { + active = id; + } + + if (id >= next_snapshot) + { + next_snapshot = id + 1; + } + + snapshot_pool.insert(pair(id, snap)); + } + + int did; + + if (snapshot_template.get("DISK_ID", did)) + { + disk_id = did; + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int Snapshots::create_snapshot(const string& tag) +{ + VectorAttribute * snapshot = new VectorAttribute("SNAPSHOT"); + + if (!tag.empty()) + { + snapshot->replace("TAG",tag); + } + + snapshot->replace("ID", next_snapshot); + snapshot->replace("DATE", static_cast(time(0))); + snapshot->replace("PARENT", active); + + if (active != -1) + { + VectorAttribute * parent = get_snapshot(active); + + if (parent == 0) + { + delete snapshot; + return -1; + } + + string children = parent->vector_value("CHILDREN"); + + if (children.empty()) + { + parent->replace("CHILDREN", next_snapshot); + } + else + { + ostringstream oss; + + oss << children << "," << next_snapshot; + + parent->replace("CHILDREN", oss.str()); + } + } + + snapshot_template.set(snapshot); + + snapshot_pool.insert( + pair(next_snapshot, snapshot)); + + return next_snapshot++; +}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void Snapshots::delete_snapshot(unsigned int id) +{ + int parent_id; + + VectorAttribute * snapshot = get_snapshot(id); + + if (snapshot == 0) + { + return; + } + + snapshot->vector_value("PARENT", parent_id); + + if (parent_id != -1) + { + set child_set; + + VectorAttribute * parent = get_snapshot(parent_id); + + if (parent != 0) + { + string children = parent->vector_value("CHILDREN"); + + one_util::split_unique(children, ',', child_set); + + child_set.erase(id); + + children = one_util::join(child_set.begin(), child_set.end(), ','); + + if (children.empty()) + { + parent->remove("CHILDREN"); + } + else + { + parent->replace("CHILDREN", children); + } + } + } + + snapshot_template.remove(snapshot); + + delete snapshot; + + snapshot_pool.erase(id); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int Snapshots::active_snapshot(unsigned int id) +{ + if (static_cast(id) == active) + { + return 0; + } + + VectorAttribute * snapshot = get_snapshot(id); + + if (snapshot == 0) + { + return -1; + } + + snapshot->replace("ACTIVE", true); + + snapshot = get_snapshot(active); + + if (snapshot != 0) + { + snapshot->remove("ACTIVE"); + } + + active = id; + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +const VectorAttribute * Snapshots::get_snapshot(unsigned int id) const +{ + map::const_iterator it; + + it = snapshot_pool.find(id); + + if (it == snapshot_pool.end()) + { + return 0; + } + + return it->second; +}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +string Snapshots::get_snapshot_attribute(unsigned int id, const char * name) +{ + VectorAttribute * snapshot = get_snapshot(id); + + if (snapshot == 0) + { + return ""; + } + + return snapshot->vector_value(name); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +bool Snapshots::test_delete(unsigned int id, string& error) const +{ + bool current; + string children; + + const VectorAttribute * snapshot = get_snapshot(id); + + if (snapshot == 0) + { + error = "Snapshot does not exists"; + return false; + } + + snapshot->vector_value("ACTIVE", current); + + if (current) + { + error = "Cannot delete the active snapshot"; + return false; + } + + snapshot->vector_value("CHILDREN", children); + + if (!children.empty()) + { + error = "Cannot delete snapshot with children"; + return false; + } + + return true; +} + diff --git a/src/vm/VirtualMachine.cc b/src/vm/VirtualMachine.cc index bc5526fa37..a87af5db8f 100644 --- a/src/vm/VirtualMachine.cc +++ b/src/vm/VirtualMachine.cc @@ -30,6 +30,7 @@ #include "ImagePool.h" #include "NebulaLog.h" #include "NebulaUtil.h" +#include "Snapshots.h" #include "Nebula.h" @@ -89,6 +90,12 @@ VirtualMachine::~VirtualMachine() delete history_records[i]; } + for (map::const_iterator it = snapshots.begin(); + it != snapshots.end() ; it++) + { + delete it->second; + } + delete _log; delete obj_template; delete user_obj_template; @@ -883,12 +890,12 @@ int VirtualMachine::parse_context(string& error_str) continue; } - parse_context_network(NETWORK_CONTEXT, NUM_NETWORK_CONTEXT, + parse_context_network(NETWORK_CONTEXT, NUM_NETWORK_CONTEXT, context, vatt); if (!vatt->vector_value("IP6_GLOBAL").empty()) { - parse_context_network(NETWORK6_CONTEXT, NUM_NETWORK6_CONTEXT, + parse_context_network(NETWORK6_CONTEXT, NUM_NETWORK6_CONTEXT, context, vatt); } } @@ -1791,6 +1798,8 @@ int VirtualMachine::get_disk_images(string& error_str) // ------------------------------------------------------------------------- for(int i=0; i(disks[i]); if ( disk == 0 ) @@ -1805,9 +1814,22 @@ int VirtualMachine::get_disk_images(string& error_str) dev_prefix, uid, image_id, + &snap, error_str); if (rc == 0 ) { + if (snap != 0) + { + if (img_type == Image::OS || img_type == Image::DATABLOCK) + { + snapshots.insert(pair(i, snap)); + } + else + { + delete snap; + } + } + acquired_images.push_back(image_id); target = disk->vector_value("TARGET"); @@ -1997,6 +2019,7 @@ VectorAttribute * VirtualMachine::set_up_attach_disk( int max_disk_id, int uid, int& image_id, + Snapshots ** snap, string& error_str) { vector disks; @@ -2012,6 +2035,7 @@ VectorAttribute * VirtualMachine::set_up_attach_disk( Image::ImageType img_type; image_id = -1; + *snap = 0; // ------------------------------------------------------------------------- // Get the DISK attribute from the template @@ -2044,6 +2068,7 @@ VectorAttribute * VirtualMachine::set_up_attach_disk( dev_prefix, uid, image_id, + snap, error_str); if ( rc != 0 ) { @@ -2065,6 +2090,8 @@ VectorAttribute * VirtualMachine::set_up_attach_disk( imagem->release_image(vm_id, image_id, false); delete new_disk; + delete snap; + return 0; } } @@ -2158,13 +2185,15 @@ void VirtualMachine::clear_attach_disk() /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -VectorAttribute * VirtualMachine::delete_attach_disk() +VectorAttribute * VirtualMachine::delete_attach_disk(Snapshots **snap) { vector disks; VectorAttribute * disk; int num_disks = obj_template->get("DISK", disks); + *snap = 0; + for(int i=0; i(disks[i]); @@ -2176,6 +2205,18 @@ VectorAttribute * VirtualMachine::delete_attach_disk() if ( disk->vector_value("ATTACH") == "YES" ) { + int disk_id; + + disk->vector_value("DISK_ID", disk_id); + + map::iterator it = snapshots.find(disk_id); + + if (it != snapshots.end()) + { + *snap = it->second; + snapshots.erase(it); + } + return static_cast(obj_template->remove(disk)); } } @@ -2488,9 +2529,9 @@ int VirtualMachine::set_attach_nic(int nic_id) void VirtualMachine::release_disk_images() { - int iid; - int save_as_id; - int num_disks; + int iid; + int num_disks; + int did = -1; bool img_error; @@ -2516,14 +2557,19 @@ void VirtualMachine::release_disk_images() img_error = state != ACTIVE || lcm_state != EPILOG; + if ( disk->vector_value("IMAGE_ID", iid) == 0 ) { - imagem->release_image(oid, iid, img_error); - } + disk->vector_value("DISK_ID", did); - if ( disk->vector_value("SAVE_AS", save_as_id) == 0 ) - { - imagem->release_image(oid, save_as_id, img_error); + map::iterator it = snapshots.find(did); + + if (it != snapshots.end()) + { + imagem->set_image_snapshots(iid, *(it->second), img_error); + } + + imagem->release_image(oid, iid, img_error); } } } @@ -2987,7 +3033,8 @@ void VirtualMachine::release_security_groups(int id, VectorAttribute const * nic /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -int VirtualMachine::generate_context(string &files, int &disk_id, string& token_password) +int VirtualMachine::generate_context(string &files, int &disk_id, + string& token_password) { ofstream file; string files_ds; @@ -3126,178 +3173,22 @@ int VirtualMachine::generate_context(string &files, int &disk_id, string& token_ return 1; } -/* -------------------------------------------------------------------------- */ - -int VirtualMachine::get_image_from_disk(int disk_id, bool hot, string& err_str) -{ - int iid = -1; - int rc; - - VectorAttribute * disk; - - ostringstream oss; - - disk = get_disk(disk_id); - - if ( disk == 0 ) - { - goto error_not_found; - } - - if(!((disk->vector_value("SAVE_AS")).empty())) - { - goto error_saved; - } - - if(!(disk->vector_value("PERSISTENT").empty()) && !hot) - { - goto error_persistent; - } - - rc = disk->vector_value("IMAGE_ID", iid); - - if ( rc != 0 ) - { - goto error_image_id; - } - - return iid; - -error_persistent: - oss << "Source image for DISK " << disk_id << " is persistent."; - goto error_common; - -error_saved: - oss << "The DISK " << disk_id << " is already going to be saved."; - goto error_common; - -error_image_id: - oss << "The DISK " << disk_id << " does not have a valid IMAGE_ID."; - goto error_common; - -error_not_found: - oss << "The DISK " << disk_id << " does not exist for VM " << oid << "."; - -error_common: - err_str = oss.str(); - - return -1; -} - /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -int VirtualMachine::set_saveas_state(int disk_id, bool hot) -{ - VectorAttribute* disk; - - switch (state) - { - case ACTIVE: - switch (lcm_state) - { - case RUNNING: - lcm_state = HOTPLUG_SAVEAS; - break; - - default: - return -1; - } - break; - - case POWEROFF: - state = ACTIVE; - lcm_state = HOTPLUG_SAVEAS_POWEROFF; - break; - - case SUSPENDED: - state = ACTIVE; - lcm_state = HOTPLUG_SAVEAS_SUSPENDED; - break; - - default: - return -1; - } - - disk = get_disk(disk_id); - - if ( disk != 0 ) - { - if (hot) - { - disk->replace("HOTPLUG_SAVE_AS_ACTIVE", "YES"); - } - else - { - disk->replace("SAVE_AS_ACTIVE", "YES"); - } - } - - return 0; -} - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - -int VirtualMachine::clear_saveas_state(int disk_id, bool hot) -{ - VectorAttribute * disk; - - disk = get_disk(disk_id); - - if (disk != 0) - { - if (hot) - { - disk->remove("HOTPLUG_SAVE_AS_ACTIVE"); - disk->remove("HOTPLUG_SAVE_AS"); - disk->remove("HOTPLUG_SAVE_AS_SOURCE"); - } - else - { - disk->remove("SAVE_AS_ACTIVE"); - } - } - - switch (lcm_state) - { - case HOTPLUG_SAVEAS: - lcm_state = RUNNING; - break; - - case HOTPLUG_SAVEAS_POWEROFF: - state = POWEROFF; - lcm_state = LCM_INIT; - break; - - case HOTPLUG_SAVEAS_SUSPENDED: - state = SUSPENDED; - lcm_state = LCM_INIT; - break; - - default: - return -1; - } - - return 0; -} - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - -VectorAttribute* VirtualMachine::get_disk(int disk_id) +const VectorAttribute* VirtualMachine::get_disk(int disk_id) const { int num_disks; int tdisk_id; - vector disks; - VectorAttribute * disk; + vector disks; + const VectorAttribute * disk; num_disks = obj_template->get("DISK", disks); for(int i=0; i(disks[i]); + disk = dynamic_cast(disks[i]); if ( disk == 0 ) { @@ -3318,27 +3209,130 @@ VectorAttribute* VirtualMachine::get_disk(int disk_id) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -int VirtualMachine::save_disk(int disk_id, - const string& source, - int img_id) +int VirtualMachine::set_saveas_disk(int disk_id, int snap_id, string& err_str) { - VectorAttribute * disk; + int iid = -1; + VectorAttribute * disk = get_disk(disk_id); + + if (disk == 0) + { + err_str = "DISK does not exist."; + return -1; + } + + if (disk->vector_value("IMAGE_ID", iid) != 0) + { + err_str = "DISK does not have a valid IMAGE_ID."; + return -1; + } + + const Snapshots * snaps = get_disk_snapshots(disk_id, err_str); + + if (snap_id != -1) + { + if (snaps == 0 || !snaps->exists(snap_id)) + { + err_str = "Snapshot does not exist."; + return -1; + } + } + + disk->replace("HOTPLUG_SAVE_AS_ACTIVE", "YES"); + disk->replace("HOTPLUG_SAVE_AS_SNAPSHOT_ID", snap_id); + + return iid; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int VirtualMachine::set_saveas_disk(int disk_id, const string& source, int iid) +{ if (lcm_state != HOTPLUG_SAVEAS && lcm_state != HOTPLUG_SAVEAS_SUSPENDED && lcm_state != HOTPLUG_SAVEAS_POWEROFF ) { return -1; } - disk = get_disk(disk_id); + VectorAttribute * disk = get_disk(disk_id); - if ( disk != 0 ) + if ( disk == 0 ) { - disk->replace("SAVE_AS_SOURCE", source); + return -1; + } - disk->replace("SAVE_AS", img_id); + disk->replace("HOTPLUG_SAVE_AS", iid); + disk->replace("HOTPLUG_SAVE_AS_SOURCE", source); - disk->replace("SAVE", "YES"); + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int VirtualMachine::set_saveas_state() +{ + string s; + + switch (state) + { + case ACTIVE: + if (lcm_state != RUNNING) + { + return -1; + } + + lcm_state = HOTPLUG_SAVEAS; + break; + + case POWEROFF: + state = ACTIVE; + lcm_state = HOTPLUG_SAVEAS_POWEROFF; + break; + + case SUSPENDED: + state = ACTIVE; + lcm_state = HOTPLUG_SAVEAS_SUSPENDED; + break; + + default: + return -1; + } + + log("VM", Log::INFO, "New state is " + lcm_state_to_str(s,lcm_state)); + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int VirtualMachine::clear_saveas_state() +{ + string s; + + switch (lcm_state) + { + case HOTPLUG_SAVEAS: + lcm_state = RUNNING; + log("VM", Log::INFO, "New state is "+lcm_state_to_str(s,lcm_state)); + break; + + case HOTPLUG_SAVEAS_POWEROFF: + state = POWEROFF; + lcm_state = LCM_INIT; + log("VM", Log::INFO, "New state is " + vm_state_to_str(s,state)); + break; + + case HOTPLUG_SAVEAS_SUSPENDED: + state = SUSPENDED; + lcm_state = LCM_INIT; + log("VM", Log::INFO, "New state is " + vm_state_to_str(s,state)); + break; + + default: + return -1; } return 0; @@ -3347,78 +3341,49 @@ int VirtualMachine::save_disk(int disk_id, /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -int VirtualMachine::clear_save_disk(int disk_id) +int VirtualMachine::clear_saveas_disk() { - VectorAttribute * disk; + vector disks; + VectorAttribute * disk; - disk = get_disk(disk_id); + int num_disks, image_id; + bool active; - if ( disk != 0 ) + num_disks = obj_template->get("DISK", disks); + + for(int i=0; iremove("SAVE_AS_SOURCE"); - disk->remove("SAVE_AS"); - disk->replace("SAVE", "NO"); + disk = dynamic_cast(disks[i]); - return 0; + if ( disk == 0 ) + { + continue; + } + + disk->vector_value("HOTPLUG_SAVE_AS_ACTIVE", active); + + if (active) + { + disk->vector_value("HOTPLUG_SAVE_AS", image_id); + + disk->remove("HOTPLUG_SAVE_AS_ACTIVE"); + disk->remove("HOTPLUG_SAVE_AS"); + disk->remove("HOTPLUG_SAVE_AS_SOURCE"); + disk->remove("HOTPLUG_SAVE_AS_SNAPSHOT_ID"); + + return image_id; + } } return -1; } -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - -int VirtualMachine::get_save_disk_image(int disk_id) -{ - VectorAttribute * disk; - bool save; - int img_id = -1; - - disk = get_disk(disk_id); - - if ( disk != 0 ) - { - disk->vector_value("SAVE", save); - - if (save) - { - disk->vector_value("SAVE_AS", img_id); - } - } - - return img_id; -} /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -int VirtualMachine::save_disk_hot(int disk_id, - const string& source, - int img_id) -{ - VectorAttribute * disk; - - if (lcm_state != HOTPLUG_SAVEAS && lcm_state != HOTPLUG_SAVEAS_SUSPENDED - && lcm_state != HOTPLUG_SAVEAS_POWEROFF ) - { - return -1; - } - - disk = get_disk(disk_id); - - if ( disk != 0 ) - { - disk->replace("HOTPLUG_SAVE_AS", img_id); - disk->replace("HOTPLUG_SAVE_AS_SOURCE", source); - } - - return 0; -} - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - -int VirtualMachine::get_saveas_disk_hot(int& disk_id, string& source, int& image_id) +int VirtualMachine::get_saveas_disk(int& disk_id, string& source, + int& image_id, string& snap_id, string& tm_mad, string& ds_id) { vector disks; VectorAttribute * disk; @@ -3439,78 +3404,20 @@ int VirtualMachine::get_saveas_disk_hot(int& disk_id, string& source, int& image if ( disk->vector_value("HOTPLUG_SAVE_AS_ACTIVE") == "YES" ) { - source = disk->vector_value("HOTPLUG_SAVE_AS_SOURCE"); - - rc = disk->vector_value("HOTPLUG_SAVE_AS", image_id); + rc = disk->vector_value("HOTPLUG_SAVE_AS_SOURCE", source); + rc += disk->vector_value("HOTPLUG_SAVE_AS", image_id); + rc += disk->vector_value("HOTPLUG_SAVE_AS_SNAPSHOT_ID", snap_id); rc += disk->vector_value("DISK_ID", disk_id); + rc += disk->vector_value("DATASTORE_ID", ds_id); + rc += disk->vector_value("TM_MAD", tm_mad); - if ( rc != 0 || source.empty() ) - { - return -1; - } - - return 0; + return rc; } } return -1; } -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - -int VirtualMachine::cancel_saveas_disk(int& image_id) -{ - vector disks; - VectorAttribute * disk; - - int num_disks; - - num_disks = obj_template->get("DISK", disks); - - bool active, hot_active; - - image_id = -1; - - for(int i=0; i(disks[i]); - - if ( disk == 0 ) - { - continue; - } - - disk->vector_value("SAVE_AS_ACTIVE", active); - disk->vector_value("HOTPLUG_SAVE_AS_ACTIVE", hot_active); - - if (active) - { - disk->vector_value("SAVE_AS", image_id); - - disk->remove("SAVE_AS_ACTIVE"); - disk->remove("SAVE_AS_SOURCE"); - disk->remove("SAVE_AS"); - - disk->replace("SAVE", "NO"); - - return 0; - } - - if (hot_active) - { - disk->vector_value("HOTPLUG_SAVE_AS", image_id); - - disk->remove("HOTPLUG_SAVE_AS_ACTIVE"); - disk->remove("HOTPLUG_SAVE_AS"); - disk->remove("HOTPLUG_SAVE_AS_SOURCE"); - - return 0; - } - } - - return -1; -} /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ @@ -3731,6 +3638,8 @@ string& VirtualMachine::to_xml_extended(string& xml, int n_history) const string user_template_xml; string history_xml; string perm_xml; + string snap_xml; + ostringstream oss; oss << "" @@ -3780,6 +3689,12 @@ string& VirtualMachine::to_xml_extended(string& xml, int n_history) const oss << ""; } + for (map::const_iterator it = snapshots.begin(); + it != snapshots.end() ; it++) + { + oss << it->second->to_xml(snap_xml); + } + oss << ""; xml = oss.str(); @@ -3878,6 +3793,32 @@ int VirtualMachine::from_xml(const string &xml_str) history_records[history->seq] = history; ObjectXML::free_nodes(content); + content.clear(); + } + + // Virtual Machine user template + + ObjectXML::get_nodes("/VM/SNAPSHOTS", content); + + for (vector::iterator it=content.begin();it!=content.end();it++) + { + Snapshots * snap = new Snapshots(-1); + + rc += snap->from_xml_node(*it); + + if ( rc != 0) + { + delete snap; + break; + } + + snapshots.insert(pair(snap->get_disk_id(), snap)); + } + + if (!content.empty()) + { + ObjectXML::free_nodes(content); + content.clear(); } if (rc != 0) @@ -4078,7 +4019,8 @@ void VirtualMachine::clear_template_monitor_error() /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -int VirtualMachine::get_public_cloud_hypervisors(vector &public_cloud_hypervisors) const +int VirtualMachine::get_public_cloud_hypervisors( + vector &public_cloud_hypervisors) const { vector attrs; vector::const_iterator it; @@ -4116,3 +4058,242 @@ int VirtualMachine::get_public_cloud_hypervisors(vector &public_cloud_hy return public_cloud_hypervisors.size(); } + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int VirtualMachine::set_snapshot_disk(int did, int snap_id) +{ + VectorAttribute * disk; + + disk = get_disk(did); + + if ( disk == 0 ) + { + return -1; + } + + disk->replace("DISK_SNAPSHOT_ACTIVE", "YES"); + disk->replace("DISK_SNAPSHOT_ID", snap_id); + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +void VirtualMachine::clear_snapshot_disk() +{ + int num_disks; + vector disks; + VectorAttribute * disk; + + num_disks = obj_template->get("DISK", disks); + + for(int i=0; i(disks[i]); + + if ( disk == 0 ) + { + continue; + } + + if ( disk->vector_value("DISK_SNAPSHOT_ACTIVE") == "YES" ) + { + disk->remove("DISK_SNAPSHOT_ACTIVE"); + disk->remove("DISK_SNAPSHOT_ID"); + return; + } + } +} + +/* -------------------------------------------------------------------------- */ + +int VirtualMachine::get_snapshot_disk(string& ds_id, string& tm_mad, + string& disk_id, string& snap_id) +{ + vector disks; + VectorAttribute * disk; + + int num_disks; + + num_disks = obj_template->get("DISK", disks); + + for(int i=0; i(disks[i]); + + if ( disk == 0 ) + { + continue; + } + + if ( disk->vector_value("DISK_SNAPSHOT_ACTIVE") == "YES" ) + { + map::iterator it; + int did; + + if (disk->vector_value("DISK_ID", did) == -1) + { + return -1; + } + + it = snapshots.find(did); + + if (it == snapshots.end()) + { + return -1; + } + + tm_mad = disk->vector_value("TM_MAD"); + ds_id = disk->vector_value("DATASTORE_ID"); + disk_id = disk->vector_value("DISK_ID"); + snap_id = disk->vector_value("DISK_SNAPSHOT_ID"); + + if (snap_id.empty()||tm_mad.empty()||ds_id.empty()||disk_id.empty()) + { + return -1; + } + + return 0; + } + } + + return -1; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int VirtualMachine::new_disk_snapshot(int did, const string& tag, string& error) +{ + map::iterator it; + int snap_id; + + VectorAttribute * disk; + + disk = get_disk(did); + + if ( disk == 0 ) + { + error = "VM disk does not exists"; + return -1; + } + + if (isVolatile(disk)) + { + error = "Cannot make snapshots on volatile disks"; + return -1; + } + + it = snapshots.find(did); + + if ( it == snapshots.end() ) + { + Snapshots * snap = new Snapshots(did); + + snap_id = snap->create_snapshot(tag); + + if (snap_id != -1) + { + snapshots.insert(pair(did, snap)); + } + else + { + delete snap; + } + } + else + { + snap_id = it->second->create_snapshot(tag); + } + + if (snap_id != -1) + { + disk->replace("DISK_SNAPSHOT_ACTIVE", "YES"); + disk->replace("DISK_SNAPSHOT_ID", snap_id); + } + + return snap_id; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +const Snapshots * VirtualMachine::get_disk_snapshots(int did, string& error) const +{ + const VectorAttribute * disk = get_disk(did); + + if ( disk == 0 ) + { + error = "VM disk does not exists"; + return 0; + } + + map::const_iterator it = snapshots.find(did); + + if (it == snapshots.end()) + { + error = "Snapshot does not exists"; + return 0; + } + + return it->second; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int VirtualMachine::revert_disk_snapshot(int did, int snap_id) +{ + map::iterator it; + + VectorAttribute * disk = get_disk(did); + + if ( disk == 0 ) + { + return -1; + } + + it = snapshots.find(did); + + if (it == snapshots.end()) + { + return -1; + } + + return it->second->active_snapshot(snap_id); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void VirtualMachine::delete_disk_snapshot(int did, int snap_id) +{ + map::iterator it; + VectorAttribute * disk = get_disk(did); + + if ( disk == 0 ) + { + return; + } + + it = snapshots.find(did); + + if (it == snapshots.end()) + { + return; + } + + it->second->delete_snapshot(snap_id); + + if (it->second->size() == 0) + { + Snapshots * tmp = it->second; + + snapshots.erase(it); + + delete tmp; + } +} + diff --git a/src/vm/VirtualMachinePool.cc b/src/vm/VirtualMachinePool.cc index fdb9455f02..43f83fd109 100644 --- a/src/vm/VirtualMachinePool.cc +++ b/src/vm/VirtualMachinePool.cc @@ -222,7 +222,7 @@ VirtualMachinePool::VirtualMachinePool( /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -int VirtualMachinePool::insert_index(const string& deploy_id, int vmid, +int VirtualMachinePool::insert_index(const string& deploy_id, int vmid, bool replace) { ostringstream oss; @@ -262,7 +262,7 @@ void VirtualMachinePool::drop_index(const string& deploy_id) return; } - oss << "DELETE FROM " << import_table << " WHERE deploy_id='" + oss << "DELETE FROM " << import_table << " WHERE deploy_id='" << deploy_name << "'"; db->exec(oss); @@ -541,13 +541,13 @@ int VirtualMachinePool::db_int_cb(void * _int_output, int num, char **values, ch int VirtualMachinePool::get_vmid (const string& deploy_id) { int rc; - int vmid = -1; + int vmid = -1; ostringstream oss; set_callback(static_cast(&VirtualMachinePool::db_int_cb), static_cast(&vmid)); - oss << "SELECT vmid FROM " << import_table + oss << "SELECT vmid FROM " << import_table << " WHERE deploy_id = '" << db->escape_str(deploy_id.c_str()) << "'"; rc = db->exec(oss, this); @@ -634,7 +634,7 @@ int VirtualMachinePool::calculate_showback( vector showback_slots; vector::iterator slot_it; - + map > vm_cost; map >::iterator vm_it; @@ -1028,10 +1028,11 @@ int VirtualMachinePool::calculate_showback( /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -void VirtualMachinePool::delete_attach_disk(int vid, bool release_save_as) +void VirtualMachinePool::delete_attach_disk(int vid) { VirtualMachine * vm; VectorAttribute * disk; + Snapshots * snap; int uid; int gid; @@ -1044,7 +1045,7 @@ void VirtualMachinePool::delete_attach_disk(int vid, bool release_save_as) return; } - disk = vm->delete_attach_disk(); + disk = vm->delete_attach_disk(&snap); uid = vm->get_uid(); gid = vm->get_gid(); oid = vm->get_oid(); @@ -1068,18 +1069,13 @@ void VirtualMachinePool::delete_attach_disk(int vid, bool release_save_as) // Disk using an Image Quotas::quota_del(Quotas::IMAGE, uid, gid, &tmpl); - imagem->release_image(oid, image_id, false); - - // Release non-persistent images in the detach event - if (release_save_as) + if (snap != 0) { - int save_as_id; - - if ( disk->vector_value("SAVE_AS", save_as_id) == 0 ) - { - imagem->release_image(oid, save_as_id, false); - } + imagem->set_image_snapshots(image_id, *snap, false); + delete snap; } + + imagem->release_image(oid, image_id, false); } else // Volatile disk { diff --git a/src/vmm_mad/exec/one_vmm_exec.rb b/src/vmm_mad/exec/one_vmm_exec.rb index 4e4ffaa7b2..3f45fb4560 100755 --- a/src/vmm_mad/exec/one_vmm_exec.rb +++ b/src/vmm_mad/exec/one_vmm_exec.rb @@ -478,9 +478,11 @@ class ExecDriver < VirtualMachineDriver action = VmmAction.new(self, id, :migrate, drv_message) pre = "PRE" post = "POST" + failed = "FAIL" pre << action.data[:tm_command] << " " << action.data[:vm] post << action.data[:tm_command] << " " << action.data[:vm] + failed << action.data[:tm_command] << " " << action.data[:vm] steps=[ # Execute a pre-migrate TM setup @@ -499,7 +501,15 @@ class ExecDriver < VirtualMachineDriver { :driver => :vmm, :action => :migrate, - :parameters => [:deploy_id, :dest_host, :host] + :parameters => [:deploy_id, :dest_host, :host], + :fail_actions => [ + { + :driver => :tm, + :action => :tm_failmigrate, + :parameters => failed.split, + :no_fail => true + } + ] }, # Execute networking clean up operations # NOTE: VM is now in the new host. If we fail from now on, oned will diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index c65ae733da..a85ff1fbc6 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -146,7 +146,50 @@ class VIClient # The associated resource pool for this connection ######################################################################## def resource_pool - return @cluster.resourcePool + rp_name = @one_host["TEMPLATE/VCENTER_RESOURCE_POOL"] + + if rp_name.nil? + @cluster.resourcePool + else + find_resource_pool(rp_name) + end + end + + ######################################################################## + # Searches the desired ResourcePool of the DataCenter for the current + # connection. Returns a RbVmomi::VIM::ResourcePool or the default pool + # if not found + # @param rpool [String] the ResourcePool name + ######################################################################## + def find_resource_pool(poolName) + baseEntity = @cluster + entityArray = poolName.split('/') + entityArray.each do |entityArrItem| + if entityArrItem != '' + if baseEntity.is_a? RbVmomi::VIM::Folder + baseEntity = baseEntity.childEntity.find { |f| + f.name == entityArrItem + } or return @cluster.resourcePool + elsif baseEntity.is_a? RbVmomi::VIM::ClusterComputeResource + baseEntity = baseEntity.resourcePool.resourcePool.find { |f| + f.name == entityArrItem + } or return @cluster.resourcePool + elsif baseEntity.is_a? RbVmomi::VIM::ResourcePool + baseEntity = baseEntity.resourcePool.find { |f| + f.name == entityArrItem + } or return @cluster.resourcePool + else + return @cluster.resourcePool + end + end + end + + if !baseEntity.is_a?(RbVmomi::VIM::ResourcePool) and + baseEntity.respond_to?(:resourcePool) + baseEntity = baseEntity.resourcePool + end + + baseEntity end ######################################################################## @@ -221,7 +264,7 @@ class VIClient datacenters.each { |dc| vms = get_entities(dc.vmFolder, 'VirtualMachine') - tmp = vms.select { |v| v.config.template == true } + tmp = vms.select { |v| v.config && (v.config.template == true) } one_tmp = [] @@ -691,6 +734,22 @@ class VCenterVm hid = VIClient::translate_hostname(hostname) connection = VIClient.new(hid) vm = connection.find_vm_template(deploy_id) + + # Find out if we need to reconfigure capacity + xml = REXML::Document.new xml_text + + expected_cpu = xml.root.elements["//TEMPLATE/VCPU"].text + expected_memory = xml.root.elements["//TEMPLATE/MEMORY"].text + current_cpu = vm.config.hardware.numCPU + current_memory = vm.config.hardware.memoryMB + + if current_cpu != expected_cpu or current_memory != expected_memory + capacity_hash = {:numCPUs => expected_cpu.to_i, + :memoryMB => expected_memory } + spec = RbVmomi::VIM.VirtualMachineConfigSpec(capacity_hash) + vm.ReconfigVM_Task(:spec => spec).wait_for_completion + end + vm.PowerOnVM_Task.wait_for_completion return vm.config.uuid end @@ -1200,7 +1259,6 @@ private def self.clone_vm(xml_text) xml = REXML::Document.new xml_text - pcs = xml.root.get_elements("//USER_TEMPLATE/PUBLIC_CLOUD") raise "Cannot find VCenter element in VM template." if pcs.nil? @@ -1217,33 +1275,29 @@ private raise "Cannot find VM_TEMPLATE in VCenter element." if uuid.nil? uuid = uuid.text - vmid = xml.root.elements["/VM/ID"].text - hid = xml.root.elements["//HISTORY_RECORDS/HISTORY/HID"] raise "Cannot find host id in deployment file history." if hid.nil? context = xml.root.elements["//TEMPLATE/CONTEXT"] - connection = VIClient.new(hid) - vc_template = connection.find_vm_template(uuid) relocate_spec = RbVmomi::VIM.VirtualMachineRelocateSpec( - :diskMoveType => :moveChildMostDiskBacking, - :pool => connection.resource_pool) + :diskMoveType => :moveChildMostDiskBacking, + :pool => connection.resource_pool) clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec( - :location => relocate_spec, - :powerOn => false, - :template => false) + :location => relocate_spec, + :powerOn => false, + :template => false) begin vm = vc_template.CloneVM_Task( - :folder => vc_template.parent, - :name => "one-#{vmid}", - :spec => clone_spec).wait_for_completion + :folder => vc_template.parent, + :name => "one-#{vmid}", + :spec => clone_spec).wait_for_completion rescue Exception => e if !e.message.start_with?('DuplicateName') @@ -1254,8 +1308,7 @@ private raise "Cannot clone VM Template" if vm.nil? - vm.Destroy_Task.wait_for_completion - + vm.Destroy_Task.wait_for_completion vm = vc_template.CloneVM_Task( :folder => vc_template.parent, :name => "one-#{vmid}", @@ -1309,6 +1362,7 @@ private end # NIC section, build the reconfig hash + nics = xml.root.get_elements("//TEMPLATE/NIC") nic_spec = {} @@ -1324,12 +1378,19 @@ private nic_spec = {:deviceChange => nic_array} end - if !context_vnc_spec.empty? or !nic_spec.empty? - spec_hash = context_vnc_spec.merge(nic_spec) - spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash) - vm.ReconfigVM_Task(:spec => spec).wait_for_completion - end + # Capacity section + cpu = xml.root.elements["//TEMPLATE/VCPU"].text + memory = xml.root.elements["//TEMPLATE/MEMORY"].text + capacity_spec = {:numCPUs => cpu.to_i, + :memoryMB => memory } + + # Perform the VM reconfiguration + spec_hash = context_vnc_spec.merge(nic_spec).merge(capacity_spec) + spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash) + vm.ReconfigVM_Task(:spec => spec).wait_for_completion + + # Power on the VM vm.PowerOnVM_Task.wait_for_completion return vm_uuid diff --git a/src/vmm_mad/remotes/vmware/shutdown b/src/vmm_mad/remotes/vmware/shutdown index fbaac03238..50041948de 100755 --- a/src/vmm_mad/remotes/vmware/shutdown +++ b/src/vmm_mad/remotes/vmware/shutdown @@ -28,6 +28,7 @@ $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) require 'vmware_driver' +require 'vi_driver' #------------------------------------------------------------------------------ # Wait the VM to shutdown TIMEOUT (xPOLL_INTERVAL) seconds. @@ -39,12 +40,14 @@ TIMEOUT=300 deploy_id = ARGV[0] host = ARGV[1] +VIDriver::initialize(host) + vmware_drv = VMwareDriver.new(host) vmware_drv.shutdown(deploy_id) count=0 -while (vmware_drv.poll(deploy_id).match(/STATE=(.*)/)[1] != "d") do +while (VIDriver::poll_vm(deploy_id).match(/STATE=(.*)/)[1] != "d") do sleep POLL_INTERVAL if count > TIMEOUT then OpenNebula.log_debug("Timeout reached and VM #{deploy_id} is still alive.") diff --git a/src/vnm_mad/remotes/ebtables/Ebtables.rb b/src/vnm_mad/remotes/ebtables/Ebtables.rb index 931bd23308..cf1f29b788 100644 --- a/src/vnm_mad/remotes/ebtables/Ebtables.rb +++ b/src/vnm_mad/remotes/ebtables/Ebtables.rb @@ -62,8 +62,15 @@ class EbtablesVLAN < VNMMAD::VNMDriver def deactivate lock + attach_nic_id = @vm['TEMPLATE/NIC[ATTACH="YES"]/NIC_ID'] + process do |nic| + if attach_nic_id && attach_nic_id != nic[:nic_id] + next + end + mac = nic[:mac] + # remove 0-padding mac = mac.split(":").collect{|e| e.hex.to_s(16)}.join(":") diff --git a/src/vnm_mad/remotes/lib/fw_driver.rb b/src/vnm_mad/remotes/lib/fw_driver.rb index 513f7980ed..592b3f7f44 100644 --- a/src/vnm_mad/remotes/lib/fw_driver.rb +++ b/src/vnm_mad/remotes/lib/fw_driver.rb @@ -40,7 +40,7 @@ module VNMMAD lock vm_id = @vm['ID'] - + process do |nic| #:white_ports_tcp => iptables_range #:white_ports_udp => iptables_range @@ -93,8 +93,15 @@ module VNMMAD def deactivate lock - vm_id = @vm['ID'] + vm_id = @vm['ID'] + + attach_nic_id = @vm['TEMPLATE/NIC[ATTACH="YES"]/NIC_ID'] + process do |nic| + if attach_nic_id && attach_nic_id != nic[:nic_id] + next + end + chain = "one-#{vm_id}-#{nic[:network_id]}" iptables_out = `#{command(:iptables)} -n -v --line-numbers -L FORWARD` if m = iptables_out.match(/.*#{chain}.*/) @@ -196,4 +203,4 @@ module VNMMAD "#{command(:iptables)} #{rule}" end end -end \ No newline at end of file +end diff --git a/src/vnm_mad/remotes/lib/sg_driver.rb b/src/vnm_mad/remotes/lib/sg_driver.rb index bf2efea5f4..9a87b0ccbb 100644 --- a/src/vnm_mad/remotes/lib/sg_driver.rb +++ b/src/vnm_mad/remotes/lib/sg_driver.rb @@ -23,7 +23,7 @@ module VNMMAD DRIVER = "sg" XPATH_FILTER = "TEMPLATE/NIC" - + # Creates a new SG driver and scans SG Rules def initialize(vm, deploy_id = nil, hypervisor = nil) super(vm, XPATH_FILTER, deploy_id, hypervisor) @@ -48,7 +48,7 @@ module VNMMAD @security_group_rules = rules end - # Activate the rules, bootstrap iptables chains and set filter rules for + # Activate the rules, bootstrap iptables chains and set filter rules for # each VM NIC def activate deactivate @@ -68,7 +68,7 @@ module VNMMAD sg_ids.each do |sg_id| rules = @security_group_rules[sg_id] - sg = SGIPTables::SecurityGroupIPTables.new(@vm, nic, sg_id, + sg = SGIPTables::SecurityGroupIPTables.new(@vm, nic, sg_id, rules) begin @@ -92,7 +92,13 @@ module VNMMAD lock begin + attach_nic_id = @vm['TEMPLATE/NIC[ATTACH="YES"]/NIC_ID'] + @vm.nics.each do |nic| + if attach_nic_id && attach_nic_id != nic[:nic_id] + next + end + SGIPTables.nic_deactivate(@vm, nic) end rescue Exception => e diff --git a/src/vnm_mad/remotes/ovswitch/OpenvSwitch.rb b/src/vnm_mad/remotes/ovswitch/OpenvSwitch.rb index 8a1bd5e848..adb9e74a44 100644 --- a/src/vnm_mad/remotes/ovswitch/OpenvSwitch.rb +++ b/src/vnm_mad/remotes/ovswitch/OpenvSwitch.rb @@ -72,7 +72,13 @@ class OpenvSwitchVLAN < VNMMAD::VNMDriver def deactivate lock + attach_nic_id = @vm['TEMPLATE/NIC[ATTACH="YES"]/NIC_ID'] + process do |nic| + if attach_nic_id && attach_nic_id != nic[:nic_id] + next + end + @nic = nic # Remove flows