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

Make EntityConverter singleton #2267

Merged
merged 6 commits into from
Aug 19, 2022
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
6 changes: 2 additions & 4 deletions src/ApiService/ApiService/Functions/AgentEvents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ public AgentEvents(ILogTracer log, IEndpointAuthorization auth, IOnefuzzContext
_context = context;
}

private static readonly EntityConverter _entityConverter = new();

[Function("AgentEvents")]
public Async.Task<HttpResponseData> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "POST", Route="agents/events")]
Expand All @@ -31,7 +29,7 @@ private async Async.Task<HttpResponseData> Post(HttpRequestData req) {
}

var envelope = request.OkV;
_log.Info($"node event: machine_id: {envelope.MachineId} event: {_entityConverter.ToJsonString(envelope)}");
_log.Info($"node event: machine_id: {envelope.MachineId} event: {EntityConverter.ToJsonString(envelope)}");

var error = envelope.Event switch {
NodeStateUpdate updateEvent => await OnStateUpdate(envelope.MachineId, updateEvent),
Expand Down Expand Up @@ -145,7 +143,7 @@ private async Async.Task<HttpResponseData> Post(HttpRequestData req) {
Error? error = null;
if (ev.Data is NodeDoneEventData doneData) {
if (doneData.Error is not null) {
var errorText = _entityConverter.ToJsonString(doneData);
var errorText = EntityConverter.ToJsonString(doneData);
error = new Error(ErrorCode.TASK_FAILED, Errors: new string[] { errorText });
_log.Error($"node 'done' with error: machine_id:{machineId}, data:{errorText}");
}
Expand Down
1 change: 1 addition & 0 deletions src/ApiService/ApiService/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ public async static Async.Task Main() {
.AddScoped<IAutoScaleOperations, AutoScaleOperations>()

.AddSingleton<ICreds, Creds>()
.AddSingleton<EntityConverter>()
.AddSingleton<IServiceConfig, ServiceConfiguration>()
.AddSingleton<IStorage, Storage>()
.AddSingleton<ILogSinks, LogSinks>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public async Task<HttpResponseData> Get([HttpTrigger(AuthorizationLevel.Anonymou
await resp.WriteAsJsonAsync(err);
return resp;
} else {
var str = (new EntityConverter()).ToJsonString(config);
var str = EntityConverter.ToJsonString(config);

var resp = req.CreateResponse(HttpStatusCode.OK);
await resp.WriteStringAsync(str);
Expand Down
6 changes: 5 additions & 1 deletion src/ApiService/ApiService/onefuzzlib/OnefuzzContext.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Microsoft.OneFuzz.Service;
using Microsoft.OneFuzz.Service.OneFuzzLib.Orm;

namespace Microsoft.OneFuzz.Service;

using Microsoft.Extensions.DependencyInjection;

Expand Down Expand Up @@ -40,6 +42,7 @@ public interface IOnefuzzContext {
INsgOperations NsgOperations { get; }
ISubnet Subnet { get; }
IImageOperations ImageOperations { get; }
EntityConverter EntityConverter { get; }
}

public class OnefuzzContext : IOnefuzzContext {
Expand Down Expand Up @@ -85,4 +88,5 @@ public OnefuzzContext(IServiceProvider serviceProvider) {
public INsgOperations NsgOperations => _serviceProvider.GetRequiredService<INsgOperations>();
public ISubnet Subnet => _serviceProvider.GetRequiredService<ISubnet>();
public IImageOperations ImageOperations => _serviceProvider.GetRequiredService<IImageOperations>();
public EntityConverter EntityConverter => _serviceProvider.GetRequiredService<EntityConverter>();
}
3 changes: 2 additions & 1 deletion src/ApiService/ApiService/onefuzzlib/ProxyOperations.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Threading.Tasks;
using ApiService.OneFuzzLib.Orm;
using Azure.Storage.Sas;
using Microsoft.OneFuzz.Service.OneFuzzLib.Orm;

namespace Microsoft.OneFuzz.Service;

Expand Down Expand Up @@ -105,7 +106,7 @@ public async Async.Task SaveProxyConfig(Proxy proxy) {
MicrosoftTelemetryKey: _context.ServiceConfiguration.OneFuzzTelemetry.EnsureNotNull("missing Telemetry"),
InstanceId: await _context.Containers.GetInstanceId());

await _context.Containers.SaveBlob(new Container("proxy-configs"), $"{proxy.Region}/{proxy.ProxyId}/config.json", _entityConverter.ToJsonString(proxyConfig), StorageType.Config);
await _context.Containers.SaveBlob(new Container("proxy-configs"), $"{proxy.Region}/{proxy.ProxyId}/config.json", EntityConverter.ToJsonString(proxyConfig), StorageType.Config);
}


Expand Down
1 change: 0 additions & 1 deletion src/ApiService/ApiService/onefuzzlib/WebhookOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ public async Task<EventPing> Ping(Webhook webhook) {

// Not converting to bytes, as it's not neccessary in C#. Just keeping as string.
public async Async.Task<Tuple<string, string?>> BuildMessage(Guid webhookId, Guid eventId, EventType eventType, BaseEvent webhookEvent, String? secretToken, WebhookMessageFormat? messageFormat) {
var entityConverter = new EntityConverter();
string data = "";
if (messageFormat != null && messageFormat == WebhookMessageFormat.EventGrid) {
var eventGridMessage = new[] { new WebhookMessageEventGrid(Id: eventId, Data: webhookEvent, DataVersion: "1.0.0", Subject: _context.Creds.GetInstanceName(), EventType: eventType, EventTime: DateTimeOffset.UtcNow) };
Expand Down
22 changes: 12 additions & 10 deletions src/ApiService/ApiService/onefuzzlib/orm/EntityConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,22 +88,24 @@ public override string ConvertName(string name) {
}
}
public class EntityConverter {
chkeita marked this conversation as resolved.
Show resolved Hide resolved
private readonly JsonSerializerOptions _options;

private readonly ConcurrentDictionary<Type, EntityInfo> _cache;
private static readonly JsonSerializerOptions _options;

static EntityConverter() {
_options = new JsonSerializerOptions() {
PropertyNamingPolicy = new OnefuzzNamingPolicy(),
};
_options.Converters.Add(new CustomEnumConverterFactory());
_options.Converters.Add(new PolymorphicConverterFactory());
}

public EntityConverter() {
_options = GetJsonSerializerOptions();
_cache = new ConcurrentDictionary<Type, EntityInfo>();
}

public static JsonSerializerOptions GetJsonSerializerOptions() {
var options = new JsonSerializerOptions() {
PropertyNamingPolicy = new OnefuzzNamingPolicy(),
};
options.Converters.Add(new CustomEnumConverterFactory());
options.Converters.Add(new PolymorphicConverterFactory());
return options;
return _options;
}

internal static Func<object?[], object> BuildConstructerFrom(ConstructorInfo constructorInfo) {
Expand Down Expand Up @@ -167,9 +169,9 @@ private EntityInfo GetEntityInfo<T>() {
});
}

public string ToJsonString<T>(T typedEntity) => JsonSerializer.Serialize(typedEntity, _options);
public static string ToJsonString<T>(T typedEntity) => JsonSerializer.Serialize(typedEntity, _options);

public T? FromJsonString<T>(string value) => JsonSerializer.Deserialize<T>(value, _options);
public static T? FromJsonString<T>(string value) => JsonSerializer.Deserialize<T>(value, _options);

public TableEntity ToTableEntity<T>(T typedEntity) where T : EntityBase {
if (typedEntity == null) {
Expand Down
2 changes: 1 addition & 1 deletion src/ApiService/ApiService/onefuzzlib/orm/Orm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public class Orm<T> : IOrm<T> where T : EntityBase {
public Orm(ILogTracer logTracer, IOnefuzzContext context) {
_context = context;
_logTracer = logTracer;
_entityConverter = new EntityConverter();
_entityConverter = _context.EntityConverter;
}

public async IAsyncEnumerable<T> QueryAsync(string? filter = null) {
Expand Down
8 changes: 4 additions & 4 deletions src/ApiService/IntegrationTests/Fakes/TestContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,12 @@ namespace IntegrationTests.Fakes;
// of functions as unit or integration tests.
public sealed class TestContext : IOnefuzzContext {
public TestContext(ILogTracer logTracer, IStorage storage, ICreds creds, string storagePrefix) {
EntityConverter = new EntityConverter();
ServiceConfiguration = new TestServiceConfiguration(storagePrefix);

Storage = storage;
Creds = creds;
Containers = new Containers(logTracer, Storage, Creds, ServiceConfiguration);
Queue = new Queue(Storage, logTracer);

RequestHandling = new RequestHandling(logTracer);
TaskOperations = new TaskOperations(logTracer, this);
NodeOperations = new NodeOperations(logTracer, this);
Expand All @@ -28,9 +27,7 @@ public TestContext(ILogTracer logTracer, IStorage storage, ICreds creds, string
ConfigOperations = new ConfigOperations(logTracer, this);
PoolOperations = new PoolOperations(logTracer, this);
ScalesetOperations = new ScalesetOperations(logTracer, this);

UserCredentials = new UserCredentials(logTracer, ConfigOperations);

}

public TestEvents Events { get; set; } = new();
Expand Down Expand Up @@ -71,6 +68,7 @@ public Async.Task InsertAll(params EntityBase[] objs)
public IConfigOperations ConfigOperations { get; }
public IPoolOperations PoolOperations { get; }
public IScalesetOperations ScalesetOperations { get; }
public EntityConverter EntityConverter { get; }

// -- Remainder not implemented --

Expand Down Expand Up @@ -113,4 +111,6 @@ public Async.Task InsertAll(params EntityBase[] objs)
public ISubnet Subnet => throw new NotImplementedException();

public IImageOperations ImageOperations => throw new NotImplementedException();


}
2 changes: 1 addition & 1 deletion src/ApiService/IntegrationTests/_FunctionTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ protected static string BodyAsString(HttpResponseData data) {
}

protected static T BodyAs<T>(HttpResponseData data)
=> new EntityConverter().FromJsonString<T>(BodyAsString(data)) ?? throw new Exception($"unable to deserialize body as {typeof(T)}");
=> EntityConverter.FromJsonString<T>(BodyAsString(data)) ?? throw new Exception($"unable to deserialize body as {typeof(T)}");

public void Dispose() {
GC.SuppressFinalize(this);
Expand Down
4 changes: 2 additions & 2 deletions src/ApiService/Tests/RequestsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
namespace Tests;

// This class contains tests for serialization and
// deserialization of examples generated by the
// deserialization of examples generated by the
// onefuzz-agent’s `debug` sub-command. We test each
// example for roundtripping which ensures that no
// data is lost upon deserialization.
Expand All @@ -25,7 +25,7 @@ public class RequestsTests {
private static JsonSerializerOptions serializationOptions() {
// base on the serialization options used at runtime, but
// also indent to match inputs:
var result = EntityConverter.GetJsonSerializerOptions();
var result = new JsonSerializerOptions(EntityConverter.GetJsonSerializerOptions());
result.WriteIndented = true;
return result;
}
Expand Down