public async Task CreateTaskAsync_ReturnsTesCreateTaskResponse()
        {
            // Arrange
            var mockRepo = new Mock <IRepository <TesTask> >();
            var tesTask  = new TesTask()
            {
                Executors = new List <TesExecutor> {
                    new TesExecutor {
                        Image = "ubuntu"
                    }
                }
            };

            var controller = new TaskServiceApiController(mockRepo.Object, new NullLogger <TaskServiceApiController>());

            // Act
            var result = await controller.CreateTaskAsync(tesTask) as ObjectResult;

            // Assert
            Assert.IsNotNull(result);
            mockRepo.Verify(x => x.CreateItemAsync(tesTask));
            Assert.AreEqual(32, tesTask.Id.Length);
            Assert.AreEqual(TesState.QUEUEDEnum, tesTask.State);
            Assert.AreEqual(200, result.StatusCode);
        }
Esempio n. 2
0
        public virtual async Task <IActionResult> CreateTaskAsync([FromBody] TesTask tesTask)
        {
            if (!string.IsNullOrWhiteSpace(tesTask.Id))
            {
                return(BadRequest("Id should not be included by the client in the request; the server is responsible for generating a unique Id."));
            }

            if (string.IsNullOrWhiteSpace(tesTask.Executors?.FirstOrDefault()?.Image))
            {
                return(BadRequest("Docker container image name is required."));
            }

            // If the description starts with a GUID (Cromwell's job id), prefix the TES task id with first eight characters (of job id) to facilitate easier debugging
            var tesTaskIdPrefix = tesTask.Description?.Length >= 36 && Guid.TryParse(tesTask.Description.Substring(0, 36), out _) ? $"{tesTask.Description.Substring(0, 8)}_" : "";

            tesTask.Id           = $"{tesTaskIdPrefix}{Guid.NewGuid().ToString("N")}";
            tesTask.State        = TesState.QUEUEDEnum;
            tesTask.CreationTime = DateTime.UtcNow.ToString("yyyy-MM-dd'T'HH:mm:ss.fffzzz", DateTimeFormatInfo.InvariantInfo);
            logger.LogDebug($"Creating task with id {tesTask.Id} state {tesTask.State}");
            await repository.CreateItemAsync(tesTask);

            return(StatusCode(200, new TesCreateTaskResponse {
                Id = tesTask.Id
            }));
        }
