- Move some persistent resources into SingletonResources class (#1835)

- Rename ResultOk to ResultVoid

Move environment variables to singleton

Co-authored-by: stas <statis@microsoft.com>
This commit is contained in:
Stas
2022-04-22 17:40:11 -07:00
committed by GitHub
parent 62d824383a
commit e86854cf2a
22 changed files with 192 additions and 158 deletions

View File

@ -1,65 +0,0 @@
namespace Microsoft.OneFuzz.Service;
public enum LogDestination
{
Console,
AppInsights,
}
public static class EnvironmentVariables
{
static EnvironmentVariables()
{
#if DEBUG
LogDestinations = new LogDestination[] { LogDestination.AppInsights, LogDestination.Console };
#else
LogDestinations = new LogDestination[] { LogDestination.AppInsights };
#endif
}
//TODO: Add environment variable to control where to write logs to
public static LogDestination[] LogDestinations { get; set; }
//TODO: Get this from Environment variable
public static ApplicationInsights.DataContracts.SeverityLevel LogSeverityLevel() { return ApplicationInsights.DataContracts.SeverityLevel.Verbose; }
public static class AppInsights
{
public static string? AppId { get => Environment.GetEnvironmentVariable("APPINSIGHTS_APPID"); }
public static string? InstrumentationKey { get => Environment.GetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY"); }
}
public static class AzureSignalR
{
public static string? ConnectionString { get => Environment.GetEnvironmentVariable("AzureSignalRConnectionString"); }
public static string? ServiceTransportType { get => Environment.GetEnvironmentVariable("AzureSignalRServiceTransportType"); }
}
public static class AzureWebJob
{
public static string? DisableHomePage { get => Environment.GetEnvironmentVariable("AzureWebJobsDisableHomepage"); }
public static string? Storage { get => Environment.GetEnvironmentVariable("AzureWebJobsStorage"); }
}
public static class DiagnosticsAzureBlob
{
public static string? ContainerSasUrl { get => Environment.GetEnvironmentVariable("DIAGNOSTICS_AZUREBLOBCONTAINERSASURL"); }
public static string? RetentionDays { get => Environment.GetEnvironmentVariable("DIAGNOSTICS_AZUREBLOBRETENTIONINDAYS"); }
}
public static string? MultiTenantDomain { get => Environment.GetEnvironmentVariable("MULTI_TENANT_DOMAIN"); }
public static class OneFuzz
{
public static string? DataStorage { get => Environment.GetEnvironmentVariable("ONEFUZZ_DATA_STORAGE"); }
public static string? FuncStorage { get => Environment.GetEnvironmentVariable("ONEFUZZ_FUNC_STORAGE"); }
public static string? Instance { get => Environment.GetEnvironmentVariable("ONEFUZZ_INSTANCE"); }
public static string? InstanceName { get => Environment.GetEnvironmentVariable("ONEFUZZ_INSTANCE_NAME"); }
public static string? Keyvault { get => Environment.GetEnvironmentVariable("ONEFUZZ_KEYVAULT"); }
public static string? Monitor { get => Environment.GetEnvironmentVariable("ONEFUZZ_MONITOR"); }
public static string? Owner { get => Environment.GetEnvironmentVariable("ONEFUZZ_OWNER"); }
public static string? ResourceGroup { get => Environment.GetEnvironmentVariable("ONEFUZZ_RESOURCE_GROUP"); }
public static string? Telemetry { get => Environment.GetEnvironmentVariable("ONEFUZZ_TELEMETRY"); }
}
}

View File

@ -8,22 +8,23 @@ using AccessToken = String;
public class Request public class Request
{ {
private static HttpClient httpClient = new HttpClient(); private readonly HttpClient _httpClient;
Func<Task<(TokenType, AccessToken)>>? auth; Func<Task<(TokenType, AccessToken)>>? _auth;
public Request(Func<Task<(TokenType, AccessToken)>>? auth = null) public Request(HttpClient httpClient, Func<Task<(TokenType, AccessToken)>>? auth = null)
{ {
this.auth = auth; _auth = auth;
_httpClient = httpClient;
} }
private async Task<HttpResponseMessage> Send(HttpMethod method, Uri url, HttpContent? content = null, IDictionary<string, string>? headers = null) private async Task<HttpResponseMessage> Send(HttpMethod method, Uri url, HttpContent? content = null, IDictionary<string, string>? headers = null)
{ {
var request = new HttpRequestMessage(method: method, requestUri: url); var request = new HttpRequestMessage(method: method, requestUri: url);
if (auth is not null) if (_auth is not null)
{ {
var (tokenType, accessToken) = await auth(); var (tokenType, accessToken) = await _auth();
request.Headers.Authorization = new AuthenticationHeaderValue(tokenType, accessToken); request.Headers.Authorization = new AuthenticationHeaderValue(tokenType, accessToken);
} }
@ -40,7 +41,7 @@ public class Request
} }
} }
return await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); return await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
} }
public async Task<HttpResponseMessage> Get(Uri url) public async Task<HttpResponseMessage> Get(Uri url)

