From 0aca28d52dd9adefe9156013c757473ab06bbe4d Mon Sep 17 00:00:00 2001 From: Victor Chang Date: Tue, 5 Sep 2023 10:09:02 -0700 Subject: [PATCH] Fix allowed Argo parameter list and logging scope data not being rendered correctly (#870) * Fix argo parameter validation keys. Fix to correctly serialize logger scope values. Signed-off-by: Victor Chang * Fix unit tests Change argo pod date time to use the universal full ("U") format specifier Signed-off-by: Victor Chang --- .../Configuration/ArgoParameters.cs} | 62 ++++++++++++++- .../Miscellaneous/LoggingDataDictionary.cs | 40 ++++++++++ .../Miscellaneous/ValidationConstants.cs | 33 -------- .../AideClinicalReviewPlugin.cs | 2 +- src/TaskManager/Plug-ins/Argo/ArgoPlugin.cs | 77 +++++++++---------- .../Plug-ins/Argo/ExitHookTemplate.cs | 11 ++- .../Argo/StaticValues/ResourcesKey.cs | 24 ------ .../Argo/StaticValues/ResourcesKeys.cs | 29 ------- .../Plug-ins/Docker/DockerPlugin.cs | 3 +- ....WorkflowManager.TaskManager.Docker.csproj | 1 + src/TaskManager/Plug-ins/Email/EmailPlugin.cs | 2 +- src/TaskManager/TaskManager/TaskManager.cs | 8 +- .../TaskManager/packages.lock.json | 1 + .../Services/EventPayloadRecieverService.cs | 6 +- .../Services/PayloadListenerService.cs | 6 +- .../Validators/EventPayloadValidator.cs | 6 +- .../WorkflowExecuter/Common/ArtifactMapper.cs | 3 +- .../Services/WorkflowExecuterService.cs | 10 +-- .../Controllers/WorkflowInstanceController.cs | 5 +- .../Validators/WorkflowValidator.cs | 24 +++--- .../TaskManager.Argo.Tests/ArgoPluginTest.cs | 30 ++++---- .../Validators/WorkflowValidatorTests.cs | 2 +- 22 files changed, 195 insertions(+), 190 deletions(-) rename src/{TaskManager/Plug-ins/Argo/StaticValues/Keys.cs => Common/Configuration/ArgoParameters.cs} (65%) create mode 100644 src/Common/Miscellaneous/LoggingDataDictionary.cs delete mode 100644 src/TaskManager/Plug-ins/Argo/StaticValues/ResourcesKey.cs delete mode 100644 src/TaskManager/Plug-ins/Argo/StaticValues/ResourcesKeys.cs diff --git a/src/TaskManager/Plug-ins/Argo/StaticValues/Keys.cs b/src/Common/Configuration/ArgoParameters.cs similarity index 65% rename from src/TaskManager/Plug-ins/Argo/StaticValues/Keys.cs rename to src/Common/Configuration/ArgoParameters.cs index 5e78c2f15..b816994ed 100644 --- a/src/TaskManager/Plug-ins/Argo/StaticValues/Keys.cs +++ b/src/Common/Configuration/ArgoParameters.cs @@ -14,10 +14,25 @@ * limitations under the License. */ -namespace Monai.Deploy.WorkflowManager.TaskManager.Argo.StaticValues +using System.Collections.Generic; + +namespace Monai.Deploy.WorkflowManager.Common.Configuration { - internal static class Keys + public static class ArgoParameters { + public struct ResourcesKey + { + public string TaskKey { get; set; } + public string ArgoKey { get; set; } + } + public static class ResourcesKeys + { + public static readonly ResourcesKey GpuLimit = new() { TaskKey = GpuRequired, ArgoKey = "nvidia.com/gpu" }; + + public static readonly ResourcesKey MemoryLimit = new() { TaskKey = Memory, ArgoKey = "memory" }; + + public static readonly ResourcesKey CpuLimit = new() { TaskKey = Cpu, ArgoKey = "cpu" }; + } /// /// Key for the namespace where the Argo workflows are stored and executed. /// @@ -76,18 +91,33 @@ internal static class Keys /// /// Key for resource limitations /// - public static readonly string ArgoResource = "resources"; + public static readonly string Resources = "resources"; /// /// Key for resource limitations /// - public static readonly string ArgoParameters = "parameters"; + public static readonly string Parameters = "parameters"; /// /// Key for priority classnames on task plugin arguments side /// public static readonly string TaskPriorityClassName = "priority"; + /// + /// Key for the CPU. + /// + public static readonly string Cpu = "cpu"; + + /// + /// Key for the memory. + /// + public static readonly string Memory = "memory"; + + /// + /// Key for the GPU. + /// + public static readonly string GpuRequired = "gpu_required"; + /// /// Required arguments to run the Argo workflow. /// @@ -96,6 +126,30 @@ internal static class Keys WorkflowTemplateName }; + /// + /// Required arguments to run the Argo workflow. + /// + public static readonly IReadOnlyList VaildParameters = + new List { + Namespace, + BaseUrl, + AllowInsecureseUrl, + WorkflowTemplateName, + TimeoutSeconds, + ArgoApiToken, + MessagingEndpoint, + MessagingUsername, + MessagingPassword, + MessagingExchange, + MessagingVhost, + Resources, + Parameters, + TaskPriorityClassName, + Cpu, + Memory, + GpuRequired, + }; + /// /// Required settings to run the Argo workflow. /// diff --git a/src/Common/Miscellaneous/LoggingDataDictionary.cs b/src/Common/Miscellaneous/LoggingDataDictionary.cs new file mode 100644 index 000000000..9048a9640 --- /dev/null +++ b/src/Common/Miscellaneous/LoggingDataDictionary.cs @@ -0,0 +1,40 @@ +/* + * Copyright 2021-2023 MONAI Consortium + * Copyright 2021 NVIDIA Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System.Globalization; +using System.Runtime.Serialization; + +namespace Monai.Deploy.WorkflowManager.Common.Miscellaneous +{ + [Serializable] + public class LoggingDataDictionary : Dictionary where TKey : notnull + { + public LoggingDataDictionary() + { + } + + protected LoggingDataDictionary(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + + public override string ToString() + { + var pairs = this.Select(x => string.Format(CultureInfo.InvariantCulture, "{0}={1}", x.Key, x.Value)); + return string.Join(", ", pairs); + } + } +} diff --git a/src/Common/Miscellaneous/ValidationConstants.cs b/src/Common/Miscellaneous/ValidationConstants.cs index 1429ac56e..727ab8b56 100644 --- a/src/Common/Miscellaneous/ValidationConstants.cs +++ b/src/Common/Miscellaneous/ValidationConstants.cs @@ -53,21 +53,6 @@ public static class ValidationConstants /// public static readonly string Notifications = "notifications"; - /// - /// Key for the CPU. - /// - public static readonly string Cpu = "cpu"; - - /// - /// Key for the memory. - /// - public static readonly string Memory = "memory"; - - /// - /// Key for the GPU. - /// - public static readonly string GpuRequired = "gpu_required"; - /// /// Key for recipient emails. /// @@ -107,24 +92,6 @@ public enum NotificationValues Mode }; - /// - /// Key for the endpoint where the Argo server is running. - /// - public static readonly string BaseUrl = "server_url"; - - /// - /// Key for the name of the main 'WorkflowTemplate' stored on the targeted Argo server. - /// - public static readonly string WorkflowTemplateName = "workflow_template_name"; - - /// - /// Required arguments to run the Argo task args. - /// - public static readonly IReadOnlyList ArgoRequiredParameters = - new List { - BaseUrl, - WorkflowTemplateName - }; /// diff --git a/src/TaskManager/Plug-ins/AideClinicalReview/AideClinicalReviewPlugin.cs b/src/TaskManager/Plug-ins/AideClinicalReview/AideClinicalReviewPlugin.cs index 0af719ecd..e6e37063b 100644 --- a/src/TaskManager/Plug-ins/AideClinicalReview/AideClinicalReviewPlugin.cs +++ b/src/TaskManager/Plug-ins/AideClinicalReview/AideClinicalReviewPlugin.cs @@ -189,7 +189,7 @@ private void ValidateEventAndInit() public override async Task ExecuteTask(CancellationToken cancellationToken = default) { - using var loggingScope = _logger.BeginScope(new Dictionary + using var loggingScope = _logger.BeginScope(new LoggingDataDictionary { ["correlationId"] = Event.CorrelationId, ["workflowInstanceId"] = Event.WorkflowInstanceId, diff --git a/src/TaskManager/Plug-ins/Argo/ArgoPlugin.cs b/src/TaskManager/Plug-ins/Argo/ArgoPlugin.cs index 2aa6c20b9..fdafd7232 100755 --- a/src/TaskManager/Plug-ins/Argo/ArgoPlugin.cs +++ b/src/TaskManager/Plug-ins/Argo/ArgoPlugin.cs @@ -29,7 +29,6 @@ using Monai.Deploy.WorkflowManager.TaskManager.API.Extensions; using Monai.Deploy.WorkflowManager.TaskManager.API.Models; using Monai.Deploy.WorkflowManager.TaskManager.Argo.Logging; -using Monai.Deploy.WorkflowManager.TaskManager.Argo.StaticValues; using Newtonsoft.Json; [assembly: PlugIn()] @@ -84,7 +83,7 @@ public ArgoPlugin( private void Initialize() { - using var loggingScope = _logger.BeginScope(new Dictionary + using var loggingScope = _logger.BeginScope(new LoggingDataDictionary { ["correlationId"] = Event.CorrelationId, ["workflowInstanceId"] = Event.WorkflowInstanceId, @@ -93,54 +92,54 @@ private void Initialize() ["payloadId"] = Event.PayloadId }); - if (Event.TaskPluginArguments.ContainsKey(Keys.TimeoutSeconds) && - !string.IsNullOrWhiteSpace(Event.TaskPluginArguments[Keys.TimeoutSeconds]) && - int.TryParse(Event.TaskPluginArguments[Keys.TimeoutSeconds], out var result)) + if (Event.TaskPluginArguments.ContainsKey(ArgoParameters.TimeoutSeconds) && + !string.IsNullOrWhiteSpace(Event.TaskPluginArguments[ArgoParameters.TimeoutSeconds]) && + int.TryParse(Event.TaskPluginArguments[ArgoParameters.TimeoutSeconds], out var result)) { _activeDeadlineSeconds = result; } - if (Event.TaskPluginArguments.ContainsKey(Keys.ArgoApiToken) && - !string.IsNullOrWhiteSpace(Event.TaskPluginArguments[Keys.ArgoApiToken])) + if (Event.TaskPluginArguments.ContainsKey(ArgoParameters.ArgoApiToken) && + !string.IsNullOrWhiteSpace(Event.TaskPluginArguments[ArgoParameters.ArgoApiToken])) { - _apiToken = Event.TaskPluginArguments[Keys.ArgoApiToken]; + _apiToken = Event.TaskPluginArguments[ArgoParameters.ArgoApiToken]; } bool updateEvent = false; - if (Event.TaskPluginArguments.ContainsKey(Keys.Namespace) && - !string.IsNullOrWhiteSpace(Event.TaskPluginArguments[Keys.Namespace])) + if (Event.TaskPluginArguments.ContainsKey(ArgoParameters.Namespace) && + !string.IsNullOrWhiteSpace(Event.TaskPluginArguments[ArgoParameters.Namespace])) { - _namespace = Event.TaskPluginArguments[Keys.Namespace]; + _namespace = Event.TaskPluginArguments[ArgoParameters.Namespace]; } else { _namespace = Strings.DefaultNamespace; - Event.TaskPluginArguments.Add(Keys.Namespace, _namespace); + Event.TaskPluginArguments.Add(ArgoParameters.Namespace, _namespace); updateEvent = true; } - if (Event.TaskPluginArguments.ContainsKey(Keys.AllowInsecureseUrl) && - !string.IsNullOrWhiteSpace(Event.TaskPluginArguments[Keys.AllowInsecureseUrl])) + if (Event.TaskPluginArguments.ContainsKey(ArgoParameters.AllowInsecureseUrl) && + !string.IsNullOrWhiteSpace(Event.TaskPluginArguments[ArgoParameters.AllowInsecureseUrl])) { - _allowInsecure = string.Compare("true", Event.TaskPluginArguments[Keys.AllowInsecureseUrl], true) == 0; + _allowInsecure = string.Compare("true", Event.TaskPluginArguments[ArgoParameters.AllowInsecureseUrl], true) == 0; } else { _allowInsecure = true; - Event.TaskPluginArguments.Add(Keys.AllowInsecureseUrl, "true"); + Event.TaskPluginArguments.Add(ArgoParameters.AllowInsecureseUrl, "true"); updateEvent = true; } - if (Event.TaskPluginArguments.ContainsKey(Keys.BaseUrl) && - !string.IsNullOrWhiteSpace(Event.TaskPluginArguments[Keys.BaseUrl])) + if (Event.TaskPluginArguments.ContainsKey(ArgoParameters.BaseUrl) && + !string.IsNullOrWhiteSpace(Event.TaskPluginArguments[ArgoParameters.BaseUrl])) { - _baseUrl = Event.TaskPluginArguments[Keys.BaseUrl]; + _baseUrl = Event.TaskPluginArguments[ArgoParameters.BaseUrl]; } else { _baseUrl = _options.Value.TaskManager.ArgoPluginArguments.ServerUrl; - Event.TaskPluginArguments.Add(Keys.BaseUrl, _baseUrl); + Event.TaskPluginArguments.Add(ArgoParameters.BaseUrl, _baseUrl); updateEvent = true; } @@ -161,10 +160,10 @@ private void ValidateEvent() { if (Event.TaskPluginArguments is null || Event.TaskPluginArguments.Count == 0) { - throw new InvalidTaskException($"Required parameters to execute Argo workflow are missing: {string.Join(',', Keys.RequiredParameters)}"); + throw new InvalidTaskException($"Required parameters to execute Argo workflow are missing: {string.Join(',', ArgoParameters.RequiredParameters)}"); } - foreach (var key in Keys.RequiredParameters) + foreach (var key in ArgoParameters.RequiredParameters) { if (!Event.TaskPluginArguments.ContainsKey(key) && string.IsNullOrWhiteSpace(Event.TaskPluginArguments[key])) @@ -173,7 +172,7 @@ private void ValidateEvent() } } - foreach (var key in Keys.RequiredSettings) + foreach (var key in ArgoParameters.RequiredSettings) { if (!_options.Value.Messaging.PublisherSettings.ContainsKey(key)) { @@ -181,16 +180,16 @@ private void ValidateEvent() } } - if (Event.TaskPluginArguments.ContainsKey(Keys.BaseUrl) && - !string.IsNullOrWhiteSpace(Event.TaskPluginArguments[Keys.BaseUrl]) && !Uri.IsWellFormedUriString(Event.TaskPluginArguments[Keys.BaseUrl], UriKind.Absolute)) + if (Event.TaskPluginArguments.ContainsKey(ArgoParameters.BaseUrl) && + !string.IsNullOrWhiteSpace(Event.TaskPluginArguments[ArgoParameters.BaseUrl]) && !Uri.IsWellFormedUriString(Event.TaskPluginArguments[ArgoParameters.BaseUrl], UriKind.Absolute)) { - throw new InvalidTaskException($"The value '{Event.TaskPluginArguments[Keys.BaseUrl]}' provided for '{Keys.BaseUrl}' is not a valid URI."); + throw new InvalidTaskException($"The value '{Event.TaskPluginArguments[ArgoParameters.BaseUrl]}' provided for '{ArgoParameters.BaseUrl}' is not a valid URI."); } } public override async Task ExecuteTask(CancellationToken cancellationToken = default) { - using var loggingScope = _logger.BeginScope(new Dictionary + using var loggingScope = _logger.BeginScope(new LoggingDataDictionary { ["correlationId"] = Event.CorrelationId, ["workflowInstanceId"] = Event.WorkflowInstanceId, @@ -348,8 +347,8 @@ private Dictionary GetExecutuionStats(Workflow workflow) preprend = Strings.ExitHookTemplateSendTemplateName; } #pragma warning disable CS8604 // Possible null reference argument. - stats.Add($"{preprend}podStartTime{podcount}", item.Value.StartedAt is not null ? item.Value.StartedAt.ToString() : ""); - stats.Add($"{preprend}podFinishTime{podcount++}", item.Value.FinishedAt is not null ? item.Value.FinishedAt.ToString() : ""); + stats.Add($"{preprend}podStartTime{podcount}", item.Value.StartedAt?.UtcDateTime.ToString("u") ?? string.Empty); + stats.Add($"{preprend}podFinishTime{podcount++}", item.Value.FinishedAt?.UtcDateTime.ToString("u") ?? string.Empty); #pragma warning restore CS8604 // Possible null reference argument. } } @@ -386,7 +385,7 @@ private async Task BuildWorkflowWrapper(CancellationToken cancellation Kind = Strings.KindWorkflow, Metadata = new ObjectMeta() { - GenerateName = $"md-{Event.TaskPluginArguments![Keys.WorkflowTemplateName]}-", + GenerateName = $"md-{Event.TaskPluginArguments![ArgoParameters.WorkflowTemplateName]}-", Labels = new Dictionary { { Strings.TaskIdLabelSelectorName, Event.TaskId! }, @@ -417,7 +416,7 @@ private async Task BuildWorkflowWrapper(CancellationToken cancellation _logger.ArgoWorkflowTemplateGenerated(workflow.Metadata.GenerateName); var workflowJson = JsonConvert.SerializeObject(workflow, Formatting.Indented); - workflowJson = workflowJson.Replace(_options.Value.Messaging.PublisherSettings[Keys.MessagingPassword], "*****"); + workflowJson = workflowJson.Replace(_options.Value.Messaging.PublisherSettings[ArgoParameters.MessagingPassword], "*****"); _logger.ArgoWorkflowTemplateJson(workflow.Metadata.GenerateName, workflowJson); @@ -433,19 +432,19 @@ private async Task BuildWorkflowWrapper(CancellationToken cancellation private void ProcessTaskPluginArguments(Workflow workflow) { Guard.Against.Null(workflow, nameof(workflow)); - var priorityClassName = Event.GetTaskPluginArgumentsParameter(Keys.TaskPriorityClassName) ?? "standard"; + var priorityClassName = Event.GetTaskPluginArgumentsParameter(ArgoParameters.TaskPriorityClassName) ?? "standard"; foreach (var template in workflow.Spec.Templates) { - AddLimit(template, ResourcesKeys.CpuLimit); - AddLimit(template, ResourcesKeys.MemoryLimit); - AddLimit(template, ResourcesKeys.GpuLimit); + AddLimit(template, ArgoParameters.ResourcesKeys.CpuLimit); + AddLimit(template, ArgoParameters.ResourcesKeys.MemoryLimit); + AddLimit(template, ArgoParameters.ResourcesKeys.GpuLimit); template.PriorityClassName = priorityClassName; } workflow.Spec.PodPriorityClassName = priorityClassName; } - private void AddLimit(Template2 template, ResourcesKey key) + private void AddLimit(Template2 template, ArgoParameters.ResourcesKey key) { Guard.Against.Null(template, nameof(template)); Guard.Against.Null(key, nameof(key)); @@ -463,7 +462,7 @@ private void AddLimit(Template2 template, ResourcesKey key) } // Convert true / false value to 0 or 1 for number of GPU - if (key.TaskKey == ResourcesKeys.GpuLimit.TaskKey) + if (key.TaskKey == ArgoParameters.ResourcesKeys.GpuLimit.TaskKey) { value = bool.TryParse(value, out bool gpuRequired) && gpuRequired ? "1" : "0"; } @@ -475,11 +474,11 @@ private async Task AddMainWorkflowTemplate(Workflow workflow, CancellationToken { Guard.Against.Null(workflow, nameof(workflow)); - var workflowTemplate = await LoadWorkflowTemplate(Event.TaskPluginArguments![Keys.WorkflowTemplateName]).ConfigureAwait(false); + var workflowTemplate = await LoadWorkflowTemplate(Event.TaskPluginArguments![ArgoParameters.WorkflowTemplateName]).ConfigureAwait(false); if (workflowTemplate is null) { - throw new TemplateNotFoundException(Event.TaskPluginArguments![Keys.WorkflowTemplateName]); + throw new TemplateNotFoundException(Event.TaskPluginArguments![ArgoParameters.WorkflowTemplateName]); } var mainTemplateSteps = new Template2() { diff --git a/src/TaskManager/Plug-ins/Argo/ExitHookTemplate.cs b/src/TaskManager/Plug-ins/Argo/ExitHookTemplate.cs index 87b018d45..5c6a6b74f 100755 --- a/src/TaskManager/Plug-ins/Argo/ExitHookTemplate.cs +++ b/src/TaskManager/Plug-ins/Argo/ExitHookTemplate.cs @@ -17,7 +17,6 @@ using Argo; using Monai.Deploy.Messaging.Events; using Monai.Deploy.WorkflowManager.Common.Configuration; -using Monai.Deploy.WorkflowManager.TaskManager.Argo.StaticValues; using Newtonsoft.Json; namespace Monai.Deploy.WorkflowManager.TaskManager.Argo @@ -42,13 +41,13 @@ public ExitHookTemplate(WorkflowManagerOptions options, TaskDispatchEvent taskDi _messagingEndpoint = options.Messaging.ArgoCallback.ArgoCallbackOverrideEnabled ? options.Messaging.ArgoCallback.ArgoRabbitOverrideEndpoint : - options.Messaging.PublisherSettings[Keys.MessagingEndpoint]; + options.Messaging.PublisherSettings[ArgoParameters.MessagingEndpoint]; - _messagingUsername = options.Messaging.PublisherSettings[Keys.MessagingUsername]; - _messagingPassword = options.Messaging.PublisherSettings[Keys.MessagingPassword]; + _messagingUsername = options.Messaging.PublisherSettings[ArgoParameters.MessagingUsername]; + _messagingPassword = options.Messaging.PublisherSettings[ArgoParameters.MessagingPassword]; _messagingTopic = options.Messaging.Topics.TaskCallbackRequest; - _messagingExchange = options.Messaging.PublisherSettings[Keys.MessagingExchange]; - _messagingVhost = options.Messaging.PublisherSettings[Keys.MessagingVhost]; + _messagingExchange = options.Messaging.PublisherSettings[ArgoParameters.MessagingExchange]; + _messagingVhost = options.Messaging.PublisherSettings[ArgoParameters.MessagingVhost]; _messageId = Guid.NewGuid(); _messageFileName = $"{_messageId}.json"; } diff --git a/src/TaskManager/Plug-ins/Argo/StaticValues/ResourcesKey.cs b/src/TaskManager/Plug-ins/Argo/StaticValues/ResourcesKey.cs deleted file mode 100644 index 350dd052d..000000000 --- a/src/TaskManager/Plug-ins/Argo/StaticValues/ResourcesKey.cs +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2022 MONAI Consortium - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -namespace Monai.Deploy.WorkflowManager.TaskManager.Argo.StaticValues -{ - public struct ResourcesKey - { - public string TaskKey { get; set; } - public string ArgoKey { get; set; } - } -} diff --git a/src/TaskManager/Plug-ins/Argo/StaticValues/ResourcesKeys.cs b/src/TaskManager/Plug-ins/Argo/StaticValues/ResourcesKeys.cs deleted file mode 100644 index 52fcfd174..000000000 --- a/src/TaskManager/Plug-ins/Argo/StaticValues/ResourcesKeys.cs +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2022 MONAI Consortium - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using static Monai.Deploy.WorkflowManager.Common.Miscellaneous.ValidationConstants; - -namespace Monai.Deploy.WorkflowManager.TaskManager.Argo.StaticValues -{ - public static class ResourcesKeys - { - public static readonly ResourcesKey GpuLimit = new() { TaskKey = GpuRequired, ArgoKey = "nvidia.com/gpu" }; - - public static readonly ResourcesKey MemoryLimit = new() { TaskKey = Memory, ArgoKey = "memory" }; - - public static readonly ResourcesKey CpuLimit = new() { TaskKey = Cpu, ArgoKey = "cpu" }; - } -} diff --git a/src/TaskManager/Plug-ins/Docker/DockerPlugin.cs b/src/TaskManager/Plug-ins/Docker/DockerPlugin.cs index b10d746fd..c75e1eb10 100644 --- a/src/TaskManager/Plug-ins/Docker/DockerPlugin.cs +++ b/src/TaskManager/Plug-ins/Docker/DockerPlugin.cs @@ -22,6 +22,7 @@ using Microsoft.Extensions.Logging; using Monai.Deploy.Messaging.Events; using Monai.Deploy.Storage.API; +using Monai.Deploy.WorkflowManager.Common.Miscellaneous; using Monai.Deploy.WorkflowManager.TaskManager.API; using Monai.Deploy.WorkflowManager.TaskManager.Docker.Logging; @@ -109,7 +110,7 @@ public override async Task ExecuteTask(CancellationToken cancel ContainerVolumeMount intermediateVolumeMount; List outputVolumeMounts; - using var loggingScope = _logger.BeginScope(new Dictionary + using var loggingScope = _logger.BeginScope(new LoggingDataDictionary { ["correlationId"] = Event.CorrelationId, ["workflowInstanceId"] = Event.WorkflowInstanceId, diff --git a/src/TaskManager/Plug-ins/Docker/Monai.Deploy.WorkflowManager.TaskManager.Docker.csproj b/src/TaskManager/Plug-ins/Docker/Monai.Deploy.WorkflowManager.TaskManager.Docker.csproj index 99d94b012..03b04f619 100644 --- a/src/TaskManager/Plug-ins/Docker/Monai.Deploy.WorkflowManager.TaskManager.Docker.csproj +++ b/src/TaskManager/Plug-ins/Docker/Monai.Deploy.WorkflowManager.TaskManager.Docker.csproj @@ -38,6 +38,7 @@ + diff --git a/src/TaskManager/Plug-ins/Email/EmailPlugin.cs b/src/TaskManager/Plug-ins/Email/EmailPlugin.cs index e0b582fcf..6a1a53d13 100644 --- a/src/TaskManager/Plug-ins/Email/EmailPlugin.cs +++ b/src/TaskManager/Plug-ins/Email/EmailPlugin.cs @@ -113,7 +113,7 @@ private void ValidateEventAndInit() public override async Task ExecuteTask(CancellationToken cancellationToken = default) { - using var loggingScope = _logger.BeginScope(new Dictionary + using var loggingScope = _logger.BeginScope(new LoggingDataDictionary { ["correlationId"] = Event.CorrelationId, ["workflowInstanceId"] = Event.WorkflowInstanceId, diff --git a/src/TaskManager/TaskManager/TaskManager.cs b/src/TaskManager/TaskManager/TaskManager.cs index 0e29af285..7cdfe9453 100644 --- a/src/TaskManager/TaskManager/TaskManager.cs +++ b/src/TaskManager/TaskManager/TaskManager.cs @@ -196,7 +196,7 @@ private async Task TaskCallBackGeneric(MessageReceivedEventArgs args, Func + using var loggingScope = _logger.BeginScope(new Common.Miscellaneous.LoggingDataDictionary { ["correlationId"] = args.Message.CorrelationId, ["messageId"] = args.Message.MessageId, @@ -288,7 +288,7 @@ private async Task HandleTaskCallback(JsonMessage message) ITaskPlugin? taskRunner = null; - using var loggingScope = _logger.BeginScope(new Dictionary + using var loggingScope = _logger.BeginScope(new Common.Miscellaneous.LoggingDataDictionary { ["durationSoFar"] = (DateTime.UtcNow - taskExecution.Started).TotalMilliseconds, ["correlationId"] = taskExecution.Event.CorrelationId, @@ -404,7 +404,7 @@ private async Task HandleDispatchTask(JsonMessage message) var eventInfo = new API.Models.TaskDispatchEventInfo(message.Body); try { - using var messageLoggingScope = _logger.BeginScope(new Dictionary + using var messageLoggingScope = _logger.BeginScope(new Common.Miscellaneous.LoggingDataDictionary { ["workflowInstanceId"] = eventInfo.Event.WorkflowInstanceId, ["taskId"] = eventInfo.Event.TaskId, @@ -631,7 +631,7 @@ private async Task HandleMessageException(MessageBase message, string workflowIn return; } - using var loggingScope = _logger.BeginScope(new Dictionary + using var loggingScope = _logger.BeginScope(new Common.Miscellaneous.LoggingDataDictionary { ["correlationId"] = message.CorrelationId, ["workflowInstanceId"] = workflowInstanceId, diff --git a/src/TaskManager/TaskManager/packages.lock.json b/src/TaskManager/TaskManager/packages.lock.json index 104933168..79d9b4cf9 100644 --- a/src/TaskManager/TaskManager/packages.lock.json +++ b/src/TaskManager/TaskManager/packages.lock.json @@ -1643,6 +1643,7 @@ "dependencies": { "Docker.DotNet": "[3.125.13, )", "Monai.Deploy.WorkflowManager.Common.Configuration": "[1.0.0, )", + "Monai.Deploy.WorkflowManager.Common.Miscellaneous": "[1.0.0, )", "Monai.Deploy.WorkflowManager.TaskManager.API": "[1.0.0, )" } }, diff --git a/src/WorkflowManager/PayloadListener/Services/EventPayloadRecieverService.cs b/src/WorkflowManager/PayloadListener/Services/EventPayloadRecieverService.cs index 67d781124..dcc7dbcc8 100644 --- a/src/WorkflowManager/PayloadListener/Services/EventPayloadRecieverService.cs +++ b/src/WorkflowManager/PayloadListener/Services/EventPayloadRecieverService.cs @@ -57,7 +57,7 @@ public async Task ReceiveWorkflowPayload(MessageReceivedEventArgs message) { var requestEvent = message.Message.ConvertTo(); - using var loggingScope = (Logger.BeginScope(new Dictionary + using var loggingScope = (Logger.BeginScope(new LoggingDataDictionary { ["correlationId"] = requestEvent.CorrelationId, ["workflowId"] = requestEvent.Workflows.FirstOrDefault() @@ -105,7 +105,7 @@ public async Task TaskUpdatePayload(MessageReceivedEventArgs message) { var payload = message.Message.ConvertTo(); - using var loggerScope = Logger.BeginScope(new Dictionary + using var loggerScope = Logger.BeginScope(new LoggingDataDictionary { ["correlationId"] = payload.CorrelationId, ["workflowInstanceId"] = payload.WorkflowInstanceId, @@ -143,7 +143,7 @@ public async Task ExportCompletePayload(MessageReceivedEventArgs message) { var payload = message.Message.ConvertTo(); - using var loggerScope = Logger.BeginScope(new Dictionary { ["workflowInstanceId"] = payload.WorkflowInstanceId }); + using var loggerScope = Logger.BeginScope(new LoggingDataDictionary { ["workflowInstanceId"] = payload.WorkflowInstanceId }); if (!PayloadValidator.ValidateExportComplete(payload)) { diff --git a/src/WorkflowManager/PayloadListener/Services/PayloadListenerService.cs b/src/WorkflowManager/PayloadListener/Services/PayloadListenerService.cs index 62a39607a..74490f57f 100644 --- a/src/WorkflowManager/PayloadListener/Services/PayloadListenerService.cs +++ b/src/WorkflowManager/PayloadListener/Services/PayloadListenerService.cs @@ -108,7 +108,7 @@ private void SetupPolling() private async Task OnWorkflowRequestReceivedCallbackAsync(MessageReceivedEventArgs eventArgs) { - using var loggerScope = _logger.BeginScope(new Dictionary + using var loggerScope = _logger.BeginScope(new Common.Miscellaneous.LoggingDataDictionary { ["correlationId"] = eventArgs.Message.CorrelationId, ["source"] = eventArgs.Message.ApplicationId, @@ -122,7 +122,7 @@ private async Task OnWorkflowRequestReceivedCallbackAsync(MessageReceivedEventAr private async Task OnTaskUpdateStatusReceivedCallback(MessageReceivedEventArgs eventArgs) { - using var loggerScope = _logger.BeginScope(new Dictionary + using var loggerScope = _logger.BeginScope(new Common.Miscellaneous.LoggingDataDictionary { ["correlationId"] = eventArgs.Message.CorrelationId, ["source"] = eventArgs.Message.ApplicationId, @@ -136,7 +136,7 @@ private async Task OnTaskUpdateStatusReceivedCallback(MessageReceivedEventArgs e private async Task OnExportCompleteReceivedCallback(MessageReceivedEventArgs eventArgs) { - using var loggerScope = _logger.BeginScope(new Dictionary + using var loggerScope = _logger.BeginScope(new Common.Miscellaneous.LoggingDataDictionary { ["correlationId"] = eventArgs.Message.CorrelationId, ["source"] = eventArgs.Message.ApplicationId, diff --git a/src/WorkflowManager/PayloadListener/Validators/EventPayloadValidator.cs b/src/WorkflowManager/PayloadListener/Validators/EventPayloadValidator.cs index e1c2f5682..c188d9388 100644 --- a/src/WorkflowManager/PayloadListener/Validators/EventPayloadValidator.cs +++ b/src/WorkflowManager/PayloadListener/Validators/EventPayloadValidator.cs @@ -36,7 +36,7 @@ public bool ValidateWorkflowRequest(WorkflowRequestEvent payload) { Guard.Against.Null(payload, nameof(payload)); - using var loggingScope = Logger.BeginScope(new Dictionary + using var loggingScope = Logger.BeginScope(new LoggingDataDictionary { ["correlationId"] = payload.CorrelationId, ["payloadId"] = payload.PayloadId, @@ -71,7 +71,7 @@ public bool ValidateTaskUpdate(TaskUpdateEvent payload) { Guard.Against.Null(payload, nameof(payload)); - using var loggingScope = Logger.BeginScope(new Dictionary + using var loggingScope = Logger.BeginScope(new LoggingDataDictionary { ["correlationId"] = payload.CorrelationId, ["executionId"] = payload.ExecutionId, @@ -95,7 +95,7 @@ public bool ValidateExportComplete(ExportCompleteEvent payload) { Guard.Against.Null(payload, nameof(payload)); - using var loggingScope = Logger.BeginScope(new Dictionary + using var loggingScope = Logger.BeginScope(new LoggingDataDictionary { ["workflowInstanceId"] = payload.WorkflowInstanceId, ["exportTaskId"] = payload.ExportTaskId, diff --git a/src/WorkflowManager/WorkflowExecuter/Common/ArtifactMapper.cs b/src/WorkflowManager/WorkflowExecuter/Common/ArtifactMapper.cs index f3b773776..731942445 100755 --- a/src/WorkflowManager/WorkflowExecuter/Common/ArtifactMapper.cs +++ b/src/WorkflowManager/WorkflowExecuter/Common/ArtifactMapper.cs @@ -20,6 +20,7 @@ using Monai.Deploy.WorkflowManager.Common.Contracts.Models; using Monai.Deploy.WorkflowManager.Common.Database.Interfaces; using Monai.Deploy.WorkflowManager.Common.Logging; +using Monai.Deploy.WorkflowManager.Common.Miscellaneous; namespace Monai.Deploy.WorkflowManager.Common.WorkfowExecuter.Common { @@ -41,7 +42,7 @@ public ArtifactMapper( public bool TryConvertArtifactVariablesToPath(Artifact[] artifacts, string payloadId, string workflowInstanceId, string bucketId, bool shouldExistYet, out Dictionary artifactPaths) { - using var loggingScope = _logger.BeginScope(new Dictionary + using var loggingScope = _logger.BeginScope(new LoggingDataDictionary { ["payloadId"] = payloadId, ["workflowInstanceId"] = workflowInstanceId, diff --git a/src/WorkflowManager/WorkflowExecuter/Services/WorkflowExecuterService.cs b/src/WorkflowManager/WorkflowExecuter/Services/WorkflowExecuterService.cs index 78f290ea5..12e41525a 100644 --- a/src/WorkflowManager/WorkflowExecuter/Services/WorkflowExecuterService.cs +++ b/src/WorkflowManager/WorkflowExecuter/Services/WorkflowExecuterService.cs @@ -197,7 +197,7 @@ public async Task ProcessFirstWorkflowTask(WorkflowInstance workflowInstance, st return; } - using var loggingScope = _logger.BeginScope(new Dictionary + using var loggingScope = _logger.BeginScope(new LoggingDataDictionary { ["workflowInstanceId"] = workflowInstance.Id, ["durationSoFar"] = (DateTime.UtcNow - workflowInstance.StartTime).TotalMilliseconds, @@ -285,7 +285,7 @@ public async Task ProcessTaskUpdate(TaskUpdateEvent message) var currentTask = workflowInstance.Tasks.FirstOrDefault(t => t.TaskId == message.TaskId); - using var loggingScope = _logger.BeginScope(new Dictionary + using var loggingScope = _logger.BeginScope(new LoggingDataDictionary { ["workflowInstanceId"] = workflowInstance.Id, ["taskStatus"] = message.Status, @@ -393,7 +393,7 @@ public async Task ProcessExportComplete(ExportCompleteEvent message, strin return false; } - using var loggingScope = _logger.BeginScope(new Dictionary + using var loggingScope = _logger.BeginScope(new LoggingDataDictionary { ["workflowInstanceId"] = workflowInstance.Id, ["durationSoFar"] = (DateTime.UtcNow - workflowInstance.StartTime).TotalMilliseconds, @@ -627,7 +627,7 @@ private async Task DispatchTaskDestinations(WorkflowInstance workflowInsta foreach (var taskExec in taskExecutions) { - using var loggingScope = _logger.BeginScope(new Dictionary { ["executionId"] = taskExec?.ExecutionId ?? "" }); + using var loggingScope = _logger.BeginScope(new LoggingDataDictionary { ["executionId"] = taskExec?.ExecutionId ?? "" }); if (taskExec is null) { @@ -745,7 +745,7 @@ private async Task DispatchTask(WorkflowInstance workflowInstance, Workflo return false; } - using (_logger.BeginScope(new Dictionary { ["correlationId"] = correlationId, ["taskId"] = task.Id, ["executionId"] = taskExec.ExecutionId })) + using (_logger.BeginScope(new LoggingDataDictionary { ["correlationId"] = correlationId, ["taskId"] = task.Id, ["executionId"] = taskExec.ExecutionId })) { var outputArtifacts = task.Artifacts?.Output; diff --git a/src/WorkflowManager/WorkflowManager/Controllers/WorkflowInstanceController.cs b/src/WorkflowManager/WorkflowManager/Controllers/WorkflowInstanceController.cs index 98703c9e7..9e3b30546 100644 --- a/src/WorkflowManager/WorkflowManager/Controllers/WorkflowInstanceController.cs +++ b/src/WorkflowManager/WorkflowManager/Controllers/WorkflowInstanceController.cs @@ -25,6 +25,7 @@ using Monai.Deploy.WorkflowManager.Common.Configuration; using Monai.Deploy.WorkflowManager.Common.Contracts.Models; using Monai.Deploy.WorkflowManager.Common.Logging; +using Monai.Deploy.WorkflowManager.Common.Miscellaneous; using Monai.Deploy.WorkflowManager.Common.Miscellaneous.Exceptions; using Monai.Deploy.WorkflowManager.Common.Miscellaneous.Filter; using Monai.Deploy.WorkflowManager.Common.Miscellaneous.Interfaces; @@ -141,7 +142,7 @@ public async Task GetByIdAsync([FromRoute] string id) return Problem($"Failed to validate {nameof(id)}, not a valid GUID", $"{ENDPOINT}{id}", BadRequest); } - using var loggingScope = _logger.BeginScope(new Dictionary + using var loggingScope = _logger.BeginScope(new LoggingDataDictionary { ["workflowId"] = id, }); @@ -219,7 +220,7 @@ public async Task AcknowledgeTaskError([FromRoute] string id, [Fr return Problem($"Failed to validate {nameof(executionId)}, not a valid GUID", $"/workflows/{id}/executions/{executionId}/acknowledge", BadRequest); } - using var loggingScope = _logger.BeginScope(new Dictionary + using var loggingScope = _logger.BeginScope(new LoggingDataDictionary { ["workflowId"] = id, ["executionId"] = executionId, diff --git a/src/WorkflowManager/WorkflowManager/Validators/WorkflowValidator.cs b/src/WorkflowManager/WorkflowManager/Validators/WorkflowValidator.cs index 52e21ae62..335828560 100644 --- a/src/WorkflowManager/WorkflowManager/Validators/WorkflowValidator.cs +++ b/src/WorkflowManager/WorkflowManager/Validators/WorkflowValidator.cs @@ -44,11 +44,6 @@ public class WorkflowValidator /// public static readonly string Separator = ";"; - /// - /// the name of the class for priority. - /// - public static readonly string TaskPriorityClassName = "priority"; - private const string Comma = ", "; private readonly ILogger _logger; private readonly IOptions _options; @@ -385,22 +380,21 @@ private void ValidateInputs(TaskObject currentTask) private void ValidateArgoTask(TaskObject currentTask) { - if (!currentTask.Args.ContainsKey(WorkflowTemplateName)) + if (!currentTask.Args.ContainsKey(ArgoParameters.WorkflowTemplateName)) { Errors.Add($"Task: '{currentTask.Id}' workflow_template_name must be specified{Comma}this corresponds to an Argo template name."); } - var validKeys = new string[] { WorkflowTemplateName, TaskPriorityClassName, Cpu, Memory, GpuRequired }; - var invalidKeys = currentTask.Args.Keys.Where(k => !validKeys.Contains(k)); + var invalidKeys = currentTask.Args.Keys.Where(k => !ArgoParameters.VaildParameters.Contains(k)); if (invalidKeys.Count() > 0) { - Errors.Add($"Task: '{currentTask.Id}' args has invalid keys: {string.Join(", ", invalidKeys)}. Please only specify keys from the following list: {string.Join(", ", validKeys)}."); + Errors.Add($"Task: '{currentTask.Id}' args has invalid keys: {string.Join(", ", invalidKeys)}. Please only specify keys from the following list: {string.Join(", ", ArgoParameters.VaildParameters)}."); return; } - if (currentTask.Args.ContainsKey(TaskPriorityClassName)) + if (currentTask.Args.ContainsKey(ArgoParameters.TaskPriorityClassName)) { - switch (currentTask.Args[TaskPriorityClassName].ToLower()) + switch (currentTask.Args[ArgoParameters.TaskPriorityClassName].ToLower()) { case "high" or "standard" or "low": break; @@ -411,18 +405,18 @@ private void ValidateArgoTask(TaskObject currentTask) } if ( - currentTask.Args.TryGetValue(Cpu, out var val) && + currentTask.Args.TryGetValue(ArgoParameters.Cpu, out var val) && (string.IsNullOrEmpty(val) || (double.TryParse(val, out double parsedVal) && (parsedVal < 1 || Math.Truncate(parsedVal) != parsedVal)))) { - Errors.Add($"Task: '{currentTask.Id}' value '{val}' provided for argument '{Cpu}' is not valid. The value needs to be a whole number greater than 0."); + Errors.Add($"Task: '{currentTask.Id}' value '{val}' provided for argument '{ArgoParameters.Cpu}' is not valid. The value needs to be a whole number greater than 0."); } if ( - currentTask.Args.TryGetValue(GpuRequired, out var gpuRequired) && + currentTask.Args.TryGetValue(ArgoParameters.GpuRequired, out var gpuRequired) && (string.IsNullOrEmpty(gpuRequired) || !bool.TryParse(gpuRequired, out var _))) { - Errors.Add($"Task: '{currentTask.Id}' value '{gpuRequired}' provided for argument '{GpuRequired}' is not valid. The value needs to be 'true' or 'false'."); + Errors.Add($"Task: '{currentTask.Id}' value '{gpuRequired}' provided for argument '{ArgoParameters.GpuRequired}' is not valid. The value needs to be 'true' or 'false'."); } } diff --git a/tests/UnitTests/TaskManager.Argo.Tests/ArgoPluginTest.cs b/tests/UnitTests/TaskManager.Argo.Tests/ArgoPluginTest.cs index 7c3d6154e..f54dc8153 100755 --- a/tests/UnitTests/TaskManager.Argo.Tests/ArgoPluginTest.cs +++ b/tests/UnitTests/TaskManager.Argo.Tests/ArgoPluginTest.cs @@ -28,9 +28,9 @@ using Microsoft.Extensions.Logging; using Monai.Deploy.Messaging.Configuration; using Monai.Deploy.Messaging.Events; +using Monai.Deploy.WorkflowManager.Common.Configuration; using Monai.Deploy.WorkflowManager.Common.SharedTest; using Monai.Deploy.WorkflowManager.TaskManager.API; -using Monai.Deploy.WorkflowManager.TaskManager.Argo.StaticValues; using Moq; using Moq.Language.Flow; using Newtonsoft.Json; @@ -67,12 +67,12 @@ public void ArgoPlugin_ThrowsWhenMissingRequiredSettings() Options.Value.Messaging.PublisherSettings.Remove("password"); Assert.Throws(() => new ArgoPlugin(ServiceScopeFactory.Object, _logger.Object, Options, message)); - foreach (var key in Keys.RequiredSettings.Take(Keys.RequiredSettings.Count - 1)) + foreach (var key in ArgoParameters.RequiredSettings.Take(ArgoParameters.RequiredSettings.Count - 1)) { message.TaskPluginArguments.Add(key, Guid.NewGuid().ToString()); Assert.Throws(() => new ArgoPlugin(ServiceScopeFactory.Object, _logger.Object, Options, message)); } - message.TaskPluginArguments[Keys.RequiredSettings[Keys.RequiredSettings.Count - 1]] = Guid.NewGuid().ToString(); + message.TaskPluginArguments[ArgoParameters.RequiredSettings[ArgoParameters.RequiredSettings.Count - 1]] = Guid.NewGuid().ToString(); Assert.Throws(() => new ArgoPlugin(ServiceScopeFactory.Object, _logger.Object, Options, message)); } @@ -236,7 +236,7 @@ public async Task ArgoPlugin_ExecuteTask_ReturnsExecutionStatusWhenFailedToLocat Assert.Equal(TaskExecutionStatus.Failed, result.Status); Assert.Equal(FailureReason.PluginError, result.FailureReason); - Assert.Equal($"Template '{argoTemplate.Spec.Entrypoint}' cannot be found in the referenced WorkflowTmplate '{message.TaskPluginArguments[Keys.WorkflowTemplateName]}'.", result.Errors); + Assert.Equal($"Template '{argoTemplate.Spec.Entrypoint}' cannot be found in the referenced WorkflowTmplate '{message.TaskPluginArguments[ArgoParameters.WorkflowTemplateName]}'.", result.Errors); ArgoClient.Verify(p => p.Argo_CreateWorkflowAsync(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never()); K8sCoreOperations.Verify(p => p.CreateNamespacedSecretWithHttpMessagesAsync( @@ -506,9 +506,9 @@ public async Task ArgoPlugin_GetStatus_Argregates_stats() Message = Strings.ArgoPhaseSucceeded, Nodes = new Dictionary { - { "first", new NodeStatus { Id = "firstId" ,Type="Pod" ,Name="", StartedAt = new DateTime(2023,3,3) , FinishedAt = new DateTime(2023,3,3,8,0,32)} }, - { "second", new NodeStatus { Id = "secondId",Type="Pod" ,Name = $"node-{Strings.ExitHookTemplateSendTemplateName}" , StartedAt = new DateTime(2023,3,4) , FinishedAt = new DateTime(2023,3,4,8,0,32)} }, - { "third", new NodeStatus { Id = "thirdId" ,Type="Pod" ,Name="", StartedAt = new DateTime(2023,3,4) , FinishedAt = new DateTime(2023,3,4,8,0,32)} }, + { "first", new NodeStatus { Id = "firstId" ,Type="Pod" ,Name="", StartedAt = DateTime.SpecifyKind(new DateTime(2023,3,3), DateTimeKind.Utc) , FinishedAt = DateTime.SpecifyKind(new DateTime(2023,3,3,8,0,32), DateTimeKind.Utc)} }, + { "second", new NodeStatus { Id = "secondId",Type="Pod" ,Name = $"node-{Strings.ExitHookTemplateSendTemplateName}" , StartedAt = DateTime.SpecifyKind(new DateTime(2023,3,4), DateTimeKind.Utc) , FinishedAt = DateTime.SpecifyKind(new DateTime(2023,3,4,8,0,32), DateTimeKind.Utc)} }, + { "third", new NodeStatus { Id = "thirdId" ,Type="Pod" ,Name="", StartedAt = DateTime.SpecifyKind(new DateTime(2023,3,4) , DateTimeKind.Utc), FinishedAt = DateTime.SpecifyKind(new DateTime(2023,3,4,8,0,32), DateTimeKind.Utc)} }, } } }; @@ -528,7 +528,7 @@ public async Task ArgoPlugin_GetStatus_Argregates_stats() Assert.True(nodeInfo.ContainsKey("podStartTime0")); Assert.True(nodeInfo.ContainsKey("podFinishTime0")); Assert.True(nodeInfo.ContainsKey("send-messagepodFinishTime1")); - Assert.Equal("03/03/2023 08:00:32 +00:00", nodeInfo["podFinishTime0"]); + Assert.Equal("2023-03-03 08:00:32Z", nodeInfo["podFinishTime0"]); ArgoClient.Verify(p => p.Argo_GetWorkflowAsync(It.Is(p => p.Equals("namespace", StringComparison.OrdinalIgnoreCase)), It.Is(p => p.Equals("identity", StringComparison.OrdinalIgnoreCase)), It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(3)); } @@ -893,15 +893,15 @@ private void SetUpSimpleArgoWorkFlow(WorkflowTemplate argoTemplate) private static TaskDispatchEvent GenerateTaskDispatchEventWithValidArguments(bool withoutDefaultProperties = false) { var message = GenerateTaskDispatchEvent(); - message.TaskPluginArguments[Keys.WorkflowTemplateName] = "workflowTemplate"; - message.TaskPluginArguments[Keys.TimeoutSeconds] = "50"; - message.TaskPluginArguments[Keys.ArgoApiToken] = "token"; + message.TaskPluginArguments[ArgoParameters.WorkflowTemplateName] = "workflowTemplate"; + message.TaskPluginArguments[ArgoParameters.TimeoutSeconds] = "50"; + message.TaskPluginArguments[ArgoParameters.ArgoApiToken] = "token"; if (withoutDefaultProperties is false) { - message.TaskPluginArguments[Keys.BaseUrl] = "http://api-endpoint/"; - message.TaskPluginArguments[Keys.Namespace] = "namespace"; - message.TaskPluginArguments[Keys.AllowInsecureseUrl] = "true"; + message.TaskPluginArguments[ArgoParameters.BaseUrl] = "http://api-endpoint/"; + message.TaskPluginArguments[ArgoParameters.Namespace] = "namespace"; + message.TaskPluginArguments[ArgoParameters.AllowInsecureseUrl] = "true"; } return message; @@ -973,7 +973,7 @@ private static TaskDispatchEvent GenerateTaskDispatchEvent() Kind = "WorkflowTemplate", Metadata = new ObjectMeta() { - Name = taskDispatchEvent.TaskPluginArguments[Keys.WorkflowTemplateName], + Name = taskDispatchEvent.TaskPluginArguments[ArgoParameters.WorkflowTemplateName], }, Spec = new WorkflowSpec { diff --git a/tests/UnitTests/WorkflowManager.Tests/Validators/WorkflowValidatorTests.cs b/tests/UnitTests/WorkflowManager.Tests/Validators/WorkflowValidatorTests.cs index 5072a4d15..422a52ce3 100644 --- a/tests/UnitTests/WorkflowManager.Tests/Validators/WorkflowValidatorTests.cs +++ b/tests/UnitTests/WorkflowManager.Tests/Validators/WorkflowValidatorTests.cs @@ -670,7 +670,7 @@ public async Task ValidateWorkflow_ValidatesAWorkflow_ReturnsErrorsAndHasCorrect var invalidSourceName = "Data origin invalid_origin does not exists. Please review sources configuration management."; Assert.Contains(invalidSourceName, errors); - var invalidArgoKey = $"Task: 'invalid-key-argo-task' args has invalid keys: invalid_key. Please only specify keys from the following list: workflow_template_name, priority, cpu, memory, gpu_required."; + var invalidArgoKey = $"Task: 'invalid-key-argo-task' args has invalid keys: invalid_key. Please only specify keys from the following list: {string.Join(", ", ArgoParameters.VaildParameters)}."; Assert.Contains(invalidArgoKey, errors); var emailMissingEmailAndRolesArgs = "No recipients arguments specified for task EmailTask_MissingEmailAndRolesArgs. Email tasks must specify at least one of the following properties: recipient_emails, recipient_roles";