Esempio n. 3
0
        public virtual async Task <IActionResult> GetTaskAsync([FromRoute][Required] string id, [FromQuery] string view)
        {
            TesTask tesTask   = null;
            var     itemFound = await repository.TryGetItemAsync(id, item => tesTask = item);

            return(itemFound ? TesJsonResult(tesTask, view) : NotFound($"The task with id {id} does not exist."));
        }
        public async Task CreateTaskAsync_ReturnsBadRequest_ForBackendParametersStrict_DuplicateKeys()
        {
            const string backend_parameter_key = "vmsize";

            var backendParameters = new Dictionary <string, string>
            {
                { backend_parameter_key, Guid.NewGuid().ToString() },
                { "VmSize", Guid.NewGuid().ToString() }
            };

            var tesTask = new TesTask
            {
                Executors = new List <TesExecutor> {
                    new TesExecutor {
                        Image = "ubuntu"
                    }
                },
                Resources = new TesResources {
                    BackendParameters = backendParameters, BackendParametersStrict = true
                }
            };

            var controller = GetTaskServiceApiController();

            var result = await controller.CreateTaskAsync(tesTask) as BadRequestObjectResult;

            Assert.IsNotNull(result);

            Assert.AreEqual(400, result.StatusCode);
        }
        public async Task CancelTaskAsync_ReturnsEmptyObject()
        {
            // Arrange
            var tesTask = new TesTask()
            {
                Id = "testTaskId", State = TesState.QUEUEDEnum
            };
            var repositoryItem = new RepositoryItem <TesTask> {
                ETag = Guid.NewGuid().ToString(), Value = tesTask
            };

            var mockRepo = new Mock <IRepository <TesTask> >();

            mockRepo.Setup(repo => repo.GetItemAsync(tesTask.Id)).ReturnsAsync(repositoryItem);
            var controller = new TaskServiceApiController(mockRepo.Object, new NullLogger <TaskServiceApiController>());

            // Act
            var result = await controller.CancelTask(tesTask.Id) as ObjectResult;

            // Assert
            Assert.IsNotNull(result);
            Assert.AreEqual(200, result.StatusCode);
            Assert.AreEqual(TesState.CANCELEDEnum, repositoryItem.Value.State);
            mockRepo.Verify(x => x.UpdateItemAsync(tesTask.Id, repositoryItem));
        }
        public async Task GetTaskAsync_ReturnsJsonResult()
        {
            var tesTask = new TesTask
            {
                State = TesState.RUNNINGEnum
            };

            var mockRepo = new Mock <IRepository <TesTask> >();

            mockRepo.Setup(repo => repo.TryGetItemAsync(tesTask.Id, It.IsAny <Action <TesTask> >()))
            .Callback <string, Action <TesTask> >((id, action) =>
            {
                action(tesTask);
            })
            .ReturnsAsync(true);

            var controller = GetTaskServiceApiController(mockRepo.Object);

            var result = await controller.GetTaskAsync(tesTask.Id, "MINIMAL") as JsonResult;

            Assert.IsNotNull(result);
            mockRepo.Verify(x => x.TryGetItemAsync(tesTask.Id, It.IsAny <Action <TesTask> >()));
            Assert.AreEqual(TesState.RUNNINGEnum, tesTask.State);
            Assert.AreEqual(200, result.StatusCode);
        }
        public async Task ListTasks_ReturnsJsonResult()
        {
            var firstTesTask = new TesTask {
                Id = "tesTaskId1", State = TesState.COMPLETEEnum, Name = "tesTask", ETag = Guid.NewGuid().ToString()
            };
            var secondTesTask = new TesTask {
                Id = "tesTaskId2", State = TesState.EXECUTORERROREnum, Name = "tesTask2", ETag = Guid.NewGuid().ToString()
            };
            var thirdTesTask = new TesTask {
                Id = "tesTaskId3", State = TesState.EXECUTORERROREnum, Name = "someOtherTask2", ETag = Guid.NewGuid().ToString()
            };
            var namePrefix = "tesTask";

            var tesTasks = new[] { firstTesTask, secondTesTask, thirdTesTask };

            var mockRepo = new Mock <IRepository <TesTask> >();

            mockRepo.Setup(repo => repo
                           .GetItemsAsync(It.IsAny <Expression <Func <TesTask, bool> > >(), It.IsAny <int>(), It.IsAny <string>()))
            .ReturnsAsync((Expression <Func <TesTask, bool> > predicate, int pageSize, string continuationToken) =>
                          (string.Empty, tesTasks.Where(i => predicate.Compile().Invoke(i)).Take(pageSize)));

            var controller = GetTaskServiceApiController(mockRepo.Object);

            var result = await controller.ListTasks(namePrefix, 1, null, "BASIC") as JsonResult;

            var listOfTesTasks = (TesListTasksResponse)result.Value;

            Assert.IsNotNull(result);
            Assert.AreEqual(1, listOfTesTasks.Tasks.Count);
            Assert.AreEqual(200, result.StatusCode);
        }
        public async Task TES_Supports_BackendParameter_vmsize()
        {
            const string backend_parameter_key = "vm_size";

            var backendParameters = new Dictionary <string, string>
            {
                { backend_parameter_key, "VmSize1" }
            };

            var tesTask = new TesTask
            {
                Executors = new List <TesExecutor> {
                    new TesExecutor {
                        Image = "ubuntu"
                    }
                },
                Resources = new TesResources {
                    BackendParameters = backendParameters, BackendParametersStrict = true
                }
            };

            var repository = new Mock <IRepository <TesTask> >();
            var controller = GetTaskServiceApiController(repository.Object);

            var result = await controller.CreateTaskAsync(tesTask) as ObjectResult;

            Assert.IsNotNull(result);
            repository.Verify(x => x.CreateItemAsync(tesTask));
            Assert.AreEqual(32, tesTask.Id.Length);
            Assert.AreEqual(TesState.QUEUEDEnum, tesTask.State);
            Assert.IsTrue(tesTask.Resources.BackendParameters.ContainsKey(backend_parameter_key));
            Assert.AreEqual(200, result.StatusCode);
        }
        public async Task CreateTaskAsync_CromwellWorkflowIdIsUsedAsTaskIdPrefix()
        {
            var cromwellWorkflowId    = Guid.NewGuid().ToString();
            var cromwellSubWorkflowId = Guid.NewGuid().ToString();
            var taskDescription       = $"{cromwellSubWorkflowId}:BackendJobDescriptorKey_CommandCallNode_wf_hello.hello:-1:1";

            var tesTask = new TesTask()
            {
                Description = taskDescription,
                Executors   = new List <TesExecutor> {
                    new TesExecutor {
                        Image = "ubuntu"
                    }
                },
                Inputs = new List <TesInput> {
                    new TesInput {
                        Name = "commandScript", Path = $"/cromwell-executions/test/{cromwellWorkflowId}/call-hello/test-subworkflow/{cromwellSubWorkflowId}/call-subworkflow/shard-8/execution/script"
                    }
                }
            };

            var controller = GetTaskServiceApiController();

            await controller.CreateTaskAsync(tesTask);

            Assert.AreEqual(41, tesTask.Id.Length); // First eight characters of Cromwell's job id + underscore + GUID without dashes
            Assert.IsTrue(tesTask.Id.StartsWith(cromwellWorkflowId.Substring(0, 8) + "_"));
        }
