diff --git a/src/ApiService/ApiService/ApiService.csproj b/src/ApiService/ApiService/ApiService.csproj index 26b8ddadd..f2502368d 100644 --- a/src/ApiService/ApiService/ApiService.csproj +++ b/src/ApiService/ApiService/ApiService.csproj @@ -24,7 +24,7 @@ - + diff --git a/src/ApiService/ApiService/Functions/Proxy.cs b/src/ApiService/ApiService/Functions/Proxy.cs index 29013507a..74959b12c 100644 --- a/src/ApiService/ApiService/Functions/Proxy.cs +++ b/src/ApiService/ApiService/Functions/Proxy.cs @@ -149,7 +149,7 @@ public class Proxy { return await _context.RequestHandling.NotOk( req, request.ErrorV, - "debug_proxy delet"); + "debug_proxy delete"); } var regions = await _context.ProxyForwardOperations.RemoveForward( diff --git a/src/ApiService/ApiService/Functions/TimerProxy.cs b/src/ApiService/ApiService/Functions/TimerProxy.cs index 024f8a0b7..e5e89ba2f 100644 --- a/src/ApiService/ApiService/Functions/TimerProxy.cs +++ b/src/ApiService/ApiService/Functions/TimerProxy.cs @@ -64,14 +64,16 @@ public class TimerProxy { // since we do not support bring your own NSG if (await nsgOpertions.GetNsg(region) != null) { - var network = await Network.Create(region, _context); + var network = await Network.Init(region, _context); var subnet = await network.GetSubnet(); - var vnet = await network.GetVnet(); - if (subnet != null && vnet != null) { - var result = await nsgOpertions.AssociateSubnet(region, vnet, subnet); - if (!result.OkV) { - _logger.Error($"Failed to associate NSG and subnet due to {result.ErrorV} in region {region}"); + if (subnet != null) { + var vnet = await network.GetVnet(); + if (vnet != null) { + var result = await nsgOpertions.AssociateSubnet(region, vnet, subnet); + if (!result.OkV) { + _logger.Error($"Failed to associate NSG and subnet due to {result.ErrorV} in region {region}"); + } } } } diff --git a/src/ApiService/ApiService/ServiceConfiguration.cs b/src/ApiService/ApiService/ServiceConfiguration.cs index 5c55ccb62..3eef5dae6 100644 --- a/src/ApiService/ApiService/ServiceConfiguration.cs +++ b/src/ApiService/ApiService/ServiceConfiguration.cs @@ -64,47 +64,55 @@ public class ServiceConfiguration : IServiceConfig { #endif } + private static string? GetEnv(string name) { + var v = Environment.GetEnvironmentVariable(name); + if (String.IsNullOrEmpty(v)) + return null; + + return v; + } + //TODO: Add environment variable to control where to write logs to public LogDestination[] LogDestinations { get; set; } //TODO: Get this from Environment variable public ApplicationInsights.DataContracts.SeverityLevel LogSeverityLevel => ApplicationInsights.DataContracts.SeverityLevel.Verbose; - public string? ApplicationInsightsAppId => Environment.GetEnvironmentVariable("APPINSIGHTS_APPID"); - public string? ApplicationInsightsInstrumentationKey => Environment.GetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY"); + public string? ApplicationInsightsAppId => GetEnv("APPINSIGHTS_APPID"); + public string? ApplicationInsightsInstrumentationKey => GetEnv("APPINSIGHTS_INSTRUMENTATIONKEY"); - public string? AzureSignalRConnectionString => Environment.GetEnvironmentVariable("AzureSignalRConnectionString"); - public string? AzureSignalRServiceTransportType => Environment.GetEnvironmentVariable("AzureSignalRServiceTransportType"); + public string? AzureSignalRConnectionString => GetEnv("AzureSignalRConnectionString"); + public string? AzureSignalRServiceTransportType => GetEnv("AzureSignalRServiceTransportType"); - public string? AzureWebJobDisableHomePage { get => Environment.GetEnvironmentVariable("AzureWebJobsDisableHomepage"); } - public string? AzureWebJobStorage { get => Environment.GetEnvironmentVariable("AzureWebJobsStorage"); } + public string? AzureWebJobDisableHomePage { get => GetEnv("AzureWebJobsDisableHomepage"); } + public string? AzureWebJobStorage { get => GetEnv("AzureWebJobsStorage"); } - public string? DiagnosticsAzureBlobContainerSasUrl { get => Environment.GetEnvironmentVariable("DIAGNOSTICS_AZUREBLOBCONTAINERSASURL"); } - public string? DiagnosticsAzureBlobRetentionDays { get => Environment.GetEnvironmentVariable("DIAGNOSTICS_AZUREBLOBRETENTIONINDAYS"); } + public string? DiagnosticsAzureBlobContainerSasUrl { get => GetEnv("DIAGNOSTICS_AZUREBLOBCONTAINERSASURL"); } + public string? DiagnosticsAzureBlobRetentionDays { get => GetEnv("DIAGNOSTICS_AZUREBLOBRETENTIONINDAYS"); } - public string? MultiTenantDomain { get => Environment.GetEnvironmentVariable("MULTI_TENANT_DOMAIN"); } + public string? MultiTenantDomain { get => GetEnv("MULTI_TENANT_DOMAIN"); } - public string? OneFuzzDataStorage { get => Environment.GetEnvironmentVariable("ONEFUZZ_DATA_STORAGE"); } - public string? OneFuzzFuncStorage { get => Environment.GetEnvironmentVariable("ONEFUZZ_FUNC_STORAGE"); } - public string? OneFuzzInstance { get => Environment.GetEnvironmentVariable("ONEFUZZ_INSTANCE"); } - public string? OneFuzzInstanceName { get => Environment.GetEnvironmentVariable("ONEFUZZ_INSTANCE_NAME"); } - public string? OneFuzzKeyvault { get => Environment.GetEnvironmentVariable("ONEFUZZ_KEYVAULT"); } - public string? OneFuzzMonitor { get => Environment.GetEnvironmentVariable("ONEFUZZ_MONITOR"); } - public string? OneFuzzOwner { get => Environment.GetEnvironmentVariable("ONEFUZZ_OWNER"); } - public string? OneFuzzResourceGroup { get => Environment.GetEnvironmentVariable("ONEFUZZ_RESOURCE_GROUP"); } - public string? OneFuzzTelemetry { get => Environment.GetEnvironmentVariable("ONEFUZZ_TELEMETRY"); } + public string? OneFuzzDataStorage { get => GetEnv("ONEFUZZ_DATA_STORAGE"); } + public string? OneFuzzFuncStorage { get => GetEnv("ONEFUZZ_FUNC_STORAGE"); } + public string? OneFuzzInstance { get => GetEnv("ONEFUZZ_INSTANCE"); } + public string? OneFuzzInstanceName { get => GetEnv("ONEFUZZ_INSTANCE_NAME"); } + public string? OneFuzzKeyvault { get => GetEnv("ONEFUZZ_KEYVAULT"); } + public string? OneFuzzMonitor { get => GetEnv("ONEFUZZ_MONITOR"); } + public string? OneFuzzOwner { get => GetEnv("ONEFUZZ_OWNER"); } + public string? OneFuzzResourceGroup { get => GetEnv("ONEFUZZ_RESOURCE_GROUP"); } + public string? OneFuzzTelemetry { get => GetEnv("ONEFUZZ_TELEMETRY"); } public string OneFuzzVersion { get { // version can be overridden by config: - return Environment.GetEnvironmentVariable("ONEFUZZ_VERSION") + return GetEnv("ONEFUZZ_VERSION") ?? _oneFuzzVersion ?? throw new InvalidOperationException("Unable to read OneFuzz version from assembly"); } } - public string? OneFuzzAllowOutdatedAgent => Environment.GetEnvironmentVariable("ONEFUZZ_ALLOW_OUTDATED_AGENT"); + public string? OneFuzzAllowOutdatedAgent => GetEnv("ONEFUZZ_ALLOW_OUTDATED_AGENT"); - public string OneFuzzNodeDisposalStrategy { get => Environment.GetEnvironmentVariable("ONEFUZZ_NODE_DISPOSAL_STRATEGY") ?? "scale_in"; } + public string OneFuzzNodeDisposalStrategy { get => GetEnv("ONEFUZZ_NODE_DISPOSAL_STRATEGY") ?? "scale_in"; } public string OneFuzzStoragePrefix => ""; // in production we never prefix the tables } diff --git a/src/ApiService/ApiService/onefuzzlib/Creds.cs b/src/ApiService/ApiService/onefuzzlib/Creds.cs index fe81bef3c..ae0b0e4fd 100644 --- a/src/ApiService/ApiService/onefuzzlib/Creds.cs +++ b/src/ApiService/ApiService/onefuzzlib/Creds.cs @@ -122,7 +122,7 @@ public sealed class Creds : ICreds { var resource = await uid.GetAsync(); var principalId = resource.Value.Data.Properties.ToObjectFromJson().principalId; - return new Guid(principalId); + return Guid.Parse(principalId); }); } diff --git a/src/ApiService/ApiService/onefuzzlib/DiskOperations.cs b/src/ApiService/ApiService/onefuzzlib/DiskOperations.cs index 7e0268947..6225bfeca 100644 --- a/src/ApiService/ApiService/onefuzzlib/DiskOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/DiskOperations.cs @@ -5,7 +5,7 @@ using Azure.ResourceManager.Compute; namespace Microsoft.OneFuzz.Service; public interface IDiskOperations { - DiskImageCollection ListDisks(string resourceGroup); + DiskCollection ListDisks(string resourceGroup); Async.Task DeleteDisk(string resourceGroup, string name); } @@ -23,7 +23,7 @@ public class DiskOperations : IDiskOperations { public async Task DeleteDisk(string resourceGroup, string name) { try { _logTracer.Info($"deleting disks {resourceGroup} : {name}"); - var disk = await _creds.GetResourceGroupResource().GetDiskImageAsync(name); + var disk = await _creds.GetResourceGroupResource().GetDiskAsync(name); if (disk != null) { await disk.Value.DeleteAsync(WaitUntil.Started); return true; @@ -35,8 +35,8 @@ public class DiskOperations : IDiskOperations { return false; } - public DiskImageCollection ListDisks(string resourceGroup) { + public DiskCollection ListDisks(string resourceGroup) { _logTracer.Info($"listing disks {resourceGroup}"); - return _creds.GetResourceGroupResource().GetDiskImages(); + return _creds.GetResourceGroupResource().GetDisks(); } } diff --git a/src/ApiService/ApiService/onefuzzlib/Extension.cs b/src/ApiService/ApiService/onefuzzlib/Extension.cs index 22f8c447f..66836c026 100644 --- a/src/ApiService/ApiService/onefuzzlib/Extension.cs +++ b/src/ApiService/ApiService/onefuzzlib/Extension.cs @@ -226,7 +226,8 @@ public class Extensions : IExtensions { ); var fileName = $"{pool.Name}/config.json"; - await _context.Containers.SaveBlob(new Container("vm-scripts"), fileName, (JsonSerializer.Serialize(config, EntityConverter.GetJsonSerializerOptions())), StorageType.Config); + var configJson = JsonSerializer.Serialize(config, EntityConverter.GetJsonSerializerOptions()); + await _context.Containers.SaveBlob(new Container("vm-scripts"), fileName, configJson, StorageType.Config); return await ConfigUrl(new Container("vm-scripts"), fileName, false); } @@ -264,6 +265,7 @@ public class Extensions : IExtensions { await UpdateManagedScripts(); var urlsUpdated = urls ?? new(); + var managedIdentity = JsonSerializer.Serialize(new { ManagedIdentity = new Dictionary() }, _extensionSerializerOptions); if (vmOs == Os.Windows) { var vmScripts = await ConfigUrl(new Container("vm-scripts"), "managed.ps1", withSas) ?? throw new Exception("failed to get VmScripts config url"); var toolsAzCopy = await ConfigUrl(new Container("tools"), "win64/azcopy.exe", withSas) ?? throw new Exception("failed to get toolsAzCopy config url"); @@ -286,7 +288,7 @@ public class Extensions : IExtensions { TypeHandlerVersion = "1.9", AutoUpgradeMinorVersion = true, Settings = new BinaryData(JsonSerializer.Serialize(new { commandToExecute = toExecuteCmd, fileUris = urlsUpdated }, _extensionSerializerOptions)), - ProtectedSettings = new BinaryData(JsonSerializer.Serialize(new { managedIdentity = new Dictionary() }, _extensionSerializerOptions)) + ProtectedSettings = new BinaryData(managedIdentity) }; return extension; } else if (vmOs == Os.Linux) { @@ -301,7 +303,6 @@ public class Extensions : IExtensions { var toExecuteCmd = $"sh setup.sh {mode.ToString().ToLowerInvariant()}"; var extensionSettings = JsonSerializer.Serialize(new { CommandToExecute = toExecuteCmd, FileUris = urlsUpdated }, _extensionSerializerOptions); - var protectedExtensionSettings = JsonSerializer.Serialize(new { ManagedIdentity = new Dictionary() }, _extensionSerializerOptions); var extension = new VMExtensionWrapper { Name = "CustomScript", @@ -312,7 +313,7 @@ public class Extensions : IExtensions { ForceUpdateTag = Guid.NewGuid().ToString(), AutoUpgradeMinorVersion = true, Settings = new BinaryData(extensionSettings), - ProtectedSettings = new BinaryData(protectedExtensionSettings) + ProtectedSettings = new BinaryData(managedIdentity) }; return extension; } diff --git a/src/ApiService/ApiService/onefuzzlib/ImageOperations.cs b/src/ApiService/ApiService/onefuzzlib/ImageOperations.cs index 81975a388..31ec6a13f 100644 --- a/src/ApiService/ApiService/onefuzzlib/ImageOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/ImageOperations.cs @@ -65,7 +65,7 @@ public class ImageOperations : IImageOperations { } } else { try { - name = (await _context.Creds.GetResourceGroupResource().GetDiskImages().GetAsync( + name = (await _context.Creds.GetResourceGroupResource().GetImages().GetAsync( parsed.Data.Name )).Value.Data.StorageProfile.OSDisk.OSType.ToString().ToLowerInvariant(); } catch (Exception ex) when ( @@ -96,15 +96,13 @@ public class ImageOperations : IImageOperations { version = imageInfo.Version; } - var vmImage = await subscription.GetVirtualMachineImageAsync( - region, - imageInfo.Publisher, - imageInfo.Offer, - imageInfo.Sku - , version - ); - - name = vmImage.Value.OSDiskImageOperatingSystem!.Value.ToString().ToLower(); + name = (await subscription.GetVirtualMachineImageAsync( + region, + imageInfo.Publisher, + imageInfo.Offer, + imageInfo.Sku + , version + )).Value.OSDiskImageOperatingSystem.ToString().ToLower(); } catch (RequestFailedException ex) { return OneFuzzResult.Error( ErrorCode.INVALID_IMAGE, diff --git a/src/ApiService/ApiService/onefuzzlib/IpOperations.cs b/src/ApiService/ApiService/onefuzzlib/IpOperations.cs index 740963dff..fb4330e13 100644 --- a/src/ApiService/ApiService/onefuzzlib/IpOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/IpOperations.cs @@ -16,6 +16,8 @@ public interface IIpOperations { public Async.Task GetPublicIp(ResourceIdentifier resourceId); + public Async.Task GetPublicIp(string resourceId); + public Async.Task GetIp(string resourceGroup, string name); public Async.Task DeleteNic(string resourceGroup, string name); @@ -86,6 +88,9 @@ public class IpOperations : IIpOperations { var ips = await _networkInterfaceQuery.ListInstancePrivateIps(scalesetId, instance.OkV); return ips.FirstOrDefault(); } + public async Task GetPublicIp(string resourceId) { + return await GetPublicIp(new ResourceIdentifier(resourceId)); + } public async Task GetPublicIp(ResourceIdentifier resourceId) { // TODO: Parts of this function seem redundant, but I'm mirroring @@ -117,12 +122,15 @@ public class IpOperations : IIpOperations { public async Task CreatePublicNic(string resourceGroup, string name, string region, Nsg? nsg) { _logTracer.Info($"creating nic for {resourceGroup}:{name} in {region}"); - var network = await Network.Create(region, _context); + var network = await Network.Init(region, _context); var subnetId = await network.GetId(); if (subnetId is null) { - await network.Create(); - return OneFuzzResultVoid.Ok; + var r = await network.Create(); + if (!r.IsOk) { + _logTracer.Error($"failed to create network in region {region} due to {r.ErrorV}"); + } + return r; } if (nsg != null) { diff --git a/src/ApiService/ApiService/onefuzzlib/Network.cs b/src/ApiService/ApiService/onefuzzlib/Network.cs index 9efdd28db..f170fc38b 100644 --- a/src/ApiService/ApiService/onefuzzlib/Network.cs +++ b/src/ApiService/ApiService/onefuzzlib/Network.cs @@ -22,7 +22,7 @@ public class Network { _networkConfig = networkConfig; } - public static async Async.Task Create(string region, IOnefuzzContext context) { + public static async Async.Task Init(string region, IOnefuzzContext context) { var group = context.Creds.GetBaseResourceGroup(); var instanceConfig = await context.ConfigOperations.Fetch(); var networkConfig = instanceConfig.NetworkConfig; diff --git a/src/ApiService/ApiService/onefuzzlib/ProxyOperations.cs b/src/ApiService/ApiService/onefuzzlib/ProxyOperations.cs index 3f4a774e6..4754e509b 100644 --- a/src/ApiService/ApiService/onefuzzlib/ProxyOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/ProxyOperations.cs @@ -217,7 +217,7 @@ public class ProxyOperations : StatefulOrm, IPr } foreach (var status in instanceView.Statuses) { - if (status.Level == ComputeStatusLevelType.Error) { + if (status.Level == StatusLevelTypes.Error) { yield return $"code:{status.Code} status:{status.DisplayStatus} message:{status.Message}"; } } diff --git a/src/ApiService/ApiService/onefuzzlib/ScalesetOperations.cs b/src/ApiService/ApiService/onefuzzlib/ScalesetOperations.cs index 1a68363be..2f2fe602f 100644 --- a/src/ApiService/ApiService/onefuzzlib/ScalesetOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/ScalesetOperations.cs @@ -198,7 +198,7 @@ public class ScalesetOperations : StatefulOrm GetSubnet(string vnetName, string subnetName) { - var vnet = await this.GetVnet(vnetName); + try { + var vnet = await this.GetVnet(vnetName); - if (vnet != null) { - return await vnet.GetSubnetAsync(subnetName); + if (vnet != null) { + return await vnet.GetSubnetAsync(subnetName); + } + return null; + } catch (RequestFailedException ex) when (ex.Status == 404) { + return null; } - return null; + } public async Task GetSubnetId(string name, string subnetName) { diff --git a/src/ApiService/ApiService/onefuzzlib/VmExtensionWrapper.cs b/src/ApiService/ApiService/onefuzzlib/VmExtensionWrapper.cs index a017f0dce..e0f86cccb 100644 --- a/src/ApiService/ApiService/onefuzzlib/VmExtensionWrapper.cs +++ b/src/ApiService/ApiService/onefuzzlib/VmExtensionWrapper.cs @@ -1,6 +1,7 @@ using Azure.Core; using Azure.ResourceManager.Compute; + namespace Microsoft.OneFuzz.Service { public class VMExtensionWrapper { public AzureLocation? Location { get; init; } @@ -27,7 +28,7 @@ namespace Microsoft.OneFuzz.Service { var protectedSettings = ProtectedSettings ?? new BinaryData(new Dictionary()); return (Name!, new VirtualMachineExtensionData(Location.Value) { - ExtensionType = TypePropertiesType, + TypePropertiesType = TypePropertiesType, Publisher = Publisher, TypeHandlerVersion = TypeHandlerVersion, AutoUpgradeMinorVersion = AutoUpgradeMinorVersion, @@ -49,7 +50,8 @@ namespace Microsoft.OneFuzz.Service { var protectedSettings = ProtectedSettings ?? new BinaryData(new Dictionary()); return new VirtualMachineScaleSetExtensionData() { - ExtensionType = TypePropertiesType, + Name = Name, + TypePropertiesType = TypePropertiesType, Publisher = Publisher, TypeHandlerVersion = TypeHandlerVersion, AutoUpgradeMinorVersion = AutoUpgradeMinorVersion, @@ -62,3 +64,4 @@ namespace Microsoft.OneFuzz.Service { } } + diff --git a/src/ApiService/ApiService/onefuzzlib/VmOperations.cs b/src/ApiService/ApiService/onefuzzlib/VmOperations.cs index 2f2509dfa..f9f8f994c 100644 --- a/src/ApiService/ApiService/onefuzzlib/VmOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/VmOperations.cs @@ -1,6 +1,5 @@ using System.Threading.Tasks; using Azure; -using Azure.Core; using Azure.ResourceManager.Compute; using Azure.ResourceManager.Compute.Models; using Newtonsoft.Json; @@ -68,7 +67,7 @@ public class VmOperations : IVmOperations { public async Task GetVm(string name) { // _logTracer.Debug($"getting vm: {name}"); try { - var result = await _context.Creds.GetResourceGroupResource().GetVirtualMachineAsync(name, InstanceViewType.InstanceView); + var result = await _context.Creds.GetResourceGroupResource().GetVirtualMachineAsync(name, InstanceViewTypes.InstanceView); if (result == null) { return null; } @@ -256,20 +255,20 @@ public class VmOperations : IVmOperations { } var vmParams = new VirtualMachineData(location) { - OSProfile = new VirtualMachineOSProfile { + OSProfile = new OSProfile { ComputerName = "node", AdminUsername = "onefuzz", }, - HardwareProfile = new VirtualMachineHardwareProfile { + HardwareProfile = new HardwareProfile { VmSize = vmSku, }, - StorageProfile = new VirtualMachineStorageProfile { + StorageProfile = new StorageProfile { ImageReference = GenerateImageReference(image), }, - NetworkProfile = new VirtualMachineNetworkProfile(), + NetworkProfile = new NetworkProfile(), }; - vmParams.NetworkProfile.NetworkInterfaces.Add(new VirtualMachineNetworkInterfaceReference { Id = nic.Id }); + vmParams.NetworkProfile.NetworkInterfaces.Add(new NetworkInterfaceReference { Id = nic.Id }); var imageOs = await _context.ImageOperations.GetOs(location, image); if (!imageOs.IsOk) { @@ -286,7 +285,7 @@ public class VmOperations : IVmOperations { DisablePasswordAuthentication = true, }; vmParams.OSProfile.LinuxConfiguration.SshPublicKeys.Add( - new SshPublicKeyConfiguration { + new SshPublicKeyInfo { Path = "/home/onefuzz/.ssh/authorized_keys", KeyData = sshPublicKey } @@ -333,7 +332,7 @@ public class VmOperations : IVmOperations { var imageRef = new ImageReference(); if (image.StartsWith("/", StringComparison.Ordinal)) { - imageRef.Id = new ResourceIdentifier(image); + imageRef.Id = image; } else { var imageVal = image.Split(":", 4); imageRef.Publisher = imageVal[0]; diff --git a/src/ApiService/ApiService/onefuzzlib/VmssOperations.cs b/src/ApiService/ApiService/onefuzzlib/VmssOperations.cs index 62d727112..5d556feea 100644 --- a/src/ApiService/ApiService/onefuzzlib/VmssOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/VmssOperations.cs @@ -262,15 +262,15 @@ public class VmssOperations : IVmssOperations { Sku = new ComputeSku() { Name = vmSku, Capacity = vmCount }, Overprovision = false, SinglePlacementGroup = false, - UpgradePolicy = new VirtualMachineScaleSetUpgradePolicy() { Mode = VirtualMachineScaleSetUpgradeMode.Manual }, + UpgradePolicy = new UpgradePolicy() { Mode = UpgradeMode.Manual }, Identity = new ManagedServiceIdentity(managedServiceIdentityType: ManagedServiceIdentityType.UserAssigned), }; vmssData.Identity.UserAssignedIdentities.Add(_creds.GetScalesetIdentityResourcePath(), new UserAssignedIdentity()); - vmssData.VirtualMachineProfile = new VirtualMachineScaleSetVmProfile() { Priority = VirtualMachinePriorityType.Regular }; + vmssData.VirtualMachineProfile = new VirtualMachineScaleSetVmProfile() { Priority = VirtualMachinePriorityTypes.Regular }; var imageRef = new ImageReference(); if (image.StartsWith('/')) { - imageRef.Id = new ResourceIdentifier(image); + imageRef.Id = image; } else { var info = IImageOperations.GetImageInfo(image); imageRef.Publisher = info.Publisher; @@ -303,7 +303,7 @@ public class VmssOperations : IVmssOperations { case Os.Linux: vmssData.VirtualMachineProfile.OSProfile.LinuxConfiguration = new LinuxConfiguration(); vmssData.VirtualMachineProfile.OSProfile.LinuxConfiguration.DisablePasswordAuthentication = true; - var i = new SshPublicKeyConfiguration() { KeyData = sshPublicKey, Path = "/home/onefuzz/.ssh/authorized_keys" }; + var i = new SshPublicKeyInfo() { KeyData = sshPublicKey, Path = "/home/onefuzz/.ssh/authorized_keys" }; vmssData.VirtualMachineProfile.OSProfile.LinuxConfiguration.SshPublicKeys.Add(i); break; default: @@ -311,10 +311,10 @@ public class VmssOperations : IVmssOperations { } if (ephemeralOsDisks) { - vmssData.VirtualMachineProfile.StorageProfile.OSDisk = new VirtualMachineScaleSetOSDisk(DiskCreateOptionType.FromImage); + vmssData.VirtualMachineProfile.StorageProfile.OSDisk = new VirtualMachineScaleSetOSDisk(DiskCreateOptionTypes.FromImage); vmssData.VirtualMachineProfile.StorageProfile.OSDisk.DiffDiskSettings = new DiffDiskSettings(); - vmssData.VirtualMachineProfile.StorageProfile.OSDisk.DiffDiskSettings.Option = DiffDiskOption.Local; - vmssData.VirtualMachineProfile.StorageProfile.OSDisk.Caching = CachingType.ReadOnly; + vmssData.VirtualMachineProfile.StorageProfile.OSDisk.DiffDiskSettings.Option = DiffDiskOptions.Local; + vmssData.VirtualMachineProfile.StorageProfile.OSDisk.Caching = CachingTypes.ReadOnly; } if (spotInstance.HasValue && spotInstance.Value) { @@ -323,8 +323,8 @@ public class VmssOperations : IVmssOperations { // // https://docs.microsoft.com/en-us/azure/ // virtual-machine-scale-sets/use-spot#resource-manager-templates - vmssData.VirtualMachineProfile.EvictionPolicy = VirtualMachineEvictionPolicyType.Deallocate; - vmssData.VirtualMachineProfile.Priority = VirtualMachinePriorityType.Spot; + vmssData.VirtualMachineProfile.EvictionPolicy = VirtualMachineEvictionPolicyTypes.Deallocate; + vmssData.VirtualMachineProfile.Priority = VirtualMachinePriorityTypes.Spot; vmssData.VirtualMachineProfile.BillingMaxPrice = 1.0; } @@ -370,14 +370,14 @@ public class VmssOperations : IVmssOperations { entry.SetAbsoluteExpiration(TimeSpan.FromMinutes(10)); var sub = _creds.GetSubscriptionResource(); - var skus = sub.GetComputeResourceSkusAsync(filter: TableClient.CreateQueryFilter($"location eq '{region}'")); + var skus = sub.GetResourceSkusAsync(filter: TableClient.CreateQueryFilter($"location eq '{region}'")); var skuNames = new List(); await foreach (var sku in skus) { var available = true; if (sku.Restrictions is not null) { foreach (var restriction in sku.Restrictions) { - if (restriction.RestrictionsType == ComputeResourceSkuRestrictionsType.Location && + if (restriction.RestrictionsType == ResourceSkuRestrictionsType.Location && restriction.Values.Contains(region, StringComparer.OrdinalIgnoreCase)) { available = false; break; diff --git a/src/ApiService/ApiService/packages.lock.json b/src/ApiService/ApiService/packages.lock.json index f85a70138..f990631d9 100644 --- a/src/ApiService/ApiService/packages.lock.json +++ b/src/ApiService/ApiService/packages.lock.json @@ -65,12 +65,12 @@ }, "Azure.ResourceManager.Compute": { "type": "Direct", - "requested": "[1.0.0, )", - "resolved": "1.0.0", - "contentHash": "dmDhokNFcyreIYZMkha8OsLmch0hW/sdOA2nxN4MPVd8KJgGWB8DxCZWwG7qhh59RInKtmWOP8BnBS5mN+W5wQ==", + "requested": "[1.0.0-beta.8, )", + "resolved": "1.0.0-beta.8", + "contentHash": "rYYjjmEdmcOa8O4UgO/bdJ/qQclNZjuHdalxRJ0AhUHCORcM1f1BbIKR9CoN83IpfuEE+X+n5XY9QZcKvfrGVA==", "dependencies": { - "Azure.Core": "1.25.0", - "Azure.ResourceManager": "1.2.0", + "Azure.Core": "1.24.0", + "Azure.ResourceManager": "1.0.0", "System.Text.Json": "4.7.2" } }, diff --git a/src/ApiService/FunctionalTests/1f-api/ApiBase.cs b/src/ApiService/FunctionalTests/1f-api/ApiBase.cs index 5a8531d93..5c32551ba 100644 --- a/src/ApiService/FunctionalTests/1f-api/ApiBase.cs +++ b/src/ApiService/FunctionalTests/1f-api/ApiBase.cs @@ -5,11 +5,11 @@ using Xunit.Abstractions; namespace FunctionalTests; -interface IFromJsonElement { +public interface IFromJsonElement { T Convert(JsonElement e); } -class BooleanResult : IFromJsonElement { +public class BooleanResult : IFromJsonElement { JsonElement _e; public BooleanResult() { } public BooleanResult(JsonElement e) => _e = e; @@ -19,7 +19,7 @@ class BooleanResult : IFromJsonElement { public BooleanResult Convert(JsonElement e) => new BooleanResult(e); } -abstract class ApiBase { +public abstract class ApiBase { Uri _endpoint; Microsoft.OneFuzz.Service.Request _request; diff --git a/src/ApiService/FunctionalTests/1f-api/Error.cs b/src/ApiService/FunctionalTests/1f-api/Error.cs index 9fb5f2264..be2a82602 100644 --- a/src/ApiService/FunctionalTests/1f-api/Error.cs +++ b/src/ApiService/FunctionalTests/1f-api/Error.cs @@ -3,7 +3,7 @@ using Xunit; namespace FunctionalTests; -class Error : IComparable, IFromJsonElement { +public class Error : IComparable, IFromJsonElement { JsonElement _e; public Error(JsonElement e) { @@ -21,18 +21,18 @@ class Error : IComparable, IFromJsonElement { return res.ValueKind == JsonValueKind.Object && res.TryGetProperty("code", out _) && res.TryGetProperty("errors", out _); } - public int CompareTo(Error? error) { - if (error is null) { + public int CompareTo(Error? other) { + if (other is null) { return -1; } - var sameErrorMessages = Errors.Count() == error.Errors.Count(); - foreach (var s in error.Errors) { + var sameErrorMessages = Errors.Count() == other.Errors.Count(); + foreach (var s in other.Errors) { if (!sameErrorMessages) break; sameErrorMessages = Errors.Contains(s); } - if (error.Code == this.Code && sameErrorMessages) { + if (other.Code == this.Code && sameErrorMessages) { return 0; } else return 1; diff --git a/src/ApiService/FunctionalTests/1f-api/Helpers.cs b/src/ApiService/FunctionalTests/1f-api/Helpers.cs new file mode 100644 index 000000000..42e21a5e7 --- /dev/null +++ b/src/ApiService/FunctionalTests/1f-api/Helpers.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace FunctionalTests { + public class Helpers { + + public static async Task<(Pool, Scaleset)> CreatePoolAndScaleset(PoolApi poolApi, ScalesetApi scalesetApi, string os = "linux", string? region = null, int numNodes = 2) { + var image = (os == "linux") ? ScalesetApi.Image_Ubuntu_20_04 : ScalesetApi.ImageWindows; + + var newPoolId = Guid.NewGuid().ToString(); + var newPoolName = PoolApi.TestPoolPrefix + newPoolId; + var newPool = await poolApi.Create(newPoolName, os); + + Assert.True(newPool.IsOk, $"failed to create new pool: {newPool.ErrorV}"); + var newScalesetResult = await scalesetApi.Create(newPool.OkV!.Name, numNodes, region: region, image: image); + + Assert.True(newScalesetResult.IsOk, $"failed to crate new scaleset: {newScalesetResult.ErrorV}"); + var newScaleset = newScalesetResult.OkV!; + + return (newPool.OkV!, newScaleset); + + } + } +} diff --git a/src/ApiService/FunctionalTests/1f-api/Node.cs b/src/ApiService/FunctionalTests/1f-api/Node.cs index cba877fa0..a814f4a03 100644 --- a/src/ApiService/FunctionalTests/1f-api/Node.cs +++ b/src/ApiService/FunctionalTests/1f-api/Node.cs @@ -5,7 +5,7 @@ using Xunit.Abstractions; namespace FunctionalTests; -class Node : IFromJsonElement { +public class Node : IFromJsonElement { JsonElement _e; public Node() { } @@ -35,19 +35,19 @@ class Node : IFromJsonElement { } -class NodeApi : ApiBase { +public class NodeApi : ApiBase { public NodeApi(Uri endpoint, Microsoft.OneFuzz.Service.Request request, ITestOutputHelper output) : base(endpoint, "/api/Node", request, output) { } - public async Task Update(Guid machineId, bool? debugKeepNode = null) { + public async Task Update(Guid machineId, bool? debugKeepNode = null) { var j = new JsonObject(); if (debugKeepNode is not null) j.Add("debug_keep_node", JsonValue.Create(debugKeepNode)); j.Add("machine_id", JsonValue.Create(machineId)); - return await Post(j); + return Return(await Post(j)); } public async Task, Error>> Get(Guid? machineId = null, List? state = null, Guid? scalesetId = null, string? poolName = null) { var j = new JsonObject(); @@ -66,10 +66,10 @@ class NodeApi : ApiBase { return IEnumerableResult(await Get(j)); } - public async Task Patch(Guid machineId) { + public async Task Patch(Guid machineId) { var j = new JsonObject(); j.Add("machine_id", JsonValue.Create(machineId)); - return await Patch(j); + return Return(await Patch(j)); } public async Task Delete(Guid machineId) { diff --git a/src/ApiService/FunctionalTests/1f-api/Pool.cs b/src/ApiService/FunctionalTests/1f-api/Pool.cs index c9062c778..ce5a61e61 100644 --- a/src/ApiService/FunctionalTests/1f-api/Pool.cs +++ b/src/ApiService/FunctionalTests/1f-api/Pool.cs @@ -5,7 +5,7 @@ using Xunit.Abstractions; namespace FunctionalTests; -class Pool : IFromJsonElement { +public class Pool : IFromJsonElement { JsonElement _e; @@ -19,26 +19,30 @@ class Pool : IFromJsonElement { public Pool Convert(JsonElement e) => new Pool(e); } -class PoolApi : ApiBase { +public class PoolApi : ApiBase { - public static string TestPoolPrefix = "FT-DELETE-"; + public const string TestPoolPrefix = "FT-DELETE-"; public PoolApi(Uri endpoint, Microsoft.OneFuzz.Service.Request request, ITestOutputHelper output) : base(endpoint, "/api/Pool", request, output) { } public async Task Delete(string name, bool now = true) { + _output.WriteLine($"deleting pool: {name}, now: {now}"); var root = new JsonObject(); root.Add("name", JsonValue.Create(name)); root.Add("now", JsonValue.Create(now)); return Return(await Delete(root)); } - public async Task, Error>> Get(string? poolName = null, string? poolId = null, string? state = null) { + public async Task, Error>> Get(string? name = null, string? id = null, string? state = null) { var root = new JsonObject(); - root.Add("pool_id", poolId); - root.Add("name", poolName); - root.Add("state", state); + if (id is not null) + root.Add("pool_id", id); + if (name is not null) + root.Add("name", name); + if (state is not null) + root.Add("state", state); var res = await Get(root); return IEnumerableResult(res); @@ -52,7 +56,6 @@ class PoolApi : ApiBase { foreach (var pool in pools.OkV) { if (pool.Name.StartsWith(TestPoolPrefix)) { - _output.WriteLine($"Deleting {pool.Name}"); var deleted = await Delete(pool.Name); Assert.True(deleted.Result); } @@ -60,6 +63,8 @@ class PoolApi : ApiBase { } public async Task> Create(string poolName, string os, string arch = "x86_64") { + _output.WriteLine($"creating new pool {poolName} os: {os}"); + var rootPoolCreate = new JsonObject(); rootPoolCreate.Add("name", poolName); rootPoolCreate.Add("os", os); diff --git a/src/ApiService/FunctionalTests/1f-api/Proxy.cs b/src/ApiService/FunctionalTests/1f-api/Proxy.cs index c4a512557..98f51a676 100644 --- a/src/ApiService/FunctionalTests/1f-api/Proxy.cs +++ b/src/ApiService/FunctionalTests/1f-api/Proxy.cs @@ -3,9 +3,7 @@ using System.Text.Json.Nodes; using Xunit.Abstractions; namespace FunctionalTests; - - -class Proxy : IFromJsonElement { +public class Proxy : IFromJsonElement { JsonElement _e; public Proxy() { } @@ -19,8 +17,7 @@ class Proxy : IFromJsonElement { public Proxy Convert(JsonElement e) => new Proxy(e); } - -class Forward : IFromJsonElement, IComparable { +public class Forward : IFromJsonElement, IComparable { JsonElement _e; public Forward() { } public Forward(JsonElement e) => _e = e; @@ -43,14 +40,27 @@ class Forward : IFromJsonElement, IComparable { } } -class ProxyGetResult : IFromJsonElement, IComparable { +public class ProxyGetResult : IFromJsonElement, IComparable { JsonElement _e; public ProxyGetResult() { } public ProxyGetResult(JsonElement e) => _e = e; - public string? Ip => _e.ValueKind == JsonValueKind.Null ? null : _e.GetProperty("ip").GetString(); + public string? Ip { + get { + JsonElement ip; + if (_e.TryGetProperty("ip", out ip)) { + if (ip.ValueKind == JsonValueKind.Null) { + return null; + } else { + return ip.GetString(); + } + } else { + return null; + } + } + } public Forward Forward => new Forward(_e.GetProperty("forward")); @@ -76,7 +86,7 @@ class ProxyGetResult : IFromJsonElement, IComparable, Error>> Get(Guid? scalesetId = null, Guid? machineId = null, int? dstPort = null) { var root = new JsonObject(); - root.Add("scaleset_id", scalesetId); - root.Add("machine_id", machineId); - root.Add("dst_port", dstPort); + if (scalesetId is not null) + root.Add("scaleset_id", scalesetId); + if (machineId is not null) + root.Add("machine_id", machineId); + if (dstPort is not null) + root.Add("dst_port", dstPort); var r = await Get(root); if (Error.IsError(r)) { diff --git a/src/ApiService/FunctionalTests/1f-api/Scaleset.cs b/src/ApiService/FunctionalTests/1f-api/Scaleset.cs index cd9548231..969e913f4 100644 --- a/src/ApiService/FunctionalTests/1f-api/Scaleset.cs +++ b/src/ApiService/FunctionalTests/1f-api/Scaleset.cs @@ -4,10 +4,7 @@ using Xunit; using Xunit.Abstractions; namespace FunctionalTests; - - - -class Authentication { +public class Authentication { JsonElement _e; public Authentication() { } @@ -20,7 +17,7 @@ class Authentication { } -class ScalesetNodeState { +public class ScalesetNodeState { JsonElement _e; public ScalesetNodeState() { } @@ -32,7 +29,7 @@ class ScalesetNodeState { public string? NodeState => _e.GetProperty("state").GetString(); } -class Scaleset : IFromJsonElement { +public class Scaleset : IFromJsonElement { JsonElement _e; public Scaleset() { } public Scaleset(JsonElement e) => _e = e; @@ -68,9 +65,10 @@ class Scaleset : IFromJsonElement { public Scaleset Convert(JsonElement e) => new Scaleset(e); } -class ScalesetApi : ApiBase { +public class ScalesetApi : ApiBase { public const string Image_Ubuntu_20_04 = "Canonical:0001-com-ubuntu-server-focal:20_04-lts:latest"; + public const string ImageWindows = "MicrosoftWindowsDesktop:Windows-10:win10-21h2-pro:latest"; public ScalesetApi(Uri endpoint, Microsoft.OneFuzz.Service.Request request, ITestOutputHelper output) : base(endpoint, "/api/Scaleset", request, output) { } @@ -78,20 +76,26 @@ class ScalesetApi : ApiBase { public async Task, Error>> Get(Guid? id = null, string? state = null, bool? includeAuth = false) { var root = new JsonObject(); - root.Add("scaleset_id", id); - root.Add("state", state); - root.Add("include_auth", includeAuth); + if (id is not null) + root.Add("scaleset_id", id); + if (state is not null) + root.Add("state", state); + if (includeAuth is not null) + root.Add("include_auth", includeAuth); var res = await Get(root); return IEnumerableResult(res); } - public async Task> Create(string poolName, int size, string vmSku = "Standard_D2s_v3", string image = Image_Ubuntu_20_04, bool spotInstance = false) { + public async Task> Create(string poolName, int size, string? region = null, string vmSku = "Standard_D2s_v3", string image = Image_Ubuntu_20_04, bool spotInstance = false) { + _output.WriteLine($"Creating scaleset in pool {poolName}, size: {size}"); var rootScalesetCreate = new JsonObject(); rootScalesetCreate.Add("pool_name", poolName); rootScalesetCreate.Add("vm_sku", vmSku); rootScalesetCreate.Add("image", image); rootScalesetCreate.Add("size", size); - rootScalesetCreate.Add("spot_instance", spotInstance); + rootScalesetCreate.Add("spot_instances", spotInstance); + if (region is not null) + rootScalesetCreate.Add("region", region); var tags = new JsonObject(); tags.Add("Purpose", "Functional-Test"); diff --git a/src/ApiService/FunctionalTests/GlobalSuppressions.cs b/src/ApiService/FunctionalTests/GlobalSuppressions.cs index 537cde53b..6425018ac 100644 --- a/src/ApiService/FunctionalTests/GlobalSuppressions.cs +++ b/src/ApiService/FunctionalTests/GlobalSuppressions.cs @@ -6,3 +6,6 @@ using System.Diagnostics.CodeAnalysis; [assembly: SuppressMessage("Style", "IDE0005:Using directive is unnecessary.", Justification = "Test code")] +[assembly: SuppressMessage("Design", "CA1036:Override methods on comparable types", Justification = "Test code", Scope = "type", Target = "~T:FunctionalTests.Error")] +[assembly: SuppressMessage("Design", "CA1036:Override methods on comparable types", Justification = "Test code", Scope = "type", Target = "~T:FunctionalTests.Forward")] +[assembly: SuppressMessage("Design", "CA1036:Override methods on comparable types", Justification = "Test code", Scope = "type", Target = "~T:FunctionalTests.ProxyGetResult")] diff --git a/src/ApiService/FunctionalTests/TestNode.cs b/src/ApiService/FunctionalTests/TestNode.cs index 0994249b1..781996b54 100644 --- a/src/ApiService/FunctionalTests/TestNode.cs +++ b/src/ApiService/FunctionalTests/TestNode.cs @@ -8,11 +8,15 @@ namespace FunctionalTests { public class TestNode { NodeApi _nodeApi; + ScalesetApi _scalesetApi; + PoolApi _poolApi; private readonly ITestOutputHelper _output; public TestNode(ITestOutputHelper output) { _output = output; _nodeApi = new NodeApi(ApiClient.Endpoint, ApiClient.Request, output); + _scalesetApi = new ScalesetApi(ApiClient.Endpoint, ApiClient.Request, output); + _poolApi = new PoolApi(ApiClient.Endpoint, ApiClient.Request, output); } [Fact] @@ -34,5 +38,32 @@ namespace FunctionalTests { } + [Fact] + async Task GetPatchPostDelete() { + + var (pool, scaleset) = await Helpers.CreatePoolAndScaleset(_poolApi, _scalesetApi, "linux"); + + scaleset = await _scalesetApi.WaitWhile(scaleset.ScalesetId, sc => sc.State == "init" || sc.State == "setup"); + Assert.True(scaleset.Nodes!.Count > 0); + + var nodeState = scaleset.Nodes!.First(); + var nodeResult = await _nodeApi.Get(nodeState.MachineId); + + Assert.True(nodeResult.IsOk, $"failed to get node due to {nodeResult.ErrorV}"); + var node = nodeResult.OkV!.First(); + node = await _nodeApi.WaitWhile(node.MachineId, n => n.State == "init" || n.State == "setup"); + + var r = await _nodeApi.Patch(node.MachineId); + Assert.True(r.Result); + + var rr = await _nodeApi.Update(node.MachineId, false); + + var d = await _nodeApi.Delete(node.MachineId); + Assert.True(d.Result); + + var deletePool = await _poolApi.Delete(pool.Name); + Assert.True(deletePool.Result); + } + } } diff --git a/src/ApiService/FunctionalTests/TestPool.cs b/src/ApiService/FunctionalTests/TestPool.cs index 56fb7668d..01562a3e1 100644 --- a/src/ApiService/FunctionalTests/TestPool.cs +++ b/src/ApiService/FunctionalTests/TestPool.cs @@ -19,7 +19,7 @@ namespace FunctionalTests { [Fact] async Task GetNonExistentPool() { - var p = await _poolApi.Get(poolName: Guid.NewGuid().ToString()); + var p = await _poolApi.Get(name: Guid.NewGuid().ToString()); Assert.True(p.ErrorV!.UnableToFindPoolError); } diff --git a/src/ApiService/FunctionalTests/TestProxy.cs b/src/ApiService/FunctionalTests/TestProxy.cs index a2056a20f..e24a6f7ce 100644 --- a/src/ApiService/FunctionalTests/TestProxy.cs +++ b/src/ApiService/FunctionalTests/TestProxy.cs @@ -37,16 +37,7 @@ namespace FunctionalTests { [Fact] public async Task CreateResetDelete() { - var newPoolId = Guid.NewGuid().ToString(); - var newPoolName = PoolApi.TestPoolPrefix + newPoolId; - var newPool = await _poolApi.Create(newPoolName, "linux"); - - Assert.True(newPool.IsOk, $"failed to create new pool: {newPool.ErrorV}"); - - var newScalesetResult = await _scalesetApi.Create(newPool.OkV!.Name, 2); - - Assert.True(newScalesetResult.IsOk, $"failed to crate new scaleset: {newScalesetResult.ErrorV}"); - var newScaleset = newScalesetResult.OkV!; + var (newPool, newScaleset) = await Helpers.CreatePoolAndScaleset(_poolApi, _scalesetApi, "linux"); newScaleset = await _scalesetApi.WaitWhile(newScaleset.ScalesetId, sc => sc.State == "init" || sc.State == "setup"); @@ -81,12 +72,10 @@ namespace FunctionalTests { _output.WriteLine($"deleted proxy"); - var deletePool = await _poolApi.Delete(newPoolName); + var deletePool = await _poolApi.Delete(newPool.Name); Assert.True(deletePool.Result); - _output.WriteLine($"deleted pool {newPoolName}"); + _output.WriteLine($"deleted pool {newPool.Name}"); } - - } } diff --git a/src/ApiService/FunctionalTests/TestScaleset.cs b/src/ApiService/FunctionalTests/TestScaleset.cs index 4f3cf3b0d..fd700798f 100644 --- a/src/ApiService/FunctionalTests/TestScaleset.cs +++ b/src/ApiService/FunctionalTests/TestScaleset.cs @@ -34,18 +34,11 @@ namespace FunctionalTests { } } - [Fact] - public async Task CreateAndDelete() { - var newPoolId = Guid.NewGuid().ToString(); - var newPoolName = PoolApi.TestPoolPrefix + newPoolId; - var newPool = await _poolApi.Create(newPoolName, "linux"); + public async Task CreateAndDelete(string os) { + var (newPool, newScaleset) = await Helpers.CreatePoolAndScaleset(_poolApi, _scalesetApi, os); - Assert.True(newPool.IsOk, $"failed to create new pool: {newPool.ErrorV}"); - - var newScalesetResult = await _scalesetApi.Create(newPool.OkV!.Name, 2); - - Assert.True(newScalesetResult.IsOk, $"failed to crate new scaleset: {newScalesetResult.ErrorV}"); - var newScaleset = newScalesetResult.OkV!; + var newScalesetResultAgain = await _scalesetApi.Create(newPool.Name, 2); + var newScalesetResultAgainAgain = await _scalesetApi.Create(newPool.Name, 5); try { _output.WriteLine($"New scale set info id: {newScaleset.ScalesetId}, pool: {newScaleset.PoolName}, state: {newScaleset.State}, error: {newScaleset.Error}"); @@ -56,7 +49,7 @@ namespace FunctionalTests { var poolsCreated = await _poolApi.Get(); Assert.True(poolsCreated.IsOk, $"failed to get pools: {poolsCreated.ErrorV}"); - var newPools = poolsCreated.OkV!.Where(p => p.Name == newPoolName); + var newPools = poolsCreated.OkV!.Where(p => p.Name == newPool.Name); var newScalesets = scalesetsCreated.OkV!.Where(sc => sc.ScalesetId == newScaleset.ScalesetId); Assert.True(newPools.Count() == 1); @@ -94,31 +87,43 @@ namespace FunctionalTests { } } finally { var preDeleteScalesets = await _scalesetApi.Get(); - var deletedPoolResult = await _poolApi.Delete(newPoolName); + var deletedPoolResult = await _poolApi.Delete(newPool.Name); Assert.True(preDeleteScalesets.IsOk, $"failed to get pre-deleted scalesets due to: {preDeleteScalesets.ErrorV}"); - var preDelete = preDeleteScalesets.OkV!.Where(sc => sc.PoolName == newPoolName); - Assert.True(preDelete.Count() == 1); + var preDelete = preDeleteScalesets.OkV!.Where(sc => sc.PoolName == newPool.Name); + Assert.True(preDelete.Count() == 3); Result, Error> deletedPool; do { await Task.Delay(TimeSpan.FromSeconds(10.0)); - deletedPool = await _poolApi.Get(newPoolName); + deletedPool = await _poolApi.Get(newPool.Name); } while (deletedPool.IsOk); Assert.True(deletedPool.ErrorV!.UnableToFindPoolError); var postDeleteScalesets = await _scalesetApi.Get(); Assert.True(postDeleteScalesets.IsOk, $"failed to get scalesets after finishing pool deletion due to {postDeleteScalesets.ErrorV}"); - _output.WriteLine($"Pool is deleted {newPoolName}"); + _output.WriteLine($"Pool is deleted {newPool.Name}"); - var postDelete = postDeleteScalesets.OkV!.Where(sc => sc.PoolName == newPoolName); + var postDelete = postDeleteScalesets.OkV!.Where(sc => sc.PoolName == newPool.Name); Assert.False(postDelete.Any()); var patch1 = await _scalesetApi.Patch(newScaleset.ScalesetId, 1); Assert.False(patch1.IsOk); Assert.True(patch1.ErrorV!.UnableToFindScalesetError); } return; + + } + + + [Fact] + public async Task CreateAndDeleteLinux() { + await CreateAndDelete("linux"); + } + + [Fact] + public async Task CreateAndDeleteWindows() { + await CreateAndDelete("windows"); } } } diff --git a/src/ApiService/IntegrationTests/packages.lock.json b/src/ApiService/IntegrationTests/packages.lock.json index ba79ae0f3..4e78e7fd1 100644 --- a/src/ApiService/IntegrationTests/packages.lock.json +++ b/src/ApiService/IntegrationTests/packages.lock.json @@ -103,11 +103,11 @@ }, "Azure.ResourceManager.Compute": { "type": "Transitive", - "resolved": "1.0.0", - "contentHash": "dmDhokNFcyreIYZMkha8OsLmch0hW/sdOA2nxN4MPVd8KJgGWB8DxCZWwG7qhh59RInKtmWOP8BnBS5mN+W5wQ==", + "resolved": "1.0.0-beta.8", + "contentHash": "rYYjjmEdmcOa8O4UgO/bdJ/qQclNZjuHdalxRJ0AhUHCORcM1f1BbIKR9CoN83IpfuEE+X+n5XY9QZcKvfrGVA==", "dependencies": { - "Azure.Core": "1.25.0", - "Azure.ResourceManager": "1.2.0", + "Azure.Core": "1.24.0", + "Azure.ResourceManager": "1.0.0", "System.Text.Json": "4.7.2" } }, @@ -2153,7 +2153,7 @@ "Azure.Identity": "1.6.0", "Azure.Messaging.EventGrid": "4.10.0", "Azure.ResourceManager": "1.3.1", - "Azure.ResourceManager.Compute": "1.0.0", + "Azure.ResourceManager.Compute": "[1.0.0-beta.8, )", "Azure.ResourceManager.Monitor": "1.0.0-beta.2", "Azure.ResourceManager.Network": "1.0.0", "Azure.ResourceManager.Resources": "1.3.0", diff --git a/src/ApiService/Tests/packages.lock.json b/src/ApiService/Tests/packages.lock.json index 4676b47a2..2cc8b530c 100644 --- a/src/ApiService/Tests/packages.lock.json +++ b/src/ApiService/Tests/packages.lock.json @@ -131,11 +131,11 @@ }, "Azure.ResourceManager.Compute": { "type": "Transitive", - "resolved": "1.0.0", - "contentHash": "dmDhokNFcyreIYZMkha8OsLmch0hW/sdOA2nxN4MPVd8KJgGWB8DxCZWwG7qhh59RInKtmWOP8BnBS5mN+W5wQ==", + "resolved": "1.0.0-beta.8", + "contentHash": "rYYjjmEdmcOa8O4UgO/bdJ/qQclNZjuHdalxRJ0AhUHCORcM1f1BbIKR9CoN83IpfuEE+X+n5XY9QZcKvfrGVA==", "dependencies": { - "Azure.Core": "1.25.0", - "Azure.ResourceManager": "1.2.0", + "Azure.Core": "1.24.0", + "Azure.ResourceManager": "1.0.0", "System.Text.Json": "4.7.2" } }, @@ -2297,7 +2297,7 @@ "Azure.Identity": "1.6.0", "Azure.Messaging.EventGrid": "4.10.0", "Azure.ResourceManager": "1.3.1", - "Azure.ResourceManager.Compute": "1.0.0", + "Azure.ResourceManager.Compute": "[1.0.0-beta.8, )", "Azure.ResourceManager.Monitor": "1.0.0-beta.2", "Azure.ResourceManager.Network": "1.0.0", "Azure.ResourceManager.Resources": "1.3.0",