diff --git a/src/ResourceManager/AzureBackup/Commands.AzureBackup/AzureBackupCmdletHelpMessage.cs b/src/ResourceManager/AzureBackup/Commands.AzureBackup/AzureBackupCmdletHelpMessage.cs index eca778111c9f..31fa28afd861 100644 --- a/src/ResourceManager/AzureBackup/Commands.AzureBackup/AzureBackupCmdletHelpMessage.cs +++ b/src/ResourceManager/AzureBackup/Commands.AzureBackup/AzureBackupCmdletHelpMessage.cs @@ -26,6 +26,7 @@ internal static class AzureBackupCmdletHelpMessage public const string ContainerId = "The container ID."; public const string ContainerRegistrationStatus = "The container registration status."; public const string ContainerType = "The container type."; + public const string VirtualMachine = "Virtual Machine."; public const string ContainerResourceGroupName = "The container resource group name."; public const string ProtectionStatus = "Protection Status of the azure backup item."; public const string AzureBackUpItem = "Azure BackUp Item."; diff --git a/src/ResourceManager/AzureBackup/Commands.AzureBackup/Cmdlets/Container/GetAzureBackupContainer.cs b/src/ResourceManager/AzureBackup/Commands.AzureBackup/Cmdlets/Container/GetAzureBackupContainer.cs index 0e3edf307f2d..ebeb8f0748eb 100644 --- a/src/ResourceManager/AzureBackup/Commands.AzureBackup/Cmdlets/Container/GetAzureBackupContainer.cs +++ b/src/ResourceManager/AzureBackup/Commands.AzureBackup/Cmdlets/Container/GetAzureBackupContainer.cs @@ -40,11 +40,11 @@ public class GetAzureBackupContainer : AzureBackupVaultCmdletBase [Parameter(Mandatory = false, HelpMessage = AzureBackupCmdletHelpMessage.ContainerRegistrationStatus)] [ValidateNotNullOrEmpty] - public AzureBackupContainerStatus Status { get; set; } + public AzureBackupContainerStatusInput Status { get; set; } [Parameter(Mandatory = false, HelpMessage = AzureBackupCmdletHelpMessage.ContainerType)] [ValidateNotNullOrEmpty] - public AzureBackupContainerType Type { get; set; } + public AzureBackupContainerTypeInput Type { get; set; } public override void ExecuteCmdlet() { @@ -98,7 +98,7 @@ private string ConstructQueryFilterString() switch (Type) { - case AzureBackupContainerType.AzureVirtualMachine: + case AzureBackupContainerTypeInput.AzureVirtualMachine: containerQueryObject.Type = BCI.ContainerType.IaasVMContainer.ToString(); break; default: @@ -107,15 +107,12 @@ private string ConstructQueryFilterString() switch (Status) { - case AzureBackupContainerStatus.Registered: + case AzureBackupContainerStatusInput.Registered: containerQueryObject.Status = BCI.RegistrationStatus.Registered.ToString(); break; - case AzureBackupContainerStatus.Registering: + case AzureBackupContainerStatusInput.Registering: containerQueryObject.Status = BCI.RegistrationStatus.Registering.ToString(); break; - case AzureBackupContainerStatus.NotRegistered: - containerQueryObject.Status = BCI.RegistrationStatus.NotRegistered.ToString(); - break; default: break; } diff --git a/src/ResourceManager/AzureBackup/Commands.AzureBackup/Cmdlets/Container/RegisterAzureBackupContainer.cs b/src/ResourceManager/AzureBackup/Commands.AzureBackup/Cmdlets/Container/RegisterAzureBackupContainer.cs new file mode 100644 index 000000000000..2b3d175c37dd --- /dev/null +++ b/src/ResourceManager/AzureBackup/Commands.AzureBackup/Cmdlets/Container/RegisterAzureBackupContainer.cs @@ -0,0 +1,202 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.Web; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Linq; +using System.Management.Automation; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Azure.Commands.Compute; +using Microsoft.Azure.Management.BackupServices.Models; +using MBS = Microsoft.Azure.Management.BackupServices; +using Microsoft.Azure.Commands.Compute.Models; + +namespace Microsoft.Azure.Commands.AzureBackup.Cmdlets +{ + /// + /// Get list of containers + /// + [Cmdlet(VerbsLifecycle.Register, "AzureBackupContainer"), OutputType(typeof(Guid))] + public class RegisterAzureBackupContainer : AzureBackupVaultCmdletBase + { + //[Parameter(Position = 2, Mandatory = true, HelpMessage = AzureBackupCmdletHelpMessage.VirtualMachine)] + //[ValidateNotNullOrEmpty] + //public PSVirtualMachineInstanceView VirtualMachine { get; set; } + [Parameter(Position = 2, Mandatory = true, HelpMessage = AzureBackupCmdletHelpMessage.VirtualMachine)] + [ValidateNotNullOrEmpty] + public string VirtualMachineName { get; set; } + + [Parameter(Position = 3, Mandatory = true, HelpMessage = AzureBackupCmdletHelpMessage.VirtualMachine)] + [ValidateNotNullOrEmpty] + public string VirtualMachineRGName { get; set; } + + public override void ExecuteCmdlet() + { + base.ExecuteCmdlet(); + + ExecutionBlock(() => + { + //string vmName = VirtualMachine.Name; + //string rgName = VirtualMachine.ResourceGroupName; + string vmName = VirtualMachineName; + string rgName = VirtualMachineRGName; + Guid jobId = Guid.Empty; + bool isDiscoveryNeed = false; + MBS.OperationResponse operationResponse; + + ContainerInfo container = null; + isDiscoveryNeed = IsDiscoveryNeeded(vmName, rgName, out container); + if(isDiscoveryNeed) + { + RefreshContainer(); + isDiscoveryNeed = IsDiscoveryNeeded(vmName, rgName, out container); + if ((isDiscoveryNeed == true) || (container == null)) + { + //Container is not discovered. Throw exception + throw new NotImplementedException(); + } + } + + //Container is discovered. Register the container + List containerNameList = new List(); + containerNameList.Add(container.Name); + RegisterContainerRequestInput registrationRequest = new RegisterContainerRequestInput(containerNameList, AzureBackupContainerType.IaasVMContainer.ToString()); + operationResponse = AzureBackupClient.Container.RegisterAsync(registrationRequest, GetCustomRequestHeaders(), CmdletCancellationToken).Result; + + //TODO fix the OperationResponse to JobID conversion + jobId = operationResponse.OperationId; + WriteObject(jobId); + }); + } + + private void RefreshContainer() + { + bool isRetyNeeded = true; + int retryCount = 1; + bool isDiscoverySuccessful = false; + while (isRetyNeeded && retryCount <= 3) + { + MBS.OperationResponse opResponse = + AzureBackupClient.Container.RefreshAsync(GetCustomRequestHeaders(), CmdletCancellationToken).Result; + + //Now wait for the operation to Complete + isRetyNeeded = WaitForDiscoveryToCOmplete(opResponse.OperationId.ToString(), out isDiscoverySuccessful); + retryCount++; + } + + if (!isDiscoverySuccessful) + { + //Discovery failed + throw new Exception(); //TODO: + } + } + + private bool WaitForDiscoveryToCOmplete(string operationId, out bool isDiscoverySuccessful) + { + bool isRetryNeeded = false; + + + BMSOperationStatusResponse status = new BMSOperationStatusResponse() + { + OperationStatus = AzureBackupOperationStatus.InProgress.ToString() + }; + + while (status.OperationStatus != AzureBackupOperationStatus.Completed.ToString()) + { + status = AzureBackupClient.OperationStatus.GetAsync(operationId, GetCustomRequestHeaders(), CmdletCancellationToken).Result; + System.Threading.Thread.Sleep(TimeSpan.FromSeconds(15)); + } + + isDiscoverySuccessful = true; + //If operation fails check if retry is needed or not + if (status.OperationResult != AzureBackupOperationResult.Succeeded.ToString()) + { + isDiscoverySuccessful = false; + if ((status.ErrorCode == AzureBackupOperationErrorCode.DiscoveryInProgress.ToString() || + (status.ErrorCode == AzureBackupOperationErrorCode.BMSUserErrorObjectLocked.ToString()))) + { + //Need to retry for this errors + isRetryNeeded = true; + } + } + return isRetryNeeded; + } + + private bool IsDiscoveryNeeded(string vmName, string rgName, out ContainerInfo container) + { + bool isDiscoveryNeed = false; + //First check if container is discoverd or not + ListContainerQueryParameter queryParams = new ListContainerQueryParameter(); + queryParams.ContainerTypeField = AzureBackupContainerType.IaasVMContainer.ToString(); + queryParams.ContainerStatusField = String.Empty; + queryParams.ContainerFriendlyNameField = vmName; + string queryString = GetQueryFileter(queryParams); + + ListContainerResponse containers = AzureBackupClient.Container.ListAsync(queryString, + GetCustomRequestHeaders(), CmdletCancellationToken).Result; + if (containers.Objects.Count() == 0) + { + //Container is not discover + WriteVerbose("Container is not discovered"); + container = null; + isDiscoveryNeed = true; + } + + else + { + //We can have multiple container with same friendly name. + //Look for resourceGroup name in the container unoque name + container = containers.Objects.Where(c => c.ParentContainerFriendlyName.ToLower().Equals(rgName.ToLower())).FirstOrDefault(); + if (container == null) + { + //Container is not in list of registered container + isDiscoveryNeed = true; + } + } + return isDiscoveryNeed; + } + + private string GetQueryFileter(ListContainerQueryParameter queryParams) + { + NameValueCollection collection = new NameValueCollection(); + if (!String.IsNullOrEmpty(queryParams.ContainerTypeField)) + { + collection.Add("ContainerType", queryParams.ContainerTypeField); + } + + if (!String.IsNullOrEmpty(queryParams.ContainerStatusField)) + { + collection.Add("ContainerStatus", queryParams.ContainerStatusField); + } + + if (!String.IsNullOrEmpty(queryParams.ContainerFriendlyNameField)) + { + collection.Add("FriendlyName", queryParams.ContainerFriendlyNameField); + } + + if (collection == null || collection.Count == 0) + { + return String.Empty; + } + + var httpValueCollection = HttpUtility.ParseQueryString(String.Empty); + httpValueCollection.Add(collection); + + return "&" + httpValueCollection.ToString(); + } + } +} diff --git a/src/ResourceManager/AzureBackup/Commands.AzureBackup/Cmdlets/Container/UnregisterAzureBackupContainer.cs b/src/ResourceManager/AzureBackup/Commands.AzureBackup/Cmdlets/Container/UnregisterAzureBackupContainer.cs new file mode 100644 index 000000000000..0d7ec45cbd7b --- /dev/null +++ b/src/ResourceManager/AzureBackup/Commands.AzureBackup/Cmdlets/Container/UnregisterAzureBackupContainer.cs @@ -0,0 +1,84 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.Web; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Linq; +using System.Management.Automation; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Azure.Commands.Compute; +using Microsoft.Azure.Management.BackupServices.Models; +using MBS = Microsoft.Azure.Management.BackupServices; +using Microsoft.Azure.Commands.Compute.Models; + +namespace Microsoft.Azure.Commands.AzureBackup.Cmdlets +{ + /// + /// Get list of containers + /// + [Cmdlet(VerbsLifecycle.Unregister, "AzureBackupContainer"), OutputType(typeof(Guid))] + public class UnregisterAzureBackupContainer : AzureBackupVaultCmdletBase + { + [Parameter(Position = 2, Mandatory = true, HelpMessage = AzureBackupCmdletHelpMessage.VirtualMachine, ValueFromPipelineByPropertyName = true)] + [ValidateNotNullOrEmpty] + public string ContainerUniqueName { get; set; } + + public override void ExecuteCmdlet() + { + base.ExecuteCmdlet(); + + ExecutionBlock(() => + { + UnregisterContainerRequestInput unregRequest = new UnregisterContainerRequestInput(ContainerUniqueName, AzureBackupContainerType.IaasVMContainer.ToString()); + MBS.OperationResponse operationResponse = AzureBackupClient.Container.UnregisterAsync(unregRequest, GetCustomRequestHeaders(), CmdletCancellationToken).Result; + Guid jobId = operationResponse.OperationId; //TODO: Fix it once PiyushKa publish the rest APi to get jobId based on operationId + + WriteObject(jobId); + }); + } + + private string GetQueryFileter(ListContainerQueryParameter queryParams) + { + NameValueCollection collection = new NameValueCollection(); + if (!String.IsNullOrEmpty(queryParams.ContainerTypeField)) + { + collection.Add("ContainerType", queryParams.ContainerTypeField); + } + + if (!String.IsNullOrEmpty(queryParams.ContainerStatusField)) + { + collection.Add("ContainerStatus", queryParams.ContainerStatusField); + } + + if (!String.IsNullOrEmpty(queryParams.ContainerFriendlyNameField)) + { + collection.Add("FriendlyName", queryParams.ContainerFriendlyNameField); + } + + if (collection == null || collection.Count == 0) + { + return String.Empty; + } + + var httpValueCollection = HttpUtility.ParseQueryString(String.Empty); + httpValueCollection.Add(collection); + + return "&" + httpValueCollection.ToString(); + + } + } +} diff --git a/src/ResourceManager/AzureBackup/Commands.AzureBackup/Cmdlets/RegisterContainer/RegisterAzureBackupContainer.cs b/src/ResourceManager/AzureBackup/Commands.AzureBackup/Cmdlets/RegisterContainer/RegisterAzureBackupContainer.cs new file mode 100644 index 000000000000..1f896324275f --- /dev/null +++ b/src/ResourceManager/AzureBackup/Commands.AzureBackup/Cmdlets/RegisterContainer/RegisterAzureBackupContainer.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Management.Automation; + +namespace Microsoft.Azure.Commands.AzureBackup.Cmdlets.RegisterContainer +{ + [Cmdlet(VerbsCommon.Get, ProfileNouns.VirtualMachine, DefaultParameterSetName = ListAllVirtualMachinesParamSet)] + class RegisterAzureBackupContainer + { + } +} diff --git a/src/ResourceManager/AzureBackup/Commands.AzureBackup/Commands.AzureBackup.csproj b/src/ResourceManager/AzureBackup/Commands.AzureBackup/Commands.AzureBackup.csproj index 9368865fe23e..27938f9f65a5 100644 --- a/src/ResourceManager/AzureBackup/Commands.AzureBackup/Commands.AzureBackup.csproj +++ b/src/ResourceManager/AzureBackup/Commands.AzureBackup/Commands.AzureBackup.csproj @@ -117,6 +117,7 @@ + @@ -132,6 +133,8 @@ + + @@ -141,10 +144,10 @@ - - + + True @@ -158,6 +161,10 @@ {5ee72c53-1720-4309-b54b-5fb79703195f} Commands.Common + + {52643bd5-6378-49bd-9f6e-dac9dd8a867b} + Commands.Compute + @@ -194,6 +201,10 @@ + + + +