View File

@ -16,16 +16,19 @@ public interface ILog
class AppInsights : ILog class AppInsights : ILog
{ {
private TelemetryClient telemetryClient = private TelemetryClient _telemetryClient;
new TelemetryClient(
new TelemetryConfiguration(EnvironmentVariables.AppInsights.InstrumentationKey)); public AppInsights(string instrumentationKey)
{
_telemetryClient = new TelemetryClient(new TelemetryConfiguration(instrumentationKey));
}
public void Log(Guid correlationId, String message, SeverityLevel level, IReadOnlyDictionary<string, string> tags, string? caller) public void Log(Guid correlationId, String message, SeverityLevel level, IReadOnlyDictionary<string, string> tags, string? caller)
{ {
Dictionary<string, string> copyTags = new(tags); Dictionary<string, string> copyTags = new(tags);
copyTags["Correlation ID"] = correlationId.ToString(); copyTags["Correlation ID"] = correlationId.ToString();
if (caller is not null) copyTags["CalledBy"] = caller; if (caller is not null) copyTags["CalledBy"] = caller;
telemetryClient.TrackTrace(message, level, copyTags); _telemetryClient.TrackTrace(message, level, copyTags);
} }
public void LogEvent(Guid correlationId, String evt, IReadOnlyDictionary<string, string> tags, IReadOnlyDictionary<string, double>? metrics, string? caller) public void LogEvent(Guid correlationId, String evt, IReadOnlyDictionary<string, string> tags, IReadOnlyDictionary<string, double>? metrics, string? caller)
{ {
@ -39,7 +42,7 @@ class AppInsights : ILog
copyMetrics = new(metrics); copyMetrics = new(metrics);
} }
telemetryClient.TrackEvent(evt, properties: copyTags, metrics: copyMetrics); _telemetryClient.TrackEvent(evt, properties: copyTags, metrics: copyMetrics);
} }
public void LogException(Guid correlationId, Exception ex, IReadOnlyDictionary<string, string> tags, IReadOnlyDictionary<string, double>? metrics, string? caller) public void LogException(Guid correlationId, Exception ex, IReadOnlyDictionary<string, string> tags, IReadOnlyDictionary<string, double>? metrics, string? caller)
{ {
@ -52,12 +55,12 @@ class AppInsights : ILog
{ {
copyMetrics = new(metrics); copyMetrics = new(metrics);
} }
telemetryClient.TrackException(ex, copyTags, copyMetrics); _telemetryClient.TrackException(ex, copyTags, copyMetrics);
} }
public void Flush() public void Flush()
{ {
telemetryClient.Flush(); _telemetryClient.Flush();
} }
} }

View File

@ -352,7 +352,7 @@ public record InstanceConfig
//# At the moment, this only checks allowed_aad_tenants, however adding //# At the moment, this only checks allowed_aad_tenants, however adding
//# support for 3rd party JWT validation is anticipated in a future release. //# support for 3rd party JWT validation is anticipated in a future release.
public ResultOk<List<string>> CheckInstanceConfig() public ResultVoid<List<string>> CheckInstanceConfig()
{ {
List<string> errors = new(); List<string> errors = new();
if (AllowedAadTenants.Length == 0) if (AllowedAadTenants.Length == 0)
@ -361,11 +361,11 @@ public record InstanceConfig
} }
if (errors.Count == 0) if (errors.Count == 0)
{ {
return ResultOk<List<string>>.Ok(); return ResultVoid<List<string>>.Ok();
} }
else else
{ {
return ResultOk<List<string>>.Error(errors); return ResultVoid<List<string>>.Error(errors);
} }
} }
} }

View File

