mirror of
https://github.com/microsoft/onefuzz.git
synced 2025-06-17 12:28:07 +00:00
[C# Port] Adding new Proxy Update Queue Function. (#1757)
* Adding QueueProxyUpdate. * Setting to serializer. * Updates. * Updating with new ORM model and [model]Operation. * Fixing return type. * Working on changes. * Tested and ready for review. * Formatting. * Removing test code. * Update src/ApiService/Tests/OrmTest.cs Co-authored-by: Cheick Keita <chkeita@microsoft.com> * Fixing tests. * Fixing tests again. * Asserting null in tests. * Adding null param. * Removing whitespace. * syntax error. Co-authored-by: Cheick Keita <chkeita@microsoft.com>
This commit is contained in:
committed by
GitHub
parent
5aceb25843
commit
75039a96eb
@ -26,6 +26,16 @@
|
|||||||
INVALID_CONFIGURATION = 473,
|
INVALID_CONFIGURATION = 473,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum VmState
|
||||||
|
{
|
||||||
|
Init,
|
||||||
|
ExtensionsLaunched,
|
||||||
|
ExtensionsFailed,
|
||||||
|
VmAllocationFailed,
|
||||||
|
Running,
|
||||||
|
Stopping,
|
||||||
|
Stopped
|
||||||
|
}
|
||||||
|
|
||||||
public enum WebhookMessageState
|
public enum WebhookMessageState
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using Microsoft.OneFuzz.Service.OneFuzzLib.Orm;
|
using Microsoft.OneFuzz.Service.OneFuzzLib.Orm;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using PoolName = System.String;
|
using PoolName = System.String;
|
||||||
|
|
||||||
namespace Microsoft.OneFuzz.Service;
|
namespace Microsoft.OneFuzz.Service;
|
||||||
@ -14,6 +15,12 @@ namespace Microsoft.OneFuzz.Service;
|
|||||||
/// the "partion key" and "row key" are identified by the [PartitionKey] and [RowKey] attributes
|
/// the "partion key" and "row key" are identified by the [PartitionKey] and [RowKey] attributes
|
||||||
/// Guids are mapped to string in the db
|
/// Guids are mapped to string in the db
|
||||||
|
|
||||||
|
public record Authentication
|
||||||
|
(
|
||||||
|
string Password,
|
||||||
|
string PublicKey,
|
||||||
|
string PrivateKey
|
||||||
|
);
|
||||||
|
|
||||||
[SkipRename]
|
[SkipRename]
|
||||||
public enum HeartbeatType
|
public enum HeartbeatType
|
||||||
@ -70,6 +77,13 @@ public enum NodeState
|
|||||||
Halt,
|
Halt,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public record ProxyHeartbeat
|
||||||
|
(
|
||||||
|
string Region,
|
||||||
|
Guid ProxyId,
|
||||||
|
List<ProxyForward> Forwards,
|
||||||
|
DateTimeOffset TimeStamp
|
||||||
|
);
|
||||||
|
|
||||||
public partial record Node
|
public partial record Node
|
||||||
(
|
(
|
||||||
@ -87,6 +101,39 @@ public partial record Node
|
|||||||
) : EntityBase();
|
) : EntityBase();
|
||||||
|
|
||||||
|
|
||||||
|
public partial record ProxyForward
|
||||||
|
(
|
||||||
|
[PartitionKey] string Region,
|
||||||
|
[RowKey] int DstPort,
|
||||||
|
int SrcPort,
|
||||||
|
string DstIp
|
||||||
|
) : EntityBase();
|
||||||
|
|
||||||
|
public partial record ProxyConfig
|
||||||
|
(
|
||||||
|
Uri Url,
|
||||||
|
string Notification,
|
||||||
|
string Region,
|
||||||
|
Guid? ProxyId,
|
||||||
|
List<ProxyForward> Forwards,
|
||||||
|
string InstanceTelemetryKey,
|
||||||
|
string MicrosoftTelemetryKey
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
public partial record Proxy
|
||||||
|
(
|
||||||
|
[PartitionKey] string Region,
|
||||||
|
[RowKey] Guid ProxyId,
|
||||||
|
DateTimeOffset? CreatedTimestamp,
|
||||||
|
VmState State,
|
||||||
|
Authentication Auth,
|
||||||
|
string? Ip,
|
||||||
|
Error? Error,
|
||||||
|
string Version,
|
||||||
|
ProxyHeartbeat? heartbeat
|
||||||
|
) : EntityBase();
|
||||||
|
|
||||||
public record Error(ErrorCode Code, string[]? Errors = null);
|
public record Error(ErrorCode Code, string[]? Errors = null);
|
||||||
|
|
||||||
public record UserInfo(Guid? ApplicationId, Guid? ObjectId, String? Upn);
|
public record UserInfo(Guid? ApplicationId, Guid? ObjectId, String? Upn);
|
||||||
|
@ -42,6 +42,7 @@ public class Program
|
|||||||
.AddSingleton<IQueue, Queue>()
|
.AddSingleton<IQueue, Queue>()
|
||||||
.AddSingleton<ICreds>(_ => new Creds())
|
.AddSingleton<ICreds>(_ => new Creds())
|
||||||
.AddSingleton<IStorage, Storage>()
|
.AddSingleton<IStorage, Storage>()
|
||||||
|
.AddSingleton<IProxyOperations, ProxyOperations>()
|
||||||
)
|
)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
|
42
src/ApiService/ApiService/QueueProxyHeartbeat.cs
Normal file
42
src/ApiService/ApiService/QueueProxyHeartbeat.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.Azure.Functions.Worker;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.OneFuzz.Service.OneFuzzLib.Orm;
|
||||||
|
|
||||||
|
namespace Microsoft.OneFuzz.Service;
|
||||||
|
|
||||||
|
public class QueueProxyHearbeat
|
||||||
|
{
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
|
private readonly IProxyOperations _proxy;
|
||||||
|
|
||||||
|
public QueueProxyHearbeat(ILoggerFactory loggerFactory, IProxyOperations proxy)
|
||||||
|
{
|
||||||
|
_logger = loggerFactory.CreateLogger<QueueProxyHearbeat>();
|
||||||
|
_proxy = proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Function("QueueProxyHearbeat")]
|
||||||
|
public async Task Run([QueueTrigger("myqueue-items", Connection = "AzureWebJobsStorage")] string msg)
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"heartbeat: {msg}");
|
||||||
|
|
||||||
|
var hb = JsonSerializer.Deserialize<ProxyHeartbeat>(msg, EntityConverter.GetJsonSerializerOptions()).EnsureNotNull($"wrong data {msg}"); ;
|
||||||
|
var newHb = hb with { TimeStamp = DateTimeOffset.UtcNow };
|
||||||
|
|
||||||
|
var proxy = await _proxy.GetByProxyId(newHb.ProxyId);
|
||||||
|
|
||||||
|
if (proxy == null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning($"invalid proxy id: {newHb.ProxyId}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var newProxy = proxy with { heartbeat = newHb };
|
||||||
|
|
||||||
|
await _proxy.Replace(newProxy);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
30
src/ApiService/ApiService/onefuzzlib/ProxyOperations.cs
Normal file
30
src/ApiService/ApiService/onefuzzlib/ProxyOperations.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
using ApiService.OneFuzzLib.Orm;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace Microsoft.OneFuzz.Service;
|
||||||
|
|
||||||
|
public interface IProxyOperations : IOrm<Proxy>
|
||||||
|
{
|
||||||
|
Task<Proxy?> GetByProxyId(Guid proxyId);
|
||||||
|
}
|
||||||
|
public class ProxyOperations : Orm<Proxy>, IProxyOperations
|
||||||
|
{
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
|
public ProxyOperations(ILoggerFactory loggerFactory, IStorage storage)
|
||||||
|
: base(storage)
|
||||||
|
{
|
||||||
|
_logger = loggerFactory.CreateLogger<QueueProxyHearbeat>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Proxy?> GetByProxyId(Guid proxyId)
|
||||||
|
{
|
||||||
|
|
||||||
|
var data = QueryAsync(filter: $"RowKey eq '{proxyId}'");
|
||||||
|
|
||||||
|
return await data.FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
}
|
@ -245,6 +245,10 @@ public class EntityConverter
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var value = entity.GetString(fieldName);
|
var value = entity.GetString(fieldName);
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return JsonSerializer.Deserialize(value, ef.type, options: _options); ;
|
return JsonSerializer.Deserialize(value, ef.type, options: _options); ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,8 @@ namespace Tests
|
|||||||
TestEnum TheEnum,
|
TestEnum TheEnum,
|
||||||
TestFlagEnum TheFlag,
|
TestFlagEnum TheFlag,
|
||||||
[property: JsonPropertyName("a__special__name")] string Renamed,
|
[property: JsonPropertyName("a__special__name")] string Renamed,
|
||||||
TestObject TheObject
|
TestObject TheObject,
|
||||||
|
TestObject? TestNull
|
||||||
) : EntityBase();
|
) : EntityBase();
|
||||||
|
|
||||||
|
|
||||||
@ -60,7 +61,8 @@ namespace Tests
|
|||||||
TheName = "testobject",
|
TheName = "testobject",
|
||||||
TheEnum = TestEnum.TheTwo,
|
TheEnum = TestEnum.TheTwo,
|
||||||
TheFlag = TestFlagEnum.FlagOne | TestFlagEnum.FlagTwo
|
TheFlag = TestFlagEnum.FlagOne | TestFlagEnum.FlagTwo
|
||||||
});
|
},
|
||||||
|
null);
|
||||||
var tableEntity = converter.ToTableEntity(entity1);
|
var tableEntity = converter.ToTableEntity(entity1);
|
||||||
|
|
||||||
Assert.NotNull(tableEntity);
|
Assert.NotNull(tableEntity);
|
||||||
@ -97,6 +99,7 @@ namespace Tests
|
|||||||
{ "the_flag", "flag_one,flag_two"},
|
{ "the_flag", "flag_one,flag_two"},
|
||||||
{ "a__special__name", "renamed"},
|
{ "a__special__name", "renamed"},
|
||||||
{ "the_object", "{\"the_name\": \"testName\", \"the_enum\": \"the_one\", \"the_flag\": \"flag_one,flag_two\"}"},
|
{ "the_object", "{\"the_name\": \"testName\", \"the_enum\": \"the_one\", \"the_flag\": \"flag_one,flag_two\"}"},
|
||||||
|
{ "test_null", null},
|
||||||
};
|
};
|
||||||
|
|
||||||
var entity1 = converter.ToRecord<Entity1>(tableEntity);
|
var entity1 = converter.ToRecord<Entity1>(tableEntity);
|
||||||
@ -109,6 +112,8 @@ namespace Tests
|
|||||||
Assert.Equal(tableEntity.GetDouble("the_float"), entity1.TheFloat);
|
Assert.Equal(tableEntity.GetDouble("the_float"), entity1.TheFloat);
|
||||||
Assert.Equal(TestEnum.TheTwo, entity1.TheEnum);
|
Assert.Equal(TestEnum.TheTwo, entity1.TheEnum);
|
||||||
Assert.Equal(tableEntity.GetString("a__special__name"), entity1.Renamed);
|
Assert.Equal(tableEntity.GetString("a__special__name"), entity1.Renamed);
|
||||||
|
Assert.Null(tableEntity.GetString("test_null"));
|
||||||
|
Assert.Null(entity1.TestNull);
|
||||||
|
|
||||||
Assert.Equal("testName", entity1.TheObject.TheName);
|
Assert.Equal("testName", entity1.TheObject.TheName);
|
||||||
Assert.Equal(TestEnum.TheOne, entity1.TheObject.TheEnum);
|
Assert.Equal(TestEnum.TheOne, entity1.TheObject.TheEnum);
|
||||||
|
Reference in New Issue
Block a user