From e743e2cd559af266169a62881569abb381812c8d Mon Sep 17 00:00:00 2001 From: MelindaWang Date: Mon, 7 Aug 2023 14:24:23 -0700 Subject: [PATCH] add reset command --- Program.cs | 28 +++++++++++++++++-- ResetOptionsBinder.cs | 25 +++++++++++++++-- ams/AssetMigrationTracker.cs | 7 +++++ ams/CleanupCommand.cs | 12 ++++---- ams/ResetCommand.cs | 51 ++++++++++++++++++++++------------ contracts/IMigrationTracker.cs | 2 ++ 6 files changed, 97 insertions(+), 28 deletions(-) diff --git a/Program.cs b/Program.cs index ab16702..1bcc3b5 100644 --- a/Program.cs +++ b/Program.cs @@ -1,4 +1,5 @@ -using AMSMigrate.Ams; +using AMSMigrate.ams; +using AMSMigrate.Ams; using AMSMigrate.Azure; using AMSMigrate.Contracts; using AMSMigrate.Local; @@ -75,6 +76,21 @@ This command forcefully removes the Azure Media Services (AMS) account. await CleanupAsync(context, cleanupOptions, context.GetCancellationToken()); }); + var resetOptionsBinder = new ResetOptionsBinder(); + var resetCommand = resetOptionsBinder.GetCommand("reset", @"Reset assets back to their original NotMigrated state in the AMS account +Examples to reset assets in the AMS account: +reset -s -g -n -a true +This command will forcibly revert all assets in the Azure Media Services (AMS) account to their initial NotMigrated state. +reset -s -g -n -f true +This command will forcefully revert migrated assets that have failed back to their original NotMigrated state within the Azure Media Services (AMS) account."); + rootCommand.Add(resetCommand); + resetCommand.SetHandler( + async context => + { + var resetOptions =resetOptionsBinder.GetValue(context.BindingContext); + await ResetAsync(context, resetOptions, context.GetCancellationToken()); + }); + // disable storage migrate option until ready /* var storageOptionsBinder = new StorageOptionsBinder(); @@ -223,7 +239,15 @@ static async Task CleanupAsync( await ActivatorUtilities.CreateInstance(provider, cleanupOptions) .MigrateAsync(cancellationToken); } - + static async Task ResetAsync( + InvocationContext context, + ResetOptions resetOptions, + CancellationToken cancellationToken) + { + var provider = context.BindingContext.GetRequiredService(); + await ActivatorUtilities.CreateInstance(provider, resetOptions) + .MigrateAsync(cancellationToken); + } static async Task MigrateKeysAsync( InvocationContext context, diff --git a/ResetOptionsBinder.cs b/ResetOptionsBinder.cs index 81c0f02..83a58fb 100644 --- a/ResetOptionsBinder.cs +++ b/ResetOptionsBinder.cs @@ -1,13 +1,16 @@ -using System; +using AMSMigrate.Contracts; +using FFMpegCore.Enums; +using System; using System.Collections.Generic; using System.CommandLine; +using System.CommandLine.Binding; using System.Linq; using System.Text; using System.Threading.Tasks; namespace AMSMigrate { - internal class ResetOptionsBinder + internal class ResetOptionsBinder : BinderBase { private readonly Option _sourceAccount = new Option( aliases: new[] { "--source-account-name", "-n" }, @@ -29,6 +32,24 @@ internal class ResetOptionsBinder { IsRequired = false }; + public ResetOptions GetValue(BindingContext context) => GetBoundValue(context); + public Command GetCommand(string name, string description) + { + var command = new Command(name, description); + command.AddOption(_sourceAccount); + command.AddOption(_all); + command.AddOption(_failed); + return command; + } + + protected override ResetOptions GetBoundValue(BindingContext bindingContext) + { + return new ResetOptions( + bindingContext.ParseResult.GetValueForOption(_sourceAccount)!, + bindingContext.ParseResult.GetValueForOption(_all), + bindingContext.ParseResult.GetValueForOption(_failed) + ); + } } } diff --git a/ams/AssetMigrationTracker.cs b/ams/AssetMigrationTracker.cs index 37849c3..492a9dc 100644 --- a/ams/AssetMigrationTracker.cs +++ b/ams/AssetMigrationTracker.cs @@ -1,4 +1,5 @@ using AMSMigrate.Contracts; +using Azure; using Azure.Storage.Blobs; using Azure.Storage.Blobs.Models; @@ -64,6 +65,12 @@ internal class AssetMigrationTracker : IMigrationTracker DeleteMigrationStatus(BlobContainerClient container,string MigratedBlobName) + { + return await container.DeleteBlobIfExistsAsync(MigratedBlobName); + } + public async Task GetMigrationStatusAsync(BlobContainerClient container, CancellationToken cancellationToken) { diff --git a/ams/CleanupCommand.cs b/ams/CleanupCommand.cs index 1ec3df4..607a871 100644 --- a/ams/CleanupCommand.cs +++ b/ams/CleanupCommand.cs @@ -3,6 +3,7 @@ using Azure; using Azure.Core; using Azure.ResourceManager.Media; +using Azure.ResourceManager.Media.Models; using Azure.Storage.Blobs; using Microsoft.Extensions.Logging; using Spectre.Console; @@ -46,12 +47,6 @@ public override async Task MigrateAsync(CancellationToken cancellationToken) } Dictionary stats = new Dictionary(); - var totalAssets = await QueryMetricAsync( - account.Id.ToString(), - "AssetCount", - cancellationToken: cancellationToken); - - _logger.LogInformation("The total asset count of the media account is {count}.", totalAssets); AsyncPageable assets; //clean up asset @@ -111,6 +106,7 @@ private async Task CleanUpAccountAsync(MediaServicesAccountResource accoun { foreach (var streamingEndpoint in endpoints) { + await streamingEndpoint.StopAsync(WaitUntil.Completed); await streamingEndpoint.DeleteAsync(WaitUntil.Completed); } } @@ -125,6 +121,10 @@ private async Task CleanUpAccountAsync(MediaServicesAccountResource accoun { foreach (var liveEvent in liveevents) { + if (liveEvent?.Data.ResourceState == LiveEventResourceState.Running) + { + await liveEvent.StopAsync(WaitUntil.Completed, new LiveEventActionContent() { RemoveOutputsOnStop = true }); + } await liveEvent.DeleteAsync(WaitUntil.Completed); } } diff --git a/ams/ResetCommand.cs b/ams/ResetCommand.cs index 7a1fedf..9a0d9b5 100644 --- a/ams/ResetCommand.cs +++ b/ams/ResetCommand.cs @@ -4,14 +4,9 @@ using Azure.Core; using Azure.ResourceManager.Media; using Azure.Storage.Blobs; +using Azure.Storage.Blobs.Models; using Microsoft.Extensions.Logging; using Spectre.Console; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace AMSMigrate.ams { @@ -36,19 +31,13 @@ public ResetCommand(GlobalOptions globalOptions, public override async Task MigrateAsync(CancellationToken cancellationToken) { var account = await GetMediaAccountAsync(_options.AccountName, cancellationToken); - _logger.LogInformation("Begin cleaning up on account: {name}", account.Data.Name); + _logger.LogInformation("Begin reset assets on account: {name}", account.Data.Name); - var storage = await _resourceProvider.GetStorageAccountAsync(account, cancellationToken); - var totalAssets = await QueryMetricAsync( - account.Id.ToString(), - "AssetCount", - cancellationToken: cancellationToken); - - _logger.LogInformation("The total asset count of the media account is {count}.", totalAssets); + var storage = await _resourceProvider.GetStorageAccountAsync(account, cancellationToken); AsyncPageable assets = account.GetMediaAssets() .GetAllAsync(cancellationToken: cancellationToken); List? assetList = await assets.ToListAsync(cancellationToken); - + int resetedAssetCount = 0; foreach (var asset in assetList) { var container = storage.GetContainer(asset); @@ -58,13 +47,39 @@ public override async Task MigrateAsync(CancellationToken cancellationToken) return; } - // The asset container exists, try to check the metadata list first. - if (_options.all || (_tracker.GetMigrationStatusAsync(container, cancellationToken).Result.Status == MigrationStatus.Failed)) { - container.DeleteBlobAsync(cancellationToken); + try + { + BlobContainerProperties properties = await container.GetPropertiesAsync(cancellationToken: cancellationToken); + if (properties.Metadata != null && properties.Metadata.Count == 0) + { + _logger.LogInformation($"Container '{container.Name}' does not have metadata."); + } + else + { // Clear container metadata + properties.Metadata.Clear(); + var deleteOperation = await container.SetMetadataAsync(properties.Metadata); + if (deleteOperation.GetRawResponse().Status == 200) + { + _logger.LogInformation($"Meda data in Container '{container.Name}' is deleted successfully."); + resetedAssetCount++; + } + else + { + _logger.LogInformation($"Meda data in Container '{container.Name}' does not exist or was not deleted."); + } + } + + } + catch (Exception ex) + { + _logger.LogError($"An unexpected error occurred: {ex.Message}"); + } + } } + _logger.LogDebug($"{resetedAssetCount} out of {assetList.Count} assets has been reseted."); } } } diff --git a/contracts/IMigrationTracker.cs b/contracts/IMigrationTracker.cs index e848012..0bbf208 100644 --- a/contracts/IMigrationTracker.cs +++ b/contracts/IMigrationTracker.cs @@ -5,5 +5,7 @@ interface IMigrationTracker where TResult : MigrationResult Task GetMigrationStatusAsync(T resource, CancellationToken cancellationToken); Task UpdateMigrationStatus(T resource, TResult result, CancellationToken cancellationToken); + + Task DeleteMigrationStatus(T resource, string MigratedBlobName); } }