@ -1,17 +1,17 @@
namespace Microsoft.OneFuzz.Service namespace Microsoft.OneFuzz.Service
{ {
public struct ResultOk<T_Error> public struct ResultVoid<T_Error>
{ {
public static ResultOk<T_Error> Ok() => new(); public static ResultVoid<T_Error> Ok() => new();
public static ResultOk<T_Error> Error(T_Error err) => new(err); public static ResultVoid<T_Error> Error(T_Error err) => new(err);
readonly T_Error? error; readonly T_Error? error;
readonly bool isOk; readonly bool isOk;
public ResultOk() => (error, isOk) = (default, true); public ResultVoid() => (error, isOk) = (default, true);
public ResultOk(T_Error error) => (this.error, isOk) = (error, false); public ResultVoid(T_Error error) => (this.error, isOk) = (error, false);
public bool IsOk => isOk; public bool IsOk => isOk;

View File

@ -37,15 +37,15 @@ public class Program
} }
public static List<ILog> GetLoggers() public static List<ILog> GetLoggers(IServiceConfig config)
{ {
List<ILog> loggers = new List<ILog>(); List<ILog> loggers = new List<ILog>();
foreach (var dest in EnvironmentVariables.LogDestinations) foreach (var dest in config.LogDestinations)
{ {
loggers.Add( loggers.Add(
dest switch dest switch
{ {
LogDestination.AppInsights => new AppInsights(), LogDestination.AppInsights => new AppInsights(config.ApplicationInsightsInstrumentationKey!),
LogDestination.Console => new Console(), LogDestination.Console => new Console(),
_ => throw new Exception($"Unhandled Log Destination type: {dest}"), _ => throw new Exception($"Unhandled Log Destination type: {dest}"),
} }
@ -66,14 +66,14 @@ public class Program
) )
.ConfigureServices((context, services) => .ConfigureServices((context, services) =>
services services
.AddScoped<ILogTracer>(s => new LogTracerFactory(GetLoggers()).CreateLogTracer(Guid.Empty, severityLevel: EnvironmentVariables.LogSeverityLevel())) .AddScoped<ILogTracer>(s =>
new LogTracerFactory(GetLoggers(s.GetService<IServiceConfig>()!)).CreateLogTracer(Guid.Empty, severityLevel: s.GetService<IServiceConfig>()!.LogSeverityLevel))
.AddScoped<INodeOperations, NodeOperations>() .AddScoped<INodeOperations, NodeOperations>()
.AddScoped<IEvents, Events>() .AddScoped<IEvents, Events>()
.AddScoped<IWebhookOperations, WebhookOperations>() .AddScoped<IWebhookOperations, WebhookOperations>()
.AddScoped<IWebhookMessageLogOperations, WebhookMessageLogOperations>() .AddScoped<IWebhookMessageLogOperations, WebhookMessageLogOperations>()
.AddScoped<ITaskOperations, TaskOperations>() .AddScoped<ITaskOperations, TaskOperations>()
.AddScoped<IQueue, Queue>() .AddScoped<IQueue, Queue>()
.AddScoped<ICreds, Creds>()
.AddScoped<IStorage, Storage>() .AddScoped<IStorage, Storage>()
.AddScoped<IProxyOperations, ProxyOperations>() .AddScoped<IProxyOperations, ProxyOperations>()
.AddScoped<IConfigOperations, ConfigOperations>() .AddScoped<IConfigOperations, ConfigOperations>()
@ -83,9 +83,11 @@ public class Program
.AddScoped<INotificationOperations, NotificationOperations>() .AddScoped<INotificationOperations, NotificationOperations>()
.AddScoped<IUserCredentials, UserCredentials>() .AddScoped<IUserCredentials, UserCredentials>()
//TODO: move out expensive resources into separate class, and add those as Singleton
// ArmClient, Table Client(s), Queue Client(s), HttpClient, etc.
//Move out expensive resources into separate class, and add those as Singleton
// ArmClient, Table Client(s), Queue Client(s), HttpClient, etc.
.AddSingleton<ICreds, Creds>()
.AddSingleton<IServiceConfig, ServiceConfiguration>()
) )
.Build(); .Build();

View File

@ -0,0 +1,82 @@
namespace Microsoft.OneFuzz.Service;
public enum LogDestination
{
Console,
AppInsights,
}
public interface IServiceConfig
{
public LogDestination[] LogDestinations { get; set; }
public ApplicationInsights.DataContracts.SeverityLevel LogSeverityLevel { get; }
public string? ApplicationInsightsAppId { get; }
public string? ApplicationInsightsInstrumentationKey { get; }
public string? AzureSignalRConnectionString { get; }
public string? AzureSignalRServiceTransportType { get; }
public string? AzureWebJobDisableHomePage { get; }
public string? AzureWebJobStorage { get; }
public string? DiagnosticsAzureBlobContainerSasUrl { get; }
public string? DiagnosticsAzureBlobRetentionDays { get; }
public string? MultiTenantDomain { get; }
public string? OneFuzzDataStorage { get; }
public string? OneFuzzFuncStorage { get; }
public string? OneFuzzInstance { get; }
public string? OneFuzzInstanceName { get; }
public string? OneFuzzKeyvault { get; }
public string? OneFuzzMonitor { get; }
public string? OneFuzzOwner { get; }
public string? OneFuzzResourceGroup { get; }
public string? OneFuzzTelemetry { get; }
}
public class ServiceConfiguration : IServiceConfig
{
public ServiceConfiguration()
{
#if DEBUG
LogDestinations = new LogDestination[] { LogDestination.AppInsights, LogDestination.Console };
#else
LogDestinations = new LogDestination[] { LogDestination.AppInsights };
#endif
}
//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? AzureSignalRConnectionString => Environment.GetEnvironmentVariable("AzureSignalRConnectionString");
public string? AzureSignalRServiceTransportType => Environment.GetEnvironmentVariable("AzureSignalRServiceTransportType");
public string? AzureWebJobDisableHomePage { get => Environment.GetEnvironmentVariable("AzureWebJobsDisableHomepage"); }
public string? AzureWebJobStorage { get => Environment.GetEnvironmentVariable("AzureWebJobsStorage"); }
public string? DiagnosticsAzureBlobContainerSasUrl { get => Environment.GetEnvironmentVariable("DIAGNOSTICS_AZUREBLOBCONTAINERSASURL"); }
public string? DiagnosticsAzureBlobRetentionDays { get => Environment.GetEnvironmentVariable("DIAGNOSTICS_AZUREBLOBRETENTIONINDAYS"); }
public string? MultiTenantDomain { get => Environment.GetEnvironmentVariable("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"); }
}

View File

@ -7,20 +7,20 @@ using Microsoft.OneFuzz.Service.OneFuzzLib.Orm;
namespace Microsoft.OneFuzz.Service; namespace Microsoft.OneFuzz.Service;
public record FunctionInfo(string Name, string ResourceGroup, string? SlotName); public record FunctionInfo(string Name, string ResourceGroup, string? SlotName);
public class TestHooks public class TestHooks
{ {
private readonly ILogTracer _log; private readonly ILogTracer _log;
private readonly IConfigOperations _configOps; private readonly IConfigOperations _configOps;
private readonly IEvents _events; private readonly IEvents _events;
private readonly IServiceConfig _config;
public TestHooks(ILogTracer log, IConfigOperations configOps, IEvents events) public TestHooks(ILogTracer log, IConfigOperations configOps, IEvents events, IServiceConfig config)
{ {
_log = log; _log = log;
_configOps = configOps; _configOps = configOps;
_events = events; _events = events;
_config = config;
} }
[Function("Info")] [Function("Info")]
@ -29,8 +29,8 @@ public class TestHooks
_log.Info("Creating function info response"); _log.Info("Creating function info response");
var response = req.CreateResponse(); var response = req.CreateResponse();
FunctionInfo info = new( FunctionInfo info = new(
$"{EnvironmentVariables.OneFuzz.InstanceName}", $"{_config.OneFuzzInstanceName}",
$"{EnvironmentVariables.OneFuzz.ResourceGroup}", $"{_config.OneFuzzResourceGroup}",
Environment.GetEnvironmentVariable("WEBSITE_SLOT_NAME")); Environment.GetEnvironmentVariable("WEBSITE_SLOT_NAME"));
_log.Info("Returning function info"); _log.Info("Returning function info");

View File

@ -27,7 +27,7 @@ public class Containers : IContainers
_log = log; _log = log;
_storage = storage; _storage = storage;
_creds = creds; _creds = creds;
_armClient = new ArmClient(credential: _creds.GetIdentity(), defaultSubscriptionId: _creds.GetSubcription()); _armClient = creds.ArmClient;
} }
public async Task<IEnumerable<byte>?> GetBlob(Container container, string name, StorageType storageType) public async Task<IEnumerable<byte>?> GetBlob(Container container, string name, StorageType storageType)
{ {

View File

@ -23,26 +23,27 @@ public interface ICreds
public class Creds : ICreds public class Creds : ICreds
{ {
private readonly Lazy<ArmClient> _armClient; private readonly ArmClient _armClient;
private readonly DefaultAzureCredential _azureCredential;
private readonly IServiceConfig _config;
public ArmClient ArmClient => _armClient.Value; public ArmClient ArmClient => _armClient;
public Creds() public Creds(IServiceConfig config)
{ {
_armClient = new Lazy<ArmClient>(() => new ArmClient(this.GetIdentity(), this.GetSubcription()), true); _armClient = new ArmClient(this.GetIdentity(), this.GetSubcription());
_azureCredential = new DefaultAzureCredential();
_config = config;
} }
// TODO: @cached
public DefaultAzureCredential GetIdentity() public DefaultAzureCredential GetIdentity()
{ {
// TODO: AllowMoreWorkers return _azureCredential;
// TODO: ReduceLogging
return new DefaultAzureCredential();
} }
public string GetSubcription() public string GetSubcription()
{ {
var storageResourceId = EnvironmentVariables.OneFuzz.DataStorage var storageResourceId = _config.OneFuzzDataStorage
?? throw new System.Exception("Data storage env var is not present"); ?? throw new System.Exception("Data storage env var is not present");
var storageResource = new ResourceIdentifier(storageResourceId); var storageResource = new ResourceIdentifier(storageResourceId);
return storageResource.SubscriptionId!; return storageResource.SubscriptionId!;
@ -50,7 +51,7 @@ public class Creds : ICreds
public string GetBaseResourceGroup() public string GetBaseResourceGroup()
{ {
var storageResourceId = EnvironmentVariables.OneFuzz.DataStorage var storageResourceId = _config.OneFuzzDataStorage
?? throw new System.Exception("Data storage env var is not present"); ?? throw new System.Exception("Data storage env var is not present");
var storageResource = new ResourceIdentifier(storageResourceId); var storageResource = new ResourceIdentifier(storageResourceId);
return storageResource.ResourceGroupName!; return storageResource.ResourceGroupName!;
@ -58,7 +59,7 @@ public class Creds : ICreds
public ResourceIdentifier GetResourceGroupResourceIdentifier() public ResourceIdentifier GetResourceGroupResourceIdentifier()
{ {
var resourceId = EnvironmentVariables.OneFuzz.ResourceGroup var resourceId = _config.OneFuzzResourceGroup
?? throw new System.Exception("Resource group env var is not present"); ?? throw new System.Exception("Resource group env var is not present");
return new ResourceIdentifier(resourceId); return new ResourceIdentifier(resourceId);
} }

View File

@ -72,6 +72,8 @@ namespace Microsoft.OneFuzz.Service
{ {
public override UserInfo? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) public override UserInfo? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{ {
//TODO: I might be wrong but seems like better way of doing this is to have a separate type,
//that if object of the type - then ignore user info...
var newOptions = new JsonSerializerOptions(options); var newOptions = new JsonSerializerOptions(options);
RemoveUserInfo? self = null; RemoveUserInfo? self = null;
foreach (var converter in newOptions.Converters) foreach (var converter in newOptions.Converters)

View File

@ -15,22 +15,24 @@ public class ConfigOperations : Orm<InstanceConfig>, IConfigOperations
{ {
private readonly IEvents _events; private readonly IEvents _events;
private readonly ILogTracer _log; private readonly ILogTracer _log;
public ConfigOperations(IStorage storage, IEvents events, ILogTracer log) : base(storage, log) private readonly IServiceConfig _config;
public ConfigOperations(IStorage storage, IEvents events, ILogTracer log, IServiceConfig config) : base(storage, log, config)
{ {
_events = events; _events = events;
_log = log; _log = log;
_config = config;
} }
public async Task<InstanceConfig> Fetch() public async Task<InstanceConfig> Fetch()
{ {
var key = EnvironmentVariables.OneFuzz.InstanceName ?? throw new Exception("Environment variable ONEFUZZ_INSTANCE_NAME is not set"); var key = _config.OneFuzzInstanceName ?? throw new Exception("Environment variable ONEFUZZ_INSTANCE_NAME is not set");
var config = await GetEntityAsync(key, key); var config = await GetEntityAsync(key, key);
return config; return config;
} }
public async Async.Task Save(InstanceConfig config, bool isNew = false, bool requireEtag = false) public async Async.Task Save(InstanceConfig config, bool isNew = false, bool requireEtag = false)
{ {
ResultOk<(int, string)> r; ResultVoid<(int, string)> r;
if (isNew) if (isNew)
{ {
r = await Insert(config); r = await Insert(config);

View File

@ -11,8 +11,8 @@ public interface INodeOperations : IStatefulOrm<Node, NodeState>
public class NodeOperations : StatefulOrm<Node, NodeState>, INodeOperations public class NodeOperations : StatefulOrm<Node, NodeState>, INodeOperations
{ {
public NodeOperations(IStorage storage, ILogTracer log) public NodeOperations(IStorage storage, ILogTracer log, IServiceConfig config)
: base(storage, log) : base(storage, log, config)
{ {
} }

View File

@ -20,8 +20,8 @@ public class NotificationOperations : Orm<Notification>, INotificationOperations
private IEvents _events; private IEvents _events;
public NotificationOperations(ILogTracer log, IStorage storage, IReports reports, ITaskOperations taskOperations, IContainers containers, IQueue queue, IEvents events) public NotificationOperations(ILogTracer log, IStorage storage, IReports reports, ITaskOperations taskOperations, IContainers containers, IQueue queue, IEvents events, IServiceConfig config)
: base(storage, log) : base(storage, log, config)
{ {
_log = log; _log = log;
_reports = reports; _reports = reports;

View File

@ -19,8 +19,8 @@ public class ProxyOperations : StatefulOrm<Proxy, VmState>, IProxyOperations
private readonly IEvents _events; private readonly IEvents _events;
public ProxyOperations(ILogTracer log, IStorage storage, IEvents events) public ProxyOperations(ILogTracer log, IStorage storage, IEvents events, IServiceConfig config)
: base(storage, log) : base(storage, log, config)
{ {
_log = log; _log = log;
_events = events; _events = events;

View File

@ -10,8 +10,8 @@ public interface IScalesetOperations : IOrm<Scaleset>
public class ScalesetOperations : StatefulOrm<Scaleset, ScalesetState>, IScalesetOperations public class ScalesetOperations : StatefulOrm<Scaleset, ScalesetState>, IScalesetOperations
{ {
public ScalesetOperations(IStorage storage, ILogTracer log) public ScalesetOperations(IStorage storage, ILogTracer log, IServiceConfig config)
: base(storage, log) : base(storage, log, config)
{ {
} }

View File

@ -25,23 +25,25 @@ public class Storage : IStorage
private ICreds _creds; private ICreds _creds;
private ArmClient _armClient; private ArmClient _armClient;
private ILogTracer _log; private ILogTracer _log;
private IServiceConfig _config;
public Storage(ICreds creds, ILogTracer log) public Storage(ICreds creds, ILogTracer log, IServiceConfig config)
{ {
_creds = creds; _creds = creds;
_armClient = new ArmClient(credential: _creds.GetIdentity(), defaultSubscriptionId: _creds.GetSubcription()); _armClient = creds.ArmClient;
_log = log; _log = log;
_config = config;
} }
public static string GetFuncStorage() public string GetFuncStorage()
{ {
return EnvironmentVariables.OneFuzz.FuncStorage return _config.OneFuzzFuncStorage
?? throw new Exception("Func storage env var is missing"); ?? throw new Exception("Func storage env var is missing");
} }
public static string GetFuzzStorage() public string GetFuzzStorage()
{ {
return EnvironmentVariables.OneFuzz.DataStorage return _config.OneFuzzDataStorage
?? throw new Exception("Fuzz storage env var is missing"); ?? throw new Exception("Fuzz storage env var is missing");
} }

View File

@ -1,9 +1,6 @@
using Azure.Core; using Azure.ResourceManager.Network;
using Azure.ResourceManager.Network;
namespace Microsoft.OneFuzz.Service; namespace Microsoft.OneFuzz.Service;
public interface ISubnet public interface ISubnet
{ {
System.Threading.Tasks.Task<VirtualNetworkResource?> GetVnet(string vnetName); System.Threading.Tasks.Task<VirtualNetworkResource?> GetVnet(string vnetName);
@ -35,7 +32,7 @@ public partial class TimerProxy
public async System.Threading.Tasks.Task<VirtualNetworkResource?> GetVnet(string vnetName) public async System.Threading.Tasks.Task<VirtualNetworkResource?> GetVnet(string vnetName)
{ {
var resourceGroupId = new ResourceIdentifier(EnvironmentVariables.OneFuzz.ResourceGroup ?? throw new Exception("Missing resource group")); var resourceGroupId = _creds.GetResourceGroupResourceIdentifier();
var response = await _creds.ArmClient.GetResourceGroupResource(resourceGroupId).GetVirtualNetworkAsync(vnetName); var response = await _creds.ArmClient.GetResourceGroupResource(resourceGroupId).GetVirtualNetworkAsync(vnetName);
return response.Value; return response.Value;
} }

View File

@ -18,8 +18,8 @@ public interface ITaskOperations : IStatefulOrm<Task, TaskState>
public class TaskOperations : StatefulOrm<Task, TaskState>, ITaskOperations public class TaskOperations : StatefulOrm<Task, TaskState>, ITaskOperations
{ {
public TaskOperations(IStorage storage, ILogTracer log) public TaskOperations(IStorage storage, ILogTracer log, IServiceConfig config)
: base(storage, log) : base(storage, log, config)
{ {
} }

View File

@ -20,7 +20,7 @@ public class WebhookMessageLogOperations : Orm<WebhookMessageLog>, IWebhookMessa
private readonly IQueue _queue; private readonly IQueue _queue;
private readonly ILogTracer _log; private readonly ILogTracer _log;
public WebhookMessageLogOperations(IStorage storage, IQueue queue, ILogTracer log) : base(storage, log) public WebhookMessageLogOperations(IStorage storage, IQueue queue, ILogTracer log, IServiceConfig config) : base(storage, log, config)
{ {
_queue = queue; _queue = queue;
_log = log; _log = log;
@ -77,8 +77,8 @@ public class WebhookOperations : Orm<Webhook>, IWebhookOperations
{ {
private readonly IWebhookMessageLogOperations _webhookMessageLogOperations; private readonly IWebhookMessageLogOperations _webhookMessageLogOperations;
private readonly ILogTracer _log; private readonly ILogTracer _log;
public WebhookOperations(IStorage storage, IWebhookMessageLogOperations webhookMessageLogOperations, ILogTracer log) public WebhookOperations(IStorage storage, IWebhookMessageLogOperations webhookMessageLogOperations, ILogTracer log, IServiceConfig config)
: base(storage, log) : base(storage, log, config)
{ {
_webhookMessageLogOperations = webhookMessageLogOperations; _webhookMessageLogOperations = webhookMessageLogOperations;
_log = log; _log = log;

View File

@ -11,11 +11,11 @@ namespace ApiService.OneFuzzLib.Orm
{ {
Task<TableClient> GetTableClient(string table, string? accountId = null); Task<TableClient> GetTableClient(string table, string? accountId = null);
IAsyncEnumerable<T> QueryAsync(string? filter = null); IAsyncEnumerable<T> QueryAsync(string? filter = null);
Task<ResultOk<(int, string)>> Replace(T entity); Task<ResultVoid<(int, string)>> Replace(T entity);
Task<T> GetEntityAsync(string partitionKey, string rowKey); Task<T> GetEntityAsync(string partitionKey, string rowKey);
Task<ResultOk<(int, string)>> Insert(T entity); Task<ResultVoid<(int, string)>> Insert(T entity);
Task<ResultOk<(int, string)>> Delete(T entity); Task<ResultVoid<(int, string)>> Delete(T entity);
} }
@ -26,15 +26,16 @@ namespace ApiService.OneFuzzLib.Orm
{ {
IStorage _storage; IStorage _storage;
EntityConverter _entityConverter; EntityConverter _entityConverter;
IServiceConfig _config;
protected ILogTracer _logTracer; protected ILogTracer _logTracer;
public Orm(IStorage storage, ILogTracer logTracer) public Orm(IStorage storage, ILogTracer logTracer, IServiceConfig config)
{ {
_storage = storage; _storage = storage;
_entityConverter = new EntityConverter(); _entityConverter = new EntityConverter();
_logTracer = logTracer; _logTracer = logTracer;
_config = config;
} }
public async IAsyncEnumerable<T> QueryAsync(string? filter = null) public async IAsyncEnumerable<T> QueryAsync(string? filter = null)
@ -47,7 +48,7 @@ namespace ApiService.OneFuzzLib.Orm
} }
} }
public async Task<ResultOk<(int, string)>> Insert(T entity) public async Task<ResultVoid<(int, string)>> Insert(T entity)
{ {
var tableClient = await GetTableClient(typeof(T).Name); var tableClient = await GetTableClient(typeof(T).Name);
var tableEntity = _entityConverter.ToTableEntity(entity); var tableEntity = _entityConverter.ToTableEntity(entity);
@ -55,48 +56,48 @@ namespace ApiService.OneFuzzLib.Orm
if (response.IsError) if (response.IsError)
{ {
return ResultOk<(int, string)>.Error((response.Status, response.ReasonPhrase)); return ResultVoid<(int, string)>.Error((response.Status, response.ReasonPhrase));
} }
else else
{ {
return ResultOk<(int, string)>.Ok(); return ResultVoid<(int, string)>.Ok();
} }
} }
public async Task<ResultOk<(int, string)>> Replace(T entity) public async Task<ResultVoid<(int, string)>> Replace(T entity)
{ {
var tableClient = await GetTableClient(typeof(T).Name); var tableClient = await GetTableClient(typeof(T).Name);
var tableEntity = _entityConverter.ToTableEntity(entity); var tableEntity = _entityConverter.ToTableEntity(entity);
var response = await tableClient.UpsertEntityAsync(tableEntity); var response = await tableClient.UpsertEntityAsync(tableEntity);
if (response.IsError) if (response.IsError)
{ {
return ResultOk<(int, string)>.Error((response.Status, response.ReasonPhrase)); return ResultVoid<(int, string)>.Error((response.Status, response.ReasonPhrase));
} }
else else
{ {
return ResultOk<(int, string)>.Ok(); return ResultVoid<(int, string)>.Ok();
} }
} }
public async Task<ResultOk<(int, string)>> Update(T entity) public async Task<ResultVoid<(int, string)>> Update(T entity)
{ {
var tableClient = await GetTableClient(typeof(T).Name); var tableClient = await GetTableClient(typeof(T).Name);
var tableEntity = _entityConverter.ToTableEntity(entity); var tableEntity = _entityConverter.ToTableEntity(entity);
if (entity.ETag is null) if (entity.ETag is null)
{ {
return ResultOk<(int, string)>.Error((0, "ETag must be set when updating an entity")); return ResultVoid<(int, string)>.Error((0, "ETag must be set when updating an entity"));
} }
else else
{ {
var response = await tableClient.UpdateEntityAsync(tableEntity, entity.ETag.Value); var response = await tableClient.UpdateEntityAsync(tableEntity, entity.ETag.Value);
if (response.IsError) if (response.IsError)
{ {
return ResultOk<(int, string)>.Error((response.Status, response.ReasonPhrase)); return ResultVoid<(int, string)>.Error((response.Status, response.ReasonPhrase));
} }
else else
{ {
return ResultOk<(int, string)>.Ok(); return ResultVoid<(int, string)>.Ok();
} }
} }
} }
@ -110,25 +111,25 @@ namespace ApiService.OneFuzzLib.Orm
public async Task<TableClient> GetTableClient(string table, string? accountId = null) public async Task<TableClient> GetTableClient(string table, string? accountId = null)
{ {
var account = accountId ?? EnvironmentVariables.OneFuzz.FuncStorage ?? throw new ArgumentNullException(nameof(accountId)); var account = accountId ?? _config.OneFuzzFuncStorage ?? throw new ArgumentNullException(nameof(accountId));
var (name, key) = _storage.GetStorageAccountNameAndKey(account); var (name, key) = _storage.GetStorageAccountNameAndKey(account);
var tableClient = new TableServiceClient(new Uri($"https://{name}.table.core.windows.net"), new TableSharedKeyCredential(name, key)); var tableClient = new TableServiceClient(new Uri($"https://{name}.table.core.windows.net"), new TableSharedKeyCredential(name, key));
await tableClient.CreateTableIfNotExistsAsync(table); await tableClient.CreateTableIfNotExistsAsync(table);
return tableClient.GetTableClient(table); return tableClient.GetTableClient(table);
} }
public async Task<ResultOk<(int, string)>> Delete(T entity) public async Task<ResultVoid<(int, string)>> Delete(T entity)
{ {
var tableClient = await GetTableClient(typeof(T).Name); var tableClient = await GetTableClient(typeof(T).Name);
var tableEntity = _entityConverter.ToTableEntity(entity); var tableEntity = _entityConverter.ToTableEntity(entity);
var response = await tableClient.DeleteEntityAsync(tableEntity.PartitionKey, tableEntity.RowKey); var response = await tableClient.DeleteEntityAsync(tableEntity.PartitionKey, tableEntity.RowKey);
if (response.IsError) if (response.IsError)
{ {
return ResultOk<(int, string)>.Error((response.Status, response.ReasonPhrase)); return ResultVoid<(int, string)>.Error((response.Status, response.ReasonPhrase));
} }
else else
{ {
return ResultOk<(int, string)>.Ok(); return ResultVoid<(int, string)>.Ok();
} }
} }
} }
@ -166,7 +167,7 @@ namespace ApiService.OneFuzzLib.Orm
}; };
} }
public StatefulOrm(IStorage storage, ILogTracer logTracer) : base(storage, logTracer) public StatefulOrm(IStorage storage, ILogTracer logTracer, IServiceConfig config) : base(storage, logTracer, config)
{ {
} }

View File

@ -837,6 +837,12 @@ namespace Tests
} }
[Property]
public bool RegressionReportOrReport(RegressionReportOrReport e)
{
return Test(e);
}
/* /*
//Sample function on how repro a failing test run, using Replay //Sample function on how repro a failing test run, using Replay
//functionality of FsCheck. Feel free to //functionality of FsCheck. Feel free to