/// <summary> /// Parses a list of drive data objects from a string /// </summary> /// <param name="inpList">Input string containing drive information</param> /// <returns>List of drives with associated data</returns> public static IEnumerable<clsDriveData> GetDriveList(string inpList) { if (string.IsNullOrWhiteSpace(inpList)) { // There were no drives in string LogError("Drive list provided to GetDriveList is empty"); return null; } // Data for drives is separated by semi-colon. var driveArray = inpList.Split(';'); var driveList = new List<clsDriveData>(); // Data for an individual drive is separated by comma foreach (var driveSpec in driveArray) { if (string.IsNullOrWhiteSpace(driveSpec)) { LogError("Unable to get drive space threshold from string, should be something like G:,600 and not " + driveSpec); return null; } var driveInfo = driveSpec.Split(','); if (driveInfo.Length != 2) { LogError("Invalid parameter count for drive data string " + driveSpec + ", should be something like G:,600");; return null; } // Add the data for this drive to the return list // Note that driveInfo[0] can be either just a drive letter or a drive letter and a colon; either is supported var newDrive = new clsDriveData(driveInfo[0], double.Parse(driveInfo[1])); driveList.Add(newDrive); } return driveList; }
/// <summary> /// For remote drives, uses WMI to determine if free space on disk is above minimum threshold /// For local drives, uses DriveInfo /// </summary> /// <param name="machine">Name of server to check</param> /// <param name="driveData">Data for drive to be checked</param> /// <param name="perspective">Client/Server setting for manager. "Client" means checking a remote drive; "Server" means running on a Proto-x server </param> /// <param name="driveFreeSpaceGB">Actual drive free space in GB</param> /// <returns>Enum indicating space status</returns> public static SpaceCheckResults IsPurgeRequired(string machine, string perspective, clsDriveData driveData, out double driveFreeSpaceGB) { SpaceCheckResults testResult; driveFreeSpaceGB = -1; if (perspective.StartsWith("client", StringComparison.InvariantCultureIgnoreCase)) { // Checking a remote drive // Get WMI object representing drive var requestStr = @"\\" + machine + @"\root\cimv2:win32_logicaldisk.deviceid=""" + driveData.DriveLetter + "\""; try { var disk = new ManagementObject(requestStr); disk.Get(); var oFreeSpace = disk["FreeSpace"]; if (oFreeSpace == null) { LogError("Drive " + driveData.DriveLetter + " not found via WMI; likely is Not Ready", true); return SpaceCheckResults.Error; } var availableSpace = Convert.ToDouble(oFreeSpace); var totalSpace = Convert.ToDouble(disk["Size"]); if (totalSpace <= 0) { LogError("Drive " + driveData.DriveLetter + " reports a total size of 0 bytes via WMI; likely is Not Ready", true); return SpaceCheckResults.Error; } driveFreeSpaceGB = BytesToGB((long)availableSpace); } catch (Exception ex) { var msg = "Exception getting free disk space using WMI, drive " + driveData.DriveLetter + ": " + ex.Message; var postToDB = !Environment.MachineName.StartsWith("monroe", StringComparison.InvariantCultureIgnoreCase); LogError(msg, postToDB); if (driveFreeSpaceGB > 0) driveFreeSpaceGB = -driveFreeSpaceGB; if (Math.Abs(driveFreeSpaceGB) < float.Epsilon) driveFreeSpaceGB = -1; } } else { // Analyzing a drive local to this manager try { // Note: WMI string would be: "win32_logicaldisk.deviceid=\"" + driveData.DriveLetter + "\""; // Instantiate a new drive info object var diDrive = new DriveInfo(driveData.DriveLetter); if (!diDrive.IsReady) { LogError("Drive " + driveData.DriveLetter + " reports Not Ready via DriveInfo object; drive is offline or drive letter is invalid", true); return SpaceCheckResults.Error; } if (diDrive.TotalSize <= 0) { LogError("Drive " + driveData.DriveLetter + " reports a total size of 0 bytes via DriveInfo object; likely is Not Ready", true); return SpaceCheckResults.Error; } driveFreeSpaceGB = BytesToGB(diDrive.TotalFreeSpace); } catch (Exception ex) { LogError("Exception getting free disk space via .NET DriveInfo object, drive " + driveData.DriveLetter + ": " + ex.Message, true); if (driveFreeSpaceGB > 0) driveFreeSpaceGB = -driveFreeSpaceGB; if (Math.Abs(driveFreeSpaceGB) < float.Epsilon) driveFreeSpaceGB = -1; } } if (driveFreeSpaceGB < 0) { testResult = SpaceCheckResults.Error; // Log space requirement if debug logging enabled ReportStatus( "Drive " + driveData.DriveLetter + " Space Threshold: " + driveData.MinDriveSpace + ", Drive not found", true); } else { if (driveFreeSpaceGB > driveData.MinDriveSpace) testResult = SpaceCheckResults.Above_Threshold; else testResult = SpaceCheckResults.Below_Threshold; // Log space requirement if debug logging enabled ReportStatus("Drive " + driveData.DriveLetter + " Space Threshold: " + driveData.MinDriveSpace + ", Avail space: " + driveFreeSpaceGB.ToString("####0.0"), true); } return testResult; }
private DriveOpStatus ProcessDrive(int maxReps, clsDriveData testDrive) { const int MAX_MISSING_FOLDERS = 50; var opStatus = DriveOpStatus.KeepRunning; var repCounter = 0; var folderMissingCount = 0; try { // Start a purge loop for the current drive var bDriveInfoLogged = false; while (true) { // Check for configuration changes if (m_ConfigChanged) { // Local config has changed, so exit loop and reload settings ReportStatus("Local config changed. Reloading configuration"); opStatus = DriveOpStatus.Exit_Restart_OK; break; } // Check to see if iteration limit has been exceeded if (repCounter >= maxReps) { // Exceeded max number of repetitions for this run, so exit ReportStatus("Reached maximum repetition count of " + maxReps + "; Program exiting"); opStatus = DriveOpStatus.Exit_No_Restart; break; } if (folderMissingCount >= MAX_MISSING_FOLDERS) { // Too many missing folders; MyEMSL or the archive could be offline LogError("Too many missing folders: MyEMSL or the archive could be offline; Program exiting"); opStatus = DriveOpStatus.Exit_No_Restart; break; } // Check error count if (!TestErrorCount()) { // Excessive errors. Program exit required. Logging handled by TestErrorCount opStatus = DriveOpStatus.Exit_No_Restart; break; } // Check available space on server drive and compare it with min allowed space double driveFreeSpaceGB; var serverName = m_MgrSettings.GetParam("machname"); var perspective = m_MgrSettings.GetParam("perspective"); var checkResult = clsUtilityMethods.IsPurgeRequired(serverName, perspective, testDrive, out driveFreeSpaceGB); if (checkResult == SpaceCheckResults.Above_Threshold) { // Drive doesn't need purging, so continue to next drive ReportStatus("No purge required, drive " + testDrive.DriveLetter + " " + Math.Round(driveFreeSpaceGB, 0) + " GB free vs. " + Math.Round(testDrive.MinDriveSpace, 0) + " GB threshold"); break; } string pendingWindowsUpdateMessage; if (PRISM.clsWindowsUpdateStatus.ServerUpdatesArePending(DateTime.Now, out pendingWindowsUpdateMessage)) { ReportStatus("Exiting: " + pendingWindowsUpdateMessage); break; } if (checkResult == SpaceCheckResults.Error) { // There was an error getting the free space for this drive. Logging handled by IsPurgeRequired m_ErrorCount++; break; } if (!bDriveInfoLogged) { bDriveInfoLogged = true; // Note: there are extra spaces after "required" so the log message lines up with the "No purge required" message ReportStatus("Purge required , drive " + testDrive.DriveLetter + " " + Math.Round(driveFreeSpaceGB, 0) + " GB free vs. " + Math.Round(testDrive.MinDriveSpace, 0) + " GB threshold"); } // Request a purge task var requestResult = m_Task.RequestTask(testDrive.DriveLetter); // Check for an error if (requestResult == EnumRequestTaskResult.ResultError) { // Error requesting task. Error logging handled by RequestTask, so just continue to next purge candidate m_ErrorCount++; repCounter++; continue; } // Check for MC database config change if (requestResult == EnumRequestTaskResult.ConfigChanged) { // Manager control db has changed. Set flag and allow config test at beginning of loop to control restart m_ConfigChanged = true; continue; } // Check for task not assigned if (requestResult == EnumRequestTaskResult.NoTaskFound) { // No purge task assigned. This is a problem because the drive is low on space LogWarning("Drive purge required, but no purge task assigned"); break; } // If we got to here, the drive needs purging and a purge task was assigned. So, perform the purge var purgeResult = m_StorageOps.PurgeDataset(m_Task); // Evaluate purge result switch (purgeResult) { case EnumCloseOutType.CLOSEOUT_SUCCESS: case EnumCloseOutType.CLOSEOUT_PURGE_AUTO: case EnumCloseOutType.CLOSEOUT_PURGE_ALL_EXCEPT_QC: repCounter++; m_ErrorCount = 0; break; case EnumCloseOutType.CLOSEOUT_UPDATE_REQUIRED: repCounter++; m_ErrorCount = 0; break; case EnumCloseOutType.CLOSEOUT_FAILED: m_ErrorCount++; repCounter++; break; // Obsolete: //case EnumCloseOutType.CLOSEOUT_WAITING_HASH_FILE: // repCounter++; // m_ErrorCount = 0; // break; case EnumCloseOutType.CLOSEOUT_DRIVE_MISSING: case EnumCloseOutType.CLOSEOUT_DATASET_FOLDER_MISSING_IN_ARCHIVE: repCounter++; folderMissingCount++; break; } // Close the purge task m_Task.CloseTask(purgeResult); if (purgeResult == EnumCloseOutType.CLOSEOUT_DRIVE_MISSING) { LogWarning("Drive not found; moving on to next drive"); break; } if (purgeResult == EnumCloseOutType.CLOSEOUT_ARCHIVE_OFFLINE) { LogWarning("Archive is offline; closing the manager"); opStatus = DriveOpStatus.Exit_No_Restart; break; } } } catch (Exception ex) { LogError("Exception in ProcessDrive", ex); } return opStatus; }