1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-11 04:58:16 +03:00

feature #3782: Create and Revert operations for Disk Snapshots. Core and

OCA levels
This commit is contained in:
Ruben S. Montero 2015-05-19 18:41:23 +02:00
parent 676bfcc1db
commit 98f76cf3fe
11 changed files with 576 additions and 56 deletions

View File

@ -363,6 +363,39 @@ 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);
private:
/**
* Thread id for the Dispatch Manager

View File

@ -405,4 +405,35 @@ public:
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
class VirtualMachineDiskSnapshotCreate: public RequestManagerVirtualMachine
{
public:
VirtualMachineDiskSnapshotCreate():
RequestManagerVirtualMachine("VirtualMachineDiskSnapshotCreate",
"Creates a new virtual machine disk snapshot",
"A:siis"){};
~VirtualMachineDiskSnapshotCreate(){};
void request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att);
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
class VirtualMachineDiskSnapshotRevert: public RequestManagerVirtualMachine
{
public:
VirtualMachineDiskSnapshotRevert():
RequestManagerVirtualMachine("VirtualMachineDiskSnapshotRevert",
"Reverts disk state to a snapshot",
"A:siii"){};
~VirtualMachineDiskSnapshotRevert(){};
void request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att);
};
#endif

View File

@ -14,8 +14,8 @@
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
#ifndef SNAPSHOT_POOL_H_
#define SNAPSHOT_POOL_H_
#ifndef SNAPSHOTS_H_
#define SNAPSHOTS_H_
#include <iostream>
#include <string>
@ -30,8 +30,18 @@ using namespace std;
class VectorAttribute;
/**
* This class represents the List of Snapshots associated to an image or Virtual
* Machine Disk
* This class represents a list of Snapshots associated to an image or Virtual
* Machine Disk. The list is in the form:
* <SNAPSHOTS>
* <DISK_ID>: of the disk the snapshots are taken from (the initial backing)
* <ACTIVE>: the current snapshot in use by the VM. 0 for the original DISK
* <SNAPSHOT>
* <ID>
* <TAG>: Description
* <DATE>: the snapshot was taken
* <PARENT_ID>: backing for this snapshot, 0 for the original image
* <PARENT>: Opaque (driver specific) string representing the parent
* <SOURCE>: Opaque (driver specific) string representing the snapshot
*/
class Snapshots
{
@ -52,15 +62,41 @@ public:
*/
int from_xml_node(const xmlNodePtr node);
int create_snapshot(unsigned int p_id, const string& tag, string& error);
/**
* 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 src source of disk image (inital backing file)
* @param tag description of this snapshot (optional)
* @return id of the new snapshot
*/
int create_snapshot(const string& src, const string& tag);
/**
* Removes the snapshot from the list
* @param id of the snapshot
*/
int delete_snapshot(unsigned int id);
/**
* Set the given snapshot as active. Updates the values of the current
* snapshot
*/
int active_snapshot(unsigned int id);
int active_snapshot(unsigned int id, string& error);
/**
* Return the disk_id of the snapshot list
*/
int get_disk_id()
{
return disk_id;
}
private:
@ -71,15 +107,31 @@ private:
*/
VectorAttribute * get_snapshot(unsigned int id);
/**
* 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
*/
unsigned int active;
/**
* Id of the disk associated with this snapshot list
*/
unsigned int disk_id;
/**
* Snapshot pointer map
*/
map<unsigned int, VectorAttribute *> snapshot_pool;
unsigned int active;
};
#endif /*SNAPSHOT_H_*/
#endif /*SNAPSHOTS_H_*/

View File

@ -32,6 +32,7 @@
using namespace std;
class AuthRequest;
class Snapshots;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
@ -1495,6 +1496,28 @@ public:
*/
int set_attach_nic(int nic_id);
// ------------------------------------------------------------------------
// Snapshot related functions
// ------------------------------------------------------------------------
/**
* 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. It can be 0 to revert to the original
* disk
* @param error if any
* @return -1 if error
*/
int revert_disk_snapshot(int disk_id, int snap_id, string& error);
// ------------------------------------------------------------------------
// Snapshot related functions
@ -1651,6 +1674,11 @@ private:
*/
vector<History *> history_records;
/**
* Snapshots for each disk
*/
map<int, Snapshots *> snapshots;
// -------------------------------------------------------------------------
// Logging & Dirs
// -------------------------------------------------------------------------
@ -1797,12 +1825,12 @@ private:
*/
int parse_defaults(string& error_str);
/**
/**
* Known attributes for network contextualization rendered as:
* ETH_<nicid>_<context[0]> = $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 +1952,13 @@ 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);
protected:
//**************************************************************************
@ -1998,11 +2033,6 @@ protected:
return -1;
}
// *************************************************************************
// Helpers
// *************************************************************************
VectorAttribute* get_disk(int disk_id);
};
#endif /*VIRTUAL_MACHINE_H_*/

