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

Commit

Permalink
log analytics (#1851)
Browse files Browse the repository at this point in the history
Co-authored-by: stas <statis@microsoft.com>
  • Loading branch information
stishkin and stas authored Apr 27, 2022
1 parent 5d6f5f2 commit 7403c27
Show file tree
Hide file tree
Showing 23 changed files with 1,255 additions and 207 deletions.
2 changes: 2 additions & 0 deletions src/ApiService/ApiService/ApiService.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@
<WarningLevel>5</WarningLevel>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.ResourceManager.Monitor" Version="1.0.0-beta.2" />
<PackageReference Include="Faithlife.Utility" Version="0.12.2" />
<PackageReference Include="Azure.Security.KeyVault.Secrets" Version="4.3.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Storage" Version="5.0.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.EventGrid" Version="2.1.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.0.13" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Timer" Version="4.1.0" />
<PackageReference Include="Microsoft.Azure.Management.OperationalInsights" Version="0.24.0-preview" />
<PackageReference Include="Microsoft.Extensions.Logging.ApplicationInsights" Version="2.20.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.3.0" OutputItemType="Analyzer" />
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.6.0" />
Expand Down
7 changes: 7 additions & 0 deletions src/ApiService/ApiService/OneFuzzTypes/Enums.cs
Original file line number Diff line number Diff line change
Expand Up @@ -295,3 +295,10 @@ public static PoolState[] Available() {
public enum Architecture {
x86_64
}


public enum AgentMode {
Fuzz,
Repro,
Proxy
}
33 changes: 18 additions & 15 deletions src/ApiService/ApiService/OneFuzzTypes/Events.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ public EventType GetEventType() {
EventTaskFailed _ => EventType.TaskFailed,
EventTaskStopped _ => EventType.TaskStopped,
EventTaskStateUpdated _ => EventType.TaskStateUpdated,
EventScalesetFailed _ => EventType.ScalesetFailed,
EventScalesetResizeScheduled _ => EventType.ScalesetResizeScheduled,
EventScalesetStateUpdated _ => EventType.ScalesetStateUpdated,
_ => throw new NotImplementedException(),
};

Expand Down Expand Up @@ -166,11 +169,11 @@ Guid PingId
// int Size) : BaseEvent();


//record EventScalesetFailed(
// Guid ScalesetId,
// PoolName: PoolName,
// Error: Error
//): BaseEvent();
public record EventScalesetFailed(
Guid ScalesetId,
PoolName PoolName,
Error Error
) : BaseEvent();


//record EventScalesetDeleted(
Expand All @@ -180,11 +183,11 @@ Guid PingId
// ) : BaseEvent();


//record EventScalesetResizeScheduled(
// Guid ScalesetId,
// PoolName PoolName,
// int size
// ) : BaseEvent();
public record EventScalesetResizeScheduled(
Guid ScalesetId,
PoolName PoolName,
int size
) : BaseEvent();


//record EventPoolDeleted(
Expand Down Expand Up @@ -249,11 +252,11 @@ PoolName PoolName
// ) : BaseEvent();


// record EventScalesetStateUpdated(
// Guid ScalesetId,
// PoolName PoolName,
// ScalesetState State
// ) : BaseEvent();
public record EventScalesetStateUpdated(
Guid ScalesetId,
PoolName PoolName,
ScalesetState State
) : BaseEvent();

// record EventNodeStateUpdated(
// Guid MachineId,
Expand Down
23 changes: 21 additions & 2 deletions src/ApiService/ApiService/OneFuzzTypes/Model.cs
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ public record Scaleset(
bool SpotInstance,
bool EphemeralOsDisks,
bool NeedsConfigUpdate,
Error? Error,
List<ScalesetNodeState> Nodes,
Guid? ClientId,
Guid? ClientObjectId,
Expand Down Expand Up @@ -513,8 +514,26 @@ public record Pool(
) : StatefulEntityBase<PoolState>(State);


// TODO
public record AgentConfig();
public record ClientCredentials
(
Guid ClientId,
string ClientSecret
);


public record AgentConfig(
ClientCredentials? ClientCredentials,
[property: JsonPropertyName("onefuzz_url")] Uri OneFuzzUrl,
PoolName PoolName,
Uri? HeartbeatQueue,
string? InstanceTelemetryKey,
string? MicrosoftTelemetryKey,
string? MultiTenantDomain,
Guid InstanceId
);



public record WorkSetSummary();
public record ScalesetSummary();

Expand Down
10 changes: 7 additions & 3 deletions src/ApiService/ApiService/Program.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
// to avoid collision with Task in model.cs
global using System;
global using System.Collections.Generic;
global using System.Linq;
global using Async = System.Threading.Tasks;
global
using System.Collections.Generic;
global
using System.Linq;
global
using Async = System.Threading.Tasks;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Middleware;
using Microsoft.Extensions.DependencyInjection;
Expand Down Expand Up @@ -81,6 +84,7 @@ public static void Main() {
.AddScoped<IJobOperations, JobOperations>()
.AddScoped<IScheduler, Scheduler>()
.AddScoped<IConfig, Config>()
.AddScoped<ILogAnalytics, LogAnalytics>()

//Move out expensive resources into separate class, and add those as Singleton
// ArmClient, Table Client(s), Queue Client(s), HttpClient, etc.\
Expand Down
86 changes: 69 additions & 17 deletions src/ApiService/ApiService/onefuzzlib/Containers.cs
Original file line number Diff line number Diff line change
@@ -1,35 +1,50 @@
using System.Threading.Tasks;
using Azure;
using Azure;
using Azure.ResourceManager;
using Azure.Storage;
using Azure.Storage.Blobs;
using Azure.Storage.Sas;


namespace Microsoft.OneFuzz.Service;


public interface IContainers {
public Task<BinaryData?> GetBlob(Container container, string name, StorageType storageType);
public Async.Task<BinaryData?> GetBlob(Container container, string name, StorageType storageType);

public Async.Task<BlobContainerClient?> FindContainer(Container container, StorageType storageType);

public Async.Task<Uri?> GetFileSasUrl(Container container, string name, StorageType storageType, BlobSasPermissions permissions, TimeSpan? duration = null);
Async.Task saveBlob(Container container, string v1, string v2, StorageType config);
Task<Guid> GetInstanceId();
public Async.Task SaveBlob(Container container, string v1, string v2, StorageType config);
public Async.Task<Guid> GetInstanceId();

public Async.Task<Uri?> GetFileUrl(Container container, string name, StorageType storageType);

public Async.Task<Uri?> GetContainerSasUrl(Container container, StorageType storageType, BlobSasPermissions permissions);
}


public class Containers : IContainers {
private ILogTracer _log;
private IStorage _storage;
private ICreds _creds;
private ArmClient _armClient;

public Containers(ILogTracer log, IStorage storage, ICreds creds) {
_log = log;
_storage = storage;
_creds = creds;
_armClient = creds.ArmClient;
}
public async Task<BinaryData?> GetBlob(Container container, string name, StorageType storageType) {

public async Async.Task<Uri?> GetFileUrl(Container container, string name, StorageType storageType) {
var client = await FindContainer(container, storageType);
if (client is null)
return null;

return new Uri($"{GetUrl(client.AccountName)}{container}/{name}");
}

public async Async.Task<BinaryData?> GetBlob(Container container, string name, StorageType storageType) {
var client = await FindContainer(container, storageType);

if (client == null) {
Expand All @@ -52,17 +67,23 @@ public Containers(ILogTracer log, IStorage storage, ICreds creds) {
// #
// # Secondary accounts, if they exist, are preferred for containers and have
// # increased IOP rates, this should be a slight optimization
return await _storage.GetAccounts(storageType)

var containers = _storage.GetAccounts(storageType)
.Reverse()
.Select(account => GetBlobService(account)?.GetBlobContainerClient(container.ContainerName))
.ToAsyncEnumerable()
.WhereAwait(async client => client != null && (await client.ExistsAsync()).Value)
.FirstOrDefaultAsync();
.Select(async account => (await GetBlobService(account))?.GetBlobContainerClient(container.ContainerName));

foreach (var c in containers) {
var client = await c;
if (client != null && (await client.ExistsAsync()).Value) {
return client;
}
}
return null;
}

private BlobServiceClient? GetBlobService(string accountId) {
private async Async.Task<BlobServiceClient?> GetBlobService(string accountId) {
_log.Info($"getting blob container (account_id: {accountId}");
var (accountName, accountKey) = _storage.GetStorageAccountNameAndKey(accountId);
var (accountName, accountKey) = await _storage.GetStorageAccountNameAndKey(accountId);
if (accountName == null) {
_log.Error("Failed to get storage account name");
return null;
Expand All @@ -78,7 +99,7 @@ private static Uri GetUrl(string accountName) {

public async Async.Task<Uri?> GetFileSasUrl(Container container, string name, StorageType storageType, BlobSasPermissions permissions, TimeSpan? duration = null) {
var client = await FindContainer(container, storageType) ?? throw new Exception($"unable to find container: {container.ContainerName} - {storageType}");
var (accountName, accountKey) = _storage.GetStorageAccountNameAndKey(client.AccountName);
var (accountName, accountKey) = await _storage.GetStorageAccountNameAndKey(client.AccountName);

var (startTime, endTime) = SasTimeWindow(duration ?? TimeSpan.FromDays(30));

Expand Down Expand Up @@ -108,17 +129,48 @@ private static Uri GetUrl(string accountName) {
return (start, expiry);
}

public async System.Threading.Tasks.Task saveBlob(Container container, string name, string data, StorageType storageType) {
public async Async.Task SaveBlob(Container container, string name, string data, StorageType storageType) {
var client = await FindContainer(container, storageType) ?? throw new Exception($"unable to find container: {container.ContainerName} - {storageType}");

await client.UploadBlobAsync(name, new BinaryData(data));
}

//TODO: get this ones on startup and cache (and make this method un-accessible to everyone else)
public async Async.Task<Guid> GetInstanceId() {
var blob = await GetBlob(new Container("base-config"), "instance_id", StorageType.Config);
if (blob == null) {
throw new System.Exception("Blob Not Found");
}
return System.Guid.Parse(blob.ToString());
}
}

public Uri? GetContainerSasUrlService(
BlobContainerClient client,
BlobSasPermissions permissions,
bool tag = false,
TimeSpan? timeSpan = null) {
var (start, expiry) = SasTimeWindow(timeSpan ?? TimeSpan.FromDays(30.0));
var sasBuilder = new BlobSasBuilder(permissions, expiry) { StartsOn = start };
var sas = client.GenerateSasUri(sasBuilder);
return sas;
}


//TODO: instead of returning null when container not found, convert to return to "Result" type and set appropriate error
public async Async.Task<Uri?> GetContainerSasUrl(Container container, StorageType storageType, BlobSasPermissions permissions) {
var client = await FindContainer(container, storageType);

if (client is null) {
return null;
}

var uri = GetContainerSasUrlService(client, permissions);

if (uri is null) {
//TODO: return result error
return uri;
} else {
return uri;
}
}
}

12 changes: 9 additions & 3 deletions src/ApiService/ApiService/onefuzzlib/Creds.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Microsoft.OneFuzz.Service;
public interface ICreds {
public DefaultAzureCredential GetIdentity();

public string GetSubcription();
public string GetSubscription();

public string GetBaseResourceGroup();

Expand All @@ -21,6 +21,8 @@ public interface ICreds {
public ResourceGroupResource GetResourceGroupResource();

public string GetBaseRegion();

public Uri GetInstanceUrl();
}

public class Creds : ICreds {
Expand All @@ -33,14 +35,14 @@ public class Creds : ICreds {
public Creds(IServiceConfig config) {
_config = config;
_azureCredential = new DefaultAzureCredential();
_armClient = new ArmClient(this.GetIdentity(), this.GetSubcription());
_armClient = new ArmClient(this.GetIdentity(), this.GetSubscription());
}

public DefaultAzureCredential GetIdentity() {
return _azureCredential;
}

public string GetSubcription() {
public string GetSubscription() {
var storageResourceId = _config.OneFuzzDataStorage
?? throw new System.Exception("Data storage env var is not present");
var storageResource = new ResourceIdentifier(storageResourceId);
Expand Down Expand Up @@ -75,4 +77,8 @@ public ResourceGroupResource GetResourceGroupResource() {
public string GetBaseRegion() {
return ArmClient.GetResourceGroupResource(GetResourceGroupResourceIdentifier()).Data.Location.Name;
}

public Uri GetInstanceUrl() {
return new Uri($"https://{GetInstanceName()}.azurewebsites.net");
}
}
4 changes: 2 additions & 2 deletions src/ApiService/ApiService/onefuzzlib/IpOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ public async Async.Task<PublicIPAddressResource> GetIp(string resourceGroup, str
return await _creds.GetResourceGroupResource().GetPublicIPAddressAsync(name);
}

public System.Threading.Tasks.Task DeleteNic(string resourceGroup, string name) {
public Async.Task DeleteNic(string resourceGroup, string name) {
throw new NotImplementedException();
}

public System.Threading.Tasks.Task DeleteIp(string resourceGroup, string name) {
public Async.Task DeleteIp(string resourceGroup, string name) {
throw new NotImplementedException();
}
}
16 changes: 8 additions & 8 deletions src/ApiService/ApiService/onefuzzlib/JobOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
namespace Microsoft.OneFuzz.Service;

public interface IJobOperations : IStatefulOrm<Job, JobState> {
System.Threading.Tasks.Task<Job?> Get(Guid jobId);
System.Threading.Tasks.Task OnStart(Job job);
Async.Task<Job?> Get(Guid jobId);
Async.Task OnStart(Job job);
IAsyncEnumerable<Job> SearchExpired();
System.Threading.Tasks.Task Stopping(Job job, ITaskOperations taskOperations);
Async.Task Stopping(Job job, ITaskOperations taskOperations);
IAsyncEnumerable<Job> SearchState(IEnumerable<JobState> states);
System.Threading.Tasks.Task StopNeverStartedJobs();
Async.Task StopNeverStartedJobs();
}

public class JobOperations : StatefulOrm<Job, JobState>, IJobOperations {
Expand All @@ -18,11 +18,11 @@ public JobOperations(IStorage storage, ILogTracer logTracer, IServiceConfig conf
_events = events;
}

public async System.Threading.Tasks.Task<Job?> Get(Guid jobId) {
public async Async.Task<Job?> Get(Guid jobId) {
return await QueryAsync($"PartitionKey eq '{jobId}'").FirstOrDefaultAsync();
}

public async System.Threading.Tasks.Task OnStart(Job job) {
public async Async.Task OnStart(Job job) {
if (job.EndTime == null) {
await Replace(job with { EndTime = DateTimeOffset.UtcNow + TimeSpan.FromHours(job.Config.Duration) });
}
Expand All @@ -40,11 +40,11 @@ public IAsyncEnumerable<Job> SearchState(IEnumerable<JobState> states) {
return QueryAsync(filter: query);
}

public System.Threading.Tasks.Task StopNeverStartedJobs() {
public Async.Task StopNeverStartedJobs() {
throw new NotImplementedException();
}

public async System.Threading.Tasks.Task Stopping(Job job, ITaskOperations taskOperations) {
public async Async.Task Stopping(Job job, ITaskOperations taskOperations) {
job = job with { State = JobState.Stopping };
var tasks = await taskOperations.QueryAsync(filter: $"job_id eq '{job.JobId}'").ToListAsync();
var taskNotStopped = tasks.ToLookup(task => task.State != TaskState.Stopped);
Expand Down
Loading

0 comments on commit 7403c27

Please sign in to comment.