diff --git a/include/Image.h b/include/Image.h index 4877e06cf93..c9e4c7befb3 100644 --- a/include/Image.h +++ b/include/Image.h @@ -549,7 +549,7 @@ class Image : public PoolObjectSQL void revert_snapshot(int snap_id) { - snapshots.active_snapshot(snap_id); + snapshots.active_snapshot(snap_id, true); }; void set_target_snapshot(int snap_id) diff --git a/include/Snapshots.h b/include/Snapshots.h index 6166a57470f..545fe16b521 100644 --- a/include/Snapshots.h +++ b/include/Snapshots.h @@ -45,7 +45,60 @@ class VectorAttribute; class Snapshots { public: - Snapshots(int _disk_id, bool orphans); + + /** + * ALLOW_ORPHANS: Define how child snapshots are handled. + * - ALLOW: Children can be orphan (no parent snapshot) + * |- snap_1 + * |- snap_2 + * |- snap_3 + * + * - DENY: New snapshots are set active and child of the previous one + * |- snap_1 + * |- snap_2 + * |- snap_3 + * + * - MIXED: Snapshots are children of last snapshot reverted to + * |- snap_1 (<--- revert) + * |- snap_2 + * |- snap_3 + */ + enum AllowOrphansMode + { + ALLOW = 0, + DENY = 1, + MIXED = 2 + }; + + static string allow_orphans_mode_to_str(AllowOrphansMode aom) + { + switch (aom) + { + case ALLOW: return "YES"; + case DENY: return "NO"; + case MIXED: return "MIXED"; + } + + return "NO"; + }; + + static AllowOrphansMode str_to_allow_orphans_mode(const string& aom) + { + if (aom == "YES") + { + return ALLOW; + } + else if (aom == "MIXED") + { + return MIXED; + } + else + { + return DENY; + } + }; + + Snapshots(int _disk_id, AllowOrphansMode orphans); Snapshots(const Snapshots& s); @@ -98,8 +151,12 @@ class Snapshots /** * Set the given snapshot as active. Updates the values of the current * snapshot + * + * @param id id of the snapshot + * @param revert true if the cause of changing the active snapshot + * is because a revert */ - int active_snapshot(int id); + int active_snapshot(int id, bool revert); /** * Rename the given snapshot by the given name @@ -224,6 +281,19 @@ class Snapshots */ void init(); + /** + * Updates children list for the current base snapshot in the tree + * @param snapshot new child to be added + */ + void add_child_mixed(VectorAttribute *snapshot); + + /** + * Updates children list of the active snapshot + * @param snapshot new child to be added + * @return -1 in case of error (current active does not exist) + */ + int add_child_deny(VectorAttribute *snapshot); + /** * Text representation of the snapshot pool. To be stored as part of the * VM or Image Templates @@ -248,12 +318,17 @@ class Snapshots /** * Allow to remove parent snapshots and active one */ - bool orphans; + AllowOrphansMode orphans; /** * Snapshot pointer map */ map snapshot_pool; + + /** + * Current snaphsot base for mixed mode + */ + int current_base; }; #endif /*SNAPSHOTS_H_*/ diff --git a/include/VirtualMachine.h b/include/VirtualMachine.h index f6f70defbc3..8ef0a6fa7a5 100644 --- a/include/VirtualMachine.h +++ b/include/VirtualMachine.h @@ -1491,11 +1491,13 @@ class VirtualMachine : public PoolObjectSQL * @param disk_id of the disk * @param snap_id of the snapshot * @param error if any + * @param revert true if the cause of changing the active snapshot + * is because a revert * @return -1 if error */ - int revert_disk_snapshot(int disk_id, int snap_id) + int revert_disk_snapshot(int disk_id, int snap_id, bool revert) { - return disks.revert_snapshot(disk_id, snap_id); + return disks.revert_snapshot(disk_id, snap_id, revert); } /** diff --git a/include/VirtualMachineDisk.h b/include/VirtualMachineDisk.h index 1082f0d7417..0217bbbe29f 100644 --- a/include/VirtualMachineDisk.h +++ b/include/VirtualMachineDisk.h @@ -22,6 +22,7 @@ #include "VirtualMachineAttribute.h" #include "Snapshots.h" +#include "NebulaUtil.h" class AuthRequest; @@ -54,16 +55,16 @@ class VirtualMachineDisk : public VirtualMachineAttribute return is_flag("PERSISTENT"); } - bool allow_orphans() const + Snapshots::AllowOrphansMode allow_orphans() const { - bool orphans; + string orphans; if (vector_value("ALLOW_ORPHANS", orphans) == -1) { - orphans = false; + orphans = Snapshots::DENY; } - return orphans; + return Snapshots::str_to_allow_orphans_mode(one_util::toupper(orphans)); } void set_attach() @@ -273,9 +274,11 @@ class VirtualMachineDisk : public VirtualMachineAttribute /** * Sets the snap_id as active, the VM will boot from it next time * @param snap_id of the snapshot + * @param revert true if the cause of changing the active snapshot + * is because a revert * @return -1 if error */ - int revert_snapshot(int snap_id); + int revert_snapshot(int snap_id, bool revert); /** * Deletes the snap_id from the list @@ -730,9 +733,11 @@ class VirtualMachineDisks : public VirtualMachineAttributeSet * 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 revert true if the cause of changing the active snapshot + * is because a revert * @return -1 if error */ - int revert_snapshot(int disk_id, int snap_id); + int revert_snapshot(int disk_id, int snap_id, bool revert); /** * Deletes the snap_id from the list diff --git a/share/etc/oned.conf b/share/etc/oned.conf index 5a7331439db..a94c7763291 100644 --- a/share/etc/oned.conf +++ b/share/etc/oned.conf @@ -1239,7 +1239,20 @@ INHERIT_VNET_ATTR = "VCENTER_INSTANCE_ID" # among the different hosts or not. Valid values: "yes" or "no" # ds_migrate : The driver allows migrations across datastores. Valid values: # "yes" or "no". Note: THIS ONLY APPLIES TO SYSTEM DS. -# allow_orphans: Snapshots can live without parents +# allow_orphans: Snapshots can live without parents. Suported values: +# YES: Children can be orphan (no parent snapshot) +# |- snap_1 +# |- snap_2 +# |- snap_3 +# NO: New snapshots are set active and child of the previous one +# |- snap_1 +# |- snap_2 +# |- snap_3 +# MIXED: Snapshots are children of last snapshot reverted to +# |- snap_1 (<--- revert) +# |- snap_3 +# |- snap_4 +# |- snap_2 #******************************************************************************* TM_MAD_CONF = [ @@ -1274,7 +1287,7 @@ TM_MAD_CONF = [ TM_MAD_CONF = [ NAME = "ceph", LN_TARGET = "NONE", CLONE_TARGET = "SELF", SHARED = "YES", - DS_MIGRATE = "NO", DRIVER = "raw", ALLOW_ORPHANS="yes", + DS_MIGRATE = "NO", DRIVER = "raw", ALLOW_ORPHANS="mixed", TM_MAD_SYSTEM = "ssh", LN_TARGET_SSH = "SYSTEM", CLONE_TARGET_SSH = "SYSTEM", DISK_TYPE_SSH = "FILE", TM_MAD_SYSTEM = "shared", LN_TARGET_SHARED = "NONE", CLONE_TARGET_SHARED = "SELF", DISK_TYPE_SHARED = "RBD" diff --git a/src/datastore/Datastore.cc b/src/datastore/Datastore.cc index 0b5429b2b35..63ddc215d03 100644 --- a/src/datastore/Datastore.cc +++ b/src/datastore/Datastore.cc @@ -326,6 +326,8 @@ int Datastore::set_tm_mad(string &tm_mad, string &error_str) ostringstream oss; std::stringstream ss; + string orph; + if ( Nebula::instance().get_tm_conf_attribute(tm_mad, vatt) != 0 ) { goto error_conf; @@ -443,11 +445,9 @@ int Datastore::set_tm_mad(string &tm_mad, string &error_str) remove_template_attribute("SHARED"); } - bool orph; - if ( vatt->vector_value("ALLOW_ORPHANS", orph) == -1 ) { - orph = false; + orph = "NO"; } replace_template_attribute("ALLOW_ORPHANS", orph); diff --git a/src/image/Image.cc b/src/image/Image.cc index 84f4f348650..6cefa0750be 100644 --- a/src/image/Image.cc +++ b/src/image/Image.cc @@ -60,7 +60,7 @@ Image::Image(int _uid, vm_collection("VMS"), img_clone_collection("CLONES"), app_clone_collection("APP_CLONES"), - snapshots(-1, false), + snapshots(-1, Snapshots::DENY), target_snapshot(-1) { if (_image_template != 0) diff --git a/src/image/ImageManagerActions.cc b/src/image/ImageManagerActions.cc index 88c6893fc7f..d64c6d3234d 100644 --- a/src/image/ImageManagerActions.cc +++ b/src/image/ImageManagerActions.cc @@ -1064,7 +1064,7 @@ void ImageManager::set_image_snapshots(int iid, const Snapshots& s) void ImageManager::clear_image_snapshots(int iid) { - Snapshots _snaps(-1, false); + Snapshots _snaps(-1, Snapshots::DENY); set_image_snapshots(iid, _snaps); } diff --git a/src/lcm/LifeCycleStates.cc b/src/lcm/LifeCycleStates.cc index 715a1c8b1ed..666d6bc1984 100644 --- a/src/lcm/LifeCycleStates.cc +++ b/src/lcm/LifeCycleStates.cc @@ -1893,7 +1893,7 @@ void LifeCycleManager::disk_snapshot_success(int vid) bool img_owner, vm_owner; const VirtualMachineDisk * disk; - Snapshots snaps(-1, false); + Snapshots snaps(-1, Snapshots::DENY); const Snapshots* tmp_snaps; string error_str; @@ -1924,10 +1924,14 @@ void LifeCycleManager::disk_snapshot_success(int vid) vm->set_state(VirtualMachine::RUNNING); case VirtualMachine::DISK_SNAPSHOT_POWEROFF: case VirtualMachine::DISK_SNAPSHOT_SUSPENDED: + vm->log("LCM", Log::INFO, "VM disk snapshot operation completed."); + vm->revert_disk_snapshot(disk_id, snap_id, false); + break; + case VirtualMachine::DISK_SNAPSHOT_REVERT_POWEROFF: case VirtualMachine::DISK_SNAPSHOT_REVERT_SUSPENDED: vm->log("LCM", Log::INFO, "VM disk snapshot operation completed."); - vm->revert_disk_snapshot(disk_id, snap_id); + vm->revert_disk_snapshot(disk_id, snap_id, true); break; case VirtualMachine::DISK_SNAPSHOT_DELETE: @@ -2036,7 +2040,7 @@ void LifeCycleManager::disk_snapshot_failure(int vid) Template *vm_quotas = 0; const VirtualMachineDisk* disk; - Snapshots snaps(-1, false); + Snapshots snaps(-1, Snapshots::DENY); const Snapshots* tmp_snaps; string error_str; diff --git a/src/nebula/NebulaTemplate.cc b/src/nebula/NebulaTemplate.cc index 415b093610a..a0c0c04f8a3 100644 --- a/src/nebula/NebulaTemplate.cc +++ b/src/nebula/NebulaTemplate.cc @@ -157,8 +157,8 @@ void OpenNebulaTemplate::set_multiple_conf_default() set_conf_ds("ssh", "", "NO"); set_conf_ds("vmfs", "BRIDGE_LIST", "NO"); set_conf_ds("vcenter", - "VCENTER_INSTANCE_ID, VCENTER_DS_REF, VCENTER_DC_REF, VCENTER_HOST, VCENTER_USER, VCENTER_PASSWORD", - "NO"); + "VCENTER_INSTANCE_ID, VCENTER_DS_REF, VCENTER_DC_REF, VCENTER_HOST, VCENTER_USER, VCENTER_PASSWORD", + "NO"); set_conf_ds("ceph", "DISK_TYPE,BRIDGE_LIST,CEPH_HOST,CEPH_USER,CEPH_SECRET", "NO"); diff --git a/src/vm/Snapshots.cc b/src/vm/Snapshots.cc index 5697a008099..cf8e034f879 100644 --- a/src/vm/Snapshots.cc +++ b/src/vm/Snapshots.cc @@ -20,21 +20,24 @@ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -Snapshots::Snapshots(int _disk_id, bool _orphans): +Snapshots::Snapshots(int _disk_id, AllowOrphansMode _orphans): snapshot_template(false,'=',"SNAPSHOTS"), next_snapshot(0), active(-1), disk_id(_disk_id), - orphans(_orphans) + orphans(_orphans), + current_base(-1) { if (_disk_id != -1) { snapshot_template.add("DISK_ID", _disk_id); } - snapshot_template.add("ALLOW_ORPHANS", _orphans); + snapshot_template.add("ALLOW_ORPHANS", allow_orphans_mode_to_str(_orphans)); snapshot_template.add("NEXT_SNAPSHOT", 0); + + snapshot_template.add("CURRENT_BASE", -1); }; Snapshots::Snapshots(const Snapshots& s): @@ -42,7 +45,8 @@ Snapshots::Snapshots(const Snapshots& s): next_snapshot(0), active(-1), disk_id(-1), - orphans(false) + orphans(DENY), + current_base(-1) { init(); } @@ -55,6 +59,7 @@ Snapshots& Snapshots::operator= (const Snapshots& s) active = s.active; disk_id = s.disk_id; orphans = s.orphans; + current_base = s.current_base; snapshot_template = s.snapshot_template; @@ -119,9 +124,20 @@ void Snapshots::init() snapshot_template.get("NEXT_SNAPSHOT", next_snapshot); - if ( snapshot_template.get("ALLOW_ORPHANS", orphans) == false ) + string orphans_str; + + if (snapshot_template.get("ALLOW_ORPHANS", orphans_str) == false) + { + orphans = DENY; + } + else { - orphans = false; + orphans = str_to_allow_orphans_mode(one_util::toupper(orphans_str)); + } + + if (snapshot_template.get("CURRENT_BASE", current_base) == false) + { + current_base = -1; } } @@ -141,20 +157,45 @@ int Snapshots::create_snapshot(const string& name, long long size_mb) snapshot->replace("ID", next_snapshot); snapshot->replace("DATE", static_cast(time(0))); - if (!orphans) + if (orphans == DENY) { - snapshot->replace("PARENT", active); - - if (active != -1) + if (add_child_deny(snapshot) == -1) { - VectorAttribute * parent = get_snapshot(active); + return -1; + } + } + else if (orphans == MIXED) + { + add_child_mixed(snapshot); + } + else //ALLOW + { + snapshot->replace("PARENT", "-1"); + } - if (parent == 0) - { - delete snapshot; - return -1; - } + snapshot_template.replace("NEXT_SNAPSHOT", next_snapshot + 1); + + snapshot_template.set(snapshot); + + snapshot_pool.insert( + pair(next_snapshot, snapshot)); + + return next_snapshot++; +}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void Snapshots::add_child_mixed(VectorAttribute *snapshot) +{ + snapshot->replace("PARENT", current_base); + if (current_base != -1) + { + VectorAttribute * parent = get_snapshot(current_base); + + if (parent != 0) + { string children = parent->vector_value("CHILDREN"); if (children.empty()) @@ -171,20 +212,43 @@ int Snapshots::create_snapshot(const string& name, long long size_mb) } } } - else +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int Snapshots::add_child_deny(VectorAttribute *snapshot) +{ + snapshot->replace("PARENT", active); + + if (active != -1) { - snapshot->replace("PARENT", "-1"); - } + VectorAttribute * parent = get_snapshot(active); - snapshot_template.replace("NEXT_SNAPSHOT", next_snapshot + 1); + if (parent == 0) + { + delete snapshot; + return -1; + } - snapshot_template.set(snapshot); + string children = parent->vector_value("CHILDREN"); - snapshot_pool.insert( - pair(next_snapshot, snapshot)); + if (children.empty()) + { + parent->replace("CHILDREN", next_snapshot); + } + else + { + ostringstream oss; - return next_snapshot++; -}; + oss << children << "," << next_snapshot; + + parent->replace("CHILDREN", oss.str()); + } + } + + return 0; +} /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ @@ -200,7 +264,7 @@ void Snapshots::delete_snapshot(int id) return; } - if (!orphans) + if (orphans == DENY || orphans == MIXED) { snapshot->vector_value("PARENT", parent_id); @@ -243,7 +307,7 @@ void Snapshots::delete_snapshot(int id) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -int Snapshots::active_snapshot(int id) +int Snapshots::active_snapshot(int id, bool revert) { if (static_cast(id) == active) { @@ -257,6 +321,12 @@ int Snapshots::active_snapshot(int id) return -1; } + if (revert && (orphans == MIXED)) + { + current_base = id; + snapshot_template.replace("CURRENT_BASE", id); + } + snapshot->replace("ACTIVE", true); snapshot = get_snapshot(active); @@ -353,7 +423,7 @@ bool Snapshots::test_delete(int id, string& error) const return false; } - if (!orphans) + if (orphans == DENY || orphans == MIXED) { snapshot->vector_value("ACTIVE", current); diff --git a/src/vm/VirtualMachine.cc b/src/vm/VirtualMachine.cc index 3f82fb8a7cd..f631b1ebe4e 100644 --- a/src/vm/VirtualMachine.cc +++ b/src/vm/VirtualMachine.cc @@ -2462,7 +2462,7 @@ int VirtualMachine::from_xml(const string &xml_str) for (vector::iterator it=content.begin();it!=content.end();it++) { - Snapshots * snap = new Snapshots(-1, false); + Snapshots * snap = new Snapshots(-1, Snapshots::DENY); rc += snap->from_xml_node(*it); diff --git a/src/vm/VirtualMachineDisk.cc b/src/vm/VirtualMachineDisk.cc index 431df363cb3..b51173a706f 100644 --- a/src/vm/VirtualMachineDisk.cc +++ b/src/vm/VirtualMachineDisk.cc @@ -277,14 +277,14 @@ int VirtualMachineDisk::create_snapshot(const string& name, string& error) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -int VirtualMachineDisk::revert_snapshot(int snap_id) +int VirtualMachineDisk::revert_snapshot(int snap_id, bool revert) { if ( snapshots == 0 ) { return -1; } - return snapshots->active_snapshot(snap_id); + return snapshots->active_snapshot(snap_id, revert); } /* -------------------------------------------------------------------------- */ @@ -1367,7 +1367,7 @@ const Snapshots * VirtualMachineDisks::get_snapshots(int id, string& error) cons /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -int VirtualMachineDisks::revert_snapshot(int id, int snap_id) +int VirtualMachineDisks::revert_snapshot(int id, int snap_id, bool revert) { VirtualMachineDisk * disk = static_cast(get_attribute(id)); @@ -1377,7 +1377,7 @@ int VirtualMachineDisks::revert_snapshot(int id, int snap_id) return -1; } - return disk->revert_snapshot(snap_id); + return disk->revert_snapshot(snap_id, revert); } /* -------------------------------------------------------------------------- */