mirror of
https://github.com/microsoft/onefuzz.git
synced 2025-06-14 11:08:06 +00:00
- 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:
@ -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"); }
|
|
||||||
}
|
|
||||||
}
|
|
@ -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)
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
82
src/ApiService/ApiService/ServiceConfiguration.cs
Normal file
82
src/ApiService/ApiService/ServiceConfiguration.cs
Normal 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"); }
|
||||||
|
}
|
@ -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");
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Reference in New Issue
Block a user