diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/ArmClient.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/ArmClient.cs index 6f8568f20475a..d695e8c05035f 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/ArmClient.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/ArmClient.cs @@ -86,13 +86,14 @@ private ArmClient( TokenCredential credential, ArmClientOptions options) { - Pipeline = ManagementPipelineBuilder.Build(credential, baseUri, options); - Credential = credential; - BaseUri = baseUri; if (credential is null) throw new ArgumentNullException(nameof(credential)); + Credential = credential; + BaseUri = baseUri; ClientOptions = options?.Clone() ?? new ArmClientOptions(); + Pipeline = ManagementPipelineBuilder.Build(Credential, BaseUri, ClientOptions); + DefaultSubscription = string.IsNullOrWhiteSpace(defaultSubscriptionId) ? GetDefaultSubscription() : GetSubscriptions().TryGet(defaultSubscriptionId); diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/SingletonOperationsBase.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/SingletonOperationsBase.cs new file mode 100644 index 0000000000000..5a422406ebd3e --- /dev/null +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/SingletonOperationsBase.cs @@ -0,0 +1,84 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; + +namespace Azure.ResourceManager.Core +{ + /// + /// A class representing the operations that can be performed over a specific resource. + /// + public abstract class SingletonOperationsBase : OperationsBase + { + /// + /// Initializes a new instance of the class for mocking. + /// + protected SingletonOperationsBase() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + internal SingletonOperationsBase(OperationsBase parent) + : base(new ClientContext(parent.ClientOptions, parent.Credential, parent.BaseUri, parent.Pipeline), ResourceIdentifier.RootResourceIdentifier) + { + Parent = parent; + ParentId = parent.Id; + } + + /// + /// Gets the parent resource of this resource. + /// + protected OperationsBase Parent { get; } + + /// + /// The typed resource identifier for the underlying resource + /// + public ResourceIdentifier ParentId + { + get; + } + } + + /// + /// Base class representing a singleton operation + /// + /// The type of the class containing operations for the underlying resource. + /// The type of the resource identifier. + [System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "")] + public abstract class SingletonOperationsBase : SingletonOperationsBase + where TOperations : SingletonOperationsBase + where TIdentifier : ResourceIdentifier + { + /// + /// Initializes a new instance of the class for mocking. + /// + protected SingletonOperationsBase() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The resource representing the parent resource. + protected SingletonOperationsBase(OperationsBase parent) + : base(parent) + { + ParentId = parent.Id as TIdentifier; + if (string.IsNullOrWhiteSpace(ParentId)) + { + throw new InvalidOperationException(); + } + } + + /// + /// The typed resource identifier for the underlying resource + /// + protected new TIdentifier ParentId + { + get; + } + } +} diff --git a/sdk/resourcemanager/Proto.Client/compute/Convenience/VirtualMachineScaleSetBuilder.cs b/sdk/resourcemanager/Proto.Client/compute/Convenience/VirtualMachineScaleSetBuilder.cs new file mode 100644 index 0000000000000..64e2342dd4bd3 --- /dev/null +++ b/sdk/resourcemanager/Proto.Client/compute/Convenience/VirtualMachineScaleSetBuilder.cs @@ -0,0 +1,81 @@ +using Azure.ResourceManager.Core; +using System; +using System.Collections.Generic; +using System.Linq; +using Azure.ResourceManager.Compute.Models; + +namespace Proto.Compute +{ + /// + /// A class representing a builder object to help create a virtual machine. + /// + public partial class VirtualMachineScaleSetBuilder + { + public VirtualMachineScaleSetBuilder WithUseWindowsImage(string computerNamePrefix, string adminUser, string password) + { + _model.VirtualMachineProfile.OsProfile = new VirtualMachineScaleSetOSProfile() + { + ComputerNamePrefix = computerNamePrefix, + AdminUsername = adminUser, + AdminPassword = password, + WindowsConfiguration = new WindowsConfiguration { TimeZone = "Pacific Standard Time", ProvisionVMAgent = true } + }; + + return this; + } + + public VirtualMachineScaleSetBuilder WithUseLinuxImage(string computerNamePrefix, string adminUser, string password) + { + _model.VirtualMachineProfile.OsProfile = new VirtualMachineScaleSetOSProfile() + { + ComputerNamePrefix = computerNamePrefix, + AdminUsername = adminUser, + AdminPassword = password, + LinuxConfiguration = new LinuxConfiguration + { + DisablePasswordAuthentication = false, + ProvisionVMAgent = true + } + }; + + return this; + } + + public VirtualMachineScaleSetBuilder WithRequiredPrimaryNetworkInterface( + string name, + ResourceIdentifier subNetResourceId, + ICollection backendAddressPoolResourceIds, + ICollection inboundNatPoolResourceIds) + { + var ipconfig = new VirtualMachineScaleSetIPConfiguration($"{name}PrimaryIPConfig") + { + Subnet = new ApiEntityReference() { Id = subNetResourceId }, + }; + foreach (var id in backendAddressPoolResourceIds) + { + ipconfig.LoadBalancerBackendAddressPools.Add( + new Azure.ResourceManager.Compute.Models.SubResource { Id = id }); + } + foreach (var id in inboundNatPoolResourceIds) + { + ipconfig.LoadBalancerInboundNatPools.Add( + new Azure.ResourceManager.Compute.Models.SubResource { Id = id }); + } + + var nicConfig = new VirtualMachineScaleSetNetworkConfiguration(name) + { + Primary = true, + }; + nicConfig.IpConfigurations.Add(ipconfig); + + _model.VirtualMachineProfile.NetworkProfile.NetworkInterfaceConfigurations.Add(nicConfig); + + return this; + } + + public VirtualMachineScaleSetBuilder WithRequiredLoadBalancer(ResourceIdentifier asetResourceId) + { + return this; + } + } +} diff --git a/sdk/resourcemanager/Proto.Client/compute/Extensions/ResourceGroupExtensions.cs b/sdk/resourcemanager/Proto.Client/compute/Extensions/ResourceGroupExtensions.cs index c91d8000f2e71..dd3190efe995b 100644 --- a/sdk/resourcemanager/Proto.Client/compute/Extensions/ResourceGroupExtensions.cs +++ b/sdk/resourcemanager/Proto.Client/compute/Extensions/ResourceGroupExtensions.cs @@ -18,6 +18,16 @@ public static VirtualMachineContainer GetVirtualMachines(this ResourceGroupOpera return new VirtualMachineContainer(resourceGroup); } + /// + /// Gets an object representing a VirtualMachineScaleSetContainer along with the instance operations that can be performed on it. + /// + /// The instance the method will execute against. + /// Returns a object. + public static VirtualMachineScaleSetContainer GetVirtualMachineScaleSet(this ResourceGroupOperations resourceGroup) + { + return new VirtualMachineScaleSetContainer(resourceGroup); + } + /// /// Gets an object representing a AvailabilitySetContainer along with the instance operations that can be performed on it. /// diff --git a/sdk/resourcemanager/Proto.Client/compute/Placeholder/RollingUpgradeStatusInfo.cs b/sdk/resourcemanager/Proto.Client/compute/Placeholder/RollingUpgradeStatusInfo.cs new file mode 100644 index 0000000000000..dcbe732f5af65 --- /dev/null +++ b/sdk/resourcemanager/Proto.Client/compute/Placeholder/RollingUpgradeStatusInfo.cs @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using Azure.ResourceManager.Compute.Models; +using Azure.ResourceManager.Core; + +namespace Proto.Compute +{ + /// The status of the latest virtual machine scale set rolling upgrade. + public partial class RollingUpgradeStatusInfo : Resource + { + /// + /// Initializes a new instance of the class. + /// + public RollingUpgradeStatusInfo(Azure.ResourceManager.Compute.Models.RollingUpgradeStatusInfo rollingUpgradeStatusInfo) + : base(rollingUpgradeStatusInfo.Id, rollingUpgradeStatusInfo.Name, RollingUpgradeOperations.ResourceType) + { + Model = rollingUpgradeStatusInfo; + } + + /// + /// Gets or sets the Model this resource is based of. + /// + public virtual Azure.ResourceManager.Compute.Models.RollingUpgradeStatusInfo Model { get; } + + /// + /// Gets the subnet id. + /// + public override string Name => Model.Name; + + /// The rolling upgrade policies applied for this upgrade. + public RollingUpgradePolicy Policy => Model.Policy; + + /// Information about the current running state of the overall upgrade. + public RollingUpgradeRunningStatus RunningStatus => Model.RunningStatus; + + /// Information about the number of virtual machine instances in each upgrade state. + public RollingUpgradeProgressInfo Progress => Model.Progress; + + /// Error details for this upgrade, if there are any. + public ApiError Error => Model.Error; + } +} diff --git a/sdk/resourcemanager/Proto.Client/compute/Placeholder/VirtualMachineScaleSetData.cs b/sdk/resourcemanager/Proto.Client/compute/Placeholder/VirtualMachineScaleSetData.cs new file mode 100644 index 0000000000000..9112bb437bade --- /dev/null +++ b/sdk/resourcemanager/Proto.Client/compute/Placeholder/VirtualMachineScaleSetData.cs @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using Azure.ResourceManager.Compute.Models; +using Azure.ResourceManager.Core; +using Azure.ResourceManager.Core.Adapters; +using System.Collections.Generic; + +namespace Proto.Compute +{ + /// A class representing the VirtualMachineScaleSet data model. + public partial class VirtualMachineScaleSetData : TrackedResource + { + /// Initializes a new instance of VirtualMachineScaleSetData. + public VirtualMachineScaleSetData(Azure.ResourceManager.Compute.Models.VirtualMachineScaleSet vmScaleSet) + : base(vmScaleSet.Id, vmScaleSet.Location, vmScaleSet) + { + Sku = vmScaleSet.Sku; + Plan = vmScaleSet.Plan; + Identity = vmScaleSet.Identity; + Zones = vmScaleSet.Zones; + UpgradePolicy = vmScaleSet.UpgradePolicy; + AutomaticRepairsPolicy = vmScaleSet.AutomaticRepairsPolicy; + VirtualMachineProfile = vmScaleSet.VirtualMachineProfile; + ProvisioningState = vmScaleSet.ProvisioningState; + Overprovision = vmScaleSet.Overprovision; + DoNotRunExtensionsOnOverprovisionedVMs = vmScaleSet.DoNotRunExtensionsOnOverprovisionedVMs; + UniqueId = vmScaleSet.UniqueId; + SinglePlacementGroup = vmScaleSet.SinglePlacementGroup; + ZoneBalance = vmScaleSet.ZoneBalance; + PlatformFaultDomainCount = vmScaleSet.PlatformFaultDomainCount; + ProximityPlacementGroup = vmScaleSet.ProximityPlacementGroup; + AdditionalCapabilities = vmScaleSet.AdditionalCapabilities; + ScaleInPolicy = vmScaleSet.ScaleInPolicy; + } + + /// The virtual machine scale set sku. + public Azure.ResourceManager.Compute.Models.Sku Sku { get; set; } + /// Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use. In the Azure portal, find the marketplace image that you want to use and then click **Want to deploy programmatically, Get Started ->**. Enter any required information and then click **Save**. + public Azure.ResourceManager.Compute.Models.Plan Plan { get; set; } + /// The identity of the virtual machine scale set, if configured. + public VirtualMachineScaleSetIdentity Identity { get; set; } + /// The virtual machine scale set zones. NOTE: Availability zones can only be set when you create the scale set. + public IList Zones { get; } + /// The upgrade policy. + public UpgradePolicy UpgradePolicy { get; set; } + /// Policy for automatic repairs. + public AutomaticRepairsPolicy AutomaticRepairsPolicy { get; set; } + /// The virtual machine profile. + public VirtualMachineScaleSetVMProfile VirtualMachineProfile { get; set; } + /// The provisioning state, which only appears in the response. + public string ProvisioningState { get; } + /// Specifies whether the Virtual Machine Scale Set should be overprovisioned. + public bool? Overprovision { get; set; } + /// When Overprovision is enabled, extensions are launched only on the requested number of VMs which are finally kept. This property will hence ensure that the extensions do not run on the extra overprovisioned VMs. + public bool? DoNotRunExtensionsOnOverprovisionedVMs { get; set; } + /// Specifies the ID which uniquely identifies a Virtual Machine Scale Set. + public string UniqueId { get; } + /// When true this limits the scale set to a single placement group, of max size 100 virtual machines. NOTE: If singlePlacementGroup is true, it may be modified to false. However, if singlePlacementGroup is false, it may not be modified to true. + public bool? SinglePlacementGroup { get; set; } + /// Whether to force strictly even Virtual Machine distribution cross x-zones in case there is zone outage. + public bool? ZoneBalance { get; set; } + /// Fault Domain count for each placement group. + public int? PlatformFaultDomainCount { get; set; } + /// Specifies information about the proximity placement group that the virtual machine scale set should be assigned to. <br><br>Minimum api-version: 2018-04-01. + public Azure.ResourceManager.Compute.Models.SubResource ProximityPlacementGroup { get; set; } + /// Specifies information about the dedicated host group that the virtual machine scale set resides in. <br><br>Minimum api-version: 2020-06-01. + public Azure.ResourceManager.Compute.Models.SubResource HostGroup { get; set; } + /// Specifies additional capabilities enabled or disabled on the Virtual Machines in the Virtual Machine Scale Set. For instance: whether the Virtual Machines have the capability to support attaching managed data disks with UltraSSD_LRS storage account type. + public AdditionalCapabilities AdditionalCapabilities { get; set; } + /// Specifies the scale-in policy that decides which virtual machines are chosen for removal when a Virtual Machine Scale Set is scaled-in. + public ScaleInPolicy ScaleInPolicy { get; set; } + } +} diff --git a/sdk/resourcemanager/Proto.Client/compute/RollingUpgrade.cs b/sdk/resourcemanager/Proto.Client/compute/RollingUpgrade.cs new file mode 100644 index 0000000000000..de0f42b4e991c --- /dev/null +++ b/sdk/resourcemanager/Proto.Client/compute/RollingUpgrade.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +using System.Threading; +using System.Threading.Tasks; +using Azure.ResourceManager.Core; + +#nullable disable + +namespace Proto.Compute +{ + /// A Class representing a VirtualMachineScaleSetRollingUpgrade along with the instance operations that can be performed on it. + public class RollingUpgrade : RollingUpgradeOperations + { + /// + /// Gets the data representing this VirtualMachine. + /// + public RollingUpgradeStatusInfo Data { get; private set; } + + /// + /// Initializes a new instance of the class. + /// + /// The client parameters to use in these operations. + /// The resource that is the target of operations. + internal RollingUpgrade(OperationsBase operations, RollingUpgradeStatusInfo resource) + : base(operations) + { + Data = resource; + } + } +} diff --git a/sdk/resourcemanager/Proto.Client/compute/RollingUpgradeOperations.cs b/sdk/resourcemanager/Proto.Client/compute/RollingUpgradeOperations.cs new file mode 100644 index 0000000000000..8d6dbc2c239dd --- /dev/null +++ b/sdk/resourcemanager/Proto.Client/compute/RollingUpgradeOperations.cs @@ -0,0 +1,77 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Threading; +using System.Threading.Tasks; +using Azure; +using Azure.ResourceManager.Compute; +using Azure.ResourceManager.Core; + +namespace Proto.Compute +{ + /// A class representing the operations that can be performed over a specific VirtualMachineScaleSetRollingUpgrade. + public partial class RollingUpgradeOperations : SingletonOperationsBase + { + /// Initializes a new instance of VirtualMachineScaleSetRollingUpgradeOperations for mocking. + protected RollingUpgradeOperations() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The client parameters to use in these operations. + /// The identifier of the resource that is the target of operations. + protected internal RollingUpgradeOperations(OperationsBase operation) + : base(operation) + { + } + + public static readonly ResourceType ResourceType = "Microsoft.Compute/virtualMachineScaleSets"; + + protected override ResourceType ValidResourceType => ResourceType.RootResourceType; + + private VirtualMachineScaleSetRollingUpgradesOperations Operations => new ComputeManagementClient( + BaseUri, + ParentId.SubscriptionId, + Credential, + ClientOptions.Convert()).VirtualMachineScaleSetRollingUpgrades; + + // Note: Singleton may have different operations such as GET/PUT/PATCH/POST or a combination of these + // Individual methods will be generated as they are declared + public ArmResponse Get(CancellationToken cancellationToken = default) + { + return new PhArmResponse( + Operations.GetLatest(ParentId.ResourceGroupName, ParentId.Name, cancellationToken), + v => new RollingUpgrade(Parent, new RollingUpgradeStatusInfo(v))); + } + + public async Task> GetAsync(CancellationToken cancellationToken = default) + { + return new PhArmResponse( + await Operations.GetLatestAsync(ParentId.ResourceGroupName, ParentId.Name, cancellationToken), + v => new RollingUpgrade(Parent, new RollingUpgradeStatusInfo(v))); + } + + // Note: Singleton may have different operations such as GET/PUT/PATCH/POST or a combination of these + // Individual methods will be generated as they are declared + public ArmResponse Cancel(CancellationToken cancellationToken = default) + { + return new ArmResponse(Operations + .StartCancel(ParentId.ResourceGroupName, ParentId.Name, cancellationToken) + .WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); + } + + public async Task> CancelAsync(CancellationToken cancellationToken = default) + { + return new ArmResponse((await Operations + .StartCancel(ParentId.ResourceGroupName, ParentId.Name, cancellationToken) + .WaitForCompletionAsync(cancellationToken))); + } + } +} diff --git a/sdk/resourcemanager/Proto.Client/compute/VirtualMachineScaleSet.cs b/sdk/resourcemanager/Proto.Client/compute/VirtualMachineScaleSet.cs new file mode 100644 index 0000000000000..1b1773b3959b5 --- /dev/null +++ b/sdk/resourcemanager/Proto.Client/compute/VirtualMachineScaleSet.cs @@ -0,0 +1,40 @@ +using System.Threading; +using System.Threading.Tasks; +using Azure.ResourceManager.Core; + +namespace Proto.Compute +{ + /// + /// Class representing a VirtualMachineScaleSet along with the instance operations that can be performed on it. + /// + public class VirtualMachineScaleSet : VirtualMachineScaleSetOperations + { + /// + /// Gets the data representing this VirtualMachineScaleSet. + /// + public VirtualMachineScaleSetData Data { get; private set; } + + /// + /// Initializes a new instance of the class. + /// + /// The client parameters to use in these operations. + /// The resource that is the target of operations. + internal VirtualMachineScaleSet(ResourceOperationsBase operations, VirtualMachineScaleSetData resource) + : base(operations, resource.Id) + { + Data = resource; + } + + /// + protected override VirtualMachineScaleSet GetResource(CancellationToken cancellation = default) + { + return this; + } + + /// + protected override Task GetResourceAsync(CancellationToken cancellationToken = default) + { + return Task.FromResult(this); + } + } +} diff --git a/sdk/resourcemanager/Proto.Client/compute/VirtualMachineScaleSetBuilder.cs b/sdk/resourcemanager/Proto.Client/compute/VirtualMachineScaleSetBuilder.cs new file mode 100644 index 0000000000000..e81b855046f2b --- /dev/null +++ b/sdk/resourcemanager/Proto.Client/compute/VirtualMachineScaleSetBuilder.cs @@ -0,0 +1,179 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.ResourceManager.Core; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Proto.Compute +{ + /// + /// A class representing a builder object used to create Azure resources. + /// + public partial class VirtualMachineScaleSetBuilder + { + private VirtualMachineScaleSetData _model; + + /// + /// Initializes a new instance of the class. + /// + /// The container object to create the resource in. + /// The resource to create. + public VirtualMachineScaleSetBuilder(VirtualMachineScaleSetContainer container, VirtualMachineScaleSetData resource) + { + Resource = resource; + VirtualMachineScaleSetContainer = container; + _model = resource; + } + + /// + /// Gets the resource object to create. + /// + protected VirtualMachineScaleSetData Resource { get; private set; } + + /// + /// Gets the resource name. + /// + protected string ResourceName { get; private set; } + + /// + /// Gets the container object to create the resource in. + /// + protected VirtualMachineScaleSetContainer VirtualMachineScaleSetContainer { get; private set; } + + /// + /// Creates the resource object to send to the Azure API. + /// + /// The resource to create. + public VirtualMachineScaleSetData Build() + { + ThrowIfNotValid(); + OnBeforeBuild(); + InternalBuild(); + OnAfterBuild(); + + return Resource; + } + + /// + /// The operation to create or update a resource. Please note some properties can be set only during creation. + /// + /// The name of the new resource to create. + /// A token to allow the caller to cancel the call to the service. The default value is . + /// A response with the operation for this resource. + /// Name cannot be null or a whitespace. + public ArmResponse CreateOrUpdate(string name, CancellationToken cancellationToken = default) + { + if (string.IsNullOrWhiteSpace(name)) + throw new ArgumentException("Name cannot be null or whitespace.", nameof(name)); + + ResourceName = name; + Resource = Build(); + + return VirtualMachineScaleSetContainer.CreateOrUpdate(name, Resource, cancellationToken); + } + + /// + /// The operation to create or update a resource. Please note some properties can be set only during creation. + /// + /// The name of the new resource to create. + /// A token to allow the caller to cancel the call to the service. The default value is . + /// A that on completion returns a response with the operation for this resource. + /// Name cannot be null or a whitespace. + public async Task> CreateOrUpdateAsync( + string name, + CancellationToken cancellationToken = default) + { + if (string.IsNullOrWhiteSpace(name)) + throw new ArgumentException("Name cannot be null or whitespace.", nameof(name)); + + ResourceName = name; + Resource = Build(); + + return await VirtualMachineScaleSetContainer.CreateOrUpdateAsync(name, Resource, cancellationToken).ConfigureAwait(false); + } + + /// + /// The operation to create or update a resource. Please note some properties can be set only during creation. + /// + /// The name of the new resource to create. + /// A token to allow the caller to cancel the call to the service. The default value is . + /// An that allows polling for completion of the operation. + /// + /// Details on long running operation object. + /// + /// Name cannot be null or a whitespace. + public ArmOperation StartCreateOrUpdate(string name, CancellationToken cancellationToken = default) + { + if (string.IsNullOrWhiteSpace(name)) + throw new ArgumentException("Name cannot be null or whitespace.", nameof(name)); + + ResourceName = name; + Resource = Build(); + + return VirtualMachineScaleSetContainer.StartCreateOrUpdate(name, Resource, cancellationToken); + } + + /// + /// The operation to create or update a resource. Please note some properties can be set only during creation. + /// + /// The name of the new resource to create. + /// A token to allow the caller to cancel the call to the service. The default value is . + /// A that on completion returns an that allows polling for completion of the operation. + /// + /// Details on long running operation object. + /// + /// Name cannot be null or a whitespace. + public async Task> StartCreateOrUpdateAsync( + string name, + CancellationToken cancellationToken = default) + { + if (string.IsNullOrWhiteSpace(name)) + throw new ArgumentException("Name cannot be null or whitespace.", nameof(name)); + + ResourceName = name; + Resource = Build(); + + return await VirtualMachineScaleSetContainer.StartCreateOrUpdateAsync(name, Resource, cancellationToken).ConfigureAwait(false); + } + + /// + /// Determines whether or not the resource is valid. + /// + /// The message indicating what is wrong with the resource. + /// Whether or not the resource is valid. + protected virtual bool IsValid(out string message) + { + message = string.Empty; + + return true; + } + + /// + /// Perform any tasks necessary after the resource is built + /// + protected virtual void OnAfterBuild() + { + } + + /// + /// Perform any tasks necessary before the resource is built + /// + protected virtual void OnBeforeBuild() + { + } + + private static void InternalBuild() + { + } + + private void ThrowIfNotValid() + { + if (!IsValid(out var message)) + { + throw new InvalidOperationException(message); + } + } + } +} diff --git a/sdk/resourcemanager/Proto.Client/compute/VirtualMachineScaleSetContainer.cs b/sdk/resourcemanager/Proto.Client/compute/VirtualMachineScaleSetContainer.cs new file mode 100644 index 0000000000000..b444c7a48ec26 --- /dev/null +++ b/sdk/resourcemanager/Proto.Client/compute/VirtualMachineScaleSetContainer.cs @@ -0,0 +1,255 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Azure; +using Azure.ResourceManager.Compute; +using Azure.ResourceManager.Compute.Models; +using Azure.ResourceManager.Core; +using Azure.ResourceManager.Core.Resources; +using Proto.Compute.Convenience; + +namespace Proto.Compute +{ + /// + /// A class representing collection of VirtualMachineScaleSet and their operations over a ResourceGroup. + /// + public class VirtualMachineScaleSetContainer : ResourceContainerBase + { + /// + /// Initializes a new instance of the class. + /// + /// The ResourceGroup that is the parent of the VirtualMachineScaleSets. + internal VirtualMachineScaleSetContainer(ResourceGroupOperations resourceGroup) + : base(resourceGroup) + { + } + + /// + /// Typed Resource Identifier for the container. + /// + public new ResourceGroupResourceIdentifier Id => base.Id as ResourceGroupResourceIdentifier; + + private VirtualMachineScaleSetsOperations Operations => new ComputeManagementClient( + BaseUri, + Id.SubscriptionId, + Credential, + ClientOptions.Convert()).VirtualMachineScaleSets; + + /// + /// Gets the valid resource type for this object + /// + protected override ResourceType ValidResourceType => ResourceGroupOperations.ResourceType; + + /// + /// The operation to create a virtual machine. + /// + /// The name of the virtual machine. + /// Parameters supplied to the Create Virtual Machine operation. + /// A token to allow the caller to cancel the call to the service. The default value is . + /// A response with the operation for this resource. + public ArmResponse CreateOrUpdate(string name, VirtualMachineScaleSetData resourceDetails, CancellationToken cancellationToken = default) + { + var operation = Operations.StartCreateOrUpdate(Id.ResourceGroupName, name, resourceDetails.Model, cancellationToken); + return new PhArmResponse( + operation.WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult(), + v => new VirtualMachineScaleSet(Parent, new VirtualMachineScaleSetData(v))); + } + + /// + /// The operation to create a virtual machine. + /// + /// The name of the virtual machine. + /// Parameters supplied to the Create Virtual Machine operation. + /// A token to allow the caller to cancel the call to the service. The default value is . + /// A that on completion returns a response with the operation for this resource. + public async Task> CreateOrUpdateAsync(string name, VirtualMachineScaleSetData resourceDetails, CancellationToken cancellationToken = default) + { + var operation = await Operations.StartCreateOrUpdateAsync(Id.ResourceGroupName, name, resourceDetails.Model, cancellationToken).ConfigureAwait(false); + return new PhArmResponse( + await operation.WaitForCompletionAsync(cancellationToken).ConfigureAwait(false), + v => new VirtualMachineScaleSet(Parent, new VirtualMachineScaleSetData(v))); + } + + /// + public override ArmResponse Get(string virtualMachineScaleSetName, CancellationToken cancellationToken = default) + { + return new PhArmResponse(Operations.Get(Id.ResourceGroupName, virtualMachineScaleSetName, cancellationToken), + v => new VirtualMachineScaleSet(Parent, new VirtualMachineScaleSetData(v))); + } + + /// + public override async Task> GetAsync(string virtualMachineScaleSetName, CancellationToken cancellationToken = default) + { + return new PhArmResponse(await Operations.GetAsync(Id.ResourceGroupName, virtualMachineScaleSetName, cancellationToken), + v => new VirtualMachineScaleSet(Parent, new VirtualMachineScaleSetData(v))); + } + + /// + /// List the virtual machines for this resource group. + /// + /// A token to allow the caller to cancel the call to the service. The default value is . + /// A collection of that may take multiple service requests to iterate over. + public Pageable List(CancellationToken cancellationToken = default) + { + var result = Operations.List(Id.Name, cancellationToken); + return new PhWrappingPageable( + result, + s => new VirtualMachineScaleSet(Parent, new VirtualMachineScaleSetData(s))); + } + + /// + /// Filters the list of virtual machines for this resource group represented as generic resources. + /// Makes an additional network call to retrieve the full data model for each virtual machine. + /// + /// The substring to filter by. + /// The number of items to truncate by. + /// A token to allow the caller to cancel the call to the service. The default value is . + /// A collection of that may take multiple service requests to iterate over. + public Pageable List(string nameFilter, int? top = null, CancellationToken cancellationToken = default) + { + var results = ListAsGenericResource(nameFilter, top, cancellationToken); + return new PhWrappingPageable(results, s => (new VirtualMachineScaleSetOperations(s)).Get().Value); + } + + /// + /// Filters the list of virtual machines for this resource group represented as generic resources. + /// + /// The substring to filter by. + /// The number of items to truncate by. + /// A token to allow the caller to cancel the call to the service. The default value is . + /// A collection of that may take multiple service requests to iterate over. + public Pageable ListAsGenericResource(string nameFilter, int? top = null, CancellationToken cancellationToken = default) + { + ResourceFilterCollection filters = new ResourceFilterCollection(VirtualMachineScaleSetOperations.ResourceType); + filters.SubstringFilter = nameFilter; + return ResourceListOperations.ListAtContext(Parent as ResourceGroupOperations, filters, top, cancellationToken); + } + + /// + /// Filters the list of virtual machines for this resource group represented as generic resources. + /// + /// The substring to filter by. + /// The number of items to truncate by. + /// A token to allow the caller to cancel the call to the service. The default value is . + /// An async collection of that may take multiple service requests to iterate over. + public AsyncPageable ListAsGenericResourceAsync(string nameFilter, int? top = null, CancellationToken cancellationToken = default) + { + ResourceFilterCollection filters = new ResourceFilterCollection(VirtualMachineScaleSetOperations.ResourceType); + filters.SubstringFilter = nameFilter; + return ResourceListOperations.ListAtContextAsync(Parent as ResourceGroupOperations, filters, top, cancellationToken); + } + + /// + /// List the virtual machines for this resource group. + /// + /// A token to allow the caller to cancel the call to the service. The default value is . + /// An async collection of that may take multiple service requests to iterate over. + public AsyncPageable ListAsync(CancellationToken cancellationToken = default) + { + var result = Operations.ListAsync(Id.Name, cancellationToken); + return new PhWrappingAsyncPageable( + result, + s => new VirtualMachineScaleSet(Parent, new VirtualMachineScaleSetData(s))); + } + + /// + /// Filters the list of virtual machines for this resource group represented as generic resources. + /// Makes an additional network call to retrieve the full data model for each virtual machine. + /// + /// The substring to filter by. + /// The number of items to truncate by. + /// A token to allow the caller to cancel the call to the service. The default value is . + /// An async collection of that may take multiple service requests to iterate over. + public AsyncPageable ListAsync(string nameFilter, int? top = null, CancellationToken cancellationToken = default) + { + var results = ListAsGenericResourceAsync(nameFilter, top, cancellationToken); + return new PhWrappingAsyncPageable(results, s => (new VirtualMachineScaleSetOperations(s)).Get().Value); + } + + /// + /// The operation to create a virtual machine. + /// + /// The name of the virtual machine. + /// Parameters supplied to the Create Virtual Machine operation. + /// A token to allow the caller to cancel the call to the service. The default value is . + /// + /// Details on long running operation object. + /// + /// An that allows polling for completion of the operation. + public ArmOperation StartCreateOrUpdate(string name, VirtualMachineScaleSetData resourceDetails, CancellationToken cancellationToken = default) + { + return new PhArmOperation( + Operations.StartCreateOrUpdate(Id.ResourceGroupName, name, resourceDetails.Model, cancellationToken), + v => new VirtualMachineScaleSet(Parent, new VirtualMachineScaleSetData(v))); + } + + /// + /// The operation to create a virtual machine. + /// + /// The name of the virtual machine. + /// Parameters supplied to the Create Virtual Machine operation. + /// A token to allow the caller to cancel the call to the service. The default value is . + /// + /// Details on long running operation object. + /// + /// A that on completion returns an that allows polling for completion of the operation. + public async Task> StartCreateOrUpdateAsync(string name, VirtualMachineScaleSetData resourceDetails, CancellationToken cancellationToken = default) + { + return new PhArmOperation( + await Operations.StartCreateOrUpdateAsync(Id.ResourceGroupName, name, resourceDetails.Model, cancellationToken).ConfigureAwait(false), + v => new VirtualMachineScaleSet(Parent, new VirtualMachineScaleSetData(v))); + } + + /// + /// Construct an object used to create a VirtualMachine. + /// + /// The hostname for the virtual machine. + /// The location to create the Virtual Machine. + /// Object used to create a . + public VirtualMachineScaleSetBuilder Construct(string hostName, LocationData location = null) + { + var parent = GetParentResource(); + var vmss = new Azure.ResourceManager.Compute.Models.VirtualMachineScaleSet(location ?? parent.Data.Location) + { + // TODO SKU should not be hardcoded + Sku = new Azure.ResourceManager.Compute.Models.Sku() { Name = "Standard_DS1_v2", Capacity = 2 }, + Overprovision = false, + VirtualMachineProfile = new Azure.ResourceManager.Compute.Models.VirtualMachineScaleSetVMProfile() + { + NetworkProfile = new VirtualMachineScaleSetNetworkProfile(), + StorageProfile = new VirtualMachineScaleSetStorageProfile() + { + OsDisk = new VirtualMachineScaleSetOSDisk(DiskCreateOptionTypes.FromImage), + ImageReference = new ImageReference() + { + Offer = "WindowsServer", + Publisher = "MicrosoftWindowsServer", + Sku = "2019-Datacenter", + Version = "latest" + }, + } + }, + UpgradePolicy = new UpgradePolicy() { Mode = UpgradeMode.Automatic }, + }; + + var nicConfig = new VirtualMachineScaleSetNetworkConfiguration("scaleSetNic") + { + Primary = true, + }; + var ipconfig = new VirtualMachineScaleSetIPConfiguration("scaleSetIPConfig") + { + Subnet = new ApiEntityReference() { Id = "" }, + }; + ipconfig.LoadBalancerBackendAddressPools.Add(null); + ipconfig.LoadBalancerInboundNatPools.Add(null); + nicConfig.IpConfigurations.Add(ipconfig); + + vmss.VirtualMachineProfile.NetworkProfile.NetworkInterfaceConfigurations.Add(nicConfig); + + return new VirtualMachineScaleSetBuilder(this, new VirtualMachineScaleSetData(vmss)); + } + } +} diff --git a/sdk/resourcemanager/Proto.Client/compute/VirtualMachineScaleSetOperations.cs b/sdk/resourcemanager/Proto.Client/compute/VirtualMachineScaleSetOperations.cs new file mode 100644 index 0000000000000..d7425a1130c03 --- /dev/null +++ b/sdk/resourcemanager/Proto.Client/compute/VirtualMachineScaleSetOperations.cs @@ -0,0 +1,314 @@ +using Azure; +using Azure.ResourceManager.Compute; +using Azure.ResourceManager.Compute.Models; +using Azure.ResourceManager.Core; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Proto.Compute +{ + /// + /// A class representing the operations that can be performed over a specific VirtualMachineScaleSet. + /// + public class VirtualMachineScaleSetOperations : ResourceOperationsBase, ITaggableResource, IDeletableResource + { + /// + /// Initializes a new instance of the class. + /// + /// An instance of that has an id for a virtual machine. + internal VirtualMachineScaleSetOperations(GenericResourceOperations genericOperations) + : base(genericOperations, genericOperations.Id) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The client parameters to use in these operations. + /// The identifier of the resource that is the target of operations. + internal VirtualMachineScaleSetOperations(ResourceGroupOperations resourceGroup, string vmName) + : base(resourceGroup, resourceGroup.Id.AppendProviderResource(ResourceType.Namespace, ResourceType.Type, vmName)) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The client parameters to use in these operations. + /// The identifier of the resource that is the target of operations. + protected VirtualMachineScaleSetOperations(ResourceOperationsBase operation, ResourceGroupResourceIdentifier id) + : base(operation, id) + { + } + + /// + /// Gets the resource type definition for a virtual machine. + /// + public static readonly ResourceType ResourceType = "Microsoft.Compute/virtualMachineScaleSets"; + + /// + /// Gets the valid resources for virtual machines. + /// + protected override ResourceType ValidResourceType => ResourceType; + + private VirtualMachineScaleSetsOperations Operations => new ComputeManagementClient( + BaseUri, + Id.SubscriptionId, + Credential, + ClientOptions.Convert()).VirtualMachineScaleSets; + + /// + /// Initializes a new instance of the class from a . + /// + /// An instance of that has an id for a virtual machine. + /// A new instance of the class. + public static VirtualMachineScaleSetOperations FromGeneric(GenericResourceOperations genericOperations) + { + return new VirtualMachineScaleSetOperations(genericOperations); + } + + /// + public ArmResponse Delete(CancellationToken cancellationToken = default) + { + return new ArmResponse(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken).WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); + } + + /// + public async Task> DeleteAsync(CancellationToken cancellationToken = default) + { + return new ArmResponse((await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)).WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); + } + + /// + public ArmOperation StartDelete(CancellationToken cancellationToken = default) + { + return new ArmVoidOperation(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken)); + } + + /// + public async Task> StartDeleteAsync(CancellationToken cancellationToken = default) + { + return new ArmVoidOperation(await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)); + } + + /// + public override ArmResponse Get(CancellationToken cancellationToken = default) + { + return new PhArmResponse( + Operations.Get(Id.ResourceGroupName, Id.Name, cancellationToken), + v => new VirtualMachineScaleSet(this, new VirtualMachineScaleSetData(v))); + } + + /// + public override async Task> GetAsync(CancellationToken cancellationToken = default) + { + return new PhArmResponse( + await Operations.GetAsync(Id.ResourceGroupName, Id.Name, cancellationToken), + v => new VirtualMachineScaleSet(this, new VirtualMachineScaleSetData(v))); + } + + /// + /// The operation to update a virtual machine. Please note some properties can be set only during virtual machine creation. + /// + /// The parameters to update. + /// An that allows polling for completion of the operation. + public ArmOperation StartUpdate(VirtualMachineScaleSetUpdate patchable, CancellationToken cancellationToken = default) + { + return new PhArmOperation( + Operations.StartUpdate(Id.ResourceGroupName, Id.Name, patchable, cancellationToken), + v => new VirtualMachineScaleSet(this, new VirtualMachineScaleSetData(v))); + } + + /// + /// The operation to update a virtual machine. Please note some properties can be set only during virtual machine creation. + /// + /// The parameters to update. + /// A token to allow the caller to cancel the call to the service. The default value is . + /// A that on completion returns an that allows polling for completion of the operation. + public async Task> StartUpdateAsync(VirtualMachineScaleSetUpdate patchable, CancellationToken cancellationToken = default) + { + return new PhArmOperation( + await Operations.StartUpdateAsync(Id.ResourceGroupName, Id.Name, patchable, cancellationToken), + v => new VirtualMachineScaleSet(this, new VirtualMachineScaleSetData(v))); + } + + /// + public ArmResponse AddTag(string key, string value, CancellationToken cancellationToken = default) + { + var vm = GetResource(); + var patchable = new VirtualMachineScaleSetUpdate(); + patchable.Tags.ReplaceWith(vm.Data.Tags); + patchable.Tags[key] = value; + + return new PhArmResponse( + Operations.StartUpdate(Id.ResourceGroupName, Id.Name, patchable, cancellationToken).WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult(), + v => new VirtualMachineScaleSet(this, new VirtualMachineScaleSetData(v))); + } + + /// + public async Task> AddTagAsync(string key, string value, CancellationToken cancellationToken = default) + { + var vm = await GetResourceAsync(cancellationToken); + var patchable = new VirtualMachineScaleSetUpdate(); + patchable.Tags.ReplaceWith(vm.Data.Tags); + patchable.Tags[key] = value; + + return new PhArmResponse( + await Operations.StartUpdateAsync(Id.ResourceGroupName, Id.Name, patchable, cancellationToken).Result.WaitForCompletionAsync(), + v => new VirtualMachineScaleSet(this, new VirtualMachineScaleSetData(v))); + } + + /// + public ArmOperation StartAddTag(string key, string value, CancellationToken cancellationToken = default) + { + var vm = GetResource(); + var patchable = new VirtualMachineScaleSetUpdate(); + patchable.Tags.ReplaceWith(vm.Data.Tags); + patchable.Tags[key] = value; + + return new PhArmOperation( + Operations.StartUpdate(Id.ResourceGroupName, Id.Name, patchable, cancellationToken), + v => new VirtualMachineScaleSet(this, new VirtualMachineScaleSetData(v))); + } + + /// + public async Task> StartAddTagAsync(string key, string value, CancellationToken cancellationToken = default) + { + var vm = await GetResourceAsync(cancellationToken); + var patchable = new VirtualMachineScaleSetUpdate(); + patchable.Tags.ReplaceWith(vm.Data.Tags); + patchable.Tags[key] = value; + + return new PhArmOperation( + await Operations.StartUpdateAsync(Id.ResourceGroupName, Id.Name, patchable, cancellationToken), + v => new VirtualMachineScaleSet(this, new VirtualMachineScaleSetData(v))); + } + + /// + public ArmResponse SetTags(IDictionary tags, CancellationToken cancellationToken = default) + { + var patchable = new VirtualMachineScaleSetUpdate(); + patchable.Tags.ReplaceWith(tags); + + return new PhArmResponse( + Operations.StartUpdate(Id.ResourceGroupName, Id.Name, patchable, cancellationToken).WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult(), + v => new VirtualMachineScaleSet(this, new VirtualMachineScaleSetData(v))); + } + + /// + public async Task> SetTagsAsync(IDictionary tags, CancellationToken cancellationToken = default) + { + var patchable = new VirtualMachineScaleSetUpdate(); + patchable.Tags.ReplaceWith(tags); + + return new PhArmResponse( + await Operations.StartUpdateAsync(Id.ResourceGroupName, Id.Name, patchable, cancellationToken).Result.WaitForCompletionAsync(cancellationToken), + v => new VirtualMachineScaleSet(this, new VirtualMachineScaleSetData(v))); + } + + /// + public ArmOperation StartSetTags(IDictionary tags, CancellationToken cancellationToken = default) + { + var patchable = new VirtualMachineScaleSetUpdate(); + patchable.Tags.ReplaceWith(tags); + + return new PhArmOperation( + Operations.StartUpdate(Id.ResourceGroupName, Id.Name, patchable, cancellationToken).WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult(), + v => new VirtualMachineScaleSet(this, new VirtualMachineScaleSetData(v))); + } + + /// + public async Task> StartSetTagsAsync(IDictionary tags, CancellationToken cancellationToken = default) + { + var patchable = new VirtualMachineScaleSetUpdate(); + patchable.Tags.ReplaceWith(tags); + + return new PhArmOperation( + await Operations.StartUpdateAsync(Id.ResourceGroupName, Id.Name, patchable, cancellationToken).Result.WaitForCompletionAsync(cancellationToken), + v => new VirtualMachineScaleSet(this, new VirtualMachineScaleSetData(v))); + } + + /// + public ArmResponse RemoveTag(string key, CancellationToken cancellationToken = default) + { + var vm = GetResource(); + var patchable = new VirtualMachineScaleSetUpdate(); + patchable.Tags.ReplaceWith(vm.Data.Tags); + patchable.Tags.Remove(key); + + return new PhArmResponse( + Operations.StartUpdate(Id.ResourceGroupName, Id.Name, patchable, cancellationToken).WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult(), + v => new VirtualMachineScaleSet(this, new VirtualMachineScaleSetData(v))); + } + + /// + public async Task> RemoveTagAsync(string key, CancellationToken cancellationToken = default) + { + var vm = await GetResourceAsync(cancellationToken); + var patchable = new VirtualMachineScaleSetUpdate(); + patchable.Tags.ReplaceWith(vm.Data.Tags); + patchable.Tags.Remove(key); + + return new PhArmResponse( + await Operations.StartUpdateAsync(Id.ResourceGroupName, Id.Name, patchable, cancellationToken).Result.WaitForCompletionAsync(cancellationToken), + v => new VirtualMachineScaleSet(this, new VirtualMachineScaleSetData(v))); + } + + /// + public ArmOperation StartRemoveTag(string key, CancellationToken cancellationToken = default) + { + var vm = GetResource(); + var patchable = new VirtualMachineScaleSetUpdate(); + patchable.Tags.ReplaceWith(vm.Data.Tags); + patchable.Tags.Remove(key); + + return new PhArmOperation( + Operations.StartUpdate(Id.ResourceGroupName, Id.Name, patchable, cancellationToken).WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult(), + v => new VirtualMachineScaleSet(this, new VirtualMachineScaleSetData(v))); + } + + /// + public async Task> StartRemoveTagAsync(string key, CancellationToken cancellationToken = default) + { + var vm = await GetResourceAsync(cancellationToken); + var patchable = new VirtualMachineScaleSetUpdate(); + patchable.Tags.ReplaceWith(vm.Data.Tags); + patchable.Tags.Remove(key); + + return new PhArmOperation( + await Operations.StartUpdateAsync(Id.ResourceGroupName, Id.Name, patchable, cancellationToken).Result.WaitForCompletionAsync(cancellationToken), + v => new VirtualMachineScaleSet(this, new VirtualMachineScaleSetData(v))); + } + + /// + /// Lists all available geo-locations. + /// + /// A collection of location that may take multiple service requests to iterate over. + public IEnumerable ListAvailableLocations(CancellationToken cancellationToken = default) + { + return ListAvailableLocations(ResourceType, cancellationToken); + } + + /// + /// Lists all available geo-locations. + /// + /// A token to allow the caller to cancel the call to the service. The default value is . + /// An async collection of location that may take multiple service requests to iterate over. + /// The default subscription id is null. + public async Task> ListAvailableLocationsAsync(CancellationToken cancellationToken = default) + { + return await ListAvailableLocationsAsync(ResourceType, cancellationToken); + } + + /// + /// Gets a list of subnet in the virtual nerwork. + /// + /// An object representing collection of subnets and their operations over a virtual network. + public RollingUpgradeOperations GetRollingUpgrade() + { + return new RollingUpgradeOperations(this); + } + } +} diff --git a/sdk/resourcemanager/Proto.Client/network/Extensions/ResourceGroupExtensions.cs b/sdk/resourcemanager/Proto.Client/network/Extensions/ResourceGroupExtensions.cs index eabef4015913f..0975ca3446dbe 100644 --- a/sdk/resourcemanager/Proto.Client/network/Extensions/ResourceGroupExtensions.cs +++ b/sdk/resourcemanager/Proto.Client/network/Extensions/ResourceGroupExtensions.cs @@ -50,5 +50,15 @@ public static NetworkSecurityGroupContainer GetNetworkSecurityGroups(this Resour { return new NetworkSecurityGroupContainer(resourceGroup); } + + /// + /// Gets a under a . + /// + /// The instance the method will execute against. + /// An instance of . + public static LoadBalancerContainer GetLoadBalancers(this ResourceGroupOperations resourceGroup) + { + return new LoadBalancerContainer(resourceGroup); + } } } diff --git a/sdk/resourcemanager/Proto.Client/network/LoadBalancer.cs b/sdk/resourcemanager/Proto.Client/network/LoadBalancer.cs new file mode 100644 index 0000000000000..db9bbf280a833 --- /dev/null +++ b/sdk/resourcemanager/Proto.Client/network/LoadBalancer.cs @@ -0,0 +1,38 @@ +using System.Threading; +using System.Threading.Tasks; +using Azure.ResourceManager.Core; + +namespace Proto.Network +{ + /// + /// A class representing a LoadBalancer along with the instance operations that can be performed on it. + /// + public class LoadBalancer : LoadBalancerOperations + { + /// + /// Initializes a new instance of the class. + /// + internal LoadBalancer(ResourceOperationsBase options, LoadBalancerData resource) + : base(options, resource.Id) + { + Data = resource; + } + + /// + /// Gets the data representing the LoadBalancer + /// + public LoadBalancerData Data { get; private set; } + + /// + protected override LoadBalancer GetResource(CancellationToken cancellation = default) + { + return this; + } + + /// + protected override Task GetResourceAsync(CancellationToken cancellationToken = default) + { + return Task.FromResult(this); + } + } +} diff --git a/sdk/resourcemanager/Proto.Client/network/LoadBalancerContainer.cs b/sdk/resourcemanager/Proto.Client/network/LoadBalancerContainer.cs new file mode 100644 index 0000000000000..c19473a541f4e --- /dev/null +++ b/sdk/resourcemanager/Proto.Client/network/LoadBalancerContainer.cs @@ -0,0 +1,115 @@ +using Azure; +using Azure.ResourceManager.Core; +using Azure.ResourceManager.Network; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Proto.Network +{ + /// + /// A class representing collection of LoadBalancers and their operations over a VirtualNetwork. + /// + public class LoadBalancerContainer : ResourceContainerBase + { + /// + /// Initializes a new instance of the class. + /// + /// The parent resource group. + internal LoadBalancerContainer(ResourceGroupOperations resourceGroup) + : base(resourceGroup) + { + } + + /// + /// Typed Resource Identifier for the container. + /// + public new ResourceGroupResourceIdentifier Id => base.Id as ResourceGroupResourceIdentifier; + + /// + protected override ResourceType ValidResourceType => ResourceGroupOperations.ResourceType; + + private LoadBalancersOperations Operations => new NetworkManagementClient( + Id.SubscriptionId, + BaseUri, + Credential, + ClientOptions.Convert()).LoadBalancers; + + /// + public ArmResponse CreateOrUpdate(string name, LoadBalancerData resourceDetails, CancellationToken cancellationToken = default) + { + var operation = Operations.StartCreateOrUpdate(Id.ResourceGroupName, name, resourceDetails.Model, cancellationToken); + return new PhArmResponse( + operation.WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult(), + s => new LoadBalancer(Parent, new LoadBalancerData(s))); + } + + /// + public async Task> CreateOrUpdateAsync(string name, LoadBalancerData resourceDetails, CancellationToken cancellationToken = default) + { + var operation = await Operations.StartCreateOrUpdateAsync(Id.ResourceGroupName, name, resourceDetails.Model, cancellationToken).ConfigureAwait(false); + return new PhArmResponse( + await operation.WaitForCompletionAsync(cancellationToken).ConfigureAwait(false), + s => new LoadBalancer(Parent, new LoadBalancerData(s))); + } + + /// + public ArmOperation StartCreateOrUpdate(string name, LoadBalancerData resourceDetails, CancellationToken cancellationToken = default) + { + return new PhArmOperation( + Operations.StartCreateOrUpdate(Id.ResourceGroupName, name, resourceDetails.Model, cancellationToken), + s => new LoadBalancer(Parent, new LoadBalancerData(s))); + } + + /// + public async Task> StartCreateOrUpdateAsync(string name, LoadBalancerData resourceDetails, CancellationToken cancellationToken = default) + { + return new PhArmOperation( + await Operations.StartCreateOrUpdateAsync(Id.ResourceGroupName, name, resourceDetails.Model, cancellationToken).ConfigureAwait(false), + s => new LoadBalancer(Parent, new LoadBalancerData(s))); + } + + /// + /// Lists the LoadBalancers for this LoadBalancer. + /// + /// A token to allow the caller to cancel the call to the service. The default value is . + /// A collection of resource operations that may take multiple service requests to iterate over. + public Pageable List(CancellationToken cancellationToken = default) + { + return new PhWrappingPageable( + Operations.List(Id.ResourceGroupName, cancellationToken), + convertor()); + } + + /// + /// Lists the LoadBalancers for this LoadBalancer. + /// + /// A token to allow the caller to cancel the call to the service. The default value is . + /// An async collection of resource operations that may take multiple service requests to iterate over. + public AsyncPageable ListAsync(CancellationToken cancellationToken = default) + { + return new PhWrappingAsyncPageable( + Operations.ListAsync(Id.ResourceGroupName, cancellationToken), + convertor()); + } + + private Func convertor() + { + return s => new LoadBalancer(Parent, new LoadBalancerData(s)); + } + + /// + public override ArmResponse Get(string loadBalancerName, CancellationToken cancellationToken = default) + { + return new PhArmResponse(Operations.Get(Id.ResourceGroupName, loadBalancerName, null, cancellationToken: cancellationToken), + n => new LoadBalancer(Parent, new LoadBalancerData(n))); + } + + /// + public override async Task> GetAsync(string loadBalancerName, CancellationToken cancellationToken = default) + { + return new PhArmResponse(await Operations.GetAsync(Id.ResourceGroupName, loadBalancerName, null, cancellationToken), + n => new LoadBalancer(Parent, new LoadBalancerData(n))); + } + } +} diff --git a/sdk/resourcemanager/Proto.Client/network/LoadBalancerOperations.cs b/sdk/resourcemanager/Proto.Client/network/LoadBalancerOperations.cs new file mode 100644 index 0000000000000..2994fa8f1e50e --- /dev/null +++ b/sdk/resourcemanager/Proto.Client/network/LoadBalancerOperations.cs @@ -0,0 +1,92 @@ +using Azure; +using Azure.ResourceManager.Network; +using Azure.ResourceManager.Core; +using System.Threading; +using System.Threading.Tasks; + +namespace Proto.Network +{ + /// + /// A class representing the operations that can be performed over a specific LoadBalancer. + /// + // TODO, ITaggable was not added. + public class LoadBalancerOperations : ResourceOperationsBase, IDeletableResource + { + /// + /// Initializes a new instance of the class. + /// + /// The client parameters to use in these operations. + /// The name of the LoadBalancer. + internal LoadBalancerOperations(VirtualNetworkOperations virtualNetwork, string loadBalancerName) + : base(virtualNetwork, virtualNetwork.Id.AppendChildResource( "loadBalancers", loadBalancerName)) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The client parameters to use in these operations. + /// The identifier of the resource that is the target of operations. + protected LoadBalancerOperations(ResourceOperationsBase options, ResourceIdentifier id) + : base(options, id) + { + } + + /// + /// Gets the resource type definition for a LoadBalancer. + /// + public static readonly ResourceType ResourceType = "Microsoft.Network/loadBalancers"; + + /// + /// Gets the valid resource type definition for a LoadBalancer. + /// + protected override ResourceType ValidResourceType => ResourceType; + + private LoadBalancersOperations Operations => new NetworkManagementClient( + Id.SubscriptionId, + BaseUri, + Credential, + ClientOptions.Convert()).LoadBalancers; + + /// + public ArmResponse Delete(CancellationToken cancellationToken = default) + { + return new ArmResponse(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken) + .WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); + } + + /// + public async Task> DeleteAsync(CancellationToken cancellationToken = default) + { + return new ArmResponse((await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)) + .WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); + } + + + /// + public ArmOperation StartDelete(CancellationToken cancellationToken = default) + { + return new ArmVoidOperation(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken)); + } + + /// + public async Task> StartDeleteAsync(CancellationToken cancellationToken = default) + { + return new ArmVoidOperation(await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)); + } + + /// + public override ArmResponse Get(CancellationToken cancellationToken = default) + { + return new PhArmResponse(Operations.Get(Id.ResourceGroupName, Id.Parent.Name, Id.Name, cancellationToken: cancellationToken), + n => new LoadBalancer(this, new LoadBalancerData(n))); + } + + /// + public override async Task> GetAsync(CancellationToken cancellationToken = default) + { + return new PhArmResponse(await Operations.GetAsync(Id.ResourceGroupName, Id.Name, null, cancellationToken), + n => new LoadBalancer(this, new LoadBalancerData(n))); + } + } +} diff --git a/sdk/resourcemanager/Proto.Client/network/Placeholder/LoadBalancerData.cs b/sdk/resourcemanager/Proto.Client/network/Placeholder/LoadBalancerData.cs new file mode 100644 index 0000000000000..8b0850825ffb1 --- /dev/null +++ b/sdk/resourcemanager/Proto.Client/network/Placeholder/LoadBalancerData.cs @@ -0,0 +1,70 @@ +using Azure.ResourceManager.Network.Models; +using Azure.ResourceManager.Core; +using System.Collections.Generic; + +namespace Proto.Network +{ + /// + /// A class representing the LoadBalancer data model. + /// + public class LoadBalancerData : Resource + { + /// + /// Initializes a new instance of the class. + /// + public LoadBalancerData(Azure.ResourceManager.Network.Models.LoadBalancer loadBalancer) + : base(loadBalancer.Id, loadBalancer.Name, LoadBalancerOperations.ResourceType) + { + Model = loadBalancer; + } + + /// + /// Gets or sets the Model this resource is based of. + /// + public virtual Azure.ResourceManager.Network.Models.LoadBalancer Model { get; } + + /// + /// Gets the LoadBalancer id. + /// + public override string Name => Model.Name; + + /// + /// The provisioning state of the LoadBalancer resource. + /// + public ProvisioningState? ProvisioningState => Model.ProvisioningState; + + /// The load balancer SKU. + public LoadBalancerSku Sku + { + get => Model.Sku; + set => Model.Sku = value; + } + + /// A unique read-only string that changes whenever the resource is updated. + public string Etag => Model.Etag; + + /// Object representing the frontend IPs to be used for the load balancer. + public IList FrontendIPConfigurations => Model.FrontendIPConfigurations; + + /// Collection of backend address pools used by a load balancer. + public IList BackendAddressPools => Model.BackendAddressPools; + + /// Object collection representing the load balancing rules Gets the provisioning. + public IList LoadBalancingRules => Model.LoadBalancingRules; + + /// Collection of probe objects used in the load balancer. + public IList Probes => Model.Probes; + + /// Collection of inbound NAT Rules used by a load balancer. Defining inbound NAT rules on your load balancer is mutually exclusive with defining an inbound NAT pool. Inbound NAT pools are referenced from virtual machine scale sets. NICs that are associated with individual virtual machines cannot reference an Inbound NAT pool. They have to reference individual inbound NAT rules. + public IList InboundNatRules => Model.InboundNatRules; + + /// Defines an external port range for inbound NAT to a single backend port on NICs associated with a load balancer. Inbound NAT rules are created automatically for each NIC associated with the Load Balancer using an external port from this range. Defining an Inbound NAT pool on your Load Balancer is mutually exclusive with defining inbound Nat rules. Inbound NAT pools are referenced from virtual machine scale sets. NICs that are associated with individual virtual machines cannot reference an inbound NAT pool. They have to reference individual inbound NAT rules. + public IList InboundNatPools => Model.InboundNatPools; + + /// The outbound rules. + public IList OutboundRules => Model.OutboundRules; + + /// The resource GUID property of the load balancer resource. + public string ResourceGuid => Model.ResourceGuid; + } +} diff --git a/sdk/resourcemanager/Proto.Client/network/Placeholder/SubnetData.cs b/sdk/resourcemanager/Proto.Client/network/Placeholder/SubnetData.cs index 9a7cefb7c9377..48ef7dd88b3f7 100644 --- a/sdk/resourcemanager/Proto.Client/network/Placeholder/SubnetData.cs +++ b/sdk/resourcemanager/Proto.Client/network/Placeholder/SubnetData.cs @@ -21,7 +21,7 @@ public SubnetData(Azure.ResourceManager.Network.Models.Subnet sub) /// /// Gets or sets the Model this resource is based of. /// - public virtual Azure.ResourceManager.Network.Models.Subnet Model { get; set; } + public virtual Azure.ResourceManager.Network.Models.Subnet Model { get; } /// /// Gets the subnet id. diff --git a/sdk/resourcemanager/Proto.Client/src/ScenarioFactory.cs b/sdk/resourcemanager/Proto.Client/src/ScenarioFactory.cs index afa100e1112bf..6f094ee6b67df 100644 --- a/sdk/resourcemanager/Proto.Client/src/ScenarioFactory.cs +++ b/sdk/resourcemanager/Proto.Client/src/ScenarioFactory.cs @@ -40,7 +40,8 @@ enum Scenarios CheckResourceGroupOpsAsync, TenantResource, CheckResourceGroupContainerAsync, - GenericResourceOperationsExample + GenericResourceOperationsExample, + SingletonVmssUpgrade, } class ScenarioFactory diff --git a/sdk/resourcemanager/Proto.Client/src/Scenarios/CreateVMSS.cs b/sdk/resourcemanager/Proto.Client/src/Scenarios/CreateVMSS.cs new file mode 100644 index 0000000000000..7043318d55df6 --- /dev/null +++ b/sdk/resourcemanager/Proto.Client/src/Scenarios/CreateVMSS.cs @@ -0,0 +1,80 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Threading.Tasks; +using Azure.Identity; +using Azure.ResourceManager.Core; +using Proto.Compute; +using Proto.Network; + +namespace Proto.Client +{ + class CreateVMSS : Scenario + { + public override void Execute() + { + // TODO Not fully debugged yet around LoadBalancer + // ExecuteAsync().ConfigureAwait(false).GetAwaiter().GetResult(); + } + + private async Task ExecuteAsync() + { + var client = new ArmClient(ScenarioContext.AzureSdkSandboxId, new DefaultAzureCredential()); + + // Create Resource Group + Console.WriteLine($"--------Start StartCreate group {Context.RgName}--------"); + ResourceGroup resourceGroup = await client + .DefaultSubscription + .GetResourceGroups() + .Construct(Context.Loc) + .StartCreateOrUpdate(Context.RgName) + .WaitForCompletionAsync() + ; + CleanUp.Add(resourceGroup.Id); + + // Create VNet + Console.WriteLine("--------Start create VNet--------"); + string vnetName = Context.VmName + "_vnet"; + var vnet = resourceGroup.GetVirtualNetworks().Construct("10.0.0.0/16").CreateOrUpdate(vnetName).Value; + + //create subnet + Console.WriteLine("--------Start create Subnet async--------"); + var subnet = vnet.GetSubnets().Construct("10.0.0.0/24").CreateOrUpdate(Context.SubnetName).Value; + + //create network security group + Console.WriteLine("--------Start create NetworkSecurityGroup--------"); + _ = resourceGroup.GetNetworkSecurityGroups().Construct(80).CreateOrUpdate(Context.NsgName).Value; + + // Create Network Interface + Console.WriteLine("--------Start create Network Interface--------"); + var nic = resourceGroup.GetNetworkInterfaces().Construct(subnet.Id).CreateOrUpdate($"{Context.VmName}_nic").Value; + + + // Create Network Interface + Console.WriteLine("--------Start create Public IP--------"); + var publicIP = resourceGroup.GetPublicIpAddresss().Construct(resourceGroup.Data.Location).CreateOrUpdate($"{Context.VmName}_publicip").Value; + + // Create Network Interface + Console.WriteLine("--------Start create Load Balancer--------"); + var lbData = new LoadBalancerData(new Azure.ResourceManager.Network.Models.LoadBalancer() + { + Location = resourceGroup.Data.Location, + }); + var lb = resourceGroup.GetLoadBalancers().CreateOrUpdate($"{Context.VmName}_lb", lbData).Value; + + // Create VMSS + VirtualMachineScaleSet vmss = resourceGroup + .GetVirtualMachineScaleSet() + .Construct($"{Context.VmName}ScaleSet") + .WithRequiredLoadBalancer(lb.Id) + .WithRequiredPrimaryNetworkInterface("default", nic.Id, null, null) + //.WithUseLinuxImage("testvmss", "azureuser", "") + .WithUseWindowsImage($"{Context.VmName}Prefix", "azureuser", "") + .CreateOrUpdate($"{Context.VmName}ScaleSet"); + CleanUp.Add(vmss.Id); + + Console.WriteLine("\nDone all asserts passed ..."); + } + } +} diff --git a/sdk/resourcemanager/Proto.Client/src/Scenarios/SingletonVmssUpgrade.cs b/sdk/resourcemanager/Proto.Client/src/Scenarios/SingletonVmssUpgrade.cs new file mode 100644 index 0000000000000..00fd9c7c981a3 --- /dev/null +++ b/sdk/resourcemanager/Proto.Client/src/Scenarios/SingletonVmssUpgrade.cs @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Diagnostics; +using System.Threading.Tasks; +using Azure; +using Azure.Identity; +using Azure.ResourceManager.Core; +using Proto.Compute; +using Proto.Network; + +namespace Proto.Client +{ + class SingletonVmssUpgrade : Scenario + { + public override void Execute() + { + ExecuteAsync().ConfigureAwait(false).GetAwaiter().GetResult(); + } + + private async Task ExecuteAsync() + { + var client = new ArmClient(ScenarioContext.AzureSdkSandboxId, new DefaultAzureCredential()); + + // NOTE: due to full test involves creating LB which have another 3-5 resources needs to be in + // proto, this test relies on pre-created VMSS. + // 1. Follow instruction here (CLI), https://docs.microsoft.com/en-us/azure/virtual-machine-scale-sets/quick-create-cli + // az group create --name azhang-test --location eastus + // az vmss create --resource-group azhang-test --name myScaleSet --image UbuntuLTS --upgrade-policy-mode automatic --admin-username azureuser --generate-ssh-keys + // 2. Initiate a rolling upgrade az vmss rolling-upgrade start -g azhang-test -n myScaleSet --debug + VirtualMachineScaleSet vmss1 = await client.DefaultSubscription + .GetResourceGroups().Get("azhang-test").Value + .GetVirtualMachineScaleSet().GetAsync("myScaleSet"); + + var ru = vmss1.GetRollingUpgrade().Get().Value; + Debug.Assert(ru.Data.Model != null); + + ru = ru.Get().Value; + Debug.Assert(ru.Data.Model != null); + + try + { + vmss1.GetRollingUpgrade().Cancel(); + } + catch (RequestFailedException e) when (e.Status == 409) + { + } + catch + { + throw; + } + + Console.WriteLine("Test case SingletonVmssUpgrade passed."); + } + } +}