public override void deleteISCSIExtent(iscsiExtent extent) { lock (this) { waitingISCSIOperations++; } try { uncachedNAS.deleteISCSIExtent(extent); iscsiExtent foo; extents.TryRemove(extent.id, out foo); var toDel = TTEExtents.Where(x => x.Value.iscsi_extent == extent.id); foreach (var tte in toDel) { iscsiTargetToExtentMapping removedTTE; TTEExtents.TryRemove(tte.Key, out removedTTE); } } finally { lock (this) { waitingISCSIOperations--; } markThisThreadISCSIDirty(); } }
private static iscsiExtent getExtent(NASAccess nas, string snapshotFullName) { iscsiExtent extent = nas.getExtents() .SingleOrDefault( x => snapshotFullName.Equals(x.iscsi_target_extent_name, StringComparison.CurrentCultureIgnoreCase)); return(extent); }
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 deleteISCSIExtent(iscsiExtent extent) { lock (events) { events.Add(new mockedCall("deleteISCSIExtent", "extent: " + extent)); } lock (extents) { extents.Remove(extent.id); } }
public override iscsiExtent addISCSIExtent(iscsiExtent extent) { lock (events) { events.Add(new mockedCall("addISCSIExtent", "extent: '" + extent)); } lock (extents) { string newID = idGen.Next().ToString(); extent.id = newID; extents.Add(newID, extent); return(extents[newID]); } }
public static void restoreSnapshot <T>(hypervisorWithSpec <T> hyp, FreeNASWithCaching nas, cancellableDateTime deadline) { hypSpec_withWindbgKernel _spec = hyp.getBaseConnectionSpec(); // Find the device snapshot, so we can get information about it needed to get the ISCSI volume snapshotObjects shotObjects = getSnapshotObjectsFromNAS(nas, _spec.snapshotFullName); // Here we power the server down, tell the iSCSI server to use the right image, and power it back up again. hyp.powerOff(); // Now we can get started. We must remove the 'target to extent' mapping, then the extent. Then we can safely roll back // the ZFS snapshot, and then re-add the extent and mapping. We use a finally block so that it is less likely we will // leave the NAS object in an inconsistent state. // Note that removing the target will also remove any 'target to extent' mapping, so we don't need to do that explicitly. // FreeNAS will take care of it for us. nas.deleteISCSIExtent(shotObjects.extent); nas.waitUntilISCSIConfigFlushed(); try { // Roll back the snapshot. Use a retry, since FreeNAS is complaining the dataset is in use occasionally. int retries = 100; while (true) { try { nas.rollbackSnapshot(shotObjects.shotToRestore); break; } catch (Exception) { if (retries-- == 0) { throw; } deadline.doCancellableSleep(TimeSpan.FromSeconds(6)); // 6 sec * 100 retries = ten minutes } } } finally { // Re-add the extent and target-to-extent mapping. Use the same target ID as the old target-to-extent used, and // the new extent's ID. iscsiExtent newExtent = nas.addISCSIExtent(shotObjects.extent); nas.addISCSITargetToExtent(shotObjects.tgtToExtent.iscsi_target, newExtent); nas.waitUntilISCSIConfigFlushed(); } }
public override iscsiExtent addISCSIExtent(iscsiExtent extent) { if (String.IsNullOrEmpty(extent.iscsi_target_extent_disk)) { extent.iscsi_target_extent_disk = extent.iscsi_target_extent_path; } // See freenas bug 11296: "type is Disk, but you need to use iscsi_target_extent_disk" // ... "start it with zvol instead of dev/zvol" if (extent.iscsi_target_extent_disk.StartsWith("/dev/zvol", StringComparison.CurrentCultureIgnoreCase)) { extent.iscsi_target_extent_disk = extent.iscsi_target_extent_disk.Substring(5); } if (extent.iscsi_target_extent_type == "ZVOL") { extent.iscsi_target_extent_type = "Disk"; // You're a Disk now, 'arry } string diskNameOrFilePath; if (extent.iscsi_target_extent_type == "File") { diskNameOrFilePath = String.Format("\"iscsi_target_extent_path\": \"{0}\" ", extent.iscsi_target_extent_path); } else if (extent.iscsi_target_extent_type == "Disk") { diskNameOrFilePath = String.Format("\"iscsi_target_extent_disk\": \"{0}\" ", extent.iscsi_target_extent_disk); } else { throw new ArgumentException("iscsi_target_extent_type"); } string payload = String.Format("{{" + "\"iscsi_target_extent_type\": \"{0}\", " + "\"iscsi_target_extent_name\": \"{1}\", " + "{2}" + "}}", extent.iscsi_target_extent_type, extent.iscsi_target_extent_name, diskNameOrFilePath); return(doReqForJSON <iscsiExtent>("http://" + _serverIp + "/api/v1.0/services/iscsi/extent/", "POST", HttpStatusCode.Created, payload)); }
public override iscsiExtent addISCSIExtent(iscsiExtent extent) { lock (this) { waitingISCSIOperations++; } iscsiExtent newVal; try { newVal = uncachedNAS.addISCSIExtent(extent); extents.TryAdd(newVal.id, newVal); } finally { lock (this) { waitingISCSIOperations--; } markThisThreadISCSIDirty(); } return(newVal); }
public override iscsiTargetToExtentMapping addISCSITargetToExtent(string iscsiTargetID, iscsiExtent newExtent) { lock (events) { events.Add(new mockedCall("addISCSITargetToExtent", "iscsiTarget: '" + iscsiTargetID + "' newExtent: " + newExtent)); } lock (tgtToExtents) { string newID = idGen.Next().ToString(); iscsiTargetToExtentMapping newMapping = new iscsiTargetToExtentMapping() { id = newID, iscsi_target = iscsiTargetID, iscsi_extent = newExtent.id, iscsi_lunid = "0" }; tgtToExtents.Add(newID, newMapping); return(tgtToExtents[newID]); } }
public abstract void deleteISCSIExtent(iscsiExtent extent);
public abstract iscsiExtent addISCSIExtent(iscsiExtent extent);
public abstract iscsiTargetToExtentMapping addISCSITargetToExtent(string iscsiTargetID, iscsiExtent newExtent);
public override iscsiTargetToExtentMapping addISCSITargetToExtent(string iscsiTargetID, iscsiExtent newExtent) { lock (this) { waitingISCSIOperations++; } iscsiTargetToExtentMapping newMapping; try { newMapping = uncachedNAS.addISCSITargetToExtent(iscsiTargetID, newExtent); TTEExtents.TryAdd(newMapping.id, newMapping); } finally { lock (this) { waitingISCSIOperations--; } markThisThreadISCSIDirty(); } return(newMapping); }
private static iscsiTargetToExtentMapping getTgtToExtent(NASAccess nas, iscsiExtent extent) { iscsiTargetToExtentMapping tgtToExtent = nas.getTargetToExtents().SingleOrDefault(x => x.iscsi_extent == extent.id); return(tgtToExtent); }
public override iscsiTargetToExtentMapping addISCSITargetToExtent(string targetID, iscsiExtent extent) { string payload = String.Format("{{" + "\"iscsi_target\": \"{0}\", " + "\"iscsi_extent\": \"{1}\", " + "\"iscsi_lunid\": null " + "}}", targetID, extent.id); return(doReqForJSON <iscsiTargetToExtentMapping>("http://" + _serverIp + "/api/v1.0/services/iscsi/targettoextent/", "POST", HttpStatusCode.Created, payload)); }
public override void deleteISCSIExtent(iscsiExtent extent) { string url = String.Format("http://{0}/api/v1.0/services/iscsi/extent/{1}/", _serverIp, extent.id); doReq(url, "DELETE", HttpStatusCode.NoContent); }