Esempio n. 10
0
        /// <summary>
        /// Transitions the <see cref="TesTask"/> to the new state, based on the rules defined in the tesTaskStateTransitions list.
        /// </summary>
        /// <param name="tesTask">TES task</param>
        /// <param name="batchTaskState">Current Azure Batch task state</param>
        /// <returns>True if the TES task was changed.</returns>
        private async Task <bool> HandleTesTaskTransitionAsync(TesTask tesTask, BatchTaskState batchTaskState)
        {
            var tesTaskChanged = false;

            var mapItem = tesTaskStateTransitions
                          .FirstOrDefault(m => (m.Condition == null || m.Condition(tesTask)) && (m.CurrentBatchTaskState == null || m.CurrentBatchTaskState == batchTaskState));

            if (mapItem != null)
            {
                if (mapItem.Action != null)
                {
                    await mapItem.Action(tesTask);

                    tesTaskChanged = true;
                }

                if (mapItem.NewTesTaskState != null && mapItem.NewTesTaskState != tesTask.State)
                {
                    tesTask.State  = mapItem.NewTesTaskState.Value;
                    tesTaskChanged = true;
                }
            }

            return(tesTaskChanged);
        }
        /// <summary>
        /// Adds a new <see cref="TesTaskLog"/> to <see cref="TesTask"/>
        /// </summary>
        /// <param name="tesTask"><see cref="TesTask"/></param>
        /// <returns>Last <see cref="TesTaskLog"/></returns>
        public static TesTaskLog AddTesTaskLog(this TesTask tesTask)
        {
            tesTask.Logs ??= new List <TesTaskLog>();
            tesTask.Logs.Add(new TesTaskLog());

            return(tesTask.Logs.Last());
        }
