Skip to content

Commit

Permalink
Release V3 (#59)
Browse files Browse the repository at this point in the history
* Recommend SQL Instance rehost for IaaS migration

* Add ModernizeToAzureSqlMi option

* Added static forex rates

* Add BC and security cost

* Add Decommissioned_Machines

* Remove SQL services logic (#48)

* Fix debugging (#49)

* Add Ahub savings (#50)

* Add Financial_Summary (#51)

* integrated Financial Summary Changes

* Adjust worksheet priorities

* Updated Financial Summary code

* Financial Summary code

* Code clean up (#52)

* Add OnPrem IaaS and PaaS costs (#54)

* Update PBIT and pipeline (#55)

* Add support status to assessment reports (#56)

* Update PBIT (#58)

* Update PBIT

* Update PBIT

* Fix console self-host feedback (#60)

* Fix console self-host feedback

* Fix assessment completion message

* Update PBIT

* Fix PaaS source counts (#61)

* Fix PaaS source counts

* Fix null response API

---------

Co-authored-by: vrindagoel-microsoft <[email protected]>
  • Loading branch information
harshrathore-msft and vrindagoel-microsoft authored Sep 8, 2023
1 parent bfff4f9 commit 827a49f
Show file tree
Hide file tree
Showing 79 changed files with 2,938 additions and 153 deletions.
22 changes: 7 additions & 15 deletions .azure-pipelines/azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ variables:
OutputRootDirectory: '$(Build.ArtifactStagingDirectory)'
CopyTargetFolder: '$(OutputRootDirectory)\AzMigExport'

major: 2
major: 3
minor: 0

name: $(major).$(minor).$(Year:yy)$(DayOfYear).$(Rev:r)
Expand Down Expand Up @@ -61,47 +61,39 @@ stages:
suppressionsFile: '$(RootDirectory)\.config\CredScanSuppressions.json'

- task: CopyFiles@2
displayName: 'Copying DLLs to AzMigExport'
displayName: 'Copy DLLs to AzMigExport'
inputs:
SourceFolder: '$(CopySourceFolder)'
TargetFolder: '$(CopyTargetFolder)'
OverWrite: true
Contents: '**\*.dll'

- task: CopyFiles@2
displayName: 'Copying Executable to AzMigExport'
displayName: 'Copy Executable to AzMigExport'
inputs:
SourceFolder: '$(CopySourceFolder)'
TargetFolder: '$(CopyTargetFolder)'
OverWrite: true
Contents: '**\Azure-Migrate-Export.exe'

- task: CopyFiles@2
displayName: 'Copying Config to AzMigExport'
displayName: 'Copy Config to AzMigExport'
inputs:
SourceFolder: '$(CopySourceFolder)'
TargetFolder: '$(CopyTargetFolder)'
OverWrite: true
Contents: '**\Azure-Migrate-Export.exe.config'

- task: CopyFiles@2
displayName: 'Copying Detailed PBIT to AzMigExport'
displayName: 'Copy PBIT to AzMigExport'
inputs:
SourceFolder: '$(CopySourceFolder)'
TargetFolder: '$(CopyTargetFolder)'
OverWrite: true
Contents: '**\Azure_Migrate_Export_Detailed.pbit'
Contents: '**\Azure_Migration_and_Modernization.pbit'

- task: CopyFiles@2
displayName: 'Copying HBC-Lite PBIT to AzMigExport'
inputs:
SourceFolder: '$(CopySourceFolder)'
TargetFolder: '$(CopyTargetFolder)'
OverWrite: true
Contents: '**\Azure_Migrate_Export_HBC-Lite.pbit'

- task: CopyFiles@2
displayName: 'Copying README to AzMigExport'
displayName: 'Copy README to AzMigExport'
inputs:
SourceFolder: '$(CopySourceFolder)'
TargetFolder: '$(CopyTargetFolder)'
Expand Down
122 changes: 121 additions & 1 deletion src/Assessment/Assess.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ public bool BeginAssessment()
{
AssessmentSiteMachine obj = new AssessmentSiteMachine
{
DisplayName = value.Properties.DisplayName,
AssessmentId = value.Id?.ToLower(),
DiscoveryMachineArmId = value.Properties.DiscoveryMachineArmId?.ToLower(),
SqlInstancesCount = value.Properties.SqlInstances.Count,
Expand Down Expand Up @@ -135,6 +136,9 @@ public bool BeginAssessment()
Dictionary<string, List<string>> GroupMachinesMap = new Dictionary<string, List<string>>();
List<string> CreatedGroups = new List<string>();

HashSet<string> discoveryMachineArmIdSet = GetDiscoveredMachineIDsSet();
Dictionary<string, string> DecommissionedMachinesData = new Dictionary<string, string>();

foreach (var assessmentSiteMachine in assessmentSiteMachines)
{
if (string.IsNullOrEmpty(assessmentSiteMachine.AssessmentId))
Expand All @@ -143,6 +147,12 @@ public bool BeginAssessment()
if (string.IsNullOrEmpty(assessmentSiteMachine.DiscoveryMachineArmId))
continue;

if (!discoveryMachineArmIdSet.Contains(assessmentSiteMachine.DiscoveryMachineArmId) && IsMachineDiscoveredBySelectedSourceAppliance(assessmentSiteMachine.DiscoveryMachineArmId))
{
if (!DecommissionedMachinesData.ContainsKey(assessmentSiteMachine.DiscoveryMachineArmId))
DecommissionedMachinesData.Add(assessmentSiteMachine.DiscoveryMachineArmId, assessmentSiteMachine.DisplayName);
}

foreach (var discoverySiteMachine in DiscoveredData)
{
if (string.IsNullOrEmpty(discoverySiteMachine.MachineId))
Expand Down Expand Up @@ -211,6 +221,37 @@ public bool BeginAssessment()
string RandomSessionId = new Random().Next(0, 100000).ToString("D5");
UserInputObj.LoggerObj.LogInformation($"ID for this session: {RandomSessionId}");

BusinessCaseInformation bizCaseObj = new BusinessCaseSettingsFactory().GetBusinessCaseSettings(UserInputObj, RandomSessionId);
KeyValuePair<BusinessCaseInformation, AssessmentPollResponse> bizCaseCompletionResultKvp = new KeyValuePair<BusinessCaseInformation, AssessmentPollResponse>(bizCaseObj, AssessmentPollResponse.NotCreated);
try
{
bizCaseCompletionResultKvp = new BusinessCaseBuilder(bizCaseObj).BuildBusinessCase(UserInputObj);
}
catch (OperationCanceledException)
{
throw;
}
catch (AggregateException aeBuildBizCase)
{
string errorMessage = "";
foreach (var e in aeBuildBizCase.Flatten().InnerExceptions)
{
if (e is OperationCanceledException)
throw e;
else
{
errorMessage = errorMessage + e.Message + " ";
}
}
throw new Exception(errorMessage);
}
catch (Exception)
{
throw;
}

UserInputObj.LoggerObj.LogInformation($"Business case {bizCaseCompletionResultKvp.Key.BusinessCaseName} is in {bizCaseCompletionResultKvp.Value.ToString()} state");

foreach (var kvp in AzureVM)
{
UserInputObj.LoggerObj.LogInformation($"Total {kvp.Key} environment machines: {kvp.Value.Count}");
Expand Down Expand Up @@ -473,7 +514,7 @@ public bool BeginAssessment()
if (invalidAssessmentsCount > 0)
UserInputObj.LoggerObj.LogError($"Invalid assessments: {invalidAssessmentsCount}");

UserInputObj.LoggerObj.LogInformation(65 - UserInputObj.LoggerObj.GetCurrentProgress(), $"Completed assessment creation job"); // 75 % complete
UserInputObj.LoggerObj.LogInformation(65 - UserInputObj.LoggerObj.GetCurrentProgress(), $"Completed assessment creation job"); // 65 % complete

Dictionary<AssessmentInformation, AssessmentPollResponse> AzureVMAssessmentStatusMap = new Dictionary<AssessmentInformation, AssessmentPollResponse>();
Dictionary<AssessmentInformation, AssessmentPollResponse> AzureSQLAssessmentStatusMap = new Dictionary<AssessmentInformation, AssessmentPollResponse>();
Expand Down Expand Up @@ -546,6 +587,12 @@ public bool BeginAssessment()
ParseAzureSQLAssessedMachines(AzureSQLMachinesData, AzureSQLAssessmentStatusMap);
}

BusinessCaseDataset BusinessCaseData = new BusinessCaseDataset();
if (bizCaseCompletionResultKvp.Value == AssessmentPollResponse.Completed)
{
ParseBusinessCase(bizCaseCompletionResultKvp, BusinessCaseData);
}

ProcessDatasets processorObj = new ProcessDatasets
(
AssessmentIdToDiscoveryIdLookup,
Expand All @@ -559,13 +606,48 @@ public bool BeginAssessment()
AzureWebAppData,
AzureSQLInstancesData,
AzureSQLMachinesData,
BusinessCaseData,
DecommissionedMachinesData,
UserInputObj
);
processorObj.InititateProcessing();

return true;
}

private void ParseBusinessCase(KeyValuePair<BusinessCaseInformation, AssessmentPollResponse> bizCaseCompletionResultKvp, BusinessCaseDataset BusinessCaseData)
{
UserInputObj.LoggerObj.LogInformation("Initiating parsing for business case");
try
{
new BusinessCaseParser(bizCaseCompletionResultKvp).ParseBusinessCase(UserInputObj, BusinessCaseData);
}
catch (OperationCanceledException)
{
throw;
}
catch (AggregateException aeBizCaseParse)
{
string errorMessage = "";
foreach (var e in aeBizCaseParse.Flatten().InnerExceptions)
{
if (e is OperationCanceledException)
throw e;
else
{
errorMessage = errorMessage + e.Message + " ";
}
}
UserInputObj.LoggerObj.LogError($"Business case parsing error : {errorMessage}");
}
catch (Exception exBizCaseParse)
{
UserInputObj.LoggerObj.LogError($"Business case parsing error {exBizCaseParse.Message}");
}

UserInputObj.LoggerObj.LogInformation("Business case parsing job completed");
}

private void ParseAzureSQLAssessedMachines(Dictionary<string, AzureSQLMachineDataset> AzureSQLMachinesData, Dictionary<AssessmentInformation, AssessmentPollResponse> AzureSQLAssessmentStatusMap)
{
UserInputObj.LoggerObj.LogInformation("Initiating parsing for Azure SQL assessed machines");
Expand Down Expand Up @@ -732,6 +814,7 @@ private void ParseAzureVMAssessments(Dictionary<string, AzureVMPerformanceBasedD
UserInputObj.LoggerObj.LogInformation(70 - UserInputObj.LoggerObj.GetCurrentProgress(), "Azure VM assessment parsing job completed"); // 70 % Complete
}

#region Deletion
private void DeletePreviousAssessmentReports()
{
UserInputObj.LoggerObj.LogInformation("Deleting previous assessment reports, if any");
Expand Down Expand Up @@ -784,6 +867,7 @@ private void DeletePreviousClashReport()
UserInputObj.LoggerObj.LogInformation("Clash report found, please ensure the file is closed otherwise deleting it won't be possible and process will terminate");
Directory.Delete(directory, true);
}
#endregion

#region Utilities
private List<string> ObtainAssessmentMachineIdList(List<AssessmentSiteMachine> assessmentSiteMachines)
Expand All @@ -806,6 +890,42 @@ private static int CompareAssessmentCreationPriority(AssessmentInformation a, As

return a.AssessmentCreationPriority.CompareTo(b.AssessmentCreationPriority);
}

private HashSet<string> GetDiscoveredMachineIDsSet()
{
HashSet<string> result = new HashSet<string>();

foreach (var discoveredMachine in DiscoveredData)
{
if (!result.Contains(discoveredMachine.MachineId))
result.Add(discoveredMachine.MachineId);
}

return result;
}

private bool IsMachineDiscoveredBySelectedSourceAppliance(string discoveryArmId)
{
if (string.IsNullOrEmpty(discoveryArmId))
return false;
if (UserInputObj.AzureMigrateSourceAppliances == null || UserInputObj.AzureMigrateSourceAppliances.Count <= 0)
return false;

bool getVmware = UserInputObj.AzureMigrateSourceAppliances.Contains("vmware");
bool getHyperv = UserInputObj.AzureMigrateSourceAppliances.Contains("hyperv");
bool getPhysical = UserInputObj.AzureMigrateSourceAppliances.Contains("physical");

bool isVmwareSite = discoveryArmId.Contains("vmwaresites");
bool isHypervSite = discoveryArmId.Contains("hypervsites");
bool isServerSite = discoveryArmId.Contains("serversites");

if ((getVmware && isVmwareSite) ||
(getHyperv && isHypervSite) ||
(getPhysical && isServerSite))
return true;

return false;
}
#endregion
}
}
115 changes: 115 additions & 0 deletions src/Assessment/BusinessCaseBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

using Azure.Migrate.Export.Common;
using Azure.Migrate.Export.HttpRequestHelper;
using Azure.Migrate.Export.Models;

namespace Azure.Migrate.Export.Assessment
{
public class BusinessCaseBuilder
{
private readonly BusinessCaseInformation BusinessCaseInformationObj;

public BusinessCaseBuilder(BusinessCaseInformation businessCaseInformationObj)
{
BusinessCaseInformationObj = businessCaseInformationObj;
}

public KeyValuePair<BusinessCaseInformation, AssessmentPollResponse> BuildBusinessCase(UserInput userInputObj)
{
if (userInputObj.CancellationContext.IsCancellationRequested)
UtilityFunctions.InitiateCancellation(userInputObj);

AssessmentPollResponse result = AssessmentPollResponse.NotCreated;
bool isBusinessCaseCreated = false;

try
{
isBusinessCaseCreated = new HttpClientHelper().CreateBusinessCase(userInputObj, BusinessCaseInformationObj).Result;
}
catch (OperationCanceledException)
{
throw;
}
catch (AggregateException aeCreateBizCase)
{
string errorMessage = "";
foreach (var e in aeCreateBizCase.Flatten().InnerExceptions)
{
if (e is OperationCanceledException)
throw;
else
errorMessage = errorMessage + e.Message + " ";
}
result = AssessmentPollResponse.NotCreated;
userInputObj.LoggerObj.LogWarning($"Business case {BusinessCaseInformationObj.BusinessCaseName} creation failed: {errorMessage}");
}
catch (Exception ex)
{
result = AssessmentPollResponse.NotCreated;
userInputObj.LoggerObj.LogWarning($"Business case {BusinessCaseInformationObj.BusinessCaseName} creation failed: {ex.Message}");
}

if (!isBusinessCaseCreated)
return new KeyValuePair<BusinessCaseInformation, AssessmentPollResponse>(BusinessCaseInformationObj, AssessmentPollResponse.NotCreated);

result = PollBusinessCaseState(userInputObj).Result;

return new KeyValuePair<BusinessCaseInformation, AssessmentPollResponse>(BusinessCaseInformationObj, result);
}

private async Task<AssessmentPollResponse> PollBusinessCaseState(UserInput userInputObj)
{
int numberOfTries = 0;
AssessmentPollResponse pollResult = AssessmentPollResponse.Created;

while (numberOfTries < 25)
{
Thread.Sleep(60000);
try
{
pollResult = await new HttpClientHelper().PollBusinessCase(userInputObj, BusinessCaseInformationObj);

if (pollResult == AssessmentPollResponse.Error)
{
userInputObj.LoggerObj.LogInformation($"Polling for business case {BusinessCaseInformationObj.BusinessCaseName} resulted in non-retryable error");
numberOfTries += 1;
}
}
catch (OperationCanceledException)
{
throw;
}
catch (AggregateException aePollBizCase)
{
string errorMessage = "";
foreach (var e in aePollBizCase.Flatten().InnerExceptions)
{
if (e is OperationCanceledException)
throw e;
else
{
errorMessage = errorMessage + e.Message + " ";
}
}
userInputObj.LoggerObj.LogWarning($"Business case {BusinessCaseInformationObj.BusinessCaseName} polling failed: {errorMessage}");
}
catch (Exception ex)
{
userInputObj.LoggerObj.LogWarning($"Business case {BusinessCaseInformationObj.BusinessCaseName} polling failed: {ex.Message}");
}

if (pollResult == AssessmentPollResponse.Completed ||
pollResult == AssessmentPollResponse.OutDated ||
pollResult == AssessmentPollResponse.Invalid)
break;
}

userInputObj.LoggerObj.LogInformation($"Polling for business case {BusinessCaseInformationObj.BusinessCaseName} completed");
return pollResult;
}
}
}
2 changes: 1 addition & 1 deletion src/Assessment/Parser/AVSAssessmentParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ private void UpdateAVSAssessedMachinesDataset(Dictionary<string, AVSAssessedMach
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.Count; // TODO: handle null object reference
AVSAssessedMachinesData[key].NetworkAdapters = value.Properties.NetworkAdapters == null ? 0 : value.Properties.NetworkAdapters.Count;
AVSAssessedMachinesData[key].NetworkAdapterList = GetAssessedNetworkAdapterList(value.Properties.NetworkAdapters);
AVSAssessedMachinesData[key].GroupName = assessmentInfo.GroupName;
}
Expand Down
Loading

0 comments on commit 827a49f

Please sign in to comment.