mirror of
https://github.com/microsoft/onefuzz.git
synced 2025-06-11 01:31:38 +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.Sdk" Version="1.3.0" OutputItemType="Analyzer" />
|
||||||
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.6.0" />
|
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.6.0" />
|
||||||
<PackageReference Include="Azure.Data.Tables" Version="12.5.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.Core" Version="1.25.0" />
|
||||||
<PackageReference Include="Azure.Identity" Version="1.6.0" />
|
<PackageReference Include="Azure.Identity" Version="1.6.0" />
|
||||||
<PackageReference Include="Azure.Messaging.EventGrid" Version="4.10.0" />
|
<PackageReference Include="Azure.Messaging.EventGrid" Version="4.10.0" />
|
||||||
|
@ -149,7 +149,7 @@ public class Proxy {
|
|||||||
return await _context.RequestHandling.NotOk(
|
return await _context.RequestHandling.NotOk(
|
||||||
req,
|
req,
|
||||||
request.ErrorV,
|
request.ErrorV,
|
||||||
"debug_proxy delet");
|
"debug_proxy delete");
|
||||||
}
|
}
|
||||||
|
|
||||||
var regions = await _context.ProxyForwardOperations.RemoveForward(
|
var regions = await _context.ProxyForwardOperations.RemoveForward(
|
||||||
|
@ -64,14 +64,16 @@ public class TimerProxy {
|
|||||||
// since we do not support bring your own NSG
|
// since we do not support bring your own NSG
|
||||||
|
|
||||||
if (await nsgOpertions.GetNsg(region) != null) {
|
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 subnet = await network.GetSubnet();
|
||||||
var vnet = await network.GetVnet();
|
if (subnet != null) {
|
||||||
if (subnet != null && vnet != null) {
|
var vnet = await network.GetVnet();
|
||||||
var result = await nsgOpertions.AssociateSubnet(region, vnet, subnet);
|
if (vnet != null) {
|
||||||
if (!result.OkV) {
|
var result = await nsgOpertions.AssociateSubnet(region, vnet, subnet);
|
||||||
_logger.Error($"Failed to associate NSG and subnet due to {result.ErrorV} in region {region}");
|
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
|
#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
|
//TODO: Add environment variable to control where to write logs to
|
||||||
public LogDestination[] LogDestinations { get; set; }
|
public LogDestination[] LogDestinations { get; set; }
|
||||||
|
|
||||||
//TODO: Get this from Environment variable
|
//TODO: Get this from Environment variable
|
||||||
public ApplicationInsights.DataContracts.SeverityLevel LogSeverityLevel => ApplicationInsights.DataContracts.SeverityLevel.Verbose;
|
public ApplicationInsights.DataContracts.SeverityLevel LogSeverityLevel => ApplicationInsights.DataContracts.SeverityLevel.Verbose;
|
||||||
|
|
||||||
public string? ApplicationInsightsAppId => Environment.GetEnvironmentVariable("APPINSIGHTS_APPID");
|
public string? ApplicationInsightsAppId => GetEnv("APPINSIGHTS_APPID");
|
||||||
public string? ApplicationInsightsInstrumentationKey => Environment.GetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY");
|
public string? ApplicationInsightsInstrumentationKey => GetEnv("APPINSIGHTS_INSTRUMENTATIONKEY");
|
||||||
|
|
||||||
public string? AzureSignalRConnectionString => Environment.GetEnvironmentVariable("AzureSignalRConnectionString");
|
public string? AzureSignalRConnectionString => GetEnv("AzureSignalRConnectionString");
|
||||||
public string? AzureSignalRServiceTransportType => Environment.GetEnvironmentVariable("AzureSignalRServiceTransportType");
|
public string? AzureSignalRServiceTransportType => GetEnv("AzureSignalRServiceTransportType");
|
||||||
|
|
||||||
public string? AzureWebJobDisableHomePage { get => Environment.GetEnvironmentVariable("AzureWebJobsDisableHomepage"); }
|
public string? AzureWebJobDisableHomePage { get => GetEnv("AzureWebJobsDisableHomepage"); }
|
||||||
public string? AzureWebJobStorage { get => Environment.GetEnvironmentVariable("AzureWebJobsStorage"); }
|
public string? AzureWebJobStorage { get => GetEnv("AzureWebJobsStorage"); }
|
||||||
|
|
||||||
public string? DiagnosticsAzureBlobContainerSasUrl { get => Environment.GetEnvironmentVariable("DIAGNOSTICS_AZUREBLOBCONTAINERSASURL"); }
|
public string? DiagnosticsAzureBlobContainerSasUrl { get => GetEnv("DIAGNOSTICS_AZUREBLOBCONTAINERSASURL"); }
|
||||||
public string? DiagnosticsAzureBlobRetentionDays { get => Environment.GetEnvironmentVariable("DIAGNOSTICS_AZUREBLOBRETENTIONINDAYS"); }
|
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? OneFuzzDataStorage { get => GetEnv("ONEFUZZ_DATA_STORAGE"); }
|
||||||
public string? OneFuzzFuncStorage { get => Environment.GetEnvironmentVariable("ONEFUZZ_FUNC_STORAGE"); }
|
public string? OneFuzzFuncStorage { get => GetEnv("ONEFUZZ_FUNC_STORAGE"); }
|
||||||
public string? OneFuzzInstance { get => Environment.GetEnvironmentVariable("ONEFUZZ_INSTANCE"); }
|
public string? OneFuzzInstance { get => GetEnv("ONEFUZZ_INSTANCE"); }
|
||||||
public string? OneFuzzInstanceName { get => Environment.GetEnvironmentVariable("ONEFUZZ_INSTANCE_NAME"); }
|
public string? OneFuzzInstanceName { get => GetEnv("ONEFUZZ_INSTANCE_NAME"); }
|
||||||
public string? OneFuzzKeyvault { get => Environment.GetEnvironmentVariable("ONEFUZZ_KEYVAULT"); }
|
public string? OneFuzzKeyvault { get => GetEnv("ONEFUZZ_KEYVAULT"); }
|
||||||
public string? OneFuzzMonitor { get => Environment.GetEnvironmentVariable("ONEFUZZ_MONITOR"); }
|
public string? OneFuzzMonitor { get => GetEnv("ONEFUZZ_MONITOR"); }
|
||||||
public string? OneFuzzOwner { get => Environment.GetEnvironmentVariable("ONEFUZZ_OWNER"); }
|
public string? OneFuzzOwner { get => GetEnv("ONEFUZZ_OWNER"); }
|
||||||
public string? OneFuzzResourceGroup { get => Environment.GetEnvironmentVariable("ONEFUZZ_RESOURCE_GROUP"); }
|
public string? OneFuzzResourceGroup { get => GetEnv("ONEFUZZ_RESOURCE_GROUP"); }
|
||||||
public string? OneFuzzTelemetry { get => Environment.GetEnvironmentVariable("ONEFUZZ_TELEMETRY"); }
|
public string? OneFuzzTelemetry { get => GetEnv("ONEFUZZ_TELEMETRY"); }
|
||||||
|
|
||||||
public string OneFuzzVersion {
|
public string OneFuzzVersion {
|
||||||
get {
|
get {
|
||||||
// version can be overridden by config:
|
// version can be overridden by config:
|
||||||
return Environment.GetEnvironmentVariable("ONEFUZZ_VERSION")
|
return GetEnv("ONEFUZZ_VERSION")
|
||||||
?? _oneFuzzVersion
|
?? _oneFuzzVersion
|
||||||
?? throw new InvalidOperationException("Unable to read OneFuzz version from assembly");
|
?? 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
|
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 resource = await uid.GetAsync();
|
||||||
var principalId = resource.Value.Data.Properties.ToObjectFromJson<ScaleSetIdentity>().principalId;
|
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;
|
namespace Microsoft.OneFuzz.Service;
|
||||||
|
|
||||||
public interface IDiskOperations {
|
public interface IDiskOperations {
|
||||||
DiskImageCollection ListDisks(string resourceGroup);
|
DiskCollection ListDisks(string resourceGroup);
|
||||||
|
|
||||||
Async.Task<bool> DeleteDisk(string resourceGroup, string name);
|
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) {
|
public async Task<bool> DeleteDisk(string resourceGroup, string name) {
|
||||||
try {
|
try {
|
||||||
_logTracer.Info($"deleting disks {resourceGroup} : {name}");
|
_logTracer.Info($"deleting disks {resourceGroup} : {name}");
|
||||||
var disk = await _creds.GetResourceGroupResource().GetDiskImageAsync(name);
|
var disk = await _creds.GetResourceGroupResource().GetDiskAsync(name);
|
||||||
if (disk != null) {
|
if (disk != null) {
|
||||||
await disk.Value.DeleteAsync(WaitUntil.Started);
|
await disk.Value.DeleteAsync(WaitUntil.Started);
|
||||||
return true;
|
return true;
|
||||||
@ -35,8 +35,8 @@ public class DiskOperations : IDiskOperations {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DiskImageCollection ListDisks(string resourceGroup) {
|
public DiskCollection ListDisks(string resourceGroup) {
|
||||||
_logTracer.Info($"listing disks {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";
|
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);
|
return await ConfigUrl(new Container("vm-scripts"), fileName, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,6 +265,7 @@ public class Extensions : IExtensions {
|
|||||||
await UpdateManagedScripts();
|
await UpdateManagedScripts();
|
||||||
var urlsUpdated = urls ?? new();
|
var urlsUpdated = urls ?? new();
|
||||||
|
|
||||||
|
var managedIdentity = JsonSerializer.Serialize(new { ManagedIdentity = new Dictionary<string, string>() }, _extensionSerializerOptions);
|
||||||
if (vmOs == Os.Windows) {
|
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 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");
|
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",
|
TypeHandlerVersion = "1.9",
|
||||||
AutoUpgradeMinorVersion = true,
|
AutoUpgradeMinorVersion = true,
|
||||||
Settings = new BinaryData(JsonSerializer.Serialize(new { commandToExecute = toExecuteCmd, fileUris = urlsUpdated }, _extensionSerializerOptions)),
|
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;
|
return extension;
|
||||||
} else if (vmOs == Os.Linux) {
|
} else if (vmOs == Os.Linux) {
|
||||||
@ -301,7 +303,6 @@ public class Extensions : IExtensions {
|
|||||||
|
|
||||||
var toExecuteCmd = $"sh setup.sh {mode.ToString().ToLowerInvariant()}";
|
var toExecuteCmd = $"sh setup.sh {mode.ToString().ToLowerInvariant()}";
|
||||||
var extensionSettings = JsonSerializer.Serialize(new { CommandToExecute = toExecuteCmd, FileUris = urlsUpdated }, _extensionSerializerOptions);
|
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 {
|
var extension = new VMExtensionWrapper {
|
||||||
Name = "CustomScript",
|
Name = "CustomScript",
|
||||||
@ -312,7 +313,7 @@ public class Extensions : IExtensions {
|
|||||||
ForceUpdateTag = Guid.NewGuid().ToString(),
|
ForceUpdateTag = Guid.NewGuid().ToString(),
|
||||||
AutoUpgradeMinorVersion = true,
|
AutoUpgradeMinorVersion = true,
|
||||||
Settings = new BinaryData(extensionSettings),
|
Settings = new BinaryData(extensionSettings),
|
||||||
ProtectedSettings = new BinaryData(protectedExtensionSettings)
|
ProtectedSettings = new BinaryData(managedIdentity)
|
||||||
};
|
};
|
||||||
return extension;
|
return extension;
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ public class ImageOperations : IImageOperations {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
name = (await _context.Creds.GetResourceGroupResource().GetDiskImages().GetAsync(
|
name = (await _context.Creds.GetResourceGroupResource().GetImages().GetAsync(
|
||||||
parsed.Data.Name
|
parsed.Data.Name
|
||||||
)).Value.Data.StorageProfile.OSDisk.OSType.ToString().ToLowerInvariant();
|
)).Value.Data.StorageProfile.OSDisk.OSType.ToString().ToLowerInvariant();
|
||||||
} catch (Exception ex) when (
|
} catch (Exception ex) when (
|
||||||
@ -96,15 +96,13 @@ public class ImageOperations : IImageOperations {
|
|||||||
version = imageInfo.Version;
|
version = imageInfo.Version;
|
||||||
}
|
}
|
||||||
|
|
||||||
var vmImage = await subscription.GetVirtualMachineImageAsync(
|
name = (await subscription.GetVirtualMachineImageAsync(
|
||||||
region,
|
region,
|
||||||
imageInfo.Publisher,
|
imageInfo.Publisher,
|
||||||
imageInfo.Offer,
|
imageInfo.Offer,
|
||||||
imageInfo.Sku
|
imageInfo.Sku
|
||||||
, version
|
, version
|
||||||
);
|
)).Value.OSDiskImageOperatingSystem.ToString().ToLower();
|
||||||
|
|
||||||
name = vmImage.Value.OSDiskImageOperatingSystem!.Value.ToString().ToLower();
|
|
||||||
} catch (RequestFailedException ex) {
|
} catch (RequestFailedException ex) {
|
||||||
return OneFuzzResult<Os>.Error(
|
return OneFuzzResult<Os>.Error(
|
||||||
ErrorCode.INVALID_IMAGE,
|
ErrorCode.INVALID_IMAGE,
|
||||||
|
@ -16,6 +16,8 @@ public interface IIpOperations {
|
|||||||
|
|
||||||
public Async.Task<string?> GetPublicIp(ResourceIdentifier resourceId);
|
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<PublicIPAddressResource?> GetIp(string resourceGroup, string name);
|
||||||
|
|
||||||
public Async.Task DeleteNic(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);
|
var ips = await _networkInterfaceQuery.ListInstancePrivateIps(scalesetId, instance.OkV);
|
||||||
return ips.FirstOrDefault();
|
return ips.FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
public async Task<string?> GetPublicIp(string resourceId) {
|
||||||
|
return await GetPublicIp(new ResourceIdentifier(resourceId));
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<string?> GetPublicIp(ResourceIdentifier resourceId) {
|
public async Task<string?> GetPublicIp(ResourceIdentifier resourceId) {
|
||||||
// TODO: Parts of this function seem redundant, but I'm mirroring
|
// 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) {
|
public async Task<OneFuzzResultVoid> CreatePublicNic(string resourceGroup, string name, string region, Nsg? nsg) {
|
||||||
_logTracer.Info($"creating nic for {resourceGroup}:{name} in {region}");
|
_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();
|
var subnetId = await network.GetId();
|
||||||
|
|
||||||
if (subnetId is null) {
|
if (subnetId is null) {
|
||||||
await network.Create();
|
var r = await network.Create();
|
||||||
return OneFuzzResultVoid.Ok;
|
if (!r.IsOk) {
|
||||||
|
_logTracer.Error($"failed to create network in region {region} due to {r.ErrorV}");
|
||||||
|
}
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nsg != null) {
|
if (nsg != null) {
|
||||||
|
@ -22,7 +22,7 @@ public class Network {
|
|||||||
_networkConfig = networkConfig;
|
_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 group = context.Creds.GetBaseResourceGroup();
|
||||||
var instanceConfig = await context.ConfigOperations.Fetch();
|
var instanceConfig = await context.ConfigOperations.Fetch();
|
||||||
var networkConfig = instanceConfig.NetworkConfig;
|
var networkConfig = instanceConfig.NetworkConfig;
|
||||||
|
@ -217,7 +217,7 @@ public class ProxyOperations : StatefulOrm<Proxy, VmState, ProxyOperations>, IPr
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach (var status in instanceView.Statuses) {
|
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}";
|
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.
|
//# This was done as part of the generated per-task setup script.
|
||||||
_logTracer.Info($"{SCALESET_LOG_PREFIX} setup. scalset_id: {scaleset.ScalesetId}");
|
_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();
|
var networkId = await network.GetId();
|
||||||
if (networkId is null) {
|
if (networkId is null) {
|
||||||
_logTracer.Info($"{SCALESET_LOG_PREFIX} creating network. region: {scaleset.Region} scaleset_id:{scaleset.ScalesetId}");
|
_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) {
|
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) {
|
if (vnet != null) {
|
||||||
return await vnet.GetSubnetAsync(subnetName);
|
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) {
|
public async Task<ResourceIdentifier?> GetSubnetId(string name, string subnetName) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Azure.Core;
|
using Azure.Core;
|
||||||
using Azure.ResourceManager.Compute;
|
using Azure.ResourceManager.Compute;
|
||||||
|
|
||||||
|
|
||||||
namespace Microsoft.OneFuzz.Service {
|
namespace Microsoft.OneFuzz.Service {
|
||||||
public class VMExtensionWrapper {
|
public class VMExtensionWrapper {
|
||||||
public AzureLocation? Location { get; init; }
|
public AzureLocation? Location { get; init; }
|
||||||
@ -27,7 +28,7 @@ namespace Microsoft.OneFuzz.Service {
|
|||||||
var protectedSettings = ProtectedSettings ?? new BinaryData(new Dictionary<string, string>());
|
var protectedSettings = ProtectedSettings ?? new BinaryData(new Dictionary<string, string>());
|
||||||
|
|
||||||
return (Name!, new VirtualMachineExtensionData(Location.Value) {
|
return (Name!, new VirtualMachineExtensionData(Location.Value) {
|
||||||
ExtensionType = TypePropertiesType,
|
TypePropertiesType = TypePropertiesType,
|
||||||
Publisher = Publisher,
|
Publisher = Publisher,
|
||||||
TypeHandlerVersion = TypeHandlerVersion,
|
TypeHandlerVersion = TypeHandlerVersion,
|
||||||
AutoUpgradeMinorVersion = AutoUpgradeMinorVersion,
|
AutoUpgradeMinorVersion = AutoUpgradeMinorVersion,
|
||||||
@ -49,7 +50,8 @@ namespace Microsoft.OneFuzz.Service {
|
|||||||
var protectedSettings = ProtectedSettings ?? new BinaryData(new Dictionary<string, string>());
|
var protectedSettings = ProtectedSettings ?? new BinaryData(new Dictionary<string, string>());
|
||||||
|
|
||||||
return new VirtualMachineScaleSetExtensionData() {
|
return new VirtualMachineScaleSetExtensionData() {
|
||||||
ExtensionType = TypePropertiesType,
|
Name = Name,
|
||||||
|
TypePropertiesType = TypePropertiesType,
|
||||||
Publisher = Publisher,
|
Publisher = Publisher,
|
||||||
TypeHandlerVersion = TypeHandlerVersion,
|
TypeHandlerVersion = TypeHandlerVersion,
|
||||||
AutoUpgradeMinorVersion = AutoUpgradeMinorVersion,
|
AutoUpgradeMinorVersion = AutoUpgradeMinorVersion,
|
||||||
@ -62,3 +64,4 @@ namespace Microsoft.OneFuzz.Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Azure;
|
using Azure;
|
||||||
using Azure.Core;
|
|
||||||
using Azure.ResourceManager.Compute;
|
using Azure.ResourceManager.Compute;
|
||||||
using Azure.ResourceManager.Compute.Models;
|
using Azure.ResourceManager.Compute.Models;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
@ -68,7 +67,7 @@ public class VmOperations : IVmOperations {
|
|||||||
public async Task<VirtualMachineData?> GetVm(string name) {
|
public async Task<VirtualMachineData?> GetVm(string name) {
|
||||||
// _logTracer.Debug($"getting vm: {name}");
|
// _logTracer.Debug($"getting vm: {name}");
|
||||||
try {
|
try {
|
||||||
var result = await _context.Creds.GetResourceGroupResource().GetVirtualMachineAsync(name, InstanceViewType.InstanceView);
|
var result = await _context.Creds.GetResourceGroupResource().GetVirtualMachineAsync(name, InstanceViewTypes.InstanceView);
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -256,20 +255,20 @@ public class VmOperations : IVmOperations {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var vmParams = new VirtualMachineData(location) {
|
var vmParams = new VirtualMachineData(location) {
|
||||||
OSProfile = new VirtualMachineOSProfile {
|
OSProfile = new OSProfile {
|
||||||
ComputerName = "node",
|
ComputerName = "node",
|
||||||
AdminUsername = "onefuzz",
|
AdminUsername = "onefuzz",
|
||||||
},
|
},
|
||||||
HardwareProfile = new VirtualMachineHardwareProfile {
|
HardwareProfile = new HardwareProfile {
|
||||||
VmSize = vmSku,
|
VmSize = vmSku,
|
||||||
},
|
},
|
||||||
StorageProfile = new VirtualMachineStorageProfile {
|
StorageProfile = new StorageProfile {
|
||||||
ImageReference = GenerateImageReference(image),
|
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);
|
var imageOs = await _context.ImageOperations.GetOs(location, image);
|
||||||
if (!imageOs.IsOk) {
|
if (!imageOs.IsOk) {
|
||||||
@ -286,7 +285,7 @@ public class VmOperations : IVmOperations {
|
|||||||
DisablePasswordAuthentication = true,
|
DisablePasswordAuthentication = true,
|
||||||
};
|
};
|
||||||
vmParams.OSProfile.LinuxConfiguration.SshPublicKeys.Add(
|
vmParams.OSProfile.LinuxConfiguration.SshPublicKeys.Add(
|
||||||
new SshPublicKeyConfiguration {
|
new SshPublicKeyInfo {
|
||||||
Path = "/home/onefuzz/.ssh/authorized_keys",
|
Path = "/home/onefuzz/.ssh/authorized_keys",
|
||||||
KeyData = sshPublicKey
|
KeyData = sshPublicKey
|
||||||
}
|
}
|
||||||
@ -333,7 +332,7 @@ public class VmOperations : IVmOperations {
|
|||||||
var imageRef = new ImageReference();
|
var imageRef = new ImageReference();
|
||||||
|
|
||||||
if (image.StartsWith("/", StringComparison.Ordinal)) {
|
if (image.StartsWith("/", StringComparison.Ordinal)) {
|
||||||
imageRef.Id = new ResourceIdentifier(image);
|
imageRef.Id = image;
|
||||||
} else {
|
} else {
|
||||||
var imageVal = image.Split(":", 4);
|
var imageVal = image.Split(":", 4);
|
||||||
imageRef.Publisher = imageVal[0];
|
imageRef.Publisher = imageVal[0];
|
||||||
|
@ -262,15 +262,15 @@ public class VmssOperations : IVmssOperations {
|
|||||||
Sku = new ComputeSku() { Name = vmSku, Capacity = vmCount },
|
Sku = new ComputeSku() { Name = vmSku, Capacity = vmCount },
|
||||||
Overprovision = false,
|
Overprovision = false,
|
||||||
SinglePlacementGroup = false,
|
SinglePlacementGroup = false,
|
||||||
UpgradePolicy = new VirtualMachineScaleSetUpgradePolicy() { Mode = VirtualMachineScaleSetUpgradeMode.Manual },
|
UpgradePolicy = new UpgradePolicy() { Mode = UpgradeMode.Manual },
|
||||||
Identity = new ManagedServiceIdentity(managedServiceIdentityType: ManagedServiceIdentityType.UserAssigned),
|
Identity = new ManagedServiceIdentity(managedServiceIdentityType: ManagedServiceIdentityType.UserAssigned),
|
||||||
};
|
};
|
||||||
vmssData.Identity.UserAssignedIdentities.Add(_creds.GetScalesetIdentityResourcePath(), new UserAssignedIdentity());
|
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();
|
var imageRef = new ImageReference();
|
||||||
|
|
||||||
if (image.StartsWith('/')) {
|
if (image.StartsWith('/')) {
|
||||||
imageRef.Id = new ResourceIdentifier(image);
|
imageRef.Id = image;
|
||||||
} else {
|
} else {
|
||||||
var info = IImageOperations.GetImageInfo(image);
|
var info = IImageOperations.GetImageInfo(image);
|
||||||
imageRef.Publisher = info.Publisher;
|
imageRef.Publisher = info.Publisher;
|
||||||
@ -303,7 +303,7 @@ public class VmssOperations : IVmssOperations {
|
|||||||
case Os.Linux:
|
case Os.Linux:
|
||||||
vmssData.VirtualMachineProfile.OSProfile.LinuxConfiguration = new LinuxConfiguration();
|
vmssData.VirtualMachineProfile.OSProfile.LinuxConfiguration = new LinuxConfiguration();
|
||||||
vmssData.VirtualMachineProfile.OSProfile.LinuxConfiguration.DisablePasswordAuthentication = true;
|
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);
|
vmssData.VirtualMachineProfile.OSProfile.LinuxConfiguration.SshPublicKeys.Add(i);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -311,10 +311,10 @@ public class VmssOperations : IVmssOperations {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ephemeralOsDisks) {
|
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 = new DiffDiskSettings();
|
||||||
vmssData.VirtualMachineProfile.StorageProfile.OSDisk.DiffDiskSettings.Option = DiffDiskOption.Local;
|
vmssData.VirtualMachineProfile.StorageProfile.OSDisk.DiffDiskSettings.Option = DiffDiskOptions.Local;
|
||||||
vmssData.VirtualMachineProfile.StorageProfile.OSDisk.Caching = CachingType.ReadOnly;
|
vmssData.VirtualMachineProfile.StorageProfile.OSDisk.Caching = CachingTypes.ReadOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spotInstance.HasValue && spotInstance.Value) {
|
if (spotInstance.HasValue && spotInstance.Value) {
|
||||||
@ -323,8 +323,8 @@ public class VmssOperations : IVmssOperations {
|
|||||||
//
|
//
|
||||||
// https://docs.microsoft.com/en-us/azure/
|
// https://docs.microsoft.com/en-us/azure/
|
||||||
// virtual-machine-scale-sets/use-spot#resource-manager-templates
|
// virtual-machine-scale-sets/use-spot#resource-manager-templates
|
||||||
vmssData.VirtualMachineProfile.EvictionPolicy = VirtualMachineEvictionPolicyType.Deallocate;
|
vmssData.VirtualMachineProfile.EvictionPolicy = VirtualMachineEvictionPolicyTypes.Deallocate;
|
||||||
vmssData.VirtualMachineProfile.Priority = VirtualMachinePriorityType.Spot;
|
vmssData.VirtualMachineProfile.Priority = VirtualMachinePriorityTypes.Spot;
|
||||||
vmssData.VirtualMachineProfile.BillingMaxPrice = 1.0;
|
vmssData.VirtualMachineProfile.BillingMaxPrice = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -370,14 +370,14 @@ public class VmssOperations : IVmssOperations {
|
|||||||
entry.SetAbsoluteExpiration(TimeSpan.FromMinutes(10));
|
entry.SetAbsoluteExpiration(TimeSpan.FromMinutes(10));
|
||||||
|
|
||||||
var sub = _creds.GetSubscriptionResource();
|
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>();
|
var skuNames = new List<string>();
|
||||||
await foreach (var sku in skus) {
|
await foreach (var sku in skus) {
|
||||||
var available = true;
|
var available = true;
|
||||||
if (sku.Restrictions is not null) {
|
if (sku.Restrictions is not null) {
|
||||||
foreach (var restriction in sku.Restrictions) {
|
foreach (var restriction in sku.Restrictions) {
|
||||||
if (restriction.RestrictionsType == ComputeResourceSkuRestrictionsType.Location &&
|
if (restriction.RestrictionsType == ResourceSkuRestrictionsType.Location &&
|
||||||
restriction.Values.Contains(region, StringComparer.OrdinalIgnoreCase)) {
|
restriction.Values.Contains(region, StringComparer.OrdinalIgnoreCase)) {
|
||||||
available = false;
|
available = false;
|
||||||
break;
|
break;
|
||||||
|
@ -65,12 +65,12 @@
|
|||||||
},
|
},
|
||||||
"Azure.ResourceManager.Compute": {
|
"Azure.ResourceManager.Compute": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[1.0.0, )",
|
"requested": "[1.0.0-beta.8, )",
|
||||||
"resolved": "1.0.0",
|
"resolved": "1.0.0-beta.8",
|
||||||
"contentHash": "dmDhokNFcyreIYZMkha8OsLmch0hW/sdOA2nxN4MPVd8KJgGWB8DxCZWwG7qhh59RInKtmWOP8BnBS5mN+W5wQ==",
|
"contentHash": "rYYjjmEdmcOa8O4UgO/bdJ/qQclNZjuHdalxRJ0AhUHCORcM1f1BbIKR9CoN83IpfuEE+X+n5XY9QZcKvfrGVA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Azure.Core": "1.25.0",
|
"Azure.Core": "1.24.0",
|
||||||
"Azure.ResourceManager": "1.2.0",
|
"Azure.ResourceManager": "1.0.0",
|
||||||
"System.Text.Json": "4.7.2"
|
"System.Text.Json": "4.7.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -5,11 +5,11 @@ using Xunit.Abstractions;
|
|||||||
|
|
||||||
namespace FunctionalTests;
|
namespace FunctionalTests;
|
||||||
|
|
||||||
interface IFromJsonElement<T> {
|
public interface IFromJsonElement<T> {
|
||||||
T Convert(JsonElement e);
|
T Convert(JsonElement e);
|
||||||
}
|
}
|
||||||
|
|
||||||
class BooleanResult : IFromJsonElement<BooleanResult> {
|
public class BooleanResult : IFromJsonElement<BooleanResult> {
|
||||||
JsonElement _e;
|
JsonElement _e;
|
||||||
public BooleanResult() { }
|
public BooleanResult() { }
|
||||||
public BooleanResult(JsonElement e) => _e = e;
|
public BooleanResult(JsonElement e) => _e = e;
|
||||||
@ -19,7 +19,7 @@ class BooleanResult : IFromJsonElement<BooleanResult> {
|
|||||||
public BooleanResult Convert(JsonElement e) => new BooleanResult(e);
|
public BooleanResult Convert(JsonElement e) => new BooleanResult(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class ApiBase {
|
public abstract class ApiBase {
|
||||||
|
|
||||||
Uri _endpoint;
|
Uri _endpoint;
|
||||||
Microsoft.OneFuzz.Service.Request _request;
|
Microsoft.OneFuzz.Service.Request _request;
|
||||||
|
@ -3,7 +3,7 @@ using Xunit;
|
|||||||
|
|
||||||
namespace FunctionalTests;
|
namespace FunctionalTests;
|
||||||
|
|
||||||
class Error : IComparable<Error>, IFromJsonElement<Error> {
|
public class Error : IComparable<Error>, IFromJsonElement<Error> {
|
||||||
JsonElement _e;
|
JsonElement _e;
|
||||||
|
|
||||||
public 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 _);
|
return res.ValueKind == JsonValueKind.Object && res.TryGetProperty("code", out _) && res.TryGetProperty("errors", out _);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int CompareTo(Error? error) {
|
public int CompareTo(Error? other) {
|
||||||
if (error is null) {
|
if (other is null) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
var sameErrorMessages = Errors.Count() == error.Errors.Count();
|
var sameErrorMessages = Errors.Count() == other.Errors.Count();
|
||||||
foreach (var s in error.Errors) {
|
foreach (var s in other.Errors) {
|
||||||
if (!sameErrorMessages) break;
|
if (!sameErrorMessages) break;
|
||||||
sameErrorMessages = Errors.Contains(s);
|
sameErrorMessages = Errors.Contains(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error.Code == this.Code && sameErrorMessages) {
|
if (other.Code == this.Code && sameErrorMessages) {
|
||||||
return 0;
|
return 0;
|
||||||
} else
|
} else
|
||||||
return 1;
|
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;
|
namespace FunctionalTests;
|
||||||
|
|
||||||
class Node : IFromJsonElement<Node> {
|
public class Node : IFromJsonElement<Node> {
|
||||||
JsonElement _e;
|
JsonElement _e;
|
||||||
|
|
||||||
public Node() { }
|
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) :
|
public NodeApi(Uri endpoint, Microsoft.OneFuzz.Service.Request request, ITestOutputHelper output) :
|
||||||
base(endpoint, "/api/Node", request, 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();
|
var j = new JsonObject();
|
||||||
if (debugKeepNode is not null)
|
if (debugKeepNode is not null)
|
||||||
j.Add("debug_keep_node", JsonValue.Create(debugKeepNode));
|
j.Add("debug_keep_node", JsonValue.Create(debugKeepNode));
|
||||||
|
|
||||||
j.Add("machine_id", JsonValue.Create(machineId));
|
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) {
|
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();
|
var j = new JsonObject();
|
||||||
@ -66,10 +66,10 @@ class NodeApi : ApiBase {
|
|||||||
return IEnumerableResult<Node>(await Get(j));
|
return IEnumerableResult<Node>(await Get(j));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<JsonElement> Patch(Guid machineId) {
|
public async Task<BooleanResult> Patch(Guid machineId) {
|
||||||
var j = new JsonObject();
|
var j = new JsonObject();
|
||||||
j.Add("machine_id", JsonValue.Create(machineId));
|
j.Add("machine_id", JsonValue.Create(machineId));
|
||||||
return await Patch(j);
|
return Return<BooleanResult>(await Patch(j));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<BooleanResult> Delete(Guid machineId) {
|
public async Task<BooleanResult> Delete(Guid machineId) {
|
||||||
|
@ -5,7 +5,7 @@ using Xunit.Abstractions;
|
|||||||
|
|
||||||
namespace FunctionalTests;
|
namespace FunctionalTests;
|
||||||
|
|
||||||
class Pool : IFromJsonElement<Pool> {
|
public class Pool : IFromJsonElement<Pool> {
|
||||||
|
|
||||||
JsonElement _e;
|
JsonElement _e;
|
||||||
|
|
||||||
@ -19,26 +19,30 @@ class Pool : IFromJsonElement<Pool> {
|
|||||||
public Pool Convert(JsonElement e) => new Pool(e);
|
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) :
|
public PoolApi(Uri endpoint, Microsoft.OneFuzz.Service.Request request, ITestOutputHelper output) :
|
||||||
base(endpoint, "/api/Pool", request, output) {
|
base(endpoint, "/api/Pool", request, output) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<BooleanResult> Delete(string name, bool now = true) {
|
public async Task<BooleanResult> Delete(string name, bool now = true) {
|
||||||
|
_output.WriteLine($"deleting pool: {name}, now: {now}");
|
||||||
var root = new JsonObject();
|
var root = new JsonObject();
|
||||||
root.Add("name", JsonValue.Create(name));
|
root.Add("name", JsonValue.Create(name));
|
||||||
root.Add("now", JsonValue.Create(now));
|
root.Add("now", JsonValue.Create(now));
|
||||||
return Return<BooleanResult>(await Delete(root));
|
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();
|
var root = new JsonObject();
|
||||||
root.Add("pool_id", poolId);
|
if (id is not null)
|
||||||
root.Add("name", poolName);
|
root.Add("pool_id", id);
|
||||||
root.Add("state", state);
|
if (name is not null)
|
||||||
|
root.Add("name", name);
|
||||||
|
if (state is not null)
|
||||||
|
root.Add("state", state);
|
||||||
|
|
||||||
var res = await Get(root);
|
var res = await Get(root);
|
||||||
return IEnumerableResult<Pool>(res);
|
return IEnumerableResult<Pool>(res);
|
||||||
@ -52,7 +56,6 @@ class PoolApi : ApiBase {
|
|||||||
|
|
||||||
foreach (var pool in pools.OkV) {
|
foreach (var pool in pools.OkV) {
|
||||||
if (pool.Name.StartsWith(TestPoolPrefix)) {
|
if (pool.Name.StartsWith(TestPoolPrefix)) {
|
||||||
_output.WriteLine($"Deleting {pool.Name}");
|
|
||||||
var deleted = await Delete(pool.Name);
|
var deleted = await Delete(pool.Name);
|
||||||
Assert.True(deleted.Result);
|
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") {
|
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();
|
var rootPoolCreate = new JsonObject();
|
||||||
rootPoolCreate.Add("name", poolName);
|
rootPoolCreate.Add("name", poolName);
|
||||||
rootPoolCreate.Add("os", os);
|
rootPoolCreate.Add("os", os);
|
||||||
|
@ -3,9 +3,7 @@ using System.Text.Json.Nodes;
|
|||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace FunctionalTests;
|
namespace FunctionalTests;
|
||||||
|
public class Proxy : IFromJsonElement<Proxy> {
|
||||||
|
|
||||||
class Proxy : IFromJsonElement<Proxy> {
|
|
||||||
|
|
||||||
JsonElement _e;
|
JsonElement _e;
|
||||||
public Proxy() { }
|
public Proxy() { }
|
||||||
@ -19,8 +17,7 @@ class Proxy : IFromJsonElement<Proxy> {
|
|||||||
public Proxy Convert(JsonElement e) => new Proxy(e);
|
public Proxy Convert(JsonElement e) => new Proxy(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class Forward : IFromJsonElement<Forward>, IComparable<Forward> {
|
||||||
class Forward : IFromJsonElement<Forward>, IComparable<Forward> {
|
|
||||||
JsonElement _e;
|
JsonElement _e;
|
||||||
public Forward() { }
|
public Forward() { }
|
||||||
public Forward(JsonElement e) => _e = e;
|
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;
|
JsonElement _e;
|
||||||
|
|
||||||
public ProxyGetResult() { }
|
public ProxyGetResult() { }
|
||||||
|
|
||||||
public ProxyGetResult(JsonElement e) => _e = e;
|
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"));
|
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) :
|
public ProxyApi(Uri endpoint, Microsoft.OneFuzz.Service.Request request, ITestOutputHelper output) :
|
||||||
base(endpoint, "/api/proxy", request, 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) {
|
public async Task<Result<IEnumerable<Proxy>, Error>> Get(Guid? scalesetId = null, Guid? machineId = null, int? dstPort = null) {
|
||||||
var root = new JsonObject();
|
var root = new JsonObject();
|
||||||
root.Add("scaleset_id", scalesetId);
|
if (scalesetId is not null)
|
||||||
root.Add("machine_id", machineId);
|
root.Add("scaleset_id", scalesetId);
|
||||||
root.Add("dst_port", dstPort);
|
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);
|
var r = await Get(root);
|
||||||
if (Error.IsError(r)) {
|
if (Error.IsError(r)) {
|
||||||
|
@ -4,10 +4,7 @@ using Xunit;
|
|||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace FunctionalTests;
|
namespace FunctionalTests;
|
||||||
|
public class Authentication {
|
||||||
|
|
||||||
|
|
||||||
class Authentication {
|
|
||||||
JsonElement _e;
|
JsonElement _e;
|
||||||
|
|
||||||
public Authentication() { }
|
public Authentication() { }
|
||||||
@ -20,7 +17,7 @@ class Authentication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ScalesetNodeState {
|
public class ScalesetNodeState {
|
||||||
JsonElement _e;
|
JsonElement _e;
|
||||||
|
|
||||||
public ScalesetNodeState() { }
|
public ScalesetNodeState() { }
|
||||||
@ -32,7 +29,7 @@ class ScalesetNodeState {
|
|||||||
public string? NodeState => _e.GetProperty("state").GetString();
|
public string? NodeState => _e.GetProperty("state").GetString();
|
||||||
}
|
}
|
||||||
|
|
||||||
class Scaleset : IFromJsonElement<Scaleset> {
|
public class Scaleset : IFromJsonElement<Scaleset> {
|
||||||
JsonElement _e;
|
JsonElement _e;
|
||||||
public Scaleset() { }
|
public Scaleset() { }
|
||||||
public Scaleset(JsonElement e) => _e = e;
|
public Scaleset(JsonElement e) => _e = e;
|
||||||
@ -68,9 +65,10 @@ class Scaleset : IFromJsonElement<Scaleset> {
|
|||||||
public Scaleset Convert(JsonElement e) => new Scaleset(e);
|
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 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) :
|
public ScalesetApi(Uri endpoint, Microsoft.OneFuzz.Service.Request request, ITestOutputHelper output) :
|
||||||
base(endpoint, "/api/Scaleset", request, 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) {
|
public async Task<Result<IEnumerable<Scaleset>, Error>> Get(Guid? id = null, string? state = null, bool? includeAuth = false) {
|
||||||
var root = new JsonObject();
|
var root = new JsonObject();
|
||||||
root.Add("scaleset_id", id);
|
if (id is not null)
|
||||||
root.Add("state", state);
|
root.Add("scaleset_id", id);
|
||||||
root.Add("include_auth", includeAuth);
|
if (state is not null)
|
||||||
|
root.Add("state", state);
|
||||||
|
if (includeAuth is not null)
|
||||||
|
root.Add("include_auth", includeAuth);
|
||||||
var res = await Get(root);
|
var res = await Get(root);
|
||||||
return IEnumerableResult<Scaleset>(res);
|
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();
|
var rootScalesetCreate = new JsonObject();
|
||||||
rootScalesetCreate.Add("pool_name", poolName);
|
rootScalesetCreate.Add("pool_name", poolName);
|
||||||
rootScalesetCreate.Add("vm_sku", vmSku);
|
rootScalesetCreate.Add("vm_sku", vmSku);
|
||||||
rootScalesetCreate.Add("image", image);
|
rootScalesetCreate.Add("image", image);
|
||||||
rootScalesetCreate.Add("size", size);
|
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();
|
var tags = new JsonObject();
|
||||||
tags.Add("Purpose", "Functional-Test");
|
tags.Add("Purpose", "Functional-Test");
|
||||||
|
@ -6,3 +6,6 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
[assembly: SuppressMessage("Style", "IDE0005:Using directive is unnecessary.", Justification = "Test code")]
|
[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 {
|
public class TestNode {
|
||||||
|
|
||||||
NodeApi _nodeApi;
|
NodeApi _nodeApi;
|
||||||
|
ScalesetApi _scalesetApi;
|
||||||
|
PoolApi _poolApi;
|
||||||
private readonly ITestOutputHelper _output;
|
private readonly ITestOutputHelper _output;
|
||||||
|
|
||||||
public TestNode(ITestOutputHelper output) {
|
public TestNode(ITestOutputHelper output) {
|
||||||
_output = output;
|
_output = output;
|
||||||
_nodeApi = new NodeApi(ApiClient.Endpoint, ApiClient.Request, 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]
|
[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]
|
[Fact]
|
||||||
async Task GetNonExistentPool() {
|
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);
|
Assert.True(p.ErrorV!.UnableToFindPoolError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,16 +37,7 @@ namespace FunctionalTests {
|
|||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task CreateResetDelete() {
|
public async Task CreateResetDelete() {
|
||||||
var newPoolId = Guid.NewGuid().ToString();
|
var (newPool, newScaleset) = await Helpers.CreatePoolAndScaleset(_poolApi, _scalesetApi, "linux");
|
||||||
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!;
|
|
||||||
|
|
||||||
newScaleset = await _scalesetApi.WaitWhile(newScaleset.ScalesetId, sc => sc.State == "init" || sc.State == "setup");
|
newScaleset = await _scalesetApi.WaitWhile(newScaleset.ScalesetId, sc => sc.State == "init" || sc.State == "setup");
|
||||||
|
|
||||||
@ -81,12 +72,10 @@ namespace FunctionalTests {
|
|||||||
|
|
||||||
_output.WriteLine($"deleted proxy");
|
_output.WriteLine($"deleted proxy");
|
||||||
|
|
||||||
var deletePool = await _poolApi.Delete(newPoolName);
|
var deletePool = await _poolApi.Delete(newPool.Name);
|
||||||
Assert.True(deletePool.Result);
|
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(string os) {
|
||||||
public async Task CreateAndDelete() {
|
var (newPool, newScaleset) = await Helpers.CreatePoolAndScaleset(_poolApi, _scalesetApi, os);
|
||||||
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 newScalesetResultAgain = await _scalesetApi.Create(newPool.Name, 2);
|
||||||
|
var newScalesetResultAgainAgain = await _scalesetApi.Create(newPool.Name, 5);
|
||||||
var newScalesetResult = await _scalesetApi.Create(newPool.OkV!.Name, 2);
|
|
||||||
|
|
||||||
Assert.True(newScalesetResult.IsOk, $"failed to crate new scaleset: {newScalesetResult.ErrorV}");
|
|
||||||
var newScaleset = newScalesetResult.OkV!;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
_output.WriteLine($"New scale set info id: {newScaleset.ScalesetId}, pool: {newScaleset.PoolName}, state: {newScaleset.State}, error: {newScaleset.Error}");
|
_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();
|
var poolsCreated = await _poolApi.Get();
|
||||||
Assert.True(poolsCreated.IsOk, $"failed to get pools: {poolsCreated.ErrorV}");
|
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);
|
var newScalesets = scalesetsCreated.OkV!.Where(sc => sc.ScalesetId == newScaleset.ScalesetId);
|
||||||
|
|
||||||
Assert.True(newPools.Count() == 1);
|
Assert.True(newPools.Count() == 1);
|
||||||
@ -94,31 +87,43 @@ namespace FunctionalTests {
|
|||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
var preDeleteScalesets = await _scalesetApi.Get();
|
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}");
|
Assert.True(preDeleteScalesets.IsOk, $"failed to get pre-deleted scalesets due to: {preDeleteScalesets.ErrorV}");
|
||||||
var preDelete = preDeleteScalesets.OkV!.Where(sc => sc.PoolName == newPoolName);
|
var preDelete = preDeleteScalesets.OkV!.Where(sc => sc.PoolName == newPool.Name);
|
||||||
Assert.True(preDelete.Count() == 1);
|
Assert.True(preDelete.Count() == 3);
|
||||||
|
|
||||||
Result<IEnumerable<Pool>, Error> deletedPool;
|
Result<IEnumerable<Pool>, Error> deletedPool;
|
||||||
do {
|
do {
|
||||||
await Task.Delay(TimeSpan.FromSeconds(10.0));
|
await Task.Delay(TimeSpan.FromSeconds(10.0));
|
||||||
deletedPool = await _poolApi.Get(newPoolName);
|
deletedPool = await _poolApi.Get(newPool.Name);
|
||||||
|
|
||||||
} while (deletedPool.IsOk);
|
} while (deletedPool.IsOk);
|
||||||
Assert.True(deletedPool.ErrorV!.UnableToFindPoolError);
|
Assert.True(deletedPool.ErrorV!.UnableToFindPoolError);
|
||||||
var postDeleteScalesets = await _scalesetApi.Get();
|
var postDeleteScalesets = await _scalesetApi.Get();
|
||||||
Assert.True(postDeleteScalesets.IsOk, $"failed to get scalesets after finishing pool deletion due to {postDeleteScalesets.ErrorV}");
|
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());
|
Assert.False(postDelete.Any());
|
||||||
var patch1 = await _scalesetApi.Patch(newScaleset.ScalesetId, 1);
|
var patch1 = await _scalesetApi.Patch(newScaleset.ScalesetId, 1);
|
||||||
Assert.False(patch1.IsOk);
|
Assert.False(patch1.IsOk);
|
||||||
Assert.True(patch1.ErrorV!.UnableToFindScalesetError);
|
Assert.True(patch1.ErrorV!.UnableToFindScalesetError);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CreateAndDeleteLinux() {
|
||||||
|
await CreateAndDelete("linux");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CreateAndDeleteWindows() {
|
||||||
|
await CreateAndDelete("windows");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,11 +103,11 @@
|
|||||||
},
|
},
|
||||||
"Azure.ResourceManager.Compute": {
|
"Azure.ResourceManager.Compute": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "1.0.0",
|
"resolved": "1.0.0-beta.8",
|
||||||
"contentHash": "dmDhokNFcyreIYZMkha8OsLmch0hW/sdOA2nxN4MPVd8KJgGWB8DxCZWwG7qhh59RInKtmWOP8BnBS5mN+W5wQ==",
|
"contentHash": "rYYjjmEdmcOa8O4UgO/bdJ/qQclNZjuHdalxRJ0AhUHCORcM1f1BbIKR9CoN83IpfuEE+X+n5XY9QZcKvfrGVA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Azure.Core": "1.25.0",
|
"Azure.Core": "1.24.0",
|
||||||
"Azure.ResourceManager": "1.2.0",
|
"Azure.ResourceManager": "1.0.0",
|
||||||
"System.Text.Json": "4.7.2"
|
"System.Text.Json": "4.7.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -2153,7 +2153,7 @@
|
|||||||
"Azure.Identity": "1.6.0",
|
"Azure.Identity": "1.6.0",
|
||||||
"Azure.Messaging.EventGrid": "4.10.0",
|
"Azure.Messaging.EventGrid": "4.10.0",
|
||||||
"Azure.ResourceManager": "1.3.1",
|
"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.Monitor": "1.0.0-beta.2",
|
||||||
"Azure.ResourceManager.Network": "1.0.0",
|
"Azure.ResourceManager.Network": "1.0.0",
|
||||||
"Azure.ResourceManager.Resources": "1.3.0",
|
"Azure.ResourceManager.Resources": "1.3.0",
|
||||||
|
@ -131,11 +131,11 @@
|
|||||||
},
|
},
|
||||||
"Azure.ResourceManager.Compute": {
|
"Azure.ResourceManager.Compute": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "1.0.0",
|
"resolved": "1.0.0-beta.8",
|
||||||
"contentHash": "dmDhokNFcyreIYZMkha8OsLmch0hW/sdOA2nxN4MPVd8KJgGWB8DxCZWwG7qhh59RInKtmWOP8BnBS5mN+W5wQ==",
|
"contentHash": "rYYjjmEdmcOa8O4UgO/bdJ/qQclNZjuHdalxRJ0AhUHCORcM1f1BbIKR9CoN83IpfuEE+X+n5XY9QZcKvfrGVA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Azure.Core": "1.25.0",
|
"Azure.Core": "1.24.0",
|
||||||
"Azure.ResourceManager": "1.2.0",
|
"Azure.ResourceManager": "1.0.0",
|
||||||
"System.Text.Json": "4.7.2"
|
"System.Text.Json": "4.7.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -2297,7 +2297,7 @@
|
|||||||
"Azure.Identity": "1.6.0",
|
"Azure.Identity": "1.6.0",
|
||||||
"Azure.Messaging.EventGrid": "4.10.0",
|
"Azure.Messaging.EventGrid": "4.10.0",
|
||||||
"Azure.ResourceManager": "1.3.1",
|
"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.Monitor": "1.0.0-beta.2",
|
||||||
"Azure.ResourceManager.Network": "1.0.0",
|
"Azure.ResourceManager.Network": "1.0.0",
|
||||||
"Azure.ResourceManager.Resources": "1.3.0",
|
"Azure.ResourceManager.Resources": "1.3.0",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user