Esempio n. 12
0
        public virtual async Task <IActionResult> CancelTask([FromRoute][Required] string id)
        {
            TesTask tesTask = null;

            if (await repository.TryGetItemAsync(id, item => tesTask = item))
            {
                if (tesTask.State == TesState.COMPLETEEnum ||
                    tesTask.State == TesState.EXECUTORERROREnum ||
                    tesTask.State == TesState.SYSTEMERROREnum)
                {
                    logger.LogInformation($"Task {id} cannot be canceled because it is in {tesTask.State} state.");
                }
                else if (tesTask.State != TesState.CANCELEDEnum)
                {
                    logger.LogInformation("Canceling task");
                    tesTask.IsCancelRequested = true;
                    tesTask.State             = TesState.CANCELEDEnum;
                    await repository.UpdateItemAsync(tesTask);
                }
            }
            else
            {
                return(NotFound($"The task with id {id} does not exist."));
            }


            return(StatusCode(200, new object()));
        }
        public async Task CreateTaskAsync_ReturnsTesCreateTaskResponseWithBackendParameters_UnsupportedKey()
        {
            const string unsupportedKey = "unsupported_key_2021";

            var backendParameters = new Dictionary <string, string>
            {
                { unsupportedKey, Guid.NewGuid().ToString() }
            };

            var tesTask = new TesTask
            {
                Executors = new List <TesExecutor> {
                    new TesExecutor {
                        Image = "ubuntu"
                    }
                },
                Resources = new TesResources {
                    BackendParameters = backendParameters
                }
            };

            var repository = new Mock <IRepository <TesTask> >();
            var controller = GetTaskServiceApiController(repository.Object);

            var result = await controller.CreateTaskAsync(tesTask) as ObjectResult;

            Assert.IsNotNull(result);
            repository.Verify(x => x.CreateItemAsync(tesTask));
            Assert.AreEqual(32, tesTask.Id.Length);
            Assert.AreEqual(TesState.QUEUEDEnum, tesTask.State);

            // Unsupported keys should not be persisted
            Assert.IsFalse(tesTask?.Resources?.BackendParameters?.ContainsKey(unsupportedKey));
            Assert.AreEqual(200, result.StatusCode);
        }
        public async Task CreateTaskAsync_ExtractsWorkflowId()
        {
            var cromwellWorkflowId = "daf1a044-d741-4db9-8eb5-d6fd0519b1f1";
            var taskDescription    = $"{cromwellWorkflowId}:BackendJobDescriptorKey_CommandCallNode_wf_hello.hello:-1:1";

            var tesTask = new TesTask()
            {
                Description = taskDescription,
                Executors   = new List <TesExecutor> {
                    new TesExecutor {
                        Image = "ubuntu"
                    }
                },
                Inputs = new List <TesInput> {
                    new TesInput {
                        Path = "/cromwell-executions/test/daf1a044-d741-4db9-8eb5-d6fd0519b1f1/call-hello/execution/script"
                    }
                }
            };

            var controller = this.GetTaskServiceApiController();

            await controller.CreateTaskAsync(tesTask);

            Assert.AreEqual(cromwellWorkflowId, tesTask.WorkflowId);
        }
        private async Task <TesTask> CreateCwlTesTaskAsync(string cwlFileContent, TesResources tesResourcesReceivedFromCromwell)
        {
            var tesTask = new TesTask()
            {
                Name      = "test.cwl",
                Executors = new List <TesExecutor> {
                    new TesExecutor {
                        Image = "ubuntu"
                    }
                },
                Inputs = new List <TesInput> {
                    new TesInput {
                        Path = "/cromwell-executions/test.cwl/daf1a044-d741-4db9-8eb5-d6fd0519b1f1/call-hello/execution/script"
                    }
                },
                Resources = tesResourcesReceivedFromCromwell
            };

            var azureProxy = new Mock <IAzureProxy>();

            azureProxy.Setup(a => a.TryReadCwlFile(It.IsAny <string>(), out cwlFileContent)).Returns(true);
            var controller = this.GetTaskServiceApiController(azureProxy.Object);

            await controller.CreateTaskAsync(tesTask);

            return(tesTask);
        }
        public async Task CancelTaskAsync_ReturnsEmptyObject()
        {
            var tesTask = new TesTask()
            {
                Id = "testTaskId", State = TesState.QUEUEDEnum
            };
            var repositoryItem = new RepositoryItem <TesTask> {
                ETag = Guid.NewGuid().ToString(), Value = tesTask
            };
            var mockRepo = new Mock <IRepository <TesTask> >();

            mockRepo.Setup(repo => repo.TryGetItemAsync(tesTask.Id, It.IsAny <Action <RepositoryItem <TesTask> > >()))
            .Callback <string, Action <RepositoryItem <TesTask> > >((id, action) =>
            {
                action(repositoryItem);
            })
            .ReturnsAsync(true);

            var controller = this.GetTaskServiceApiController(mockRepo.Object);

            var result = await controller.CancelTask(tesTask.Id) as ObjectResult;

            Assert.IsNotNull(result);
            Assert.AreEqual(200, result.StatusCode);
            Assert.AreEqual(TesState.CANCELEDEnum, repositoryItem.Value.State);
            mockRepo.Verify(x => x.UpdateItemAsync(tesTask.Id, repositoryItem));
        }