View File

@ -785,6 +785,34 @@ 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. To revert
disk state to the base disk image use 0 as snapshot id
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
list_desc = <<-EOT.unindent
Lists VMs in the pool
EOT

View File

@ -1146,10 +1146,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 +1606,117 @@ 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;
}
//TODO set state (reuse HOTPLUG_SNAPSHOT?)
//vm->set_state(VirtualMachine::HOTPLUG_SNAPSHOT);
snap_id = vm->new_disk_snapshot(did, tag, error_str);
if (snap_id == -1)
{
vm->unlock();
return -1;
}
vm->unlock();
vmpool->update(vm);
//TODO Trigger snapshot action on the TM
//vmm->trigger(VirtualMachineManager::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;
}
//TODO set state (reuse HOTPLUG_SNAPSHOT?)
//vm->set_state(VirtualMachine::HOTPLUG_SNAPSHOT);
if (vm->revert_disk_snapshot(did, snap_id, error_str) == -1)
{
vm->unlock();
return -1;
}
vm->unlock();
vmpool->update(vm);
//TODO Regenerate Deployment FILE (and send it to host?)
//vmm->trigger(VirtualMachineManager::SNAPSHOT_CREATE,vid);
return 0;
}

View File

@ -44,7 +44,9 @@ module OpenNebula
:snapshotdelete => "vm.snapshotdelete",
:attachnic => "vm.attachnic",
:detachnic => "vm.detachnic",
:recover => "vm.recover"
:recover => "vm.recover",
:disksnapshotcreate => "vm.disksnapshotcreate",
:disksnapshotrevert => "vm.disksnapshotrevert"
}
VM_STATE=%w{INIT PENDING HOLD ACTIVE STOPPED SUSPENDED DONE FAILED
@ -610,6 +612,27 @@ 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
# Recovers an ACTIVE VM
#
# @param result [Integer] Recover with failure (0), success (1) or

View File

@ -304,6 +304,8 @@ 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_dsnap_create(new VirtualMachineDiskSnapshotCreate());
xmlrpc_c::methodPtr vm_dsnap_revert(new VirtualMachineDiskSnapshotRevert());
xmlrpc_c::methodPtr vm_recover(new VirtualMachineRecover());
xmlrpc_c::methodPtr vm_pool_acct(new VirtualMachinePoolAccounting());
@ -460,6 +462,8 @@ 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.disksnapshotcreate", vm_dsnap_create);
RequestManagerRegistry.addMethod("one.vm.disksnapshotrevert", vm_dsnap_revert);
RequestManagerRegistry.addMethod("one.vm.recover", vm_recover);
RequestManagerRegistry.addMethod("one.vmpool.info", vm_pool_info);

View File

@ -2483,3 +2483,82 @@ 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(id, att);
}
return;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -14,13 +14,13 @@
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
#include "Snapshot.h"
#include "Snapshots.h"
Snapshots::Snapshots(int _disk_id):
snapshot_template(false,'=',"SNAPSHOTS"),
next_snapshot(0),
disk_id(_disk_id),
active(-1)
next_snapshot(1),
active(0),
disk_id(_disk_id)
{
snapshot_template.add("DISK_ID",_disk_id);
};
@ -71,7 +71,7 @@ int Snapshots::from_xml_node(const xmlNodePtr node)
if (snapshot_template.get("DISK_ID", did))
{
disk_id = id;
disk_id = did;
}
return 0;
@ -80,23 +80,22 @@ int Snapshots::from_xml_node(const xmlNodePtr node)
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int Snapshots::create_snapshot(unsigned int p_id, const string& tag,
string& error)
int Snapshots::create_snapshot(const string& disk_src, const string& tag)
{
VectorAttribute * parent = get_snapshot(p_id);
string source;
int parent_id;
if (parent == 0)
if ( active > 0 )
{
error = "Parent snapshot not found.";
return -1;
VectorAttribute * parent = get_snapshot(active);
source = parent->vector_value("SOURCE");
parent_id = active;
}
string psource = parent->vector_value("SOURCE");
if (psource.empty())
else
{
error = "Parent snapshot has no source.";
return -1;
source = disk_src;
parent_id = 0;
}
VectorAttribute * snapshot = new VectorAttribute("SNAPSHOT");
@ -106,17 +105,17 @@ int Snapshots::create_snapshot(unsigned int p_id, const string& tag,
snapshot->replace("TAG",tag);
}
snapshot->replace("ID", next_snapshot++);
snapshot->replace("ID", next_snapshot);
snapshot->replace("DATE", static_cast<long long>(time(0)));
snapshot->replace("PARENT", psource);
snapshot->replace("PARENT_ID", parent_id);
snapshot->replace("PARENT", source);
snapshot_template.set(snapshot);
snapshot_pool.insert(pair<unsigned int, VectorAttribute *>(next_snapshot, snapshot));
snapshot_pool.insert(
pair<unsigned int, VectorAttribute *>(next_snapshot, snapshot));
return next_snapshot;
return next_snapshot++;
};
/* -------------------------------------------------------------------------- */
@ -152,16 +151,27 @@ int Snapshots::delete_snapshot(unsigned int id)
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int Snapshots::active_snapshot(unsigned int id)
int Snapshots::active_snapshot(unsigned int id, string& error)
{
VectorAttribute * snapshot = get_snapshot(id);
VectorAttribute * snapshot;
if (snapshot == 0)
if ( id == active )
{
return -1;
return 0;
}
snapshot->replace("ACTIVE", true);
if ( id != 0 )
{
snapshot = get_snapshot(id);
if (snapshot == 0)
{
error = "Snapshot does not exists";
return -1;
}
snapshot->replace("ACTIVE", true);
}
snapshot = get_snapshot(active);
@ -175,7 +185,6 @@ int Snapshots::active_snapshot(unsigned int id)
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -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<int, Snapshots *>::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);
}
}
@ -2987,7 +2994,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;
@ -3418,7 +3426,8 @@ int VirtualMachine::save_disk_hot(int disk_id,
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualMachine::get_saveas_disk_hot(int& disk_id, string& source, int& image_id)
int VirtualMachine::get_saveas_disk_hot(int& disk_id, string& source,
int& image_id)
{
vector<Attribute *> disks;
VectorAttribute * disk;
@ -3731,6 +3740,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 << "<VM>"
@ -3780,6 +3791,12 @@ string& VirtualMachine::to_xml_extended(string& xml, int n_history) const
oss << "<HISTORY_RECORDS/>";
}
for (map<int, Snapshots *>::const_iterator it = snapshots.begin();
it != snapshots.end() ; it++)
{
oss << it->second->to_xml(snap_xml);
}
oss << "</VM>";
xml = oss.str();
@ -3878,6 +3895,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<xmlNodePtr>::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<int, Snapshots *>(snap->get_disk_id(), snap));
}
if (!content.empty())
{
ObjectXML::free_nodes(content);
content.clear();
}
if (rc != 0)
@ -4078,7 +4121,8 @@ void VirtualMachine::clear_template_monitor_error()
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualMachine::get_public_cloud_hypervisors(vector<string> &public_cloud_hypervisors) const
int VirtualMachine::get_public_cloud_hypervisors(
vector<string> &public_cloud_hypervisors) const
{
vector<Attribute*> attrs;
vector<Attribute*>::const_iterator it;
@ -4116,3 +4160,76 @@ int VirtualMachine::get_public_cloud_hypervisors(vector<string> &public_cloud_hy
return public_cloud_hypervisors.size();
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualMachine::new_disk_snapshot(int did, const string& tag, string& error)
{
map<int, Snapshots *>::iterator it;
int snap_id;
VectorAttribute * disk;
string source;
disk = get_disk(did);
if ( disk == 0 )
{
error = "DISK does not exists";
return -1;
}
source = disk->vector_value("SOURCE");
it = snapshots.find(did);
if ( it == snapshots.end() )
{
Snapshots * snap = new Snapshots(did);
snap_id = snap->create_snapshot(source, tag);
snapshots.insert(pair<int, Snapshots *>(did, snap));
}
else
{
snap_id = it->second->create_snapshot(source, tag);
}
return snap_id;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualMachine::revert_disk_snapshot(int did, int snap_id, string& error)
{
map<int, Snapshots *>::iterator it;
int rc;
VectorAttribute * disk;
string source;
disk = get_disk(did);
if ( disk == 0 )
{
error = "DISK does not exists";
return -1;
}
it = snapshots.find(did);
if ( it == snapshots.end() && snap_id != 0 )
{
error = "Snapshot does not exists";
return -1;
}
else if ( it != snapshots.end() )
{
rc = it->second->active_snapshot(snap_id, error);
}
return rc;
}