public override snapshot createSnapshot(string dataset, string snapshotName) { snapshot newVal = uncachedNAS.createSnapshot(dataset, snapshotName); snapshots.TryAdd(newVal.id, newVal); return(newVal); }
public override void rollbackSnapshot(snapshot shotToRestore) { lock (events) { events.Add(new mockedCall("rollbackSnapshot", "shotToRestore: '" + shotToRestore)); } }
public override void deleteSnapshot(snapshot toDelete) { uncachedNAS.deleteSnapshot(toDelete); snapshot foo; snapshots.TryRemove(toDelete.id, out foo); }
private static snapshot getSnapshot(NASAccess nas, string snapshotFullName) { snapshot shotToRestore = nas.getSnapshots().SingleOrDefault( x => x.fullname.ToLower().Contains("/" + snapshotFullName.ToLower() + "@") || x.id == snapshotFullName); return(shotToRestore); }
public override void deleteSnapshot(snapshot toDelete) { string name = Uri.EscapeDataString(toDelete.fullname); string url = "http://" + _serverIp + "/api/v1.0/storage/snapshot/" + name; doReq(url, "DELETE", HttpStatusCode.NoContent); }
public override void rollbackSnapshot(snapshot shotToRestore) //, volume parentVolume, volume clone) { lock (nonAPIReqLock) { // Oh no, FreeNAS doesn't export the 'rollback' command via the API! :( We need to log into the web UI and faff with // that in order to rollback instead. // // First, do an initial GET to / so we can get a CSRF token and some cookies. DoNonAPIReq("", HttpStatusCode.OK); //doInitialReq(); // Now we can perform the login. string url = "account/login/"; string payloadStr = string.Format("username={0}&password={1}", _username, _password); DoNonAPIReq(url, HttpStatusCode.OK, payloadStr); // Now we can do the request to rollback the snapshot. string resp = DoNonAPIReq("storage/snapshot/rollback/" + shotToRestore.fullname + "/", HttpStatusCode.OK, ""); if (resp.Contains("\"error\": true") || !resp.Contains("Rollback successful.")) { throw new nasAccessException("Rollback failed: " + resp); } } }
public override void cloneSnapshot(snapshot toClone, string fullCloneName) { lock (events) { events.Add(new mockedCall("cloneSnapshot", "toClone: '" + toClone + "' fullCloneName: " + fullCloneName)); } }
private static snapshotObjects getSnapshotObjectsFromNAS(NASAccess nas, string snapshotFullName) { snapshot shotToRestore = getSnapshot(nas, snapshotFullName); if (shotToRestore == null) { nas.invalidateSnapshots(); shotToRestore = getSnapshot(nas, snapshotFullName); if (shotToRestore == null) { throw new Exception("Cannot find snapshot " + snapshotFullName); } } // Now find the extent. We'll need to delete it before we can rollback the snapshot. iscsiExtent extent = getExtent(nas, snapshotFullName); if (extent == null) { nas.invalidateExtents(); extent = getExtent(nas, snapshotFullName); if (extent == null) { throw new Exception("Cannot find extent " + snapshotFullName); } } // Find the 'target to extent' mapping, since this will need to be deleted before we can delete the extent. iscsiTargetToExtentMapping tgtToExtent = getTgtToExtent(nas, extent); if (tgtToExtent == null) { nas.invalidateTargetToExtents(); tgtToExtent = getTgtToExtent(nas, extent); if (tgtToExtent == null) { throw new Exception("Cannot find target-to-extent mapping with ID " + extent.id + " for snapshot " + shotToRestore.name); } } // We find the target, as well, just to be sure that our cache is correct. if (nas.getISCSITargets().Count(x => x.id == tgtToExtent.iscsi_target) == 0) { nas.invalidateTargets(); if (nas.getISCSITargets().Count(x => x.id == tgtToExtent.iscsi_target) == 0) { throw new Exception("Cannot find target for snapshot " + snapshotFullName); } } return(new snapshotObjects() { extent = extent, shotToRestore = shotToRestore, tgtToExtent = tgtToExtent }); }
public override void cloneSnapshot(snapshot snapshot, string path) { string url = String.Format("http://{0}/api/v1.0/storage/snapshot/{1}/clone/", _serverIp, snapshot.fullname); string payload = String.Format("{{\"name\": \"{0}\" }}", path); doReq(url, "POST", HttpStatusCode.Accepted, payload); // This API function returns a HTTP status of Accepted (202), which should indicate that the operation has been started // and will continue async. However, after studying the FreeNAS code ("FreeNAS-9.10.1 (d989edd)"), there appears to be // a shell out to 'zfs clone', which is sync. AFAICT, the call can never return before the clone is complete. }
public override void deleteSnapshot(snapshot toDelete) { lock (events) { events.Add(new mockedCall("deleteSnapshot", "toDelete: " + toDelete)); } lock (snapshots) { snapshots.Remove(toDelete.id); } }
public void addSnapshot(snapshot baseSnapshot) { lock (events) { events.Add(new mockedCall("addSnapshot", "baseSnapshot: '" + baseSnapshot + "'")); } lock (snapshots) { snapshots.Add(baseSnapshot.id, baseSnapshot); } }
public override void rollbackSnapshot(snapshot shotToRestore) { snapshotsLock.EnterWriteLock(); try { uncachedNAS.getSnapshots().Clear(); uncachedNAS.getSnapshots().ForEach(x => snapshots.TryAdd(x.id, x)); } catch (Exception) { snapshots.Clear(); throw; } finally { snapshotsLock.ExitWriteLock(); } }
public override snapshot createSnapshot(string dataset, string snapshotName) { lock (events) { events.Add(new mockedCall("createSnapshot", "dataset: '" + dataset + "' snapshotName: " + snapshotName)); } lock (snapshots) { string newID = idGen.Next().ToString(); snapshot newShot = new snapshot() { fullname = "/dev/foo/bar/" + snapshotName, id = newID, name = snapshotName, filesystem = dataset }; snapshots.Add(newID, newShot); return(snapshots[newID]); } }
public override void cloneSnapshot(snapshot toClone, string fullCloneName) { uncachedNAS.cloneSnapshot(toClone, fullCloneName); }
public abstract void rollbackSnapshot(snapshot shotToRestore);
public abstract void cloneSnapshot(snapshot toClone, string fullCloneName);
public abstract void deleteSnapshot(snapshot toDelete);