From 0df8a3e8f6f1b8641f87d3bad6f991af5c3bca84 Mon Sep 17 00:00:00 2001 From: Cheick Keita Date: Mon, 25 Jul 2022 19:00:42 -0700 Subject: [PATCH 1/5] migrate add_node_ssh_key --- .../ApiService/Functions/NodeAddSshKey.cs | 57 +++++++++++++++++++ .../ApiService/OneFuzzTypes/Requests.cs | 2 + .../ApiService/onefuzzlib/NodeOperations.cs | 39 +++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 src/ApiService/ApiService/Functions/NodeAddSshKey.cs diff --git a/src/ApiService/ApiService/Functions/NodeAddSshKey.cs b/src/ApiService/ApiService/Functions/NodeAddSshKey.cs new file mode 100644 index 0000000000..c690ea570a --- /dev/null +++ b/src/ApiService/ApiService/Functions/NodeAddSshKey.cs @@ -0,0 +1,57 @@ +using System.Net; +using Microsoft.Azure.Functions.Worker; +using Microsoft.Azure.Functions.Worker.Http; + +namespace Microsoft.OneFuzz.Service.Functions; + +public class NodeAddSshKey { + + private readonly ILogTracer _log; + private readonly IEndpointAuthorization _auth; + private readonly IOnefuzzContext _context; + + public NodeAddSshKey(ILogTracer log, IEndpointAuthorization auth, IOnefuzzContext context) { + _log = log; + _auth = auth; + _context = context; + } + + private async Async.Task Post(HttpRequestData req) { + var request = await RequestHandling.ParseRequest(req); + if (!request.IsOk) { + return await _context.RequestHandling.NotOk( + req, + request.ErrorV, + "NodeAddSshKey"); + } + + var node = await _context.NodeOperations.GetByMachineId(request.OkV.MachineId); + + if (node == null) { + return await _context.RequestHandling.NotOk( + req, + new Error(ErrorCode.UNABLE_TO_FIND, new[] { "unable to find node" }), + $"{request.OkV.MachineId}"); + } + + var result = await _context.NodeOperations.AddSshPublicKey(node, request.OkV.PublicKey); + if (!result.IsOk) { + return await _context.RequestHandling.NotOk(req, result.ErrorV, "NodeAddSshKey"); + } + + var response = req.CreateResponse(HttpStatusCode.OK); + await response.WriteAsJsonAsync(result); + return response; + + + } + + [Function("node")] + public Async.Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "POST", Route = "node/add_ssh_key")] HttpRequestData req) { + return _auth.CallIfUser(req, r => r.Method switch { + // "POST" => Post(r), + _ => throw new InvalidOperationException("Unsupported HTTP method"), + }); + } + +} diff --git a/src/ApiService/ApiService/OneFuzzTypes/Requests.cs b/src/ApiService/ApiService/OneFuzzTypes/Requests.cs index 0a10915885..fa595e9ec7 100644 --- a/src/ApiService/ApiService/OneFuzzTypes/Requests.cs +++ b/src/ApiService/ApiService/OneFuzzTypes/Requests.cs @@ -123,3 +123,5 @@ public record JobSearch( List? TaskState = null, bool? WithTasks = null ); + +public record NodeAddSshKeyPost(Guid MachineId, string PublicKey); diff --git a/src/ApiService/ApiService/onefuzzlib/NodeOperations.cs b/src/ApiService/ApiService/onefuzzlib/NodeOperations.cs index 3ecb2ff8fe..d30a4e5645 100644 --- a/src/ApiService/ApiService/onefuzzlib/NodeOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/NodeOperations.cs @@ -45,6 +45,8 @@ Async.Task Create( static readonly TimeSpan NODE_REIMAGE_TIME = TimeSpan.FromDays(6.0); Async.Task StopTask(Guid task_id); + + Async.Task> AddSshPublicKey(Node node, string publicKey); } @@ -421,6 +423,43 @@ public async Async.Task StopTask(Guid task_id) { } + public async Async.Task> Create(Container container, NotificationTemplate config, bool replaceExisting) { + if (await _context.Containers.FindContainer(container, StorageType.Corpus) == null) { + return OneFuzzResult.Error(ErrorCode.INVALID_REQUEST, errors: new[] { "invalid container" }); + } + + if (replaceExisting) { + var existing = this.SearchByRowKeys(new[] { container.ContainerName }); + await foreach (var existingEntry in existing) { + _logTracer.Info($"replacing existing notification: {existingEntry.NotificationId} - {container}"); + await this.Delete(existingEntry); + } + } + + var entry = new Notification(Guid.NewGuid(), container, config); + await this.Insert(entry); + _logTracer.Info($"created notification. notification_id:{entry.NotificationId} container:{entry.Container}"); + + return OneFuzzResult.Ok(entry); + } + + public async Task> AddSshPublicKey(Node node, string publicKey) { + if (publicKey == null) { + throw new ArgumentNullException(nameof(publicKey)); + } + + if (node.ScalesetId == null) { + return OneFuzzResult.Error(new Error(ErrorCode.INVALID_REQUEST, + new[] { "only able to add ssh keys to scaleset nodes" })); + } + + var key = publicKey.EndsWith('\n') ? publicKey : $"{publicKey}\n"; + + await SendMessage(node, new NodeCommand { AddSshKey = new NodeCommandAddSshKey(key) }); + + return OneFuzzResult.Ok(true); + } + /// returns True on stopping the node and False if this doesn't stop the node private async Task StopIfComplete(Node node, bool done = false) { var nodeTaskIds = await _context.NodeTasksOperations.GetByMachineId(node.MachineId).Select(nt => nt.TaskId).ToArrayAsync(); From 8bcaa4cdb4ebcfbfd3e3134f11aec7561d8fece6 Mon Sep 17 00:00:00 2001 From: Cheick Keita Date: Tue, 26 Jul 2022 09:26:35 -0700 Subject: [PATCH 2/5] build fix --- .../ApiService/onefuzzlib/NodeOperations.cs | 20 ------------------- .../ApiService/onefuzzlib/TaskOperations.cs | 2 +- .../ApiService/onefuzzlib/orm/Orm.cs | 12 +++++------ 3 files changed, 7 insertions(+), 27 deletions(-) diff --git a/src/ApiService/ApiService/onefuzzlib/NodeOperations.cs b/src/ApiService/ApiService/onefuzzlib/NodeOperations.cs index d30a4e5645..b6bdcadfc7 100644 --- a/src/ApiService/ApiService/onefuzzlib/NodeOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/NodeOperations.cs @@ -423,26 +423,6 @@ public async Async.Task StopTask(Guid task_id) { } - public async Async.Task> Create(Container container, NotificationTemplate config, bool replaceExisting) { - if (await _context.Containers.FindContainer(container, StorageType.Corpus) == null) { - return OneFuzzResult.Error(ErrorCode.INVALID_REQUEST, errors: new[] { "invalid container" }); - } - - if (replaceExisting) { - var existing = this.SearchByRowKeys(new[] { container.ContainerName }); - await foreach (var existingEntry in existing) { - _logTracer.Info($"replacing existing notification: {existingEntry.NotificationId} - {container}"); - await this.Delete(existingEntry); - } - } - - var entry = new Notification(Guid.NewGuid(), container, config); - await this.Insert(entry); - _logTracer.Info($"created notification. notification_id:{entry.NotificationId} container:{entry.Container}"); - - return OneFuzzResult.Ok(entry); - } - public async Task> AddSshPublicKey(Node node, string publicKey) { if (publicKey == null) { throw new ArgumentNullException(nameof(publicKey)); diff --git a/src/ApiService/ApiService/onefuzzlib/TaskOperations.cs b/src/ApiService/ApiService/onefuzzlib/TaskOperations.cs index 2bcb59988e..00710649f5 100644 --- a/src/ApiService/ApiService/onefuzzlib/TaskOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/TaskOperations.cs @@ -110,7 +110,7 @@ public async Async.Task MarkFailed(Task task, Error error, List? taskInJob } private async Async.Task MarkDependantsFailed(Task task, List? taskInJob = null) { - taskInJob ??= await SearchByPartitionKey(task.JobId.ToString()).ToListAsync(); + taskInJob ??= await SearchByPartitionKeys(new[] { $"{task.JobId}" }).ToListAsync(); foreach (var t in taskInJob) { if (t.Config.PrereqTasks != null) { diff --git a/src/ApiService/ApiService/onefuzzlib/orm/Orm.cs b/src/ApiService/ApiService/onefuzzlib/orm/Orm.cs index f7cbb65c8c..5063a346e8 100644 --- a/src/ApiService/ApiService/onefuzzlib/orm/Orm.cs +++ b/src/ApiService/ApiService/onefuzzlib/orm/Orm.cs @@ -17,8 +17,8 @@ public interface IOrm where T : EntityBase { Task> Delete(T entity); IAsyncEnumerable SearchAll(); - IAsyncEnumerable SearchByPartitionKey(string partitionKey); - IAsyncEnumerable SearchByRowKey(string rowKey); + IAsyncEnumerable SearchByPartitionKeys(IEnumerable partitionKeys); + IAsyncEnumerable SearchByRowKeys(IEnumerable rowKeys); IAsyncEnumerable SearchByTimeRange(DateTimeOffset min, DateTimeOffset max); // Allow using tuple to search. @@ -123,11 +123,11 @@ public async Task GetTableClient(string table, string? accountId = public IAsyncEnumerable SearchAll() => QueryAsync(null); - public IAsyncEnumerable SearchByPartitionKey(string partitionKey) - => QueryAsync(Query.PartitionKey(partitionKey)); + public IAsyncEnumerable SearchByPartitionKeys(IEnumerable partitionKeys) + => QueryAsync(Query.PartitionKeys(partitionKeys)); - public IAsyncEnumerable SearchByRowKey(string rowKey) - => QueryAsync(Query.RowKey(rowKey)); + public IAsyncEnumerable SearchByRowKeys(IEnumerable rowKeys) + => QueryAsync(Query.RowKeys(rowKeys)); public IAsyncEnumerable SearchByTimeRange(DateTimeOffset min, DateTimeOffset max) { return QueryAsync(Query.TimeRange(min, max)); From a80c8b3fc126087b88287154731adc52c9115f2c Mon Sep 17 00:00:00 2001 From: Cheick Keita Date: Thu, 28 Jul 2022 09:53:18 -0700 Subject: [PATCH 3/5] fix --- src/ApiService/ApiService/Functions/NodeAddSshKey.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ApiService/ApiService/Functions/NodeAddSshKey.cs b/src/ApiService/ApiService/Functions/NodeAddSshKey.cs index c690ea570a..380047accc 100644 --- a/src/ApiService/ApiService/Functions/NodeAddSshKey.cs +++ b/src/ApiService/ApiService/Functions/NodeAddSshKey.cs @@ -49,7 +49,7 @@ private async Async.Task Post(HttpRequestData req) { [Function("node")] public Async.Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "POST", Route = "node/add_ssh_key")] HttpRequestData req) { return _auth.CallIfUser(req, r => r.Method switch { - // "POST" => Post(r), + "POST" => Post(r), _ => throw new InvalidOperationException("Unsupported HTTP method"), }); } From 83039c62c32c3accd5ae878ce1ac89cda9092e03 Mon Sep 17 00:00:00 2001 From: Cheick Keita Date: Fri, 29 Jul 2022 11:34:19 -0700 Subject: [PATCH 4/5] format --- src/ApiService/ApiService/Functions/NodeAddSshKey.cs | 2 +- src/ApiService/ApiService/onefuzzlib/TaskOperations.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ApiService/ApiService/Functions/NodeAddSshKey.cs b/src/ApiService/ApiService/Functions/NodeAddSshKey.cs index 380047accc..8753509a5c 100644 --- a/src/ApiService/ApiService/Functions/NodeAddSshKey.cs +++ b/src/ApiService/ApiService/Functions/NodeAddSshKey.cs @@ -49,7 +49,7 @@ private async Async.Task Post(HttpRequestData req) { [Function("node")] public Async.Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "POST", Route = "node/add_ssh_key")] HttpRequestData req) { return _auth.CallIfUser(req, r => r.Method switch { - "POST" => Post(r), + "POST" => Post(r), _ => throw new InvalidOperationException("Unsupported HTTP method"), }); } diff --git a/src/ApiService/ApiService/onefuzzlib/TaskOperations.cs b/src/ApiService/ApiService/onefuzzlib/TaskOperations.cs index 9b56f171f6..00710649f5 100644 --- a/src/ApiService/ApiService/onefuzzlib/TaskOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/TaskOperations.cs @@ -1,4 +1,4 @@ -using ApiService.OneFuzzLib.Orm; +using ApiService.OneFuzzLib.Orm; namespace Microsoft.OneFuzz.Service; From 9290c8bfc8f23600e779e49ca62ee7ae8b8569af Mon Sep 17 00:00:00 2001 From: Cheick Keita Date: Fri, 29 Jul 2022 12:22:20 -0700 Subject: [PATCH 5/5] fix return value and function name --- src/ApiService/ApiService/Functions/NodeAddSshKey.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ApiService/ApiService/Functions/NodeAddSshKey.cs b/src/ApiService/ApiService/Functions/NodeAddSshKey.cs index 8753509a5c..ae8ac9c290 100644 --- a/src/ApiService/ApiService/Functions/NodeAddSshKey.cs +++ b/src/ApiService/ApiService/Functions/NodeAddSshKey.cs @@ -40,13 +40,13 @@ private async Async.Task Post(HttpRequestData req) { } var response = req.CreateResponse(HttpStatusCode.OK); - await response.WriteAsJsonAsync(result); + await response.WriteAsJsonAsync(new BoolResult(true)); return response; } - [Function("node")] + [Function("node_add_ssh_key")] public Async.Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "POST", Route = "node/add_ssh_key")] HttpRequestData req) { return _auth.CallIfUser(req, r => r.Method switch { "POST" => Post(r),