Skip to content
This repository has been archived by the owner on Nov 1, 2023. It is now read-only.

Add extensions functionality for C# refactor #2218

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/ApiService/ApiService/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ public async static Async.Task Main() {
.AddScoped<INodeTasksOperations, NodeTasksOperations>()
.AddScoped<INodeMessageOperations, NodeMessageOperations>()
.AddScoped<IRequestHandling, RequestHandling>()
.AddScoped<IImageOperations, ImageOperations>()
.AddScoped<IOnefuzzContext, OnefuzzContext>()
.AddScoped<IEndpointAuthorization, EndpointAuthorization>()
.AddScoped<INodeMessageOperations, NodeMessageOperations>()
Expand Down
255 changes: 178 additions & 77 deletions src/ApiService/ApiService/onefuzzlib/Extension.cs

Large diffs are not rendered by default.

115 changes: 115 additions & 0 deletions src/ApiService/ApiService/onefuzzlib/ImageOperations.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
using System.Threading.Tasks;
using Azure;
using Azure.ResourceManager.Compute;

namespace Microsoft.OneFuzz.Service;

public interface IImageOperations {
public Async.Task<OneFuzzResult<Os>> GetOs(string region, string image);
}

public class ImageOperations : IImageOperations {
private IOnefuzzContext _context;
private ILogTracer _logTracer;

public ImageOperations(ILogTracer logTracer, IOnefuzzContext context) {
_logTracer = logTracer;
_context = context;
}
public async Task<OneFuzzResult<Os>> GetOs(string region, string image) {
string? name = null;
try {
var parsed = _context.Creds.ParseResourceId(image);
parsed = await _context.Creds.GetData(parsed);
if (string.Equals(parsed.Id.ResourceType, "galleries", StringComparison.OrdinalIgnoreCase)) {
try {
// This is not _exactly_ the same as the python code
// because in C# we don't have access to child_name_1
var gallery = await _context.Creds.GetResourceGroupResource().GetGalleries().GetAsync(
parsed.Data.Name
);

var galleryImage = gallery.Value.GetGalleryImages()
.ToEnumerable()
.Where(galleryImage => string.Equals(galleryImage.Id, parsed.Id, StringComparison.OrdinalIgnoreCase))
.First();

galleryImage = await galleryImage.GetAsync();

name = galleryImage.Data?.OSType?.ToString().ToLowerInvariant()!;

} catch (Exception ex) when (
ex is RequestFailedException ||
ex is NullReferenceException
) {
return OneFuzzResult<Os>.Error(
ErrorCode.INVALID_IMAGE,
ex.ToString()
);
}
} else {
try {
name = (await _context.Creds.GetResourceGroupResource().GetImages().GetAsync(
parsed.Data.Name
)).Value.Data.StorageProfile.OSDisk.OSType.ToString().ToLowerInvariant();
} catch (Exception ex) when (
ex is RequestFailedException ||
ex is NullReferenceException
) {
return OneFuzzResult<Os>.Error(
ErrorCode.INVALID_IMAGE,
ex.ToString()
);
}
}
} catch (FormatException) {
var imageParts = image.Split(":");

// The python code would throw if more than 4 parts are found in the split
System.Diagnostics.Trace.Assert(imageParts.Length == 4, $"Expected 4 ':' separated parts in {image}");

var publisher = imageParts[0];
var offer = imageParts[1];
var sku = imageParts[2];
var version = imageParts[3];

try {
var subscription = await _context.Creds.ArmClient.GetDefaultSubscriptionAsync();
if (string.Equals(version, "latest", StringComparison.Ordinal)) {
version = (await subscription.GetVirtualMachineImagesAsync(
region,
publisher,
offer,
sku,
top: 1
).FirstAsync()).Name;
}

name = (await subscription.GetVirtualMachineImageAsync(
region,
publisher,
offer,
sku
, version
)).Value.OSDiskImageOperatingSystem.ToString().ToLower();
} catch (RequestFailedException ex) {
return OneFuzzResult<Os>.Error(
ErrorCode.INVALID_IMAGE,
ex.ToString()
);
}
}

if (name != null) {
name = string.Concat(name[0].ToString().ToUpper(), name.AsSpan(1));
if (Enum.TryParse(name, out Os os)) {
return OneFuzzResult<Os>.Ok(os);
}
}

return OneFuzzResult<Os>.Error(
ErrorCode.INVALID_IMAGE,
$"Unexpected image os type: {name}"
);
}
}
2 changes: 2 additions & 0 deletions src/ApiService/ApiService/onefuzzlib/OnefuzzContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public interface IOnefuzzContext {
IRequestHandling RequestHandling { get; }
INsgOperations NsgOperations { get; }
ISubnet Subnet { get; }
IImageOperations ImageOperations { get; }
}

public class OnefuzzContext : IOnefuzzContext {
Expand Down Expand Up @@ -81,4 +82,5 @@ public OnefuzzContext(IServiceProvider serviceProvider) {
public IRequestHandling RequestHandling => _serviceProvider.GetRequiredService<IRequestHandling>();
public INsgOperations NsgOperations => _serviceProvider.GetRequiredService<INsgOperations>();
public ISubnet Subnet => _serviceProvider.GetRequiredService<ISubnet>();
public IImageOperations ImageOperations => _serviceProvider.GetRequiredService<IImageOperations>();
}
11 changes: 11 additions & 0 deletions src/ApiService/ApiService/onefuzzlib/Reports.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.OneFuzz.Service.OneFuzzLib.Orm;

namespace Microsoft.OneFuzz.Service;

public interface IReports {
public Async.Task<IReport?> GetReportOrRegression(Container container, string fileName, bool expectReports = false, params string[] args);
public Async.Task<Report?> GetReport(Container container, string fileName);
}

public class Reports : IReports {
Expand All @@ -15,6 +17,15 @@ public Reports(ILogTracer log, IContainers containers) {
_containers = containers;
}

public async Task<Report?> GetReport(Container container, string fileName) {
var result = await GetReportOrRegression(container, fileName);
if (result != null && result is Report) {
return result as Report;
}

return null;
}

public async Async.Task<IReport?> GetReportOrRegression(Container container, string fileName, bool expectReports = false, params string[] args) {
var filePath = String.Join("/", new[] { container.ContainerName, fileName });
if (!fileName.EndsWith(".json", StringComparison.Ordinal)) {
Expand Down
62 changes: 62 additions & 0 deletions src/ApiService/ApiService/onefuzzlib/VmExtensionWrapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using Azure.Core;
using Azure.ResourceManager.Compute;

namespace Microsoft.OneFuzz.Service {
public class VMExtensionWrapper {
public AzureLocation? Location { get; init; }
public string? Name { get; init; }
public string? TypePropertiesType { get; init; }
public string? Publisher { get; init; }
public string? TypeHandlerVersion { get; init; }
public string? ForceUpdateTag { get; init; }
public bool? AutoUpgradeMinorVersion { get; init; }
public bool? EnableAutomaticUpgrade { get; init; }
public BinaryData? Settings { get; init; }
public BinaryData? ProtectedSettings { get; init; }

public (string, VirtualMachineExtensionData) GetAsVirtualMachineExtension() {
tevoinea marked this conversation as resolved.
Show resolved Hide resolved
if (Location == null) { // EnsureNotNull does not satisfy the nullability checker
throw new ArgumentNullException("Location required for VirtualMachineExtension");
}
TypePropertiesType.EnsureNotNull("TypePropertiesType required for VirtualMachineExtension");
Publisher.EnsureNotNull("Publisher required for VirtualMachineExtension");
TypeHandlerVersion.EnsureNotNull("TypeHandlerVersion required for VirtualMachineExtension");
AutoUpgradeMinorVersion.EnsureNotNull("AutoUpgradeMinorVersion required for VirtualMachineExtension");
Settings.EnsureNotNull("Settings required for VirtualMachineExtension");
ProtectedSettings.EnsureNotNull("ProtectedSettings required for VirtualMachineExtension");

return (Name!, new VirtualMachineExtensionData(Location.Value) {
TypePropertiesType = TypePropertiesType,
Publisher = Publisher,
TypeHandlerVersion = TypeHandlerVersion,
AutoUpgradeMinorVersion = AutoUpgradeMinorVersion,
EnableAutomaticUpgrade = EnableAutomaticUpgrade,
ForceUpdateTag = ForceUpdateTag,
Settings = Settings,
ProtectedSettings = ProtectedSettings
});
}

public VirtualMachineScaleSetExtensionData GetAsVirtualMachineScaleSetExtension() {
Name.EnsureNotNull("Name required for VirtualMachineScaleSetExtension");
TypePropertiesType.EnsureNotNull("TypePropertiesType required for VirtualMachineScaleSetExtension");
Publisher.EnsureNotNull("Publisher required for VirtualMachineScaleSetExtension");
TypeHandlerVersion.EnsureNotNull("TypeHandlerVersion required for VirtualMachineScaleSetExtension");
AutoUpgradeMinorVersion.EnsureNotNull("AutoUpgradeMinorVersion required for VirtualMachineScaleSetExtension");
Settings.EnsureNotNull("Settings required for VirtualMachineScaleSetExtension");
ProtectedSettings.EnsureNotNull("ProtectedSettings required for VirtualMachineScaleSetExtension");
return new VirtualMachineScaleSetExtensionData() {
Name = Name,
TypePropertiesType = TypePropertiesType,
Publisher = Publisher,
TypeHandlerVersion = TypeHandlerVersion,
AutoUpgradeMinorVersion = AutoUpgradeMinorVersion,
EnableAutomaticUpgrade = EnableAutomaticUpgrade,
ForceUpdateTag = ForceUpdateTag,
Settings = Settings,
ProtectedSettings = ProtectedSettings
};
}
}

}
2 changes: 2 additions & 0 deletions src/ApiService/ApiService/onefuzzlib/orm/Orm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,8 @@ public StatefulOrm(ILogTracer logTracer, IOnefuzzContext context) : base(logTrac
if (func != null) {
_logTracer.Info($"processing state update: {typeof(T)} - PartitionKey {_partitionKeyGetter?.Value()} {_rowKeyGetter?.Value()} - %s");
return await func(entity);
} else {
_logTracer.Info($"State function for state: '{state}' not found on type {typeof(T)}");
}
return null;
}
Expand Down
2 changes: 2 additions & 0 deletions src/ApiService/IntegrationTests/Fakes/TestContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,6 @@ public Async.Task InsertAll(params EntityBase[] objs)
public INsgOperations NsgOperations => throw new NotImplementedException();

public ISubnet Subnet => throw new NotImplementedException();

public IImageOperations ImageOperations => throw new NotImplementedException();
}