Esempio n. 17
0
        private async Task DeleteOldBatchJobs()
        {
            var jobsToDelete = await azureProxy.ListOldJobsToDeleteAsync(oldestJobAge);

            foreach (var jobId in jobsToDelete)
            {
                logger.LogInformation($"Job Id to delete: {jobId}");

                var tesTaskId = jobId.Split(new[] { '-' })[0];
                logger.LogInformation($"TES task Id to delete: {tesTaskId}");

                TesTask tesTask = null;

                if (await repository.TryGetItemAsync(tesTaskId, item => tesTask = item))
                {
                    if (tesTask.State == TesState.COMPLETEEnum ||
                        tesTask.State == TesState.EXECUTORERROREnum ||
                        tesTask.State == TesState.SYSTEMERROREnum ||
                        tesTask.State == TesState.CANCELEDEnum ||
                        tesTask.State == TesState.UNKNOWNEnum)
                    {
                        await azureProxy.DeleteBatchJobAsync(tesTaskId);
                    }
                }
            }
        }
        /// <summary>
        /// Adds a new Azure Batch pool/job/task for the given <see cref="TesTask"/>
        /// </summary>
        /// <param name="tesTask">The <see cref="TesTask"/> to schedule on Azure Batch</param>
        /// <returns>A task to await</returns>
        private async Task AddBatchJobAsync(TesTask tesTask)
        {
            try
            {
                var jobId = await azureProxy.GetNextBatchJobIdAsync(tesTask.Id);

                var virtualMachineInfo = await GetVmSizeAsync(tesTask.Resources);

                await CheckBatchAccountQuotas((int)tesTask.Resources.CpuCores.GetValueOrDefault(DefaultCoreCount), virtualMachineInfo.LowPriority);

                // TODO?: Support for multiple executors. Cromwell has single executor per task.
                var dockerImage = tesTask.Executors.First().Image;
                var cloudTask   = await ConvertTesTaskToBatchTaskAsync(tesTask);

                var poolInformation = await CreatePoolInformation(dockerImage, virtualMachineInfo.VmSize, virtualMachineInfo.LowPriority);

                tesTask.Resources.VmInfo = virtualMachineInfo;

                logger.LogInformation($"Creating batch job for TES task {tesTask.Id}. Using VM size {virtualMachineInfo}.");
                await azureProxy.CreateBatchJobAsync(jobId, cloudTask, poolInformation);

                tesTask.State = TesState.INITIALIZINGEnum;
            }
            catch (AzureBatchQuotaMaxedOutException exception)
            {
                logger.LogInformation($"Not enough quota available for task Id {tesTask.Id}. Reason: {exception.Message}. Task will remain in queue.");
            }
            catch (Exception exc)
            {
                tesTask.State = TesState.SYSTEMERROREnum;
                tesTask.WriteToSystemLog(exc.Message, exc.StackTrace);
                logger.LogError(exc, exc.Message);
            }
        }
        public async Task CreateTaskAsync_ExtractsWorkflowId()
        {
            var cromwellWorkflowId    = Guid.NewGuid().ToString();
            var cromwellSubWorkflowId = Guid.NewGuid().ToString();
            var taskDescription       = $"{cromwellSubWorkflowId}:BackendJobDescriptorKey_CommandCallNode_wf_hello.hello:-1:1";

            var tesTask = new TesTask()
            {
                Description = taskDescription,
                Executors   = new List <TesExecutor> {
                    new TesExecutor {
                        Image = "ubuntu"
                    }
                },
                Inputs = new List <TesInput> {
                    new TesInput {
                        Name = "commandScript", Path = $"/cromwell-executions/test/{cromwellWorkflowId}/call-hello/test-subworkflow/{cromwellSubWorkflowId}/call-subworkflow/shard-8/execution/script"
                    }
                }
            };

            var controller = GetTaskServiceApiController();

            await controller.CreateTaskAsync(tesTask);

            Assert.AreEqual(cromwellWorkflowId, tesTask.WorkflowId);
        }
        public async Task CreateTaskAsync_ReturnsBadRequest_ForBackendParametersStrict_UnsupportedKey()
        {
            const string unsupportedKey = "unsupported_key_2021";

            var backendParameters = new Dictionary <string, string>
            {
                { unsupportedKey, Guid.NewGuid().ToString() }
            };

            var tesTask = new TesTask
            {
                Executors = new List <TesExecutor> {
                    new TesExecutor {
                        Image = "ubuntu"
                    }
                },
                Resources = new TesResources {
                    BackendParameters = backendParameters, BackendParametersStrict = true
                }
            };

            var controller = GetTaskServiceApiController();

            var result = await controller.CreateTaskAsync(tesTask) as BadRequestObjectResult;

            Assert.IsNotNull(result);

            // Unsupported keys should cause a bad request when BackendParametersStrict = true
            Assert.AreEqual(400, result.StatusCode);

            // Unsupported keys should be returned in the warning message
            Assert.IsTrue(result.Value.ToString().Contains(unsupportedKey));
        }
        public async Task TES_Supports_BackendParameter_workflow_execution_identity()
        {
            const string backend_parameter_key = "workflow_execution_identity";

            var backendParameters = new Dictionary <string, string>
            {
                { backend_parameter_key, "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/coa/providers/Microsoft.ManagedIdentity/userAssignedIdentities/coa-test-uami" }
            };

            var tesTask = new TesTask
            {
                Executors = new List <TesExecutor> {
                    new TesExecutor {
                        Image = "ubuntu"
                    }
                },
                Resources = new TesResources {
                    BackendParameters = backendParameters, BackendParametersStrict = true
                }
            };

            var repository = new Mock <IRepository <TesTask> >();
            var controller = GetTaskServiceApiController(repository.Object);

            var result = await controller.CreateTaskAsync(tesTask) as ObjectResult;

            Assert.IsNotNull(result);
            repository.Verify(x => x.CreateItemAsync(tesTask));
            Assert.AreEqual(32, tesTask.Id.Length);
            Assert.AreEqual(TesState.QUEUEDEnum, tesTask.State);
            Assert.IsTrue(tesTask.Resources.BackendParameters.ContainsKey(backend_parameter_key));
            Assert.AreEqual(200, result.StatusCode);
        }
        public async Task GetTaskAsync_ReturnsJsonResult()
        {
            // Arrange
            var mockRepo = new Mock <IRepository <TesTask> >();
            var tesTask  = new TesTask
            {
                State = TesState.RUNNINGEnum
            };

            var repositoryItem = new RepositoryItem <TesTask> {
                ETag = Guid.NewGuid().ToString(), Value = tesTask
            };

            mockRepo.Setup(repo => repo.GetItemAsync(tesTask.Id)).ReturnsAsync(repositoryItem);
            var controller = new TaskServiceApiController(mockRepo.Object, new NullLogger <TaskServiceApiController>());

            // Act
            var result = await controller.GetTaskAsync(tesTask.Id, "MINIMAL") as JsonResult;

            // Assert
            Assert.IsNotNull(result);
            mockRepo.Verify(x => x.GetItemAsync(tesTask.Id));
            Assert.AreEqual(TesState.RUNNINGEnum, tesTask.State);
            Assert.AreEqual(200, result.StatusCode);
        }
