src/Assessment/Parser/AVSAssessmentParser.cs (257 lines of code) (raw):

using Newtonsoft.Json; using System; using System.Collections.Generic; using Azure.Migrate.Export.Common; using Azure.Migrate.Export.HttpRequestHelper; using Azure.Migrate.Export.Models; namespace Azure.Migrate.Export.Assessment.Parser { public class AVSAssessmentParser { private readonly Dictionary<AssessmentInformation, AssessmentPollResponse> AVSAssessmentStatusMap; public AVSAssessmentParser(Dictionary<AssessmentInformation, AssessmentPollResponse> avsAssessmentStatusMap) { AVSAssessmentStatusMap = avsAssessmentStatusMap; } public void ParseAVSAssessment(Dictionary<AssessmentInformation, AVSAssessmentPropertiesDataset> AVSAssessmentsData, Dictionary<string, AVSAssessedMachinesDataset> AVSAssessedMachinesData, UserInput userInputObj) { if (userInputObj == null) throw new Exception("Received null user input object."); if (AVSAssessmentStatusMap == null) { userInputObj.LoggerObj.LogError($"AVS assessment status map is null, terminating parsing"); return; } if (AVSAssessmentStatusMap.Count <= 0) { userInputObj.LoggerObj.LogError($"AVS assessment status map is empty, terminating parsing"); return; } foreach (var kvp in AVSAssessmentStatusMap) { if (!UtilityFunctions.IsAssessmentCompleted(kvp)) { userInputObj.LoggerObj.LogWarning($"Skipping parsing assessment {kvp.Key.AssessmentName} as it is in {new EnumDescriptionHelper().GetEnumDescription(kvp.Value)} state"); continue; } userInputObj.LoggerObj.LogInformation($"Parsing AVS assessment {kvp.Key.AssessmentName}"); string apiVersion = Routes.AssessmentMachineListApiVersion; if (kvp.Key.AssessmentType == AssessmentType.AVSAssessment) apiVersion = Routes.AvsAssessmentApiVersion; string url = Routes.ProtocolScheme + Routes.AzureManagementApiHostname + Routes.ForwardSlash + Routes.SubscriptionPath + Routes.ForwardSlash + userInputObj.Subscription.Key + Routes.ForwardSlash + Routes.ResourceGroupPath + Routes.ForwardSlash + userInputObj.ResourceGroupName.Value + Routes.ForwardSlash + Routes.ProvidersPath + Routes.ForwardSlash + Routes.MigrateProvidersPath + Routes.ForwardSlash + Routes.AssessmentProjectsPath + Routes.ForwardSlash + userInputObj.AssessmentProjectName + Routes.ForwardSlash + Routes.GroupsPath + Routes.ForwardSlash + kvp.Key.GroupName + Routes.ForwardSlash + new EnumDescriptionHelper().GetEnumDescription(kvp.Key.AssessmentType) + Routes.ForwardSlash + kvp.Key.AssessmentName + Routes.QueryStringQuestionMark + Routes.QueryParameterApiVersion + Routes.QueryStringEquals + apiVersion; string assessmentPropertiesResponse = ""; try { assessmentPropertiesResponse = new HttpClientHelper().GetHttpRequestJsonStringResponse(url, userInputObj).Result; } catch (OperationCanceledException) { throw; } catch (AggregateException aeAVSProperties) { string errorMessage = ""; foreach (var e in aeAVSProperties.Flatten().InnerExceptions) { if (e is OperationCanceledException) throw e; else { errorMessage = errorMessage + e.Message + " "; } } userInputObj.LoggerObj.LogError($"Failed to retrieve AVS assessment properties for assessment: {errorMessage}"); url = ""; continue; } catch (Exception exAVSProperties) { userInputObj.LoggerObj.LogError($"Failed to retrieve AVS assessment properties for assessment: {exAVSProperties.Message}"); url = ""; continue; } AVSAssessmentPropertiesJSON avsPropertiesObj = JsonConvert.DeserializeObject<AVSAssessmentPropertiesJSON>(assessmentPropertiesResponse); UpdateAVSPropertiesDataset(avsPropertiesObj, AVSAssessmentsData, kvp.Key, userInputObj); url = Routes.ProtocolScheme + Routes.AzureManagementApiHostname + Routes.ForwardSlash + Routes.SubscriptionPath + Routes.ForwardSlash + userInputObj.Subscription.Key + Routes.ForwardSlash + Routes.ResourceGroupPath + Routes.ForwardSlash + userInputObj.ResourceGroupName.Value + Routes.ForwardSlash + Routes.ProvidersPath + Routes.ForwardSlash + Routes.MigrateProvidersPath + Routes.ForwardSlash + Routes.AssessmentProjectsPath + Routes.ForwardSlash + userInputObj.AssessmentProjectName + Routes.ForwardSlash + Routes.GroupsPath + Routes.ForwardSlash + kvp.Key.GroupName + Routes.ForwardSlash + new EnumDescriptionHelper().GetEnumDescription(kvp.Key.AssessmentType) + Routes.ForwardSlash + kvp.Key.AssessmentName + Routes.ForwardSlash + Routes.AVSAssessedMachinesPath + Routes.QueryStringQuestionMark + Routes.QueryParameterApiVersion + Routes.QueryStringEquals + apiVersion; while (!string.IsNullOrEmpty(url)) { if (userInputObj.CancellationContext.IsCancellationRequested) UtilityFunctions.InitiateCancellation(userInputObj); string assessedMachinesResponse = ""; try { assessedMachinesResponse = new HttpClientHelper().GetHttpRequestJsonStringResponse(url, userInputObj).Result; } catch (OperationCanceledException) { throw; } catch (AggregateException aeAssessedMachines) { string errorMessage = ""; foreach (var e in aeAssessedMachines.Flatten().InnerExceptions) { if (e is OperationCanceledException) throw e; else { errorMessage = errorMessage + e.Message + " "; } } userInputObj.LoggerObj.LogError($"Failed to retrieve machine data from assessment: {errorMessage}"); url = ""; continue; } catch (Exception exAVSAssessedMachines) { userInputObj.LoggerObj.LogError($"Failed to retrieve machine data from assessment: {exAVSAssessedMachines.Message}"); url = ""; continue; } AVSAssessedMachinesJSON obj = JsonConvert.DeserializeObject<AVSAssessedMachinesJSON>(assessedMachinesResponse); url = obj.NextLink; foreach (var value in obj.Values) { string key = value.Properties.DatacenterMachineArmId?.ToLower(); UpdateAVSAssessedMachinesDataset(AVSAssessedMachinesData, value, key, kvp.Key); } } } } private void UpdateAVSAssessedMachinesDataset(Dictionary<string, AVSAssessedMachinesDataset> AVSAssessedMachinesData, AVSAssessedMachineValue value, string key, AssessmentInformation assessmentInfo) { if (AVSAssessedMachinesData.ContainsKey(key)) return; AVSAssessedMachinesData.Add(key, new AVSAssessedMachinesDataset()); AVSAssessedMachinesData[key].DisplayName = value.Properties.DisplayName; AVSAssessedMachinesData[key].DatacenterMachineArmId = value.Properties.DatacenterMachineArmId?.ToLower(); AVSAssessedMachinesData[key].Suitability = value.Properties.Suitability; AVSAssessedMachinesData[key].SuitabilityExplanation = value.Properties.SuitabilityExplanation; AVSAssessedMachinesData[key].OperatingSystemName = value.Properties.OperatingSystemName; AVSAssessedMachinesData[key].OperatingSystemVersion = value.Properties.OperatingSystemVersion; AVSAssessedMachinesData[key].OperatingSystemArchitecture = value.Properties.OperatingSystemArchitecture; AVSAssessedMachinesData[key].BootType = value.Properties.BootType; AVSAssessedMachinesData[key].NumberOfCores = value.Properties.NumberOfCores; AVSAssessedMachinesData[key].MegabytesOfMemory = value.Properties.MegabytesOfMemory; AVSAssessedMachinesData[key].Disks = GetAssessedDiskList(value.Properties.Disks); AVSAssessedMachinesData[key].StorageInUseGB = value.Properties.StorageInUseGB; AVSAssessedMachinesData[key].NetworkAdapters = value.Properties.NetworkAdapters == null ? 0 : value.Properties.NetworkAdapters.Count; AVSAssessedMachinesData[key].NetworkAdapterList = GetAssessedNetworkAdapterList(value.Properties.NetworkAdapters); AVSAssessedMachinesData[key].GroupName = assessmentInfo.GroupName; } private void UpdateAVSPropertiesDataset(AVSAssessmentPropertiesJSON avsPropertiesObj, Dictionary<AssessmentInformation, AVSAssessmentPropertiesDataset> AVSAssessmentsData, AssessmentInformation assessmentInfo, UserInput userInputObj) { if (AVSAssessmentsData.ContainsKey(assessmentInfo)) return; AVSAssessmentsData.Add(assessmentInfo, new AVSAssessmentPropertiesDataset()); string recommendedNodes = ""; string recommendedFttRaidLevels = ""; string nodeTypes = ""; string recommendedExternalStorages = ""; foreach (var item in avsPropertiesObj.Properties.EstimatedNodes) { recommendedNodes += item.NodeNumber + " nodes of " + item.NodeType + ", "; string uppercaseFttRaidLevel = item.FttRaidLevel.ToUpper(); recommendedFttRaidLevels += uppercaseFttRaidLevel.Substring(0, 3) + "-" + uppercaseFttRaidLevel.Substring(3, 1) + " & " + uppercaseFttRaidLevel.Substring(4, 4) + "-" + uppercaseFttRaidLevel.Substring(8, 1) + " on " + item.NodeType + ", "; nodeTypes += item.NodeType + ", "; } nodeTypes = nodeTypes.Substring(0, nodeTypes.Length - 2); recommendedNodes = recommendedNodes.Substring(0, recommendedNodes.Length - 2); recommendedFttRaidLevels = recommendedFttRaidLevels.Substring(0, recommendedFttRaidLevels.Length - 2); foreach (var item in avsPropertiesObj.Properties.AvsEstimatedExternalStorages) { string storageType = item.StorageType.Substring(0, 3).ToUpper() + "-" + item.StorageType.Substring(3); recommendedExternalStorages += item.TotalStorageInGB/1024 + " TB of " + storageType + ", "; } if (recommendedExternalStorages.Length > 0) { recommendedExternalStorages = recommendedExternalStorages.Substring(0, recommendedExternalStorages.Length - 2); } AVSAssessmentsData[assessmentInfo].SubscriptionId = userInputObj.Subscription.Key; AVSAssessmentsData[assessmentInfo].ResourceGroup = userInputObj.ResourceGroupName.Value; AVSAssessmentsData[assessmentInfo].AssessmentProjectName = userInputObj.AssessmentProjectName; AVSAssessmentsData[assessmentInfo].GroupName = assessmentInfo.GroupName; AVSAssessmentsData[assessmentInfo].AssessmentName = avsPropertiesObj.Name; AVSAssessmentsData[assessmentInfo].SizingCriterion = new EnumDescriptionHelper().GetEnumDescription(assessmentInfo.AssessmentTag); AVSAssessmentsData[assessmentInfo].CreatedOn = avsPropertiesObj.Properties.CreatedTimestamp; AVSAssessmentsData[assessmentInfo].TotalMachinesAssessd = avsPropertiesObj.Properties.NumberOfMachines ?? 0; AVSAssessmentsData[assessmentInfo].MachinesReady = avsPropertiesObj.Properties.SuitabilitySummary?.Suitable ?? 0; AVSAssessmentsData[assessmentInfo].MachinesReadyWithConditions = avsPropertiesObj.Properties.SuitabilitySummary?.ConditionallySuitable ?? 0; AVSAssessmentsData[assessmentInfo].MachinesReadinessUnknown = avsPropertiesObj.Properties.SuitabilitySummary?.ReadinessUnknown ?? 0; AVSAssessmentsData[assessmentInfo].MachinesNotReady = avsPropertiesObj.Properties.SuitabilitySummary?.NotSuitable ?? 0; AVSAssessmentsData[assessmentInfo].TotalRecommendedNumberOfNodes = avsPropertiesObj.Properties.NumberOfNodes ?? 0; AVSAssessmentsData[assessmentInfo].NodeTypes = nodeTypes; AVSAssessmentsData[assessmentInfo].RecommendedNodes = recommendedNodes; AVSAssessmentsData[assessmentInfo].RecommendedFttRaidLevels = recommendedFttRaidLevels; AVSAssessmentsData[assessmentInfo].RecommendedExternalStorage = recommendedExternalStorages; AVSAssessmentsData[assessmentInfo].TotalMonthlyCostEstimate = avsPropertiesObj.Properties.TotalMonthlyCost ?? 0.00; AVSAssessmentsData[assessmentInfo].PredictedCpuUtilizationPercentage = avsPropertiesObj.Properties.CpuUtilization ?? 0.00; AVSAssessmentsData[assessmentInfo].PredictedMemoryUtilizationPercentage = avsPropertiesObj.Properties.RamUtilization ?? 0.00; AVSAssessmentsData[assessmentInfo].PredictedStorageUtilizationPercentage = avsPropertiesObj.Properties.StorageUtilization ?? 0.00; AVSAssessmentsData[assessmentInfo].NumberOfCpuCoresAvailable = avsPropertiesObj.Properties.TotalCpuCores ?? 0.00; AVSAssessmentsData[assessmentInfo].MemoryInTBAvailable = avsPropertiesObj.Properties.TotalRamInGB / 1024.0 ?? 0.00; AVSAssessmentsData[assessmentInfo].StorageInTBAvailable = avsPropertiesObj.Properties.TotalStorageInGB / 1024.0 ?? 0.00; AVSAssessmentsData[assessmentInfo].NumberOfCpuCoresUsed = Math.Ceiling(AVSAssessmentsData[assessmentInfo].NumberOfCpuCoresAvailable * AVSAssessmentsData[assessmentInfo].PredictedCpuUtilizationPercentage / 100.0); AVSAssessmentsData[assessmentInfo].MemoryInTBUsed = AVSAssessmentsData[assessmentInfo].MemoryInTBAvailable * AVSAssessmentsData[assessmentInfo].PredictedMemoryUtilizationPercentage / 100.0; AVSAssessmentsData[assessmentInfo].StorageInTBUsed = AVSAssessmentsData[assessmentInfo].StorageInTBAvailable * AVSAssessmentsData[assessmentInfo].PredictedStorageUtilizationPercentage / 100.0; AVSAssessmentsData[assessmentInfo].NumberOfCpuCoresFree = AVSAssessmentsData[assessmentInfo].NumberOfCpuCoresAvailable - AVSAssessmentsData[assessmentInfo].NumberOfCpuCoresUsed; AVSAssessmentsData[assessmentInfo].MemoryInTBFree = AVSAssessmentsData[assessmentInfo].MemoryInTBAvailable - AVSAssessmentsData[assessmentInfo].MemoryInTBUsed; AVSAssessmentsData[assessmentInfo].StorageInTBFree = AVSAssessmentsData[assessmentInfo].StorageInTBAvailable - AVSAssessmentsData[assessmentInfo].StorageInTBUsed; AVSAssessmentsData[assessmentInfo].ConfidenceRating = UtilityFunctions.GetConfidenceRatingInStars(avsPropertiesObj.Properties.ConfidenceRatingInPercentage?? 0); AvsAssessmentConstants.VCpuOversubscription = ((int)(avsPropertiesObj.Properties.VCpuOversubscription)).ToString() + ":1"; AvsAssessmentConstants.DedupeCompression = avsPropertiesObj.Properties.DedupeCompression ?? 1.5; } #region Utilities private List<AssessedDisk> GetAssessedDiskList(Dictionary<string, AVSAssessedMachineDisk> disks) { List<AssessedDisk> diskList = new List<AssessedDisk>(); foreach (var kvp in disks) { AssessedDisk obj = new AssessedDisk(); obj.DisplayName = kvp.Value.DisplayName; obj.GigabytesProvisioned = kvp.Value.GigabytesProvisioned; obj.MegabytesPerSecondOfRead = kvp.Value.MegabytesPerSecondOfRead; obj.MegabytesPerSecondOfWrite = kvp.Value.MegabytesPerSecondOfWrite; obj.NumberOfReadOperationsPerSecond = kvp.Value.NumberOfReadOperationsPerSecond; obj.NumberOfWriteOperationsPerSecond = kvp.Value.NumberOfWriteOperationsPerSecond; diskList.Add(obj); } return diskList; } private List<AssessedNetworkAdapter> GetAssessedNetworkAdapterList(Dictionary<string, AVSAssessedMachineNetworkAdapter> networkAdapters) { List<AssessedNetworkAdapter> networkAdapterList = new List<AssessedNetworkAdapter>(); foreach (var kvp in networkAdapters) { AssessedNetworkAdapter obj = new AssessedNetworkAdapter(); obj.DisplayName = kvp.Value.DisplayName; obj.MacAddress = kvp.Value.MacAddress; obj.IpAddresses = kvp.Value.IpAddresses; obj.MegabytesPerSecondReceived = kvp.Value.MegabytesPerSecondReceived; obj.MegaytesPerSecondTransmitted = kvp.Value.MegabytesPerSecondTransmitted; networkAdapterList.Add(obj); } return networkAdapterList; } #endregion } }