mirror of
https://github.com/microsoft/onefuzz.git
synced 2025-06-10 01:01:34 +00:00
Functional tests (#2333)
* more tests * revert compute, since "released" version has bug when creating scaleset extensions * format * found bug, i think... * now should be fixed Co-authored-by: stas <statis@microsoft.com>
This commit is contained in:
parent
c54db04083
commit
ee1ad0abd8
@ -24,7 +24,7 @@
|
||||
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.3.0" OutputItemType="Analyzer" />
|
||||
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.6.0" />
|
||||
<PackageReference Include="Azure.Data.Tables" Version="12.5.0" />
|
||||
<PackageReference Include="Azure.ResourceManager.Compute" Version="1.0.0" />
|
||||
<PackageReference Include="Azure.ResourceManager.Compute" Version="1.0.0-beta.8" />
|
||||
<PackageReference Include="Azure.Core" Version="1.25.0" />
|
||||
<PackageReference Include="Azure.Identity" Version="1.6.0" />
|
||||
<PackageReference Include="Azure.Messaging.EventGrid" Version="4.10.0" />
|
||||
|
@ -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(
|
||||
|
@ -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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ public sealed class Creds : ICreds {
|
||||
|
||||
var resource = await uid.GetAsync();
|
||||
var principalId = resource.Value.Data.Properties.ToObjectFromJson<ScaleSetIdentity>().principalId;
|
||||
return new Guid(principalId);
|
||||
return Guid.Parse(principalId);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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<bool> DeleteDisk(string resourceGroup, string name);
|
||||
}
|
||||
@ -23,7 +23,7 @@ public class DiskOperations : IDiskOperations {
|
||||
public async Task<bool> 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();
|
||||
}
|
||||
}
|
||||
|
@ -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<string, string>() }, _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<string, string>() }, _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<string, string>() }, _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;
|
||||
}
|
||||
|
@ -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<Os>.Error(
|
||||
ErrorCode.INVALID_IMAGE,
|
||||
|
@ -16,6 +16,8 @@ public interface IIpOperations {
|
||||
|
||||
public Async.Task<string?> GetPublicIp(ResourceIdentifier resourceId);
|
||||
|
||||
public Async.Task<string?> GetPublicIp(string resourceId);
|
||||
|
||||
public Async.Task<PublicIPAddressResource?> 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<string?> GetPublicIp(string resourceId) {
|
||||
return await GetPublicIp(new ResourceIdentifier(resourceId));
|
||||
}
|
||||
|
||||
public async Task<string?> 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<OneFuzzResultVoid> 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) {
|
||||
|
@ -22,7 +22,7 @@ public class Network {
|
||||
_networkConfig = networkConfig;
|
||||
}
|
||||
|
||||
public static async Async.Task<Network> Create(string region, IOnefuzzContext context) {
|
||||
public static async Async.Task<Network> Init(string region, IOnefuzzContext context) {
|
||||
var group = context.Creds.GetBaseResourceGroup();
|
||||
var instanceConfig = await context.ConfigOperations.Fetch();
|
||||
var networkConfig = instanceConfig.NetworkConfig;
|
||||
|
@ -217,7 +217,7 @@ public class ProxyOperations : StatefulOrm<Proxy, VmState, ProxyOperations>, 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}";
|
||||
}
|
||||
}
|
||||
|
@ -198,7 +198,7 @@ public class ScalesetOperations : StatefulOrm<Scaleset, ScalesetState, ScalesetO
|
||||
//# This was done as part of the generated per-task setup script.
|
||||
_logTracer.Info($"{SCALESET_LOG_PREFIX} setup. scalset_id: {scaleset.ScalesetId}");
|
||||
|
||||
var network = await Network.Create(scaleset.Region, _context);
|
||||
var network = await Network.Init(scaleset.Region, _context);
|
||||
var networkId = await network.GetId();
|
||||
if (networkId is null) {
|
||||
_logTracer.Info($"{SCALESET_LOG_PREFIX} creating network. region: {scaleset.Region} scaleset_id:{scaleset.ScalesetId}");
|
||||
|
@ -68,12 +68,17 @@ public class Subnet : ISubnet {
|
||||
}
|
||||
|
||||
public async Async.Task<SubnetResource?> 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<ResourceIdentifier?> GetSubnetId(string name, string subnetName) {
|
||||
|
@ -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<string, string>());
|
||||
|
||||
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<string, string>());
|
||||
|
||||
return new VirtualMachineScaleSetExtensionData() {
|
||||
ExtensionType = TypePropertiesType,
|
||||
Name = Name,
|
||||
TypePropertiesType = TypePropertiesType,
|
||||
Publisher = Publisher,
|
||||
TypeHandlerVersion = TypeHandlerVersion,
|
||||
AutoUpgradeMinorVersion = AutoUpgradeMinorVersion,
|
||||
@ -62,3 +64,4 @@ namespace Microsoft.OneFuzz.Service {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -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<VirtualMachineData?> 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];
|
||||
|
@ -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<string>();
|
||||
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;
|
||||
|
@ -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"
|
||||
}
|
||||
},
|
||||
|
@ -5,11 +5,11 @@ using Xunit.Abstractions;
|
||||
|
||||
namespace FunctionalTests;
|
||||
|
||||
interface IFromJsonElement<T> {
|
||||
public interface IFromJsonElement<T> {
|
||||
T Convert(JsonElement e);
|
||||
}
|
||||
|
||||
class BooleanResult : IFromJsonElement<BooleanResult> {
|
||||
public class BooleanResult : IFromJsonElement<BooleanResult> {
|
||||
JsonElement _e;
|
||||
public BooleanResult() { }
|
||||
public BooleanResult(JsonElement e) => _e = e;
|
||||
@ -19,7 +19,7 @@ class BooleanResult : IFromJsonElement<BooleanResult> {
|
||||
public BooleanResult Convert(JsonElement e) => new BooleanResult(e);
|
||||
}
|
||||
|
||||
abstract class ApiBase {
|
||||
public abstract class ApiBase {
|
||||
|
||||
Uri _endpoint;
|
||||
Microsoft.OneFuzz.Service.Request _request;
|
||||
|
@ -3,7 +3,7 @@ using Xunit;
|
||||
|
||||
namespace FunctionalTests;
|
||||
|
||||
class Error : IComparable<Error>, IFromJsonElement<Error> {
|
||||
public class Error : IComparable<Error>, IFromJsonElement<Error> {
|
||||
JsonElement _e;
|
||||
|
||||
public Error(JsonElement e) {
|
||||
@ -21,18 +21,18 @@ class Error : IComparable<Error>, IFromJsonElement<Error> {
|
||||
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;
|
||||
|
28
src/ApiService/FunctionalTests/1f-api/Helpers.cs
Normal file
28
src/ApiService/FunctionalTests/1f-api/Helpers.cs
Normal file
@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ using Xunit.Abstractions;
|
||||
|
||||
namespace FunctionalTests;
|
||||
|
||||
class Node : IFromJsonElement<Node> {
|
||||
public class Node : IFromJsonElement<Node> {
|
||||
JsonElement _e;
|
||||
|
||||
public Node() { }
|
||||
@ -35,19 +35,19 @@ class Node : IFromJsonElement<Node> {
|
||||
}
|
||||
|
||||
|
||||
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<JsonElement> Update(Guid machineId, bool? debugKeepNode = null) {
|
||||
public async Task<BooleanResult> 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<BooleanResult>(await Post(j));
|
||||
}
|
||||
public async Task<Result<IEnumerable<Node>, Error>> Get(Guid? machineId = null, List<string>? state = null, Guid? scalesetId = null, string? poolName = null) {
|
||||
var j = new JsonObject();
|
||||
@ -66,10 +66,10 @@ class NodeApi : ApiBase {
|
||||
return IEnumerableResult<Node>(await Get(j));
|
||||
}
|
||||
|
||||
public async Task<JsonElement> Patch(Guid machineId) {
|
||||
public async Task<BooleanResult> Patch(Guid machineId) {
|
||||
var j = new JsonObject();
|
||||
j.Add("machine_id", JsonValue.Create(machineId));
|
||||
return await Patch(j);
|
||||
return Return<BooleanResult>(await Patch(j));
|
||||
}
|
||||
|
||||
public async Task<BooleanResult> Delete(Guid machineId) {
|
||||
|
@ -5,7 +5,7 @@ using Xunit.Abstractions;
|
||||
|
||||
namespace FunctionalTests;
|
||||
|
||||
class Pool : IFromJsonElement<Pool> {
|
||||
public class Pool : IFromJsonElement<Pool> {
|
||||
|
||||
JsonElement _e;
|
||||
|
||||
@ -19,26 +19,30 @@ class Pool : IFromJsonElement<Pool> {
|
||||
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<BooleanResult> 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<BooleanResult>(await Delete(root));
|
||||
}
|
||||
|
||||
public async Task<Result<IEnumerable<Pool>, Error>> Get(string? poolName = null, string? poolId = null, string? state = null) {
|
||||
public async Task<Result<IEnumerable<Pool>, 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<Pool>(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<Result<Pool, Error>> 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);
|
||||
|
@ -3,9 +3,7 @@ using System.Text.Json.Nodes;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace FunctionalTests;
|
||||
|
||||
|
||||
class Proxy : IFromJsonElement<Proxy> {
|
||||
public class Proxy : IFromJsonElement<Proxy> {
|
||||
|
||||
JsonElement _e;
|
||||
public Proxy() { }
|
||||
@ -19,8 +17,7 @@ class Proxy : IFromJsonElement<Proxy> {
|
||||
public Proxy Convert(JsonElement e) => new Proxy(e);
|
||||
}
|
||||
|
||||
|
||||
class Forward : IFromJsonElement<Forward>, IComparable<Forward> {
|
||||
public class Forward : IFromJsonElement<Forward>, IComparable<Forward> {
|
||||
JsonElement _e;
|
||||
public Forward() { }
|
||||
public Forward(JsonElement e) => _e = e;
|
||||
@ -43,14 +40,27 @@ class Forward : IFromJsonElement<Forward>, IComparable<Forward> {
|
||||
}
|
||||
}
|
||||
|
||||
class ProxyGetResult : IFromJsonElement<ProxyGetResult>, IComparable<ProxyGetResult> {
|
||||
public class ProxyGetResult : IFromJsonElement<ProxyGetResult>, IComparable<ProxyGetResult> {
|
||||
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<ProxyGetResult>, IComparable<ProxyGetRes
|
||||
}
|
||||
|
||||
|
||||
class ProxyApi : ApiBase {
|
||||
public class ProxyApi : ApiBase {
|
||||
|
||||
public ProxyApi(Uri endpoint, Microsoft.OneFuzz.Service.Request request, ITestOutputHelper output) :
|
||||
base(endpoint, "/api/proxy", request, output) {
|
||||
@ -84,9 +94,12 @@ class ProxyApi : ApiBase {
|
||||
|
||||
public async Task<Result<IEnumerable<Proxy>, 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)) {
|
||||
|
@ -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<Scaleset> {
|
||||
public class Scaleset : IFromJsonElement<Scaleset> {
|
||||
JsonElement _e;
|
||||
public Scaleset() { }
|
||||
public Scaleset(JsonElement e) => _e = e;
|
||||
@ -68,9 +65,10 @@ class Scaleset : IFromJsonElement<Scaleset> {
|
||||
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<Result<IEnumerable<Scaleset>, 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<Scaleset>(res);
|
||||
}
|
||||
|
||||
public async Task<Result<Scaleset, Error>> Create(string poolName, int size, string vmSku = "Standard_D2s_v3", string image = Image_Ubuntu_20_04, bool spotInstance = false) {
|
||||
public async Task<Result<Scaleset, Error>> 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");
|
||||
|
@ -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")]
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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}");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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<IEnumerable<Pool>, 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
Loading…
x
Reference in New Issue
Block a user