Esempio n. 23
0
        /// <summary>
        /// Iteratively manages execution of a <see cref="TesTask"/> on Azure Batch until completion or failure
        /// </summary>
        /// <param name="tesTask">The <see cref="TesTask"/></param>
        /// <returns>True if the TES task needs to be persisted.</returns>
        public async Task <bool> ProcessTesTaskAsync(TesTask tesTask)
        {
            var batchTaskState = await GetBatchTaskStateAsync(tesTask.Id);

            var tesTaskChanged = await HandleTesTaskTransitionAsync(tesTask, batchTaskState);

            return(tesTaskChanged);
        }
 /// <summary>
 /// Writes to <see cref="TesTask"/> system log.
 /// </summary>
 /// <param name="tesTask"><see cref="TesTask"/></param>
 /// <param name="logEntries">List of strings to write to the log.</param>
 public static void AddToSystemLog(this TesTask tesTask, IEnumerable <string> logEntries)
 {
     if (logEntries != null && logEntries.Any(e => !string.IsNullOrEmpty(e)))
     {
         var tesTaskLog = tesTask.GetOrAddTesTaskLog();
         tesTaskLog.SystemLogs ??= new List <string>();
         tesTaskLog.SystemLogs.AddRange(logEntries);
     }
 }
 /// <summary>
 /// Writes to <see cref="TesTask"/> system log.
 /// </summary>
 /// <param name="tesTask"><see cref="TesTask"/></param>
 /// <param name="logEntries">List of strings to write to the log.</param>
 public static void WriteToSystemLog(this TesTask tesTask, params string[] logEntries)
 {
     if (logEntries != null && logEntries.Any(e => !string.IsNullOrEmpty(e)))
     {
         tesTask.Logs = tesTask.Logs ?? new List <TesTaskLog>();
         tesTask.Logs.Add(new TesTaskLog {
             SystemLogs = logEntries.ToList()
         });
     }
 }
        private static async Task <string> ProcessTesTaskAndGetFirstLogMessageAsync(TesTask tesTask, AzureProxy.AzureBatchJobAndTaskState?azureBatchJobAndTaskState = null)
        {
            var azureProxyReturnValues = AzureProxyReturnValues.Defaults;

            azureProxyReturnValues.BatchJobAndTaskState = azureBatchJobAndTaskState ?? azureProxyReturnValues.BatchJobAndTaskState;

            await ProcessTesTaskAndGetBatchJobArgumentsAsync(tesTask, GetMockConfig(), GetMockAzureProxy(azureProxyReturnValues));

            return(tesTask.Logs?.FirstOrDefault()?.SystemLogs?.FirstOrDefault());
        }
        public async Task CreateTaskAsync_ReturnsBadRequest_ForMissingDockerImage()
        {
            var tesTask    = new TesTask();
            var controller = GetTaskServiceApiController();

            var result = await controller.CreateTaskAsync(tesTask) as ObjectResult;

            Assert.IsNotNull(result);
            Assert.AreEqual(400, result.StatusCode);
        }
        /// <summary>
        /// Returns the last <see cref="TesTaskLog"/>. Adds it if none exist.
        /// </summary>
        /// <param name="tesTask"><see cref="TesTask"/></param>
        /// <returns>Last <see cref="TesTaskLog"/></returns>
        public static TesTaskLog GetOrAddTesTaskLog(this TesTask tesTask)
        {
            if (tesTask.Logs == null || !tesTask.Logs.Any())
            {
                tesTask.Logs = new List <TesTaskLog> {
                    new TesTaskLog()
                };
            }

            return(tesTask.Logs.Last());
        }
