예제 #1
0
 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();
     }
 }
예제 #2
0
        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);
        }
예제 #3
0
        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
            });
        }
예제 #4
0
        public override void deleteISCSIExtent(iscsiExtent extent)
        {
            lock (events)
            {
                events.Add(new mockedCall("deleteISCSIExtent", "extent: " + extent));
            }

            lock (extents)
            {
                extents.Remove(extent.id);
            }
        }
예제 #5
0
        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]);
            }
        }
예제 #6
0
        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();
            }
        }
예제 #7
0
        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));
        }
예제 #8
0
        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);
        }
예제 #9
0
        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]);
            }
        }
예제 #10
0
 public abstract void deleteISCSIExtent(iscsiExtent extent);
예제 #11
0
 public abstract iscsiExtent addISCSIExtent(iscsiExtent extent);
예제 #12
0
 public abstract iscsiTargetToExtentMapping addISCSITargetToExtent(string iscsiTargetID, iscsiExtent newExtent);
예제 #13
0
        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);
        }
예제 #14
0
        private static iscsiTargetToExtentMapping getTgtToExtent(NASAccess nas, iscsiExtent extent)
        {
            iscsiTargetToExtentMapping tgtToExtent = nas.getTargetToExtents().SingleOrDefault(x => x.iscsi_extent == extent.id);

            return(tgtToExtent);
        }
예제 #15
0
        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));
        }
예제 #16
0
        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);
        }