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
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
@ -16,16 +16,19 @@ public interface ILog
|
||||
|
||||
class AppInsights : ILog
|
||||
{
|
||||
private TelemetryClient telemetryClient =
|
||||
new TelemetryClient(
|
||||
new TelemetryConfiguration(EnvironmentVariables.AppInsights.InstrumentationKey));
|
||||
private TelemetryClient _telemetryClient;
|
||||
|
||||
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)
|
||||
{
|
||||
Dictionary<string, string> copyTags = new(tags);
|
||||
copyTags["Correlation ID"] = correlationId.ToString();
|
||||
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)
|
||||
{
|
||||
@ -39,7 +42,7 @@ class AppInsights : ILog
|
||||
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)
|
||||
{
|
||||
@ -52,12 +55,12 @@ class AppInsights : ILog
|
||||
{
|
||||
copyMetrics = new(metrics);
|
||||
}
|
||||
telemetryClient.TrackException(ex, copyTags, copyMetrics);
|
||||
_telemetryClient.TrackException(ex, copyTags, copyMetrics);
|
||||
}
|
||||
|
||||
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
|
||||
//# 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();
|
||||
if (AllowedAadTenants.Length == 0)
|
||||
@ -361,11 +361,11 @@ public record InstanceConfig
|
||||
}
|
||||
if (errors.Count == 0)
|
||||
{
|
||||
return ResultOk<List<string>>.Ok();
|
||||
return ResultVoid<List<string>>.Ok();
|
||||
}
|
||||
else
|
||||
{
|
||||
return ResultOk<List<string>>.Error(errors);
|
||||
return ResultVoid<List<string>>.Error(errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,17 @@
|
||||
namespace Microsoft.OneFuzz.Service
|
||||
{
|
||||
|
||||
public struct ResultOk<T_Error>
|
||||
public struct ResultVoid<T_Error>
|
||||
{
|
||||
public static ResultOk<T_Error> Ok() => new();
|
||||
public static ResultOk<T_Error> Error(T_Error err) => new(err);
|
||||
public static ResultVoid<T_Error> Ok() => new();
|
||||
public static ResultVoid<T_Error> Error(T_Error err) => new(err);
|
||||
|
||||
readonly T_Error? error;
|
||||
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;
|
||||
|
||||
|
@ -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>();
|
||||
foreach (var dest in EnvironmentVariables.LogDestinations)
|
||||
foreach (var dest in config.LogDestinations)
|
||||
{
|
||||
loggers.Add(
|
||||
dest switch
|
||||
{
|
||||
LogDestination.AppInsights => new AppInsights(),
|
||||
LogDestination.AppInsights => new AppInsights(config.ApplicationInsightsInstrumentationKey!),
|
||||
LogDestination.Console => new Console(),
|
||||
_ => throw new Exception($"Unhandled Log Destination type: {dest}"),
|
||||
}
|
||||
@ -66,14 +66,14 @@ public class Program
|
||||
)
|
||||
.ConfigureServices((context, 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<IEvents, Events>()
|
||||
.AddScoped<IWebhookOperations, WebhookOperations>()
|
||||
.AddScoped<IWebhookMessageLogOperations, WebhookMessageLogOperations>()
|
||||
.AddScoped<ITaskOperations, TaskOperations>()
|
||||
.AddScoped<IQueue, Queue>()
|
||||
.AddScoped<ICreds, Creds>()
|
||||
.AddScoped<IStorage, Storage>()
|
||||
.AddScoped<IProxyOperations, ProxyOperations>()
|
||||
.AddScoped<IConfigOperations, ConfigOperations>()
|
||||
@ -83,9 +83,11 @@ public class Program
|
||||
.AddScoped<INotificationOperations, NotificationOperations>()
|
||||
.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();
|
||||
|
||||
|
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;
|
||||
|
||||
public record FunctionInfo(string Name, string ResourceGroup, string? SlotName);
|
||||
|
||||
|
||||
public class TestHooks
|
||||
{
|
||||
|
||||
private readonly ILogTracer _log;
|
||||
private readonly IConfigOperations _configOps;
|
||||
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;
|
||||
_configOps = configOps;
|
||||
_events = events;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
[Function("Info")]
|
||||
@ -29,8 +29,8 @@ public class TestHooks
|
||||
_log.Info("Creating function info response");
|
||||
var response = req.CreateResponse();
|
||||
FunctionInfo info = new(
|
||||
$"{EnvironmentVariables.OneFuzz.InstanceName}",
|
||||
$"{EnvironmentVariables.OneFuzz.ResourceGroup}",
|
||||
$"{_config.OneFuzzInstanceName}",
|
||||
$"{_config.OneFuzzResourceGroup}",
|
||||
Environment.GetEnvironmentVariable("WEBSITE_SLOT_NAME"));
|
||||
|
||||
_log.Info("Returning function info");
|
||||
|
@ -27,7 +27,7 @@ public class Containers : IContainers
|
||||
_log = log;
|
||||
_storage = storage;
|
||||
_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)
|
||||
{
|
||||
|
@ -23,26 +23,27 @@ public interface 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()
|
||||
{
|
||||
// TODO: AllowMoreWorkers
|
||||
// TODO: ReduceLogging
|
||||
return new DefaultAzureCredential();
|
||||
return _azureCredential;
|
||||
}
|
||||
|
||||
public string GetSubcription()
|
||||
{
|
||||
var storageResourceId = EnvironmentVariables.OneFuzz.DataStorage
|
||||
var storageResourceId = _config.OneFuzzDataStorage
|
||||
?? throw new System.Exception("Data storage env var is not present");
|
||||
var storageResource = new ResourceIdentifier(storageResourceId);
|
||||
return storageResource.SubscriptionId!;
|
||||
@ -50,7 +51,7 @@ public class Creds : ICreds
|
||||
|
||||
public string GetBaseResourceGroup()
|
||||
{
|
||||
var storageResourceId = EnvironmentVariables.OneFuzz.DataStorage
|
||||
var storageResourceId = _config.OneFuzzDataStorage
|
||||
?? throw new System.Exception("Data storage env var is not present");
|
||||
var storageResource = new ResourceIdentifier(storageResourceId);
|
||||
return storageResource.ResourceGroupName!;
|
||||
@ -58,7 +59,7 @@ public class Creds : ICreds
|
||||
|
||||
public ResourceIdentifier GetResourceGroupResourceIdentifier()
|
||||
{
|
||||
var resourceId = EnvironmentVariables.OneFuzz.ResourceGroup
|
||||
var resourceId = _config.OneFuzzResourceGroup
|
||||
?? throw new System.Exception("Resource group env var is not present");
|
||||
return new ResourceIdentifier(resourceId);
|
||||
}
|
||||
|
@ -72,6 +72,8 @@ namespace Microsoft.OneFuzz.Service
|
||||
{
|
||||
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);
|
||||
RemoveUserInfo? self = null;
|
||||
foreach (var converter in newOptions.Converters)
|
||||
|
@ -15,22 +15,24 @@ public class ConfigOperations : Orm<InstanceConfig>, IConfigOperations
|
||||
{
|
||||
private readonly IEvents _events;
|
||||
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;
|
||||
_log = log;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
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);
|
||||
return config;
|
||||
}
|
||||
|
||||
public async Async.Task Save(InstanceConfig config, bool isNew = false, bool requireEtag = false)
|
||||
{
|
||||
ResultOk<(int, string)> r;
|
||||
ResultVoid<(int, string)> r;
|
||||
if (isNew)
|
||||
{
|
||||
r = await Insert(config);
|
||||
|
@ -11,8 +11,8 @@ public interface INodeOperations : IStatefulOrm<Node, NodeState>
|
||||
public class NodeOperations : StatefulOrm<Node, NodeState>, INodeOperations
|
||||
{
|
||||
|
||||
public NodeOperations(IStorage storage, ILogTracer log)
|
||||
: base(storage, log)
|
||||
public NodeOperations(IStorage storage, ILogTracer log, IServiceConfig config)
|
||||
: base(storage, log, config)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -20,8 +20,8 @@ public class NotificationOperations : Orm<Notification>, INotificationOperations
|
||||
|
||||
private IEvents _events;
|
||||
|
||||
public NotificationOperations(ILogTracer log, IStorage storage, IReports reports, ITaskOperations taskOperations, IContainers containers, IQueue queue, IEvents events)
|
||||
: base(storage, log)
|
||||
public NotificationOperations(ILogTracer log, IStorage storage, IReports reports, ITaskOperations taskOperations, IContainers containers, IQueue queue, IEvents events, IServiceConfig config)
|
||||
: base(storage, log, config)
|
||||
{
|
||||
_log = log;
|
||||
_reports = reports;
|
||||
|
@ -19,8 +19,8 @@ public class ProxyOperations : StatefulOrm<Proxy, VmState>, IProxyOperations
|
||||
|
||||
private readonly IEvents _events;
|
||||
|
||||
public ProxyOperations(ILogTracer log, IStorage storage, IEvents events)
|
||||
: base(storage, log)
|
||||
public ProxyOperations(ILogTracer log, IStorage storage, IEvents events, IServiceConfig config)
|
||||
: base(storage, log, config)
|
||||
{
|
||||
_log = log;
|
||||
_events = events;
|
||||
|
@ -10,8 +10,8 @@ public interface IScalesetOperations : IOrm<Scaleset>
|
||||
public class ScalesetOperations : StatefulOrm<Scaleset, ScalesetState>, IScalesetOperations
|
||||
{
|
||||
|
||||
public ScalesetOperations(IStorage storage, ILogTracer log)
|
||||
: base(storage, log)
|
||||
public ScalesetOperations(IStorage storage, ILogTracer log, IServiceConfig config)
|
||||
: base(storage, log, config)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -25,23 +25,25 @@ public class Storage : IStorage
|
||||
private ICreds _creds;
|
||||
private ArmClient _armClient;
|
||||
private ILogTracer _log;
|
||||
private IServiceConfig _config;
|
||||
|
||||
public Storage(ICreds creds, ILogTracer log)
|
||||
public Storage(ICreds creds, ILogTracer log, IServiceConfig config)
|
||||
{
|
||||
_creds = creds;
|
||||
_armClient = new ArmClient(credential: _creds.GetIdentity(), defaultSubscriptionId: _creds.GetSubcription());
|
||||
_armClient = creds.ArmClient;
|
||||
_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");
|
||||
}
|
||||
|
||||
public static string GetFuzzStorage()
|
||||
public string GetFuzzStorage()
|
||||
{
|
||||
return EnvironmentVariables.OneFuzz.DataStorage
|
||||
return _config.OneFuzzDataStorage
|
||||
?? 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;
|
||||
|
||||
|
||||
public interface ISubnet
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
return response.Value;
|
||||
}
|
||||
|
@ -18,8 +18,8 @@ public interface ITaskOperations : IStatefulOrm<Task, TaskState>
|
||||
public class TaskOperations : StatefulOrm<Task, TaskState>, ITaskOperations
|
||||
{
|
||||
|
||||
public TaskOperations(IStorage storage, ILogTracer log)
|
||||
: base(storage, log)
|
||||
public TaskOperations(IStorage storage, ILogTracer log, IServiceConfig config)
|
||||
: base(storage, log, config)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ public class WebhookMessageLogOperations : Orm<WebhookMessageLog>, IWebhookMessa
|
||||
|
||||
private readonly IQueue _queue;
|
||||
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;
|
||||
_log = log;
|
||||
@ -77,8 +77,8 @@ public class WebhookOperations : Orm<Webhook>, IWebhookOperations
|
||||
{
|
||||
private readonly IWebhookMessageLogOperations _webhookMessageLogOperations;
|
||||
private readonly ILogTracer _log;
|
||||
public WebhookOperations(IStorage storage, IWebhookMessageLogOperations webhookMessageLogOperations, ILogTracer log)
|
||||
: base(storage, log)
|
||||
public WebhookOperations(IStorage storage, IWebhookMessageLogOperations webhookMessageLogOperations, ILogTracer log, IServiceConfig config)
|
||||
: base(storage, log, config)
|
||||
{
|
||||
_webhookMessageLogOperations = webhookMessageLogOperations;
|
||||
_log = log;
|
||||
|
@ -11,11 +11,11 @@ namespace ApiService.OneFuzzLib.Orm
|
||||
{
|
||||
Task<TableClient> GetTableClient(string table, string? accountId = 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<ResultOk<(int, string)>> Insert(T entity);
|
||||
Task<ResultOk<(int, string)>> Delete(T entity);
|
||||
Task<ResultVoid<(int, string)>> Insert(T entity);
|
||||
Task<ResultVoid<(int, string)>> Delete(T entity);
|
||||
|
||||
}
|
||||
|
||||
@ -26,15 +26,16 @@ namespace ApiService.OneFuzzLib.Orm
|
||||
{
|
||||
IStorage _storage;
|
||||
EntityConverter _entityConverter;
|
||||
IServiceConfig _config;
|
||||
protected ILogTracer _logTracer;
|
||||
|
||||
|
||||
public Orm(IStorage storage, ILogTracer logTracer)
|
||||
public Orm(IStorage storage, ILogTracer logTracer, IServiceConfig config)
|
||||
{
|
||||
_storage = storage;
|
||||
_entityConverter = new EntityConverter();
|
||||
_logTracer = logTracer;
|
||||
|
||||
_config = config;
|
||||
}
|
||||
|
||||
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 tableEntity = _entityConverter.ToTableEntity(entity);
|
||||
@ -55,48 +56,48 @@ namespace ApiService.OneFuzzLib.Orm
|
||||
|
||||
if (response.IsError)
|
||||
{
|
||||
return ResultOk<(int, string)>.Error((response.Status, response.ReasonPhrase));
|
||||
return ResultVoid<(int, string)>.Error((response.Status, response.ReasonPhrase));
|
||||
}
|
||||
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 tableEntity = _entityConverter.ToTableEntity(entity);
|
||||
var response = await tableClient.UpsertEntityAsync(tableEntity);
|
||||
if (response.IsError)
|
||||
{
|
||||
return ResultOk<(int, string)>.Error((response.Status, response.ReasonPhrase));
|
||||
return ResultVoid<(int, string)>.Error((response.Status, response.ReasonPhrase));
|
||||
}
|
||||
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 tableEntity = _entityConverter.ToTableEntity(entity);
|
||||
|
||||
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
|
||||
{
|
||||
var response = await tableClient.UpdateEntityAsync(tableEntity, entity.ETag.Value);
|
||||
if (response.IsError)
|
||||
{
|
||||
return ResultOk<(int, string)>.Error((response.Status, response.ReasonPhrase));
|
||||
return ResultVoid<(int, string)>.Error((response.Status, response.ReasonPhrase));
|
||||
}
|
||||
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)
|
||||
{
|
||||
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 tableClient = new TableServiceClient(new Uri($"https://{name}.table.core.windows.net"), new TableSharedKeyCredential(name, key));
|
||||
await tableClient.CreateTableIfNotExistsAsync(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 tableEntity = _entityConverter.ToTableEntity(entity);
|
||||
var response = await tableClient.DeleteEntityAsync(tableEntity.PartitionKey, tableEntity.RowKey);
|
||||
if (response.IsError)
|
||||
{
|
||||
return ResultOk<(int, string)>.Error((response.Status, response.ReasonPhrase));
|
||||
return ResultVoid<(int, string)>.Error((response.Status, response.ReasonPhrase));
|
||||
}
|
||||
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
|
||||
//functionality of FsCheck. Feel free to
|
||||
|
Reference in New Issue
Block a user