Esempio n. 29
0
        public virtual async Task <IActionResult> CreateTaskAsync([FromBody] TesTask tesTask)
        {
            if (!string.IsNullOrWhiteSpace(tesTask.Id))
            {
                return(BadRequest("Id should not be included by the client in the request; the server is responsible for generating a unique Id."));
            }

            if (string.IsNullOrWhiteSpace(tesTask.Executors?.FirstOrDefault()?.Image))
            {
                return(BadRequest("Docker container image name is required."));
            }

            tesTask.State        = TesState.QUEUEDEnum;
            tesTask.CreationTime = DateTime.UtcNow.ToString("yyyy-MM-dd'T'HH:mm:ss.fffzzz", DateTimeFormatInfo.InvariantInfo);

            // example: /cromwell-executions/test/daf1a044-d741-4db9-8eb5-d6fd0519b1f1/call-hello/execution/script
            tesTask.WorkflowId = tesTask
                                 ?.Inputs
                                 ?.FirstOrDefault(i => i?.Path?.StartsWith(rootExecutionPath, StringComparison.OrdinalIgnoreCase) == true)
                                 ?.Path
                                 ?.Split('/', StringSplitOptions.RemoveEmptyEntries)
                                 ?.Skip(2)
                                 ?.FirstOrDefault();

            // Prefix the TES task id with first eight characters of root Cromwell job id to facilitate easier debugging
            var tesTaskIdPrefix = tesTask.WorkflowId != null && Guid.TryParse(tesTask.WorkflowId, out _) ? $"{tesTask.WorkflowId.Substring(0, 8)}_" : "";

            tesTask.Id = $"{tesTaskIdPrefix}{Guid.NewGuid().ToString("N")}";

            // For CWL workflows, if disk size is not specified in TES object (always), try to retrieve it from the corresponding workflow stored by Cromwell in /cromwell-tmp directory
            // Also allow for TES-style "memory" and "cpu" hints in CWL.
            if (tesTask.Name != null &&
                tesTask.Inputs.Any(i => i.Path.Contains(".cwl/")) &&
                tesTask.WorkflowId != null &&
                azureProxy.TryReadCwlFile(tesTask.WorkflowId, out var cwlContent) &&
                CwlDocument.TryCreate(cwlContent, out var cwlDocument))
            {
                tesTask.Resources          = tesTask.Resources ?? new TesResources();
                tesTask.Resources.DiskGb   = tesTask.Resources.DiskGb ?? cwlDocument.DiskGb;
                tesTask.Resources.CpuCores = tesTask.Resources.CpuCores ?? cwlDocument.Cpu;
                tesTask.Resources.RamGb    = tesTask.Resources.RamGb ?? cwlDocument.MemoryGb;

                // Preemptible is not passed on from CWL workflows to Cromwell, so Cromwell sends the default (TRUE) to TES,
                // instead of NULL like the other values above.
                // If CWL document has it specified, override the value sent by Cromwell
                tesTask.Resources.Preemptible = cwlDocument.Preemptible ?? tesTask.Resources.Preemptible;
            }
            logger.LogDebug($"Creating task with id {tesTask.Id} state {tesTask.State}");
            await repository.CreateItemAsync(tesTask);

            return(StatusCode(200, new TesCreateTaskResponse {
                Id = tesTask.Id
            }));
        }
Esempio n. 30
0
        public async Task TryGetItemAsync_ThrowsException_DoesNotSetCache()
        {
            SystemClock.SleepAsync = (_, __) => Task.FromResult(true);
            SystemClock.Sleep      = (_, __) => { };
            var repository        = GetMockRepository();
            var cachingRepository = new CachingWithRetriesRepository <TesTask>(repository.Object);

            TesTask tesTask = null;
            await Assert.ThrowsExceptionAsync <Exception>(async() => await cachingRepository.TryGetItemAsync("throws", item => tesTask = item));

            repository.Verify(mock => mock.TryGetItemAsync("throws", It.IsAny <Action <TesTask> >()), Times.Exactly(4));
        }