From 2ccef18f69dc68e61a85be57014f84cc6986c697 Mon Sep 17 00:00:00 2001 From: Alex Lepsa Date: Fri, 22 Jan 2021 10:59:58 -0500 Subject: [PATCH 01/18] mb 2.12.0-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 680d2f9..a42fb84 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ org.icgc.argo workflow-management - 2.11.0 + 2.12.0-SNAPSHOT workflow-management ARGO Workflow Management From 9ece3ec8eae6c769fd34d0af528a20f3670a421f Mon Sep 17 00:00:00 2001 From: jaserud Date: Mon, 1 Feb 2021 14:50:11 -0500 Subject: [PATCH 02/18] Split mgmt into two profiles, api and execute (#154) * Split mgmt into two profiles, api and execute * misc clean up * rename for clarity * user queue and exchange name to create dl equivalents * update license blurbs * timestamp --- README.md | 2 +- pom.xml | 49 ++++++ .../WorkflowManagementApplication.java | 2 +- .../config/secret/ApiKeyConfig.java | 2 +- .../config/secret/NoSecretProviderConfig.java | 4 +- .../config/secret/OAuth2TokenConfig.java | 2 +- .../config/security/AuthDisabledConfig.java | 2 +- .../config/security/AuthEnabledConfig.java | 16 +- .../config/security/AuthProperties.java | 2 +- .../exception/GlobalExceptionHandler.java | 2 +- .../exception/NextflowRunException.java | 2 +- .../exception/ReflectionUtilsException.java | 2 +- .../exception/model/ErrorResponse.java | 2 +- .../AddReactiveContextInputCustomizer.java | 2 +- .../graphql/GraphQLProvider.java | 2 +- .../graphql/MutationDataFetcher.java | 64 +++----- .../graphql/model/GqlRunsRequest.java | 2 +- .../model/GqlWorkflowEngineParams.java | 2 +- .../properties/Swagger2Properties.java | 2 +- .../properties/WebfluxProperties.java | 2 +- .../rabbitmq/ApiProducerConfig.java | 102 +++++++++++++ .../rabbitmq/ExecuteConsumerConfig.java | 144 ++++++++++++++++++ .../rabbitmq/WfMgmtRunMsgConverters.java | 137 +++++++++++++++++ .../secret/SecretProvider.java | 2 +- .../secret/impl/ApiKeyProvider.java | 2 +- .../secret/impl/NoSecretProvider.java | 2 +- .../impl/OAuth2BearerTokenProvider.java | 2 +- .../ApiToWesService.java} | 10 +- .../api_to_wes/impl/ApiProducerToWes.java | 59 +++++++ .../service/api_to_wes/impl/DirectToWes.java | 64 ++++++++ .../service/{ => wes}/NextflowService.java | 32 ++-- .../{ => wes}/NextflowWebLogEventSender.java | 32 ++-- .../{ => wes}/NextflowWorkflowMonitor.java | 13 +- .../service/wes/WorkflowExecutionService.java | 29 ++++ .../{ => wes}/model/KubernetesPhase.java | 4 +- .../{ => wes}/model/NextflowMetadata.java | 4 +- .../model/NextflowWorkflowMetadata.java | 4 +- .../service/{ => wes}/model/RunParams.java | 5 +- .../service/wes/model/WfManagementEvent.java | 41 +++++ .../properties/NextflowProperties.java | 4 +- .../util/ConditionalPutMap.java | 2 +- .../util/JacksonUtils.java | 7 +- .../util/NextflowConfigFile.java | 2 +- .../workflow_management/util/ParamsFile.java | 2 +- .../workflow_management/util/Reflections.java | 2 +- .../workflow_management/util/WesUtils.java | 49 ++++++ .../wes/controller/RunsApi.java | 2 +- .../controller/impl/RunsApiController.java | 34 +---- .../wes/controller/model/RunsRequest.java | 2 +- .../wes/controller/model/RunsResponse.java | 2 +- .../model/WorkflowEngineParams.java | 4 +- src/main/resources/application.yml | 30 +++- src/main/resources/avro/WfMgmtRunMsg.avsc | 88 +++++++++++ .../ConditionalPutMapTest.java | 2 +- .../ErrorHandlingTests.java | 26 ++-- .../WorkflowManagementApplicationTests.java | 2 +- .../util/RandomGenerator.java | 2 +- .../util/WorkflowTest.java | 57 ------- 58 files changed, 943 insertions(+), 229 deletions(-) create mode 100644 src/main/java/org/icgc/argo/workflow_management/rabbitmq/ApiProducerConfig.java create mode 100644 src/main/java/org/icgc/argo/workflow_management/rabbitmq/ExecuteConsumerConfig.java create mode 100644 src/main/java/org/icgc/argo/workflow_management/rabbitmq/WfMgmtRunMsgConverters.java rename src/main/java/org/icgc/argo/workflow_management/service/{WorkflowExecutionService.java => api_to_wes/ApiToWesService.java} (84%) create mode 100644 src/main/java/org/icgc/argo/workflow_management/service/api_to_wes/impl/ApiProducerToWes.java create mode 100644 src/main/java/org/icgc/argo/workflow_management/service/api_to_wes/impl/DirectToWes.java rename src/main/java/org/icgc/argo/workflow_management/service/{ => wes}/NextflowService.java (89%) rename src/main/java/org/icgc/argo/workflow_management/service/{ => wes}/NextflowWebLogEventSender.java (79%) rename src/main/java/org/icgc/argo/workflow_management/service/{ => wes}/NextflowWorkflowMonitor.java (90%) create mode 100644 src/main/java/org/icgc/argo/workflow_management/service/wes/WorkflowExecutionService.java rename src/main/java/org/icgc/argo/workflow_management/service/{ => wes}/model/KubernetesPhase.java (90%) rename src/main/java/org/icgc/argo/workflow_management/service/{ => wes}/model/NextflowMetadata.java (91%) rename src/main/java/org/icgc/argo/workflow_management/service/{ => wes}/model/NextflowWorkflowMetadata.java (96%) rename src/main/java/org/icgc/argo/workflow_management/service/{ => wes}/model/RunParams.java (90%) create mode 100644 src/main/java/org/icgc/argo/workflow_management/service/wes/model/WfManagementEvent.java rename src/main/java/org/icgc/argo/workflow_management/service/{ => wes}/properties/NextflowProperties.java (94%) create mode 100644 src/main/java/org/icgc/argo/workflow_management/util/WesUtils.java create mode 100644 src/main/resources/avro/WfMgmtRunMsg.avsc delete mode 100644 src/test/java/org/icgc/argo/workflow_management/util/WorkflowTest.java diff --git a/README.md b/README.md index 7cd30ee..8832985 100644 --- a/README.md +++ b/README.md @@ -1 +1 @@ -# workflow-management \ No newline at end of file +# workflow-management diff --git a/pom.xml b/pom.xml index a42fb84..6a379c0 100644 --- a/pom.xml +++ b/pom.xml @@ -15,6 +15,16 @@ ARGO Workflow Management + + rabbitmq-maven-milestones + https://packagecloud.io/rabbitmq/maven-milestones/maven2 + + true + + + false + + springfox springfox @@ -29,6 +39,7 @@ 11 3.0.0-SNAPSHOT + 0.0.8 @@ -136,10 +147,48 @@ federation-graphql-java-support 0.5.0 + + + + + com.pivotal.rabbitmq + reactor-rabbitmq-streams-autoconfigure + + + + + com.pivotal.rabbitmq + reactor-rabbitmq-streams + 0.0.7 + pom + import + + + + + + org.apache.avro + avro-maven-plugin + 1.10.1 + + + generate-sources + + schema + + + ${project.basedir}/src/main/resources/avro/ + ${project.basedir}/src/main/java/ + + String + + + + org.springframework.boot spring-boot-maven-plugin diff --git a/src/main/java/org/icgc/argo/workflow_management/WorkflowManagementApplication.java b/src/main/java/org/icgc/argo/workflow_management/WorkflowManagementApplication.java index f8974fc..41ba099 100644 --- a/src/main/java/org/icgc/argo/workflow_management/WorkflowManagementApplication.java +++ b/src/main/java/org/icgc/argo/workflow_management/WorkflowManagementApplication.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/main/java/org/icgc/argo/workflow_management/config/secret/ApiKeyConfig.java b/src/main/java/org/icgc/argo/workflow_management/config/secret/ApiKeyConfig.java index 8bcde12..85ad85f 100644 --- a/src/main/java/org/icgc/argo/workflow_management/config/secret/ApiKeyConfig.java +++ b/src/main/java/org/icgc/argo/workflow_management/config/secret/ApiKeyConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/main/java/org/icgc/argo/workflow_management/config/secret/NoSecretProviderConfig.java b/src/main/java/org/icgc/argo/workflow_management/config/secret/NoSecretProviderConfig.java index ed67e77..7e0f57c 100644 --- a/src/main/java/org/icgc/argo/workflow_management/config/secret/NoSecretProviderConfig.java +++ b/src/main/java/org/icgc/argo/workflow_management/config/secret/NoSecretProviderConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with @@ -24,7 +24,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; -@Profile("default") +@Profile("!apiKey & !oauth2Token") @Configuration public class NoSecretProviderConfig { diff --git a/src/main/java/org/icgc/argo/workflow_management/config/secret/OAuth2TokenConfig.java b/src/main/java/org/icgc/argo/workflow_management/config/secret/OAuth2TokenConfig.java index 0b27fb0..1840a81 100644 --- a/src/main/java/org/icgc/argo/workflow_management/config/secret/OAuth2TokenConfig.java +++ b/src/main/java/org/icgc/argo/workflow_management/config/secret/OAuth2TokenConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/main/java/org/icgc/argo/workflow_management/config/security/AuthDisabledConfig.java b/src/main/java/org/icgc/argo/workflow_management/config/security/AuthDisabledConfig.java index 69adca8..9cf478d 100644 --- a/src/main/java/org/icgc/argo/workflow_management/config/security/AuthDisabledConfig.java +++ b/src/main/java/org/icgc/argo/workflow_management/config/security/AuthDisabledConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/main/java/org/icgc/argo/workflow_management/config/security/AuthEnabledConfig.java b/src/main/java/org/icgc/argo/workflow_management/config/security/AuthEnabledConfig.java index 36fe308..aacf934 100644 --- a/src/main/java/org/icgc/argo/workflow_management/config/security/AuthEnabledConfig.java +++ b/src/main/java/org/icgc/argo/workflow_management/config/security/AuthEnabledConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with @@ -79,12 +79,14 @@ public SecurityWebFilterChain securityFilterChain(ServerHttpSecurity http) { .permitAll() .pathMatchers("/runs/**") .permitAll() - .pathMatchers("/v2/api-docs", - "/configuration/ui", - "/swagger-resources/**", - "/configuration/security", - "/swagger-ui.html", - "/webjars/**").permitAll() + .pathMatchers( + "/v2/api-docs", + "/configuration/ui", + "/swagger-resources/**", + "/configuration/security", + "/swagger-ui.html", + "/webjars/**") + .permitAll() .and() .authorizeExchange() .anyExchange() diff --git a/src/main/java/org/icgc/argo/workflow_management/config/security/AuthProperties.java b/src/main/java/org/icgc/argo/workflow_management/config/security/AuthProperties.java index 230c812..d848472 100644 --- a/src/main/java/org/icgc/argo/workflow_management/config/security/AuthProperties.java +++ b/src/main/java/org/icgc/argo/workflow_management/config/security/AuthProperties.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/main/java/org/icgc/argo/workflow_management/exception/GlobalExceptionHandler.java b/src/main/java/org/icgc/argo/workflow_management/exception/GlobalExceptionHandler.java index 0a5cdf7..d6e0617 100644 --- a/src/main/java/org/icgc/argo/workflow_management/exception/GlobalExceptionHandler.java +++ b/src/main/java/org/icgc/argo/workflow_management/exception/GlobalExceptionHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/main/java/org/icgc/argo/workflow_management/exception/NextflowRunException.java b/src/main/java/org/icgc/argo/workflow_management/exception/NextflowRunException.java index 75cd302..a0ca751 100644 --- a/src/main/java/org/icgc/argo/workflow_management/exception/NextflowRunException.java +++ b/src/main/java/org/icgc/argo/workflow_management/exception/NextflowRunException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/main/java/org/icgc/argo/workflow_management/exception/ReflectionUtilsException.java b/src/main/java/org/icgc/argo/workflow_management/exception/ReflectionUtilsException.java index 5d0464d..bcb27c4 100644 --- a/src/main/java/org/icgc/argo/workflow_management/exception/ReflectionUtilsException.java +++ b/src/main/java/org/icgc/argo/workflow_management/exception/ReflectionUtilsException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/main/java/org/icgc/argo/workflow_management/exception/model/ErrorResponse.java b/src/main/java/org/icgc/argo/workflow_management/exception/model/ErrorResponse.java index 70ed627..f6f33e5 100644 --- a/src/main/java/org/icgc/argo/workflow_management/exception/model/ErrorResponse.java +++ b/src/main/java/org/icgc/argo/workflow_management/exception/model/ErrorResponse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/main/java/org/icgc/argo/workflow_management/graphql/AddReactiveContextInputCustomizer.java b/src/main/java/org/icgc/argo/workflow_management/graphql/AddReactiveContextInputCustomizer.java index eb86a86..cb65054 100644 --- a/src/main/java/org/icgc/argo/workflow_management/graphql/AddReactiveContextInputCustomizer.java +++ b/src/main/java/org/icgc/argo/workflow_management/graphql/AddReactiveContextInputCustomizer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/main/java/org/icgc/argo/workflow_management/graphql/GraphQLProvider.java b/src/main/java/org/icgc/argo/workflow_management/graphql/GraphQLProvider.java index 368fbc5..667341a 100644 --- a/src/main/java/org/icgc/argo/workflow_management/graphql/GraphQLProvider.java +++ b/src/main/java/org/icgc/argo/workflow_management/graphql/GraphQLProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/main/java/org/icgc/argo/workflow_management/graphql/MutationDataFetcher.java b/src/main/java/org/icgc/argo/workflow_management/graphql/MutationDataFetcher.java index 06b1b93..dc208be 100644 --- a/src/main/java/org/icgc/argo/workflow_management/graphql/MutationDataFetcher.java +++ b/src/main/java/org/icgc/argo/workflow_management/graphql/MutationDataFetcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with @@ -26,14 +26,13 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.function.Function; +import lombok.NonNull; import lombok.val; import org.icgc.argo.workflow_management.graphql.model.GqlRunsRequest; -import org.icgc.argo.workflow_management.service.WorkflowExecutionService; -import org.icgc.argo.workflow_management.service.model.RunParams; +import org.icgc.argo.workflow_management.service.api_to_wes.ApiToWesService; import org.icgc.argo.workflow_management.wes.controller.model.RunsRequest; import org.icgc.argo.workflow_management.wes.controller.model.RunsResponse; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.security.core.context.ReactiveSecurityContextHolder; import org.springframework.security.core.context.SecurityContext; import org.springframework.stereotype.Component; @@ -42,41 +41,32 @@ @Component public class MutationDataFetcher { - private final WorkflowExecutionService nextflowService; + @NonNull private final MonoDataFetcher cancelRunResolver; + @NonNull private final MonoDataFetcher startRunResolver; @Autowired - public MutationDataFetcher(@Qualifier("nextflow") WorkflowExecutionService nextflowService) { - this.nextflowService = nextflowService; + public MutationDataFetcher(ApiToWesService apiToWesService) { + cancelRunResolver = + env -> { + val args = env.getArguments(); + String runId = String.valueOf(args.get("runId")); + return apiToWesService.cancel(runId); + }; + + startRunResolver = + env -> { + val args = env.getArguments(); + + val requestMap = ImmutableMap.builder(); + + if (args.get("request") != null) + requestMap.putAll((Map) args.get("request")); + + RunsRequest runsRequest = convertValue(requestMap.build(), GqlRunsRequest.class); + return apiToWesService.run(runsRequest); + }; } - private final MonoDataFetcher cancelRunResolver = - env -> { - val args = env.getArguments(); - String runId = String.valueOf(args.get("runId")); - return getWorkflowService().cancel(runId); - }; - - private final MonoDataFetcher startRunResolver = - env -> { - val args = env.getArguments(); - - val requestMap = ImmutableMap.builder(); - - if (args.get("request") != null) - requestMap.putAll((Map) args.get("request")); - - RunsRequest runsRequest = convertValue(requestMap.build(), GqlRunsRequest.class); - - val runConfig = - RunParams.builder() - .workflowUrl(runsRequest.getWorkflowUrl()) - .workflowParams(runsRequest.getWorkflowParams()) - .workflowEngineParams(runsRequest.getWorkflowEngineParams()) - .build(); - - return getWorkflowService().run(runConfig); - }; - public Map mutationResolvers() { return Map.of( "cancelRun", securityContextAddedFetcher(cancelRunResolver), @@ -100,9 +90,5 @@ private DataFetcher> securityContextAddedFetcher( }; } - private WorkflowExecutionService getWorkflowService() { - return nextflowService; - } - interface MonoDataFetcher extends Function> {} } diff --git a/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlRunsRequest.java b/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlRunsRequest.java index da5e35d..cf507d7 100644 --- a/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlRunsRequest.java +++ b/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlRunsRequest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlWorkflowEngineParams.java b/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlWorkflowEngineParams.java index e60ddac..7e67710 100644 --- a/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlWorkflowEngineParams.java +++ b/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlWorkflowEngineParams.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/main/java/org/icgc/argo/workflow_management/properties/Swagger2Properties.java b/src/main/java/org/icgc/argo/workflow_management/properties/Swagger2Properties.java index e66acd2..2cfcf69 100644 --- a/src/main/java/org/icgc/argo/workflow_management/properties/Swagger2Properties.java +++ b/src/main/java/org/icgc/argo/workflow_management/properties/Swagger2Properties.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/main/java/org/icgc/argo/workflow_management/properties/WebfluxProperties.java b/src/main/java/org/icgc/argo/workflow_management/properties/WebfluxProperties.java index ded2d64..e429079 100644 --- a/src/main/java/org/icgc/argo/workflow_management/properties/WebfluxProperties.java +++ b/src/main/java/org/icgc/argo/workflow_management/properties/WebfluxProperties.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/ApiProducerConfig.java b/src/main/java/org/icgc/argo/workflow_management/rabbitmq/ApiProducerConfig.java new file mode 100644 index 0000000..159849f --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/rabbitmq/ApiProducerConfig.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. + * You should have received a copy of the GNU Affero General Public License along with + * this program. If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.icgc.argo.workflow_management.rabbitmq; + +import com.pivotal.rabbitmq.RabbitEndpointService; +import com.pivotal.rabbitmq.source.OnDemandSource; +import com.pivotal.rabbitmq.source.Sender; +import com.pivotal.rabbitmq.source.Source; +import com.pivotal.rabbitmq.topology.ExchangeType; +import java.util.function.Function; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.icgc.argo.workflow_management.rabbitmq.schema.WfMgmtRunMsg; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import reactor.core.Disposable; + +@Slf4j +@Profile("api") +@Configuration +public class ApiProducerConfig { + @Value("${api.producer.topology.queueName}") + private String queueName; + + @Value("${api.producer.topology.topicExchangeName}") + private String topicExchangeName; + + @Value("${api.producer.topology.topicRoutingKeys}") + private String[] topicRoutingKeys; + + private final RabbitEndpointService rabbit; + + @Autowired + public ApiProducerConfig(RabbitEndpointService rabbit) { + this.rabbit = rabbit; + } + + @Bean + public Disposable produceWfMgmtRunMsg(Source apiSourceMsgs) { + val dlxName = topicExchangeName + "-dlx"; + val dlqName = queueName + "-dlq"; + return rabbit + .declareTopology( + topologyBuilder -> + topologyBuilder + .declareExchange(dlxName) + .and() + .declareQueue(dlqName) + .boundTo(dlxName) + .and() + .declareExchange(topicExchangeName) + .type(ExchangeType.topic) + .and() + .declareQueue(queueName) + .boundTo(topicExchangeName, topicRoutingKeys) + .withDeadLetterExchange(dlxName)) + .createTransactionalProducerStream(WfMgmtRunMsg.class) + .route() + .toExchange(topicExchangeName) + .withRoutingKey(routingKeySelector()) + .then() + .send(apiSourceMsgs.source()) + .subscribe( + tx -> { + log.debug("ApiProducer sent WfMgmtRunMsg: {}", tx.get()); + tx.commit(); + }); + } + + @Bean + OnDemandSource source() { + return new OnDemandSource<>("source"); + } + + @Bean + Sender sender(OnDemandSource source) { + return source; + } + + Function routingKeySelector() { + return msg -> msg.getState().toString(); + } +} diff --git a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/ExecuteConsumerConfig.java b/src/main/java/org/icgc/argo/workflow_management/rabbitmq/ExecuteConsumerConfig.java new file mode 100644 index 0000000..00ad22c --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/rabbitmq/ExecuteConsumerConfig.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. + * You should have received a copy of the GNU Affero General Public License along with + * this program. If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.icgc.argo.workflow_management.rabbitmq; + +import static org.icgc.argo.workflow_management.rabbitmq.WfMgmtRunMsgConverters.createRunParams; +import static org.icgc.argo.workflow_management.rabbitmq.WfMgmtRunMsgConverters.createWfMgmtEvent; + +import com.pivotal.rabbitmq.RabbitEndpointService; +import com.pivotal.rabbitmq.stream.Transaction; +import com.pivotal.rabbitmq.topology.ExchangeType; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.icgc.argo.workflow_management.rabbitmq.schema.RunState; +import org.icgc.argo.workflow_management.rabbitmq.schema.WfMgmtRunMsg; +import org.icgc.argo.workflow_management.service.wes.NextflowWebLogEventSender; +import org.icgc.argo.workflow_management.service.wes.WorkflowExecutionService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import reactor.core.Disposable; + +@Profile("execute") +@Slf4j +@Configuration +public class ExecuteConsumerConfig { + @Value("${execute.consumer.topology.queueName}") + private String queueName; + + @Value("${execute.consumer.topology.topicExchangeName}") + private String topicExchangeName; + + @Value("${execute.consumer.topology.topicRoutingKeys}") + private String[] topicRoutingKeys; + + private final NextflowWebLogEventSender webLogEventSender; + private final WorkflowExecutionService wes; + private final RabbitEndpointService rabbit; + + @Autowired + public ExecuteConsumerConfig( + WorkflowExecutionService wes, + RabbitEndpointService rabbit, + NextflowWebLogEventSender webLogEventSender) { + this.wes = wes; + this.rabbit = rabbit; + this.webLogEventSender = webLogEventSender; + } + + @Bean + public Disposable wfMgmtRunMsgForExecuteConsumer() { + val dlxName = topicExchangeName + "-dlx"; + val dlqName = queueName + "-dlq"; + return rabbit + .declareTopology( + topologyBuilder -> + topologyBuilder + .declareExchange(dlxName) + .and() + .declareQueue(dlqName) + .boundTo(dlxName) + .and() + .declareExchange(topicExchangeName) + .type(ExchangeType.topic) + .and() + .declareQueue(queueName) + .boundTo(topicExchangeName, topicRoutingKeys) + .withDeadLetterExchange(dlxName)) + .createTransactionalConsumerStream(queueName, WfMgmtRunMsg.class) + .receive() + .doOnNext(consumeAndExecuteInitializeOrCancel()) + .onErrorContinue(handleError()) + .subscribe(); + } + + public Consumer> consumeAndExecuteInitializeOrCancel() { + return tx -> { + val msg = tx.get(); + log.debug("WfMgmtRunMsg received: {}", msg); + + if (msg.getState().equals(RunState.CANCELING)) { + log.info("Cancelling: {}", msg); + webLogEventSender.sendWfMgmtEvent(createWfMgmtEvent(msg)); + + wes.cancel(msg.getRunId()) + .subscribe( + runsResponse -> { + log.info("Cancelled: {}", runsResponse); + tx.commit(); + }); + } else if (msg.getState().equals(RunState.INITIALIZING)) { + log.info("Initializing: {}", msg); + webLogEventSender.sendWfMgmtEvent(createWfMgmtEvent(msg)); + + val runParams = createRunParams(msg); + + wes.run(runParams) + .subscribe( + runsResponse -> { + log.info("Initialized: {}", msg); + tx.commit(); + }); + } else { + log.debug("Ignoring: {}", msg); + tx.commit(); + } + }; + } + + public BiConsumer handleError() { + return (t, tx) -> { + t.printStackTrace(); + log.error("Error occurred with: {}", tx); + if (tx instanceof Transaction && ((Transaction) tx).get() instanceof WfMgmtRunMsg) { + val msg = (WfMgmtRunMsg) ((Transaction) tx).get(); + msg.setState(RunState.SYSTEM_ERROR); + log.info("SYSTEM_ERROR: {}", msg); + webLogEventSender.sendWfMgmtEvent(createWfMgmtEvent(msg)); + ((Transaction) tx).commit(); + } else { + log.error("Can't get WfMgmtRunMsg, transaction is lost!"); + } + }; + } +} diff --git a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/WfMgmtRunMsgConverters.java b/src/main/java/org/icgc/argo/workflow_management/rabbitmq/WfMgmtRunMsgConverters.java new file mode 100644 index 0000000..f80dc28 --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/rabbitmq/WfMgmtRunMsgConverters.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. + * You should have received a copy of the GNU Affero General Public License along with + * this program. If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.icgc.argo.workflow_management.rabbitmq; + +import static org.icgc.argo.workflow_management.util.JacksonUtils.*; + +import java.time.Instant; +import java.util.Date; +import java.util.Map; +import java.util.TimeZone; +import java.util.UUID; +import lombok.experimental.UtilityClass; +import lombok.val; +import nextflow.Const; +import nextflow.extension.Bolts; +import org.icgc.argo.workflow_management.rabbitmq.schema.EngineParams; +import org.icgc.argo.workflow_management.rabbitmq.schema.RunState; +import org.icgc.argo.workflow_management.rabbitmq.schema.WfMgmtRunMsg; +import org.icgc.argo.workflow_management.service.wes.model.RunParams; +import org.icgc.argo.workflow_management.service.wes.model.WfManagementEvent; +import org.icgc.argo.workflow_management.wes.controller.model.RunsRequest; +import org.icgc.argo.workflow_management.wes.controller.model.WorkflowEngineParams; + +@UtilityClass +public class WfMgmtRunMsgConverters { + public static WfMgmtRunMsg createWfMgmtRunMsg( + String runId, RunsRequest runsRequest, RunState state) { + val requestWep = runsRequest.getWorkflowEngineParams(); + + val msgWep = + EngineParams.newBuilder() + .setLatest(requestWep.getLatest()) + .setDefaultContainer(requestWep.getDefaultContainer()) + .setLaunchDir(requestWep.getLaunchDir()) + .setRevision(requestWep.getRevision()) + .setProjectDir(requestWep.getProjectDir()) + .setWorkDir(requestWep.getWorkDir()); + + if (requestWep.getResume() != null) { + msgWep.setResume(requestWep.getResume().toString()); + } + + return WfMgmtRunMsg.newBuilder() + .setRunId(runId) + .setState(state) + .setWorkflowUrl(runsRequest.getWorkflowUrl()) + .setWorkflowParamsJsonStr(toJsonString(runsRequest.getWorkflowParams())) + .setWorkflowEngineParams(msgWep.build()) + .setTimestamp(Instant.now().toEpochMilli()) + .build(); + } + + public static WfMgmtRunMsg createWfMgmtRunMsg(String runId, RunState state) { + return WfMgmtRunMsg.newBuilder() + .setRunId(runId) + .setTimestamp(Instant.now().toEpochMilli()) + .setState(state) + .build(); + } + + public static RunParams createRunParams(WfMgmtRunMsg msg) { + val msgWep = msg.getWorkflowEngineParams(); + + val params = readValue(msg.getWorkflowParamsJsonStr(), Map.class); + + val wepBuilder = + WorkflowEngineParams.builder() + .defaultContainer(msgWep.getDefaultContainer()) + .revision(msgWep.getRevision()) + .launchDir(msgWep.getLaunchDir()) + .projectDir(msgWep.getProjectDir()) + .workDir(msgWep.getWorkDir()) + .latest(msgWep.getLatest()); + + if (msgWep.getResume() != null) { + wepBuilder.resume(UUID.fromString(msgWep.getResume())); + } + + return RunParams.builder() + .runId(msg.getRunId()) + .workflowParams(params) + .workflowEngineParams(wepBuilder.build()) + .workflowUrl(msg.getWorkflowUrl()) + .build(); + } + + public static WfManagementEvent createWfMgmtEvent(WfMgmtRunMsg msg) { + val msgWep = msg.getWorkflowEngineParams(); + + val params = readValue(msg.getWorkflowParamsJsonStr(), Map.class); + + val wepBuilder = + WorkflowEngineParams.builder() + .defaultContainer(msgWep.getDefaultContainer()) + .revision(msgWep.getRevision()) + .launchDir(msgWep.getLaunchDir()) + .projectDir(msgWep.getProjectDir()) + .workDir(msgWep.getWorkDir()) + .latest(msgWep.getLatest()); + + if (msgWep.getResume() != null) { + wepBuilder.resume(UUID.fromString(msgWep.getResume())); + } + + String time = + Bolts.format( + new Date(msg.getTimestamp()), + Const.ISO_8601_DATETIME_FORMAT, + TimeZone.getTimeZone("UTC")); + return WfManagementEvent.builder() + .event(msg.getState().toString()) + .runId(msg.getRunId()) + .utcTime(time) + .workflowEngineParams(wepBuilder.build()) + .workflowParams(params) + .workflowType(msg.getWorkflowType()) + .workflowTypeVersion(msg.getWorkflowTypeVersion()) + .workflowUrl(msg.getWorkflowUrl()) + .build(); + } +} diff --git a/src/main/java/org/icgc/argo/workflow_management/secret/SecretProvider.java b/src/main/java/org/icgc/argo/workflow_management/secret/SecretProvider.java index e4a165d..9da7c3b 100644 --- a/src/main/java/org/icgc/argo/workflow_management/secret/SecretProvider.java +++ b/src/main/java/org/icgc/argo/workflow_management/secret/SecretProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/main/java/org/icgc/argo/workflow_management/secret/impl/ApiKeyProvider.java b/src/main/java/org/icgc/argo/workflow_management/secret/impl/ApiKeyProvider.java index eab7d5e..6deb83b 100644 --- a/src/main/java/org/icgc/argo/workflow_management/secret/impl/ApiKeyProvider.java +++ b/src/main/java/org/icgc/argo/workflow_management/secret/impl/ApiKeyProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/main/java/org/icgc/argo/workflow_management/secret/impl/NoSecretProvider.java b/src/main/java/org/icgc/argo/workflow_management/secret/impl/NoSecretProvider.java index 0586322..3602b64 100644 --- a/src/main/java/org/icgc/argo/workflow_management/secret/impl/NoSecretProvider.java +++ b/src/main/java/org/icgc/argo/workflow_management/secret/impl/NoSecretProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/main/java/org/icgc/argo/workflow_management/secret/impl/OAuth2BearerTokenProvider.java b/src/main/java/org/icgc/argo/workflow_management/secret/impl/OAuth2BearerTokenProvider.java index 305ec76..580f0df 100644 --- a/src/main/java/org/icgc/argo/workflow_management/secret/impl/OAuth2BearerTokenProvider.java +++ b/src/main/java/org/icgc/argo/workflow_management/secret/impl/OAuth2BearerTokenProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/main/java/org/icgc/argo/workflow_management/service/WorkflowExecutionService.java b/src/main/java/org/icgc/argo/workflow_management/service/api_to_wes/ApiToWesService.java similarity index 84% rename from src/main/java/org/icgc/argo/workflow_management/service/WorkflowExecutionService.java rename to src/main/java/org/icgc/argo/workflow_management/service/api_to_wes/ApiToWesService.java index 79071f9..14d1a02 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/WorkflowExecutionService.java +++ b/src/main/java/org/icgc/argo/workflow_management/service/api_to_wes/ApiToWesService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with @@ -16,18 +16,18 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.service; +package org.icgc.argo.workflow_management.service.api_to_wes; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import org.icgc.argo.workflow_management.service.model.RunParams; +import org.icgc.argo.workflow_management.wes.controller.model.RunsRequest; import org.icgc.argo.workflow_management.wes.controller.model.RunsResponse; import org.springframework.security.access.prepost.PreAuthorize; import reactor.core.publisher.Mono; -public interface WorkflowExecutionService { +public interface ApiToWesService { @HasQueryAndMutationAccess - Mono run(RunParams params); + Mono run(RunsRequest runsRequest); @HasQueryAndMutationAccess Mono cancel(String runId); diff --git a/src/main/java/org/icgc/argo/workflow_management/service/api_to_wes/impl/ApiProducerToWes.java b/src/main/java/org/icgc/argo/workflow_management/service/api_to_wes/impl/ApiProducerToWes.java new file mode 100644 index 0000000..8118ce1 --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/service/api_to_wes/impl/ApiProducerToWes.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. + * You should have received a copy of the GNU Affero General Public License along with + * this program. If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.icgc.argo.workflow_management.service.api_to_wes.impl; + +import static org.icgc.argo.workflow_management.rabbitmq.WfMgmtRunMsgConverters.createWfMgmtRunMsg; +import static org.icgc.argo.workflow_management.util.WesUtils.generateWesRunId; + +import com.pivotal.rabbitmq.source.Sender; +import lombok.val; +import org.icgc.argo.workflow_management.rabbitmq.schema.RunState; +import org.icgc.argo.workflow_management.rabbitmq.schema.WfMgmtRunMsg; +import org.icgc.argo.workflow_management.service.api_to_wes.ApiToWesService; +import org.icgc.argo.workflow_management.wes.controller.model.RunsRequest; +import org.icgc.argo.workflow_management.wes.controller.model.RunsResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +@Profile("api") +@Service +public class ApiProducerToWes implements ApiToWesService { + + private final Sender sender; + + @Autowired + public ApiProducerToWes(Sender sender) { + this.sender = sender; + } + + @Override + public Mono run(RunsRequest runsRequest) { + val runId = generateWesRunId(); + val msg = createWfMgmtRunMsg(runId, runsRequest, RunState.INITIALIZING); + return Mono.just(msg).flatMap(sender::send).map(o -> new RunsResponse(runId)); + } + + @Override + public Mono cancel(String runId) { + val event = createWfMgmtRunMsg(runId, RunState.CANCELING); + return Mono.just(event).flatMap(sender::send).map(o -> new RunsResponse(runId)); + } +} diff --git a/src/main/java/org/icgc/argo/workflow_management/service/api_to_wes/impl/DirectToWes.java b/src/main/java/org/icgc/argo/workflow_management/service/api_to_wes/impl/DirectToWes.java new file mode 100644 index 0000000..5f89214 --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/service/api_to_wes/impl/DirectToWes.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. + * You should have received a copy of the GNU Affero General Public License along with + * this program. If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.icgc.argo.workflow_management.service.api_to_wes.impl; + +import static org.icgc.argo.workflow_management.util.WesUtils.generateWesRunId; + +import lombok.val; +import org.icgc.argo.workflow_management.service.api_to_wes.ApiToWesService; +import org.icgc.argo.workflow_management.service.wes.WorkflowExecutionService; +import org.icgc.argo.workflow_management.service.wes.model.RunParams; +import org.icgc.argo.workflow_management.wes.controller.model.RunsRequest; +import org.icgc.argo.workflow_management.wes.controller.model.RunsResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +// Default setup uses no rabbitmq configs setup, so talk directly to WES +@Profile("!api & !execute") +@Service +public class DirectToWes implements ApiToWesService { + + private final WorkflowExecutionService wes; + + @Autowired + public DirectToWes(WorkflowExecutionService wes) { + this.wes = wes; + } + + @Override + public Mono run(RunsRequest runsRequest) { + // create run config from request + val runConfig = + RunParams.builder() + .workflowUrl(runsRequest.getWorkflowUrl()) + .workflowParams(runsRequest.getWorkflowParams()) + .workflowEngineParams(runsRequest.getWorkflowEngineParams()) + .runId(generateWesRunId()) + .build(); + + return wes.run(runConfig); + } + + @Override + public Mono cancel(String runId) { + return wes.cancel(runId); + } +} diff --git a/src/main/java/org/icgc/argo/workflow_management/service/NextflowService.java b/src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowService.java similarity index 89% rename from src/main/java/org/icgc/argo/workflow_management/service/NextflowService.java rename to src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowService.java index d14e1e8..0ac3c2b 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/NextflowService.java +++ b/src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with @@ -16,12 +16,11 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.service; +package org.icgc.argo.workflow_management.service.wes; -import static java.lang.Boolean.parseBoolean; import static java.lang.String.format; import static java.util.Objects.nonNull; -import static org.icgc.argo.workflow_management.service.model.KubernetesPhase.*; +import static org.icgc.argo.workflow_management.service.wes.model.KubernetesPhase.*; import static org.icgc.argo.workflow_management.util.NextflowConfigFile.createNextflowConfigFile; import static org.icgc.argo.workflow_management.util.ParamsFile.createParamsFile; import static org.icgc.argo.workflow_management.util.Reflections.createWithReflection; @@ -45,11 +44,11 @@ import org.icgc.argo.workflow_management.exception.NextflowRunException; import org.icgc.argo.workflow_management.exception.ReflectionUtilsException; import org.icgc.argo.workflow_management.secret.SecretProvider; -import org.icgc.argo.workflow_management.service.model.KubernetesPhase; -import org.icgc.argo.workflow_management.service.model.NextflowMetadata; -import org.icgc.argo.workflow_management.service.model.NextflowWorkflowMetadata; -import org.icgc.argo.workflow_management.service.model.RunParams; -import org.icgc.argo.workflow_management.service.properties.NextflowProperties; +import org.icgc.argo.workflow_management.service.wes.model.KubernetesPhase; +import org.icgc.argo.workflow_management.service.wes.model.NextflowMetadata; +import org.icgc.argo.workflow_management.service.wes.model.NextflowWorkflowMetadata; +import org.icgc.argo.workflow_management.service.wes.model.RunParams; +import org.icgc.argo.workflow_management.service.wes.properties.NextflowProperties; import org.icgc.argo.workflow_management.util.ConditionalPutMap; import org.icgc.argo.workflow_management.wes.controller.model.RunsResponse; import org.springframework.beans.factory.annotation.Autowired; @@ -257,20 +256,7 @@ private CmdKubeRun createCmd(@NonNull Launcher launcher, @NonNull RunParams para // params map to build CmdKubeRun (put if val not null) val cmdParams = new ConditionalPutMap(Objects::nonNull, new HashMap<>()); - // run name (used for paramsFile as well) - // You may be asking yourself, why is he replacing the "-" in the UUID, this is a valid - // question, well unfortunately when trying to resume a job, Nextflow searches for the - // UUID format ANYWHERE in the resume string, resulting in the incorrect assumption - // that we are passing an runId when in fact we are passing a runName ... - // thanks Nextflow ... this workaround solves that problem - // - // UPDATE: The glory of Nextflow knows no bounds ... resuming by runName while possible - // ends up reusing the run/session (yeah these are the same but still recorded separately) id - // from the "last" run ... wtv run that was ... resulting in multiple resumed runs sharing the - // same sessionId (we're going with this label) even though they have nothing to do with one - // another. This is a bug in NF and warrants a PR but for now we recommend only resuming runs - // with sessionId and never with runName - val runName = format("wes-%s", UUID.randomUUID().toString().replace("-", "")); + val runName = params.getRunId(); cmdParams.put("runName", runName); // launcher and launcher options required by CmdKubeRun diff --git a/src/main/java/org/icgc/argo/workflow_management/service/NextflowWebLogEventSender.java b/src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowWebLogEventSender.java similarity index 79% rename from src/main/java/org/icgc/argo/workflow_management/service/NextflowWebLogEventSender.java rename to src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowWebLogEventSender.java index cd4c972..2ed5889 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/NextflowWebLogEventSender.java +++ b/src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowWebLogEventSender.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with @@ -16,9 +16,9 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.service; +package org.icgc.argo.workflow_management.service.wes; -import static org.icgc.argo.workflow_management.service.NextflowWebLogEventSender.Event.*; +import static org.icgc.argo.workflow_management.service.wes.NextflowWebLogEventSender.Event.*; import static org.icgc.argo.workflow_management.util.JacksonUtils.toJsonString; import java.util.Date; @@ -30,17 +30,17 @@ import nextflow.Const; import nextflow.extension.Bolts; import nextflow.trace.TraceRecord; -import nextflow.util.SimpleHttpClient; -import org.icgc.argo.workflow_management.service.model.NextflowMetadata; +import org.icgc.argo.workflow_management.service.wes.model.NextflowMetadata; +import org.icgc.argo.workflow_management.service.wes.model.WfManagementEvent; import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.MediaType; import org.springframework.stereotype.Service; +import org.springframework.web.reactive.function.client.WebClient; @Service @AllArgsConstructor @NoArgsConstructor public class NextflowWebLogEventSender { - private final SimpleHttpClient httpClient = new SimpleHttpClient(); - @Value("${nextflow.weblogUrl}") private String endpoint; @@ -76,7 +76,7 @@ public void sendFailedPodEvent(String podName) { message.put("event", FAILED.toString()); message.put("utcTime", time); - httpClient.sendHttpMessage(endpoint, toJsonString(message)); + sendHttpMessageAsync(toJsonString(message)); } public void sendTraceEvent(Event event, TraceRecord traceRecord) {} @@ -94,7 +94,11 @@ public HashMap createMessage(Event event, String runName) { } public void sendWorkflowEvent(Event event, NextflowMetadata meta) { - httpClient.sendHttpMessage(endpoint, createWorkflowMessageJSON(event, meta)); + sendHttpMessageAsync(createWorkflowMessageJSON(event, meta)); + } + + public void sendWfMgmtEvent(WfManagementEvent event) { + sendHttpMessageAsync(toJsonString(event)); } public String createWorkflowMessageJSON(Event event, NextflowMetadata logMessage) { @@ -106,6 +110,16 @@ public String createWorkflowMessageJSON(Event event, NextflowMetadata logMessage return toJsonString(message); } + private void sendHttpMessageAsync(String jsonMessage) { + WebClient.create(endpoint) + .post() + .contentType(MediaType.APPLICATION_JSON) + .bodyValue(jsonMessage) + .retrieve() + .toBodilessEntity() + .subscribe(); + } + enum Event { STARTED, COMPLETED, diff --git a/src/main/java/org/icgc/argo/workflow_management/service/NextflowWorkflowMonitor.java b/src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowWorkflowMonitor.java similarity index 90% rename from src/main/java/org/icgc/argo/workflow_management/service/NextflowWorkflowMonitor.java rename to src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowWorkflowMonitor.java index dedf48e..e75e38d 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/NextflowWorkflowMonitor.java +++ b/src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowWorkflowMonitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with @@ -16,11 +16,11 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.service; +package org.icgc.argo.workflow_management.service.wes; import static java.lang.String.format; import static java.time.OffsetDateTime.now; -import static org.icgc.argo.workflow_management.service.NextflowService.NEXTFLOW_PREFIX; +import static org.icgc.argo.workflow_management.service.wes.NextflowService.NEXTFLOW_PREFIX; import io.fabric8.kubernetes.api.model.DoneablePod; import io.fabric8.kubernetes.api.model.Pod; @@ -32,8 +32,8 @@ import lombok.extern.slf4j.Slf4j; import lombok.val; import nextflow.util.Duration; -import org.icgc.argo.workflow_management.service.model.KubernetesPhase; -import org.icgc.argo.workflow_management.service.model.NextflowMetadata; +import org.icgc.argo.workflow_management.service.wes.model.KubernetesPhase; +import org.icgc.argo.workflow_management.service.wes.model.NextflowMetadata; @Slf4j @AllArgsConstructor @@ -110,8 +110,7 @@ public void updateFailure(NextflowMetadata metadata, Pod pod, String podLog) { workflow.update(pod); workflow.setComplete(completeTime); workflow.setDuration(Duration.between(workflow.getStart(), completeTime)); - workflow.setErrorReport(podLog); - workflow.setErrorMessage("Nextflow pod failed to start"); + workflow.setErrorReport("Nextflow pod failed to start"); workflow.setSuccess(false); } diff --git a/src/main/java/org/icgc/argo/workflow_management/service/wes/WorkflowExecutionService.java b/src/main/java/org/icgc/argo/workflow_management/service/wes/WorkflowExecutionService.java new file mode 100644 index 0000000..b76eb7a --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/service/wes/WorkflowExecutionService.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. + * You should have received a copy of the GNU Affero General Public License along with + * this program. If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.icgc.argo.workflow_management.service.wes; + +import org.icgc.argo.workflow_management.service.wes.model.RunParams; +import org.icgc.argo.workflow_management.wes.controller.model.RunsResponse; +import reactor.core.publisher.Mono; + +public interface WorkflowExecutionService { + Mono run(RunParams params); + + Mono cancel(String runId); +} diff --git a/src/main/java/org/icgc/argo/workflow_management/service/model/KubernetesPhase.java b/src/main/java/org/icgc/argo/workflow_management/service/wes/model/KubernetesPhase.java similarity index 90% rename from src/main/java/org/icgc/argo/workflow_management/service/model/KubernetesPhase.java rename to src/main/java/org/icgc/argo/workflow_management/service/wes/model/KubernetesPhase.java index 9a755c8..1a2eca5 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/model/KubernetesPhase.java +++ b/src/main/java/org/icgc/argo/workflow_management/service/wes/model/KubernetesPhase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with @@ -16,7 +16,7 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.service.model; +package org.icgc.argo.workflow_management.service.wes.model; /** * Kubernetes phases */ public enum KubernetesPhase { diff --git a/src/main/java/org/icgc/argo/workflow_management/service/model/NextflowMetadata.java b/src/main/java/org/icgc/argo/workflow_management/service/wes/model/NextflowMetadata.java similarity index 91% rename from src/main/java/org/icgc/argo/workflow_management/service/model/NextflowMetadata.java rename to src/main/java/org/icgc/argo/workflow_management/service/wes/model/NextflowMetadata.java index b26cf19..acd4078 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/model/NextflowMetadata.java +++ b/src/main/java/org/icgc/argo/workflow_management/service/wes/model/NextflowMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with @@ -16,7 +16,7 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.service.model; +package org.icgc.argo.workflow_management.service.wes.model; import lombok.Data; import nextflow.script.ScriptBinding.ParamsMap; diff --git a/src/main/java/org/icgc/argo/workflow_management/service/model/NextflowWorkflowMetadata.java b/src/main/java/org/icgc/argo/workflow_management/service/wes/model/NextflowWorkflowMetadata.java similarity index 96% rename from src/main/java/org/icgc/argo/workflow_management/service/model/NextflowWorkflowMetadata.java rename to src/main/java/org/icgc/argo/workflow_management/service/wes/model/NextflowWorkflowMetadata.java index 0eb5d6a..5ed96bc 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/model/NextflowWorkflowMetadata.java +++ b/src/main/java/org/icgc/argo/workflow_management/service/wes/model/NextflowWorkflowMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with @@ -16,7 +16,7 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.service.model; +package org.icgc.argo.workflow_management.service.wes.model; import static org.icgc.argo.workflow_management.util.Reflections.invokeDeclaredMethod; diff --git a/src/main/java/org/icgc/argo/workflow_management/service/model/RunParams.java b/src/main/java/org/icgc/argo/workflow_management/service/wes/model/RunParams.java similarity index 90% rename from src/main/java/org/icgc/argo/workflow_management/service/model/RunParams.java rename to src/main/java/org/icgc/argo/workflow_management/service/wes/model/RunParams.java index 20480c4..45cd2bc 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/model/RunParams.java +++ b/src/main/java/org/icgc/argo/workflow_management/service/wes/model/RunParams.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with @@ -16,7 +16,7 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.service.model; +package org.icgc.argo.workflow_management.service.wes.model; import java.util.Map; import lombok.Builder; @@ -29,6 +29,7 @@ @Builder @RequiredArgsConstructor public class RunParams { + @NonNull private String runId; @NonNull private final Map workflowParams; @NonNull private final String workflowUrl; private final WorkflowEngineParams workflowEngineParams; diff --git a/src/main/java/org/icgc/argo/workflow_management/service/wes/model/WfManagementEvent.java b/src/main/java/org/icgc/argo/workflow_management/service/wes/model/WfManagementEvent.java new file mode 100644 index 0000000..78b3970 --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/service/wes/model/WfManagementEvent.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. + * You should have received a copy of the GNU Affero General Public License along with + * this program. If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.icgc.argo.workflow_management.service.wes.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.util.Map; +import lombok.*; +import org.icgc.argo.workflow_management.wes.controller.model.WorkflowEngineParams; + +@Data +@Builder +@AllArgsConstructor +@RequiredArgsConstructor +@NoArgsConstructor +@JsonIgnoreProperties(ignoreUnknown = true) +public class WfManagementEvent { + @NonNull private String runId; + @NonNull private String event; + @NonNull private String utcTime; + @NonNull private String workflowUrl; + private String workflowType; + private String workflowTypeVersion; + private Map workflowParams; + private WorkflowEngineParams workflowEngineParams; +} diff --git a/src/main/java/org/icgc/argo/workflow_management/service/properties/NextflowProperties.java b/src/main/java/org/icgc/argo/workflow_management/service/wes/properties/NextflowProperties.java similarity index 94% rename from src/main/java/org/icgc/argo/workflow_management/service/properties/NextflowProperties.java rename to src/main/java/org/icgc/argo/workflow_management/service/wes/properties/NextflowProperties.java index 81330d2..e3ebbc6 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/properties/NextflowProperties.java +++ b/src/main/java/org/icgc/argo/workflow_management/service/wes/properties/NextflowProperties.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with @@ -16,7 +16,7 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.service.properties; +package org.icgc.argo.workflow_management.service.wes.properties; import java.util.List; import lombok.Data; diff --git a/src/main/java/org/icgc/argo/workflow_management/util/ConditionalPutMap.java b/src/main/java/org/icgc/argo/workflow_management/util/ConditionalPutMap.java index 26a94b0..5d9ba17 100644 --- a/src/main/java/org/icgc/argo/workflow_management/util/ConditionalPutMap.java +++ b/src/main/java/org/icgc/argo/workflow_management/util/ConditionalPutMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/main/java/org/icgc/argo/workflow_management/util/JacksonUtils.java b/src/main/java/org/icgc/argo/workflow_management/util/JacksonUtils.java index fbc738e..2cd91df 100644 --- a/src/main/java/org/icgc/argo/workflow_management/util/JacksonUtils.java +++ b/src/main/java/org/icgc/argo/workflow_management/util/JacksonUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with @@ -33,4 +33,9 @@ public static String toJsonString(Object o) { public static T convertValue(Object fromValue, Class toValueType) { return OBJECT_MAPPER.convertValue(fromValue, toValueType); } + + @SneakyThrows + public static T readValue(String jsonString, Class valueType) { + return OBJECT_MAPPER.readValue(jsonString, valueType); + } } diff --git a/src/main/java/org/icgc/argo/workflow_management/util/NextflowConfigFile.java b/src/main/java/org/icgc/argo/workflow_management/util/NextflowConfigFile.java index a49d0a9..108932e 100644 --- a/src/main/java/org/icgc/argo/workflow_management/util/NextflowConfigFile.java +++ b/src/main/java/org/icgc/argo/workflow_management/util/NextflowConfigFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/main/java/org/icgc/argo/workflow_management/util/ParamsFile.java b/src/main/java/org/icgc/argo/workflow_management/util/ParamsFile.java index 7ae1f71..e918cd4 100644 --- a/src/main/java/org/icgc/argo/workflow_management/util/ParamsFile.java +++ b/src/main/java/org/icgc/argo/workflow_management/util/ParamsFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/main/java/org/icgc/argo/workflow_management/util/Reflections.java b/src/main/java/org/icgc/argo/workflow_management/util/Reflections.java index 45df979..8612b52 100644 --- a/src/main/java/org/icgc/argo/workflow_management/util/Reflections.java +++ b/src/main/java/org/icgc/argo/workflow_management/util/Reflections.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/main/java/org/icgc/argo/workflow_management/util/WesUtils.java b/src/main/java/org/icgc/argo/workflow_management/util/WesUtils.java new file mode 100644 index 0000000..eaf04d2 --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/util/WesUtils.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. + * You should have received a copy of the GNU Affero General Public License along with + * this program. If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.icgc.argo.workflow_management.util; + +import static java.lang.String.format; + +import java.util.UUID; +import lombok.experimental.UtilityClass; + +@UtilityClass +public class WesUtils { + private static final String WES_PREFIX = "wes-"; + // run name (used for paramsFile as well) + // You may be asking yourself, why is he replacing the "-" in the UUID, this is a valid + // question, well unfortunately when trying to resume a job, Nextflow searches for the + // UUID format ANYWHERE in the resume string, resulting in the incorrect assumption + // that we are passing an runId when in fact we are passing a runName ... + // thanks Nextflow ... this workaround solves that problem + + // UPDATE: The glory of Nextflow knows no bounds ... resuming by runName while possible + // ends up reusing the run/session (yeah these are the same but still recorded separately) id + // from the "last" run ... wtv run that was ... resulting in multiple resumed runs sharing the + // same sessionId (we're going with this label) even though they have nothing to do with one + // another. This is a bug in NF and warrants a PR but for now we recommend only resuming runs + // with sessionId and never with runName + public static String generateWesRunId() { + return format("%s%s", WES_PREFIX, UUID.randomUUID().toString().replace("-", "")); + } + + public static Boolean isValidWesRunName(String runName) { + return runName != null && runName.startsWith(WES_PREFIX) && runName.split("-").length == 2; + } +} diff --git a/src/main/java/org/icgc/argo/workflow_management/wes/controller/RunsApi.java b/src/main/java/org/icgc/argo/workflow_management/wes/controller/RunsApi.java index 1930fa3..25e6f55 100644 --- a/src/main/java/org/icgc/argo/workflow_management/wes/controller/RunsApi.java +++ b/src/main/java/org/icgc/argo/workflow_management/wes/controller/RunsApi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/main/java/org/icgc/argo/workflow_management/wes/controller/impl/RunsApiController.java b/src/main/java/org/icgc/argo/workflow_management/wes/controller/impl/RunsApiController.java index b0cc067..ee87f7c 100644 --- a/src/main/java/org/icgc/argo/workflow_management/wes/controller/impl/RunsApiController.java +++ b/src/main/java/org/icgc/argo/workflow_management/wes/controller/impl/RunsApiController.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with @@ -19,14 +19,11 @@ package org.icgc.argo.workflow_management.wes.controller.impl; import javax.validation.Valid; -import lombok.val; -import org.icgc.argo.workflow_management.service.WorkflowExecutionService; -import org.icgc.argo.workflow_management.service.model.RunParams; +import org.icgc.argo.workflow_management.service.api_to_wes.ApiToWesService; import org.icgc.argo.workflow_management.wes.controller.RunsApi; import org.icgc.argo.workflow_management.wes.controller.model.RunsRequest; import org.icgc.argo.workflow_management.wes.controller.model.RunsResponse; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.web.bind.annotation.*; import reactor.core.publisher.Mono; @@ -35,39 +32,22 @@ public class RunsApiController implements RunsApi { /** Dependencies */ - private final WorkflowExecutionService nextflowService; + private final ApiToWesService apiToWesService; @Autowired - public RunsApiController(@Qualifier("nextflow") WorkflowExecutionService nextflowService) { - this.nextflowService = nextflowService; + public RunsApiController(ApiToWesService apiToWesService) { + this.apiToWesService = apiToWesService; } @PostMapping public Mono postRun(@Valid @RequestBody RunsRequest runsRequest) { - - val wesService = resolveWesType("nextflow"); - - // create run config from request - val runConfig = - RunParams.builder() - .workflowUrl(runsRequest.getWorkflowUrl()) - .workflowParams(runsRequest.getWorkflowParams()) - .workflowEngineParams(runsRequest.getWorkflowEngineParams()) - .build(); - - return wesService.run(runConfig); + return apiToWesService.run(runsRequest); } @PostMapping( path = "/{run_id}/cancel", produces = {"application/json"}) public Mono cancelRun(@Valid @PathVariable("run_id") String runId) { - val wesService = resolveWesType("nextflow"); - return wesService.cancel(runId); - } - - // This method will eventually be responsible for which workflow service we run - private WorkflowExecutionService resolveWesType(String workflowType) { - return nextflowService; + return apiToWesService.cancel(runId); } } diff --git a/src/main/java/org/icgc/argo/workflow_management/wes/controller/model/RunsRequest.java b/src/main/java/org/icgc/argo/workflow_management/wes/controller/model/RunsRequest.java index 14aa475..55a7027 100644 --- a/src/main/java/org/icgc/argo/workflow_management/wes/controller/model/RunsRequest.java +++ b/src/main/java/org/icgc/argo/workflow_management/wes/controller/model/RunsRequest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/main/java/org/icgc/argo/workflow_management/wes/controller/model/RunsResponse.java b/src/main/java/org/icgc/argo/workflow_management/wes/controller/model/RunsResponse.java index bce5dfd..3fcf7ee 100644 --- a/src/main/java/org/icgc/argo/workflow_management/wes/controller/model/RunsResponse.java +++ b/src/main/java/org/icgc/argo/workflow_management/wes/controller/model/RunsResponse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/main/java/org/icgc/argo/workflow_management/wes/controller/model/WorkflowEngineParams.java b/src/main/java/org/icgc/argo/workflow_management/wes/controller/model/WorkflowEngineParams.java index 2a71395..cd37828 100644 --- a/src/main/java/org/icgc/argo/workflow_management/wes/controller/model/WorkflowEngineParams.java +++ b/src/main/java/org/icgc/argo/workflow_management/wes/controller/model/WorkflowEngineParams.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with @@ -23,11 +23,13 @@ import io.swagger.annotations.ApiModel; import java.util.UUID; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.codehaus.jackson.annotate.JsonIgnoreProperties; @Data +@Builder @AllArgsConstructor @NoArgsConstructor @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index fdf3434..e82d497 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -35,10 +35,38 @@ secret: apiKey: testapikeytotallylegit --- -spring.profile: oauth2Token +spring.profiles: oauth2Token secret: enabled: true clientId: testId clientSecret: testSecret tokenUri: http://localhost:8080/oauth/token + +--- +spring.profiles: api,execute + +rabbit: + default-endpoint-name: standalone + endpoints: + standalone: + host: localhost + port: 5672 + username: user + password: pass + managementPort: + +--- +spring.profiles: api + +api.producer.topology: + queueName: "execute-queue" + topicExchangeName: "execute" + topicRoutingKeys: "INITIALIZING, CANCELLING" # comma separated Array of keys +--- +spring.profiles: execute + +execute.consumer.topology: + queueName: "execute-queue" + topicExchangeName: "execute" + topicRoutingKeys: "INITIALIZING, CANCELLING" # comma separated Array of keys diff --git a/src/main/resources/avro/WfMgmtRunMsg.avsc b/src/main/resources/avro/WfMgmtRunMsg.avsc new file mode 100644 index 0000000..0897f01 --- /dev/null +++ b/src/main/resources/avro/WfMgmtRunMsg.avsc @@ -0,0 +1,88 @@ +{ + "type": "record", + "name": "WfMgmtRunMsg", + "namespace": "org.icgc.argo.workflow_management.rabbitmq.schema", + "fields": [ + { + "name": "timestamp", + "type": "long", + "logicalType": "date" + }, + { + "name": "runId", + "type": "string" + }, + { + "name": "state", + "type": { + "type": "enum", + "name": "RunState", + "symbols": ["UNKNOWN", "QUEUED", "INITIALIZING", "RUNNING", "PAUSED", "CANCELING", "CANCELED", "COMPLETE", "EXECUTOR_ERROR", "SYSTEM_ERROR"] + } + }, + { + "name": "workflowUrl", + "type": ["null", "string"], + "default": null + }, + { + "name": "workflowType", + "type": ["null", "string"], + "default": null + }, + { + "name": "workflowTypeVersion", + "type": ["null", "string"], + "default": null + }, + { + "name": "workflowParamsJsonStr", + "type": ["null", "string"], + "default": null + }, + { + "name": "workflowEngineParams", + "type": { + "type": "record", + "name": "EngineParams", + "fields": [ + { + "name": "defaultContainer", + "type": ["null", "string"], + "default": null + }, + { + "name": "revision", + "type": ["null", "string"], + "default": null + }, + { + "name": "launchDir", + "type": ["null", "string"], + "default": null + }, + { + "name": "projectDir", + "type": ["null", "string"], + "default": null + }, + { + "name": "workDir", + "type": ["null", "string"], + "default": null + }, + { + "name": "latest", + "type": ["null", "boolean"], + "default": null + }, + { + "name": "resume", + "type": ["null", "string"], + "default": null + } + ] + } + } + ] +} diff --git a/src/test/java/org/icgc/argo/workflow_management/ConditionalPutMapTest.java b/src/test/java/org/icgc/argo/workflow_management/ConditionalPutMapTest.java index 48d6a02..6610315 100644 --- a/src/test/java/org/icgc/argo/workflow_management/ConditionalPutMapTest.java +++ b/src/test/java/org/icgc/argo/workflow_management/ConditionalPutMapTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/test/java/org/icgc/argo/workflow_management/ErrorHandlingTests.java b/src/test/java/org/icgc/argo/workflow_management/ErrorHandlingTests.java index 9761333..429d127 100644 --- a/src/test/java/org/icgc/argo/workflow_management/ErrorHandlingTests.java +++ b/src/test/java/org/icgc/argo/workflow_management/ErrorHandlingTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with @@ -22,8 +22,7 @@ import static org.hamcrest.Matchers.*; import static org.icgc.argo.workflow_management.util.RandomGenerator.createRandomGenerator; import static org.icgc.argo.workflow_management.util.Reflections.findResponseStatusAnnotation; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.reset; import static org.springframework.http.HttpStatus.*; @@ -41,9 +40,11 @@ import org.icgc.argo.workflow_management.config.secret.NoSecretProviderConfig; import org.icgc.argo.workflow_management.config.security.AuthDisabledConfig; import org.icgc.argo.workflow_management.exception.GlobalExceptionHandler; -import org.icgc.argo.workflow_management.service.NextflowService; -import org.icgc.argo.workflow_management.service.NextflowWebLogEventSender; -import org.icgc.argo.workflow_management.service.properties.NextflowProperties; +import org.icgc.argo.workflow_management.service.api_to_wes.ApiToWesService; +import org.icgc.argo.workflow_management.service.api_to_wes.impl.DirectToWes; +import org.icgc.argo.workflow_management.service.wes.NextflowService; +import org.icgc.argo.workflow_management.service.wes.NextflowWebLogEventSender; +import org.icgc.argo.workflow_management.service.wes.properties.NextflowProperties; import org.icgc.argo.workflow_management.wes.controller.impl.RunsApiController; import org.icgc.argo.workflow_management.wes.controller.model.RunsRequest; import org.junit.Test; @@ -70,6 +71,7 @@ @Import( value = { NoSecretProviderConfig.class, + DirectToWes.class, NextflowService.class, NextflowWebLogEventSender.class, NextflowProperties.class, @@ -81,7 +83,7 @@ @WebFluxTest(controllers = RunsApiController.class) public class ErrorHandlingTests { - @Mock private NextflowService mockNextflowService; + @Mock private ApiToWesService apiToWesService; @Autowired private RunsApiController controller; @@ -290,11 +292,15 @@ private ResponseSpec doRunRequestError( private void setup(Supplier exceptionSupplier) { // Replace nextflowService dependency in the controller with a mock - ReflectionTestUtils.setField(controller, "nextflowService", mockNextflowService); + assertNotNull( + ReflectionTestUtils.getField(controller, "apiToWesService"), + "Test setup uses reflection to inject mock into controller field, but field not found!"); + + ReflectionTestUtils.setField(controller, "apiToWesService", apiToWesService); // Setup the mock to throw an exception - reset(mockNextflowService); - given(mockNextflowService.run(Mockito.any())) + reset(apiToWesService); + given(apiToWesService.run(Mockito.any())) .willAnswer( i -> { throw exceptionSupplier.get(); diff --git a/src/test/java/org/icgc/argo/workflow_management/WorkflowManagementApplicationTests.java b/src/test/java/org/icgc/argo/workflow_management/WorkflowManagementApplicationTests.java index eac0abf..6be4590 100644 --- a/src/test/java/org/icgc/argo/workflow_management/WorkflowManagementApplicationTests.java +++ b/src/test/java/org/icgc/argo/workflow_management/WorkflowManagementApplicationTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/test/java/org/icgc/argo/workflow_management/util/RandomGenerator.java b/src/test/java/org/icgc/argo/workflow_management/util/RandomGenerator.java index 50720c7..6723139 100644 --- a/src/test/java/org/icgc/argo/workflow_management/util/RandomGenerator.java +++ b/src/test/java/org/icgc/argo/workflow_management/util/RandomGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved * * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. * You should have received a copy of the GNU Affero General Public License along with diff --git a/src/test/java/org/icgc/argo/workflow_management/util/WorkflowTest.java b/src/test/java/org/icgc/argo/workflow_management/util/WorkflowTest.java deleted file mode 100644 index 604101e..0000000 --- a/src/test/java/org/icgc/argo/workflow_management/util/WorkflowTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2020 The Ontario Institute for Cancer Research. All rights reserved - * - * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. - * You should have received a copy of the GNU Affero General Public License along with - * this program. If not, see . - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.icgc.argo.workflow_management.util; - -import java.io.IOException; -import java.util.Map; -import lombok.SneakyThrows; -import lombok.val; -import org.icgc.argo.workflow_management.secret.SecretProvider; -import org.icgc.argo.workflow_management.secret.impl.NoSecretProvider; -import org.icgc.argo.workflow_management.service.NextflowService; -import org.icgc.argo.workflow_management.service.NextflowWebLogEventSender; -import org.icgc.argo.workflow_management.service.model.RunParams; -import org.icgc.argo.workflow_management.service.properties.NextflowProperties; -import org.icgc.argo.workflow_management.wes.controller.model.WorkflowEngineParams; - -public class WorkflowTest { - - private static final String weblogUrl = "http://localhost:8081"; - - public static void main(String[] args) throws IOException { - val p = new WorkflowEngineParams(); - val params = - RunParams.builder() - .workflowUrl("nextflow-io/hello") - .workflowParams(Map.of()) - .workflowEngineParams(p) - .build(); - runTest(params); - } - - @SneakyThrows - static void runTest(RunParams params) { - NextflowProperties config = new NextflowProperties(); - SecretProvider secretProvider = new NoSecretProvider(); - NextflowWebLogEventSender webLogEventSender = new NextflowWebLogEventSender(); - val service = new NextflowService(config, secretProvider, webLogEventSender); - val result = service.run(params); - System.err.println(result.toString()); - } -} From 4fbe9a977c8cf449bba58f6648cdec9af175e104 Mon Sep 17 00:00:00 2001 From: jaserud Date: Mon, 1 Feb 2021 16:11:42 -0500 Subject: [PATCH 03/18] remove rabbit mq magement port (#156) --- src/main/resources/application.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index e82d497..f4ac122 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -54,7 +54,6 @@ rabbit: port: 5672 username: user password: pass - managementPort: --- spring.profiles: api From 98fc0cc33969bdf08680b9dd0588474b7d48c819 Mon Sep 17 00:00:00 2001 From: jaserud Date: Wed, 3 Feb 2021 09:59:18 -0500 Subject: [PATCH 04/18] fix nextflow monitor and refactor weblogeventsender (#157) * fix nextflow monitor and refactor weblogeventsender * add todo comment for @NonNull removal --- .../rabbitmq/DisabledConfig.java | 29 ++++ .../rabbitmq/ExecuteConsumerConfig.java | 14 +- .../service/wes/NextflowService.java | 80 +++++------ .../wes/NextflowWebLogEventSender.java | 132 ------------------ .../service/wes/NextflowWorkflowMonitor.java | 31 ++-- .../service/wes/WebLogEventSender.java | 114 +++++++++++++++ .../service/wes/model/NextflowEvent.java | 43 ++++++ .../wes/model/NextflowWorkflowMetadata.java | 4 +- .../service/wes/model/WesState.java | 52 +++++++ .../service/wes/model/WfManagementEvent.java | 3 +- .../service/wes/model/WorkflowEvent.java | 33 +++++ .../ErrorHandlingTests.java | 4 +- 12 files changed, 330 insertions(+), 209 deletions(-) create mode 100644 src/main/java/org/icgc/argo/workflow_management/rabbitmq/DisabledConfig.java delete mode 100644 src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowWebLogEventSender.java create mode 100644 src/main/java/org/icgc/argo/workflow_management/service/wes/WebLogEventSender.java create mode 100644 src/main/java/org/icgc/argo/workflow_management/service/wes/model/NextflowEvent.java create mode 100644 src/main/java/org/icgc/argo/workflow_management/service/wes/model/WesState.java create mode 100644 src/main/java/org/icgc/argo/workflow_management/service/wes/model/WorkflowEvent.java diff --git a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/DisabledConfig.java b/src/main/java/org/icgc/argo/workflow_management/rabbitmq/DisabledConfig.java new file mode 100644 index 0000000..9d7f19f --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/rabbitmq/DisabledConfig.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. + * You should have received a copy of the GNU Affero General Public License along with + * this program. If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.icgc.argo.workflow_management.rabbitmq; + +import com.pivotal.rabbitmq.ReactiveRabbitAutoConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +@Profile("!api & !execute") +@Configuration +@EnableAutoConfiguration(exclude = ReactiveRabbitAutoConfiguration.class) +public class DisabledConfig {} diff --git a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/ExecuteConsumerConfig.java b/src/main/java/org/icgc/argo/workflow_management/rabbitmq/ExecuteConsumerConfig.java index 00ad22c..44d9f81 100644 --- a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/ExecuteConsumerConfig.java +++ b/src/main/java/org/icgc/argo/workflow_management/rabbitmq/ExecuteConsumerConfig.java @@ -30,7 +30,7 @@ import lombok.val; import org.icgc.argo.workflow_management.rabbitmq.schema.RunState; import org.icgc.argo.workflow_management.rabbitmq.schema.WfMgmtRunMsg; -import org.icgc.argo.workflow_management.service.wes.NextflowWebLogEventSender; +import org.icgc.argo.workflow_management.service.wes.WebLogEventSender; import org.icgc.argo.workflow_management.service.wes.WorkflowExecutionService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -52,7 +52,7 @@ public class ExecuteConsumerConfig { @Value("${execute.consumer.topology.topicRoutingKeys}") private String[] topicRoutingKeys; - private final NextflowWebLogEventSender webLogEventSender; + private final WebLogEventSender webLogEventSender; private final WorkflowExecutionService wes; private final RabbitEndpointService rabbit; @@ -60,7 +60,7 @@ public class ExecuteConsumerConfig { public ExecuteConsumerConfig( WorkflowExecutionService wes, RabbitEndpointService rabbit, - NextflowWebLogEventSender webLogEventSender) { + WebLogEventSender webLogEventSender) { this.wes = wes; this.rabbit = rabbit; this.webLogEventSender = webLogEventSender; @@ -98,9 +98,6 @@ public Consumer> consumeAndExecuteInitializeOrCancel() log.debug("WfMgmtRunMsg received: {}", msg); if (msg.getState().equals(RunState.CANCELING)) { - log.info("Cancelling: {}", msg); - webLogEventSender.sendWfMgmtEvent(createWfMgmtEvent(msg)); - wes.cancel(msg.getRunId()) .subscribe( runsResponse -> { @@ -108,9 +105,6 @@ public Consumer> consumeAndExecuteInitializeOrCancel() tx.commit(); }); } else if (msg.getState().equals(RunState.INITIALIZING)) { - log.info("Initializing: {}", msg); - webLogEventSender.sendWfMgmtEvent(createWfMgmtEvent(msg)); - val runParams = createRunParams(msg); wes.run(runParams) @@ -134,7 +128,7 @@ public BiConsumer handleError() { val msg = (WfMgmtRunMsg) ((Transaction) tx).get(); msg.setState(RunState.SYSTEM_ERROR); log.info("SYSTEM_ERROR: {}", msg); - webLogEventSender.sendWfMgmtEvent(createWfMgmtEvent(msg)); + webLogEventSender.sendWfMgmtEventAsync(createWfMgmtEvent(msg)); ((Transaction) tx).commit(); } else { log.error("Can't get WfMgmtRunMsg, transaction is lost!"); diff --git a/src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowService.java b/src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowService.java index 0ac3c2b..83be06c 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowService.java +++ b/src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowService.java @@ -32,8 +32,10 @@ import java.io.IOException; import java.util.*; import java.util.concurrent.TimeUnit; +import java.util.function.Function; import java.util.stream.Collectors; import lombok.NonNull; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import lombok.val; import nextflow.cli.CliOptions; @@ -44,10 +46,7 @@ import org.icgc.argo.workflow_management.exception.NextflowRunException; import org.icgc.argo.workflow_management.exception.ReflectionUtilsException; import org.icgc.argo.workflow_management.secret.SecretProvider; -import org.icgc.argo.workflow_management.service.wes.model.KubernetesPhase; -import org.icgc.argo.workflow_management.service.wes.model.NextflowMetadata; -import org.icgc.argo.workflow_management.service.wes.model.NextflowWorkflowMetadata; -import org.icgc.argo.workflow_management.service.wes.model.RunParams; +import org.icgc.argo.workflow_management.service.wes.model.*; import org.icgc.argo.workflow_management.service.wes.properties.NextflowProperties; import org.icgc.argo.workflow_management.util.ConditionalPutMap; import org.icgc.argo.workflow_management.wes.controller.model.RunsResponse; @@ -69,7 +68,7 @@ public class NextflowService implements WorkflowExecutionService { // Dependencies private final NextflowProperties config; private final SecretProvider secretProvider; - private final NextflowWebLogEventSender webLogSender; + private final WebLogEventSender webLogSender; // State private final DefaultKubernetesClient workflowRunK8sClient; @@ -78,9 +77,7 @@ public class NextflowService implements WorkflowExecutionService { @Autowired public NextflowService( - NextflowProperties config, - SecretProvider secretProvider, - NextflowWebLogEventSender webLogSender) { + NextflowProperties config, SecretProvider secretProvider, WebLogEventSender webLogSender) { this.config = config; this.secretProvider = secretProvider; this.webLogSender = webLogSender; @@ -89,25 +86,39 @@ public NextflowService( } public Mono run(RunParams params) { - return Mono.fromSupplier( - () -> { - try { - return this.startRun(params); - } catch (RuntimeException e) { - // rethrow runtime exception for GlobalExceptionHandler - log.error("nextflow runtime exception", e); - throw e; - } catch (Exception e) { - log.error("startRun exception", e); - throw new RuntimeException(e.getMessage()); - } - }) + log.debug("Initializing run: {}", params); + return webLogSender + .sendWfMgmtEvent(params, WesState.INITIALIZING) + .map(r -> this.startRun(params)) .map(RunsResponse::new) + .doOnError(t -> webLogSender.sendWfMgmtEventAsync(params, WesState.SYSTEM_ERROR)) + .onErrorMap(toRuntimeException("startRun")) .subscribeOn(scheduler); } - private String startRun(RunParams params) - throws ReflectionUtilsException, IOException, NextflowRunException { + public Mono cancel(@NonNull String runId) { + log.debug("Cancelling run: {}", runId); + return webLogSender + .sendWfMgmtEvent(runId, WesState.CANCELING) + .map(r -> this.cancelRun(runId)) + .map(RunsResponse::new) + .doOnError(t -> webLogSender.sendWfMgmtEventAsync(runId, WesState.SYSTEM_ERROR)) + .onErrorMap(toRuntimeException("cancelRun")) + .subscribeOn(scheduler); + } + + private Function toRuntimeException(String methodName) { + return t -> { + if (t instanceof RuntimeException) { + log.error("nextflow runtime exception", t); + } + log.error(methodName + " exception", t); + return new RuntimeException(t.getMessage()); + }; + } + + @SneakyThrows + private String startRun(RunParams params) { val cmd = createCmd(createLauncher(), params); val driver = createDriver(cmd); @@ -117,7 +128,7 @@ private String startRun(RunParams params) if (exitStatus == 0) { // Build required objects for monitoring THIS run. - val workflowMetadata = NextflowWorkflowMetadata.create(cmd, driver); + val workflowMetadata = NextflowWorkflowMetadata.create(cmd, driver, params.getWorkflowUrl()); val meta = new NextflowMetadata( workflowMetadata, new ScriptBinding.ParamsMap(params.getWorkflowParams())); @@ -136,24 +147,6 @@ private String startRun(RunParams params) } } - public Mono cancel(@NonNull String runId) { - return Mono.fromSupplier( - () -> { - try { - return this.cancelRun(runId); - } catch (RuntimeException e) { - // rethrow runtime exception for GlobalExceptionHandler - log.error("nextflow runtime exception", e); - throw e; - } catch (Exception e) { - log.error("cancelRun exception", e); - throw new RuntimeException(e.getMessage()); - } - }) - .map(RunsResponse::new) - .subscribeOn(scheduler); - } - /** * Creates a k8s client to introspect and interact with wes-* and nf-* pods * @@ -177,6 +170,7 @@ private DefaultKubernetesClient createWorkflowRunK8sClient() { } } + @SneakyThrows private String cancelRun(@NonNull String runId) { val state = getPhase(runId); @@ -230,7 +224,7 @@ private String handleFailedPod(String podName) { format( "Executor pod %s is in a failed state, sending failed pod event to weblog ...", podName)); - webLogSender.sendFailedPodEvent(podName); + webLogSender.sendWfMgmtEventAsync(podName, WesState.SYSTEM_ERROR); log.info(format("Cancellation event for pod %s has been sent to weblog.", podName)); return podName; } diff --git a/src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowWebLogEventSender.java b/src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowWebLogEventSender.java deleted file mode 100644 index 2ed5889..0000000 --- a/src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowWebLogEventSender.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved - * - * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. - * You should have received a copy of the GNU Affero General Public License along with - * this program. If not, see . - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.icgc.argo.workflow_management.service.wes; - -import static org.icgc.argo.workflow_management.service.wes.NextflowWebLogEventSender.Event.*; -import static org.icgc.argo.workflow_management.util.JacksonUtils.toJsonString; - -import java.util.Date; -import java.util.HashMap; -import java.util.TimeZone; -import lombok.AllArgsConstructor; -import lombok.NoArgsConstructor; -import lombok.val; -import nextflow.Const; -import nextflow.extension.Bolts; -import nextflow.trace.TraceRecord; -import org.icgc.argo.workflow_management.service.wes.model.NextflowMetadata; -import org.icgc.argo.workflow_management.service.wes.model.WfManagementEvent; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.MediaType; -import org.springframework.stereotype.Service; -import org.springframework.web.reactive.function.client.WebClient; - -@Service -@AllArgsConstructor -@NoArgsConstructor -public class NextflowWebLogEventSender { - @Value("${nextflow.weblogUrl}") - private String endpoint; - - public void sendStartEvent(NextflowMetadata meta) { - sendWorkflowEvent(STARTED, meta); - } - - public void sendCompletedEvent(NextflowMetadata meta) { - sendWorkflowEvent(COMPLETED, meta); - } - - public void sendProcessSubmitted(TraceRecord traceRecord) { - sendTraceEvent(PROCESS_SUBMITTED, traceRecord); - } - - public void sendProcessStarted(TraceRecord traceRecord) { - sendTraceEvent(PROCESS_STARTED, traceRecord); - } - - public void sendProcessCompleted(TraceRecord traceRecord) { - sendTraceEvent(PROCESS_COMPLETED, traceRecord); - } - - public void sendErrorEvent(TraceRecord traceRecord) { - sendTraceEvent(ERROR, traceRecord); - } - - public void sendFailedPodEvent(String podName) { - val message = new HashMap(); - String time = - Bolts.format(new Date(), Const.ISO_8601_DATETIME_FORMAT, TimeZone.getTimeZone("UTC")); - message.put("runName", podName); - message.put("event", FAILED.toString()); - message.put("utcTime", time); - - sendHttpMessageAsync(toJsonString(message)); - } - - public void sendTraceEvent(Event event, TraceRecord traceRecord) {} - - public HashMap createMessage(Event event, String runName) { - val message = new HashMap(); - String time = - Bolts.format(new Date(), Const.ISO_8601_DATETIME_FORMAT, TimeZone.getTimeZone("UTC")); - message.put("runName", runName); - message.put("runId", "?"); - message.put("event", event.toString()); - message.put("utcTime", time); - - return message; - } - - public void sendWorkflowEvent(Event event, NextflowMetadata meta) { - sendHttpMessageAsync(createWorkflowMessageJSON(event, meta)); - } - - public void sendWfMgmtEvent(WfManagementEvent event) { - sendHttpMessageAsync(toJsonString(event)); - } - - public String createWorkflowMessageJSON(Event event, NextflowMetadata logMessage) { - val runName = logMessage.getWorkflow().getRunName(); - val message = createMessage(event, runName); - - message.put("metadata", logMessage); - - return toJsonString(message); - } - - private void sendHttpMessageAsync(String jsonMessage) { - WebClient.create(endpoint) - .post() - .contentType(MediaType.APPLICATION_JSON) - .bodyValue(jsonMessage) - .retrieve() - .toBodilessEntity() - .subscribe(); - } - - enum Event { - STARTED, - COMPLETED, - PROCESS_SUBMITTED, - PROCESS_STARTED, - PROCESS_COMPLETED, - ERROR, - FAILED - } -} diff --git a/src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowWorkflowMonitor.java b/src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowWorkflowMonitor.java index e75e38d..f4bb378 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowWorkflowMonitor.java +++ b/src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowWorkflowMonitor.java @@ -31,15 +31,15 @@ import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import lombok.val; -import nextflow.util.Duration; import org.icgc.argo.workflow_management.service.wes.model.KubernetesPhase; +import org.icgc.argo.workflow_management.service.wes.model.NextflowEvent; import org.icgc.argo.workflow_management.service.wes.model.NextflowMetadata; @Slf4j @AllArgsConstructor public class NextflowWorkflowMonitor implements Runnable { - private final NextflowWebLogEventSender webLogSender; + private final WebLogEventSender webLogSender; private final NextflowMetadata metadata; private final Integer maxErrorLogLines; private final DefaultKubernetesClient kubernetesClient; @@ -72,14 +72,15 @@ public boolean handlePod(NextflowMetadata metadata, Pod pod, String podLog) { // if the pod failed to start up, we'll log the start and end events, so that we know // that the pod has started, and has failed, with the pod log as the error report. if (podFailed(pod)) { - log.debug("Sending start event"); - webLogSender.sendStartEvent(metadata); - log.debug("Updating the failure message"); - updateFailure(metadata, pod, podLog); - log.debug("Sending completed event"); - webLogSender.sendCompletedEvent(metadata); - log.debug("Event sent"); - log.debug(podName + " failed! Done!"); + val workflow = metadata.getWorkflow(); + + workflow.update(pod); + workflow.setComplete(now(ZoneOffset.UTC)); + workflow.setErrorReport("Nextflow pod failed to start: " + podLog); + workflow.setSuccess(false); + + log.debug("Sending error nextflow event"); + webLogSender.sendNextflowEventAsync(metadata, NextflowEvent.ERROR); return true; } @@ -104,16 +105,6 @@ private boolean podFailed(Pod pod) { return getPhase(pod).equals(KubernetesPhase.FAILED); } - public void updateFailure(NextflowMetadata metadata, Pod pod, String podLog) { - val workflow = metadata.getWorkflow(); - val completeTime = now(ZoneOffset.UTC); - workflow.update(pod); - workflow.setComplete(completeTime); - workflow.setDuration(Duration.between(workflow.getStart(), completeTime)); - workflow.setErrorReport("Nextflow pod failed to start"); - workflow.setSuccess(false); - } - public KubernetesPhase getPhase(Pod pod) { return KubernetesPhase.valueOf(pod.getStatus().getPhase().toUpperCase()); } diff --git a/src/main/java/org/icgc/argo/workflow_management/service/wes/WebLogEventSender.java b/src/main/java/org/icgc/argo/workflow_management/service/wes/WebLogEventSender.java new file mode 100644 index 0000000..eacad1e --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/service/wes/WebLogEventSender.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. + * You should have received a copy of the GNU Affero General Public License along with + * this program. If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.icgc.argo.workflow_management.service.wes; + +import static org.icgc.argo.workflow_management.util.JacksonUtils.convertValue; +import static org.icgc.argo.workflow_management.util.JacksonUtils.toJsonString; + +import java.util.Date; +import java.util.Objects; +import java.util.TimeZone; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import nextflow.Const; +import nextflow.extension.Bolts; +import org.icgc.argo.workflow_management.service.wes.model.*; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Service; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; + +@Slf4j +@Service +public class WebLogEventSender { + @Value("${nextflow.weblogUrl}") + String endpoint; + + public void sendNextflowEventAsync(NextflowMetadata metadata, NextflowEvent event) { + val msg = + WorkflowEvent.builder() + .runId(metadata.getWorkflow().getRunName()) + .runName(metadata.getWorkflow().getRunName()) + .event(event.toString()) + .utcTime(nowInUtc()) + .metadata(metadata) + .build(); + + sendHttpMessage(msg).subscribe(); + } + + public void sendWfMgmtEventAsync(RunParams params, WesState stateForEvent) { + sendWfMgmtEvent(params, stateForEvent).subscribe(); + } + + public void sendWfMgmtEventAsync(String runId, WesState stateForEvent) { + sendWfMgmtEvent(runId, stateForEvent).subscribe(); + } + + public void sendWfMgmtEventAsync(WfManagementEvent event) { + sendWfMgmtEvent(event).subscribe(); + } + + public Mono sendWfMgmtEvent(RunParams params, WesState stateForEvent) { + val event = convertValue(params, WfManagementEvent.class); + event.setEvent(stateForEvent.getValue()); + event.setUtcTime(nowInUtc()); + + return sendHttpMessage(event); + } + + public Mono sendWfMgmtEvent(String runId, WesState stateForEvent) { + val event = + WfManagementEvent.builder() + .runId(runId) + .event(stateForEvent.getValue()) + .utcTime(nowInUtc()) + .build(); + + return sendHttpMessage(event); + } + + public Mono sendWfMgmtEvent(WfManagementEvent event) { + return sendHttpMessage(event); + } + + private Mono sendHttpMessage(Object jsonReadyObject) { + return WebClient.create(endpoint) + .post() + .contentType(MediaType.APPLICATION_JSON) + .bodyValue(toJsonString(jsonReadyObject)) + .retrieve() + .toEntity(Boolean.class) + .flatMap( + res -> { + // Don't want to proceed with stream if response from weblog is bad, so throw error + if (!res.getStatusCode().is2xxSuccessful() || !Objects.equals(res.getBody(), true)) { + log.debug("Event failed to send to or process in weblog!"); + return Mono.error(new Exception("Event failed to send to or process in weblog!")); + } + log.debug("Message sent to weblog: " + jsonReadyObject); + return Mono.just(res.getBody()); + }); + } + + private String nowInUtc() { + return Bolts.format(new Date(), Const.ISO_8601_DATETIME_FORMAT, TimeZone.getTimeZone("UTC")); + } +} diff --git a/src/main/java/org/icgc/argo/workflow_management/service/wes/model/NextflowEvent.java b/src/main/java/org/icgc/argo/workflow_management/service/wes/model/NextflowEvent.java new file mode 100644 index 0000000..0f5b59b --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/service/wes/model/NextflowEvent.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. + * You should have received a copy of the GNU Affero General Public License along with + * this program. If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.icgc.argo.workflow_management.service.wes.model; + +import lombok.Getter; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +/** + * ENUM of nextflow events from: https://www.nextflow.io/docs/latest/tracing.html#weblog-via-http + */ +@RequiredArgsConstructor +public enum NextflowEvent { + STARTED("STARTED"), + + PROCESS_SUBMITTED("PROCESS_SUBMITTED"), + + PROCESS_STARTED("PROCESS_STARTED"), + + PROCESS_COMPLETED("PROCESS_COMPLETED"), + + ERROR("ERROR"), + + COMPLETED("COMPLETED"); + + @Getter @NonNull private final String value; +} diff --git a/src/main/java/org/icgc/argo/workflow_management/service/wes/model/NextflowWorkflowMetadata.java b/src/main/java/org/icgc/argo/workflow_management/service/wes/model/NextflowWorkflowMetadata.java index 5ed96bc..9860d00 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/wes/model/NextflowWorkflowMetadata.java +++ b/src/main/java/org/icgc/argo/workflow_management/service/wes/model/NextflowWorkflowMetadata.java @@ -79,7 +79,8 @@ public void update(Pod pod) { this.setStart(OffsetDateTime.parse(pod.getStatus().getStartTime())); } - public static NextflowWorkflowMetadata create(CmdKubeRun cmd, K8sDriverLauncher driver) { + public static NextflowWorkflowMetadata create( + CmdKubeRun cmd, K8sDriverLauncher driver, String repo) { NextflowWorkflowMetadata metadata = new NextflowWorkflowMetadata(); String commandLine; try { @@ -95,6 +96,7 @@ public static NextflowWorkflowMetadata create(CmdKubeRun cmd, K8sDriverLauncher metadata.setRevision(cmd.getRevision()); metadata.setRunName(cmd.getRunName()); metadata.setSuccess(false); + metadata.setRepository(repo); return metadata; } } diff --git a/src/main/java/org/icgc/argo/workflow_management/service/wes/model/WesState.java b/src/main/java/org/icgc/argo/workflow_management/service/wes/model/WesState.java new file mode 100644 index 0000000..60deaa8 --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/service/wes/model/WesState.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. + * You should have received a copy of the GNU Affero General Public License along with + * this program. If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.icgc.argo.workflow_management.service.wes.model; + +import lombok.Getter; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +/** + * ENUM of wes state from: + * https://github.com/ga4gh/workflow-execution-service-schemas/blob/c3b19854240c4fcbaf3483e22b19db0a918a7ee5/openapi/workflow_execution_service.swagger.yaml#L483 + */ +@RequiredArgsConstructor +public enum WesState { + UNKNOWN("UNKNOWN"), + + QUEUED("QUEUED"), + + INITIALIZING("INITIALIZING"), + + RUNNING("RUNNING"), + + PAUSED("PAUSED"), + + CANCELING("CANCELING"), + + CANCELED("CANCELED"), + + COMPLETE("COMPLETE"), + + EXECUTOR_ERROR("EXECUTOR_ERROR"), + + SYSTEM_ERROR("SYSTEM_ERROR"); + + @Getter @NonNull private final String value; +} diff --git a/src/main/java/org/icgc/argo/workflow_management/service/wes/model/WfManagementEvent.java b/src/main/java/org/icgc/argo/workflow_management/service/wes/model/WfManagementEvent.java index 78b3970..be9108c 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/wes/model/WfManagementEvent.java +++ b/src/main/java/org/icgc/argo/workflow_management/service/wes/model/WfManagementEvent.java @@ -33,7 +33,8 @@ public class WfManagementEvent { @NonNull private String runId; @NonNull private String event; @NonNull private String utcTime; - @NonNull private String workflowUrl; + // TODO - workflowUrl needs to be @NonNull, its missing it now because currently only INITIALIZING events have this info available + private String workflowUrl; private String workflowType; private String workflowTypeVersion; private Map workflowParams; diff --git a/src/main/java/org/icgc/argo/workflow_management/service/wes/model/WorkflowEvent.java b/src/main/java/org/icgc/argo/workflow_management/service/wes/model/WorkflowEvent.java new file mode 100644 index 0000000..5a3a2f1 --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/service/wes/model/WorkflowEvent.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. + * You should have received a copy of the GNU Affero General Public License along with + * this program. If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.icgc.argo.workflow_management.service.wes.model; + +import lombok.Builder; +import lombok.NonNull; +import lombok.Value; + +@Value +@Builder +public class WorkflowEvent { + @NonNull String runId; + @NonNull String runName; + @NonNull String event; + @NonNull String utcTime; + @NonNull NextflowMetadata metadata; +} diff --git a/src/test/java/org/icgc/argo/workflow_management/ErrorHandlingTests.java b/src/test/java/org/icgc/argo/workflow_management/ErrorHandlingTests.java index 429d127..e258274 100644 --- a/src/test/java/org/icgc/argo/workflow_management/ErrorHandlingTests.java +++ b/src/test/java/org/icgc/argo/workflow_management/ErrorHandlingTests.java @@ -43,7 +43,7 @@ import org.icgc.argo.workflow_management.service.api_to_wes.ApiToWesService; import org.icgc.argo.workflow_management.service.api_to_wes.impl.DirectToWes; import org.icgc.argo.workflow_management.service.wes.NextflowService; -import org.icgc.argo.workflow_management.service.wes.NextflowWebLogEventSender; +import org.icgc.argo.workflow_management.service.wes.WebLogEventSender; import org.icgc.argo.workflow_management.service.wes.properties.NextflowProperties; import org.icgc.argo.workflow_management.wes.controller.impl.RunsApiController; import org.icgc.argo.workflow_management.wes.controller.model.RunsRequest; @@ -73,7 +73,7 @@ NoSecretProviderConfig.class, DirectToWes.class, NextflowService.class, - NextflowWebLogEventSender.class, + WebLogEventSender.class, NextflowProperties.class, GlobalExceptionHandler.class, AuthDisabledConfig.class From 4436d958162cd03ab4a75072f08f2323499906ec Mon Sep 17 00:00:00 2001 From: jaserud Date: Wed, 3 Feb 2021 11:07:50 -0500 Subject: [PATCH 05/18] build instead of jackson convert and more detail in error messaging (#158) * build instead of jackson convert and more detail in error messaging * run mvn format --- .../service/wes/NextflowService.java | 9 +++++---- .../service/wes/WebLogEventSender.java | 13 +++++++++---- .../service/wes/model/WfManagementEvent.java | 3 ++- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowService.java b/src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowService.java index 83be06c..fdcdc11 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowService.java +++ b/src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowService.java @@ -92,7 +92,7 @@ public Mono run(RunParams params) { .map(r -> this.startRun(params)) .map(RunsResponse::new) .doOnError(t -> webLogSender.sendWfMgmtEventAsync(params, WesState.SYSTEM_ERROR)) - .onErrorMap(toRuntimeException("startRun")) + .onErrorMap(toRuntimeException("startRun", params.getRunId())) .subscribeOn(scheduler); } @@ -103,17 +103,18 @@ public Mono cancel(@NonNull String runId) { .map(r -> this.cancelRun(runId)) .map(RunsResponse::new) .doOnError(t -> webLogSender.sendWfMgmtEventAsync(runId, WesState.SYSTEM_ERROR)) - .onErrorMap(toRuntimeException("cancelRun")) + .onErrorMap(toRuntimeException("cancelRun", runId)) .subscribeOn(scheduler); } - private Function toRuntimeException(String methodName) { + private Function toRuntimeException(String methodName, String runId) { return t -> { if (t instanceof RuntimeException) { log.error("nextflow runtime exception", t); } log.error(methodName + " exception", t); - return new RuntimeException(t.getMessage()); + return new RuntimeException( + format("%s error. runId: %s, msg: %s", methodName, runId, t.getMessage())); }; } diff --git a/src/main/java/org/icgc/argo/workflow_management/service/wes/WebLogEventSender.java b/src/main/java/org/icgc/argo/workflow_management/service/wes/WebLogEventSender.java index eacad1e..0e3d54d 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/wes/WebLogEventSender.java +++ b/src/main/java/org/icgc/argo/workflow_management/service/wes/WebLogEventSender.java @@ -18,7 +18,6 @@ package org.icgc.argo.workflow_management.service.wes; -import static org.icgc.argo.workflow_management.util.JacksonUtils.convertValue; import static org.icgc.argo.workflow_management.util.JacksonUtils.toJsonString; import java.util.Date; @@ -67,9 +66,15 @@ public void sendWfMgmtEventAsync(WfManagementEvent event) { } public Mono sendWfMgmtEvent(RunParams params, WesState stateForEvent) { - val event = convertValue(params, WfManagementEvent.class); - event.setEvent(stateForEvent.getValue()); - event.setUtcTime(nowInUtc()); + val event = + WfManagementEvent.builder() + .runId(params.getRunId()) + .workflowUrl(params.getWorkflowUrl()) + .workflowEngineParams(params.getWorkflowEngineParams()) + .workflowParams(params.getWorkflowParams()) + .event(stateForEvent.getValue()) + .utcTime(nowInUtc()) + .build(); return sendHttpMessage(event); } diff --git a/src/main/java/org/icgc/argo/workflow_management/service/wes/model/WfManagementEvent.java b/src/main/java/org/icgc/argo/workflow_management/service/wes/model/WfManagementEvent.java index be9108c..f77bcb2 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/wes/model/WfManagementEvent.java +++ b/src/main/java/org/icgc/argo/workflow_management/service/wes/model/WfManagementEvent.java @@ -33,7 +33,8 @@ public class WfManagementEvent { @NonNull private String runId; @NonNull private String event; @NonNull private String utcTime; - // TODO - workflowUrl needs to be @NonNull, its missing it now because currently only INITIALIZING events have this info available + // TODO - workflowUrl needs to be @NonNull, its missing it now because currently only INITIALIZING + // events have this info available private String workflowUrl; private String workflowType; private String workflowTypeVersion; From ddd968c699f244243e67a3f338efdbcfa48b8d36 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 2 Feb 2021 12:12:09 -0500 Subject: [PATCH 06/18] wip: general intro and layout --- README.md | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8832985..9d8d65c 100644 --- a/README.md +++ b/README.md @@ -1 +1,40 @@ -# workflow-management +# Workflow Management + +This service is responsible for managing the lifecycle of a workflow execution within the larger Workflow Execution System (WES). +At it's simplest, Workflow Management takes a workflow request and initiates a run using the requested workflow engine (currently only supporting Nextflow). +However, it is possible to configure Workflow Management to go beyond being a direct initiator and instead it can be configured to queue runs +which can then be processed by various "middleware" before finally hitting the initiator, more on this below. In addition to queuing and initiating, +Workflow Management also handles cancelling runs and ensuring that run state transitions are valid (ie. a late received duplicate message to cancel a run +will be ignored as the run is already in a state of `CANCELLING` or `CANCELLED` at that point) + +## Workflow Run Lifecycle and State Diagram + +Workflow runs can be in a number of states as they make their way through the WES, these states can be updated by user-action (starting, cancelling), +by events in the Workflow Management domain (going from queued to initiating, cancelling to cancelled, etc), and from external events from the workflow +execution engine itself (Nextflow at the present time). + +\_#\_#\_#\_INSERT_STATE_DIAGRAM_HERE\_#\_#\_#\_ + +#### Workflow State Verifier + +The workflow state verifier is essentially a state machine that ensure that only valid state transitions are processed whilst invalid transitions are ignored. + +\_#\_#\_#\_INSERT_DIAGRAM_HERE\_#\_#\_#\_ + +#### Workflow Run State + + + +## Middleware Service Support + +Workflow Management approaches to concept of middleware a little differently than a more traditional application might. Once a run is queued + +## Tech Stack +- Java 11 +- RabbitMQ 3.X +- PostgreSQL 13 +- [Spring Reactive Stack](https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html) +- [Reactor RabbitMQ Streams](https://pivotal.github.io/reactor-rabbitmq-streams/docs/current/) +- [Apache Avro](https://avro.apache.org/) + +## Build and Run From 042e8b61239aed21be9ade8386f716da57f69e66 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 3 Feb 2021 12:34:37 -0500 Subject: [PATCH 07/18] updates and diagrams --- README.md | 33 ++++++++++++++++++++++++---- docs/Managment Standalone.png | Bin 0 -> 127638 bytes docs/Managment with Middleware.png | Bin 0 -> 163751 bytes docs/WES States and Transitions.png | Bin 0 -> 200333 bytes 4 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 docs/Managment Standalone.png create mode 100644 docs/Managment with Middleware.png create mode 100644 docs/WES States and Transitions.png diff --git a/README.md b/README.md index 9d8d65c..f000d2f 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Workflow runs can be in a number of states as they make their way through the WE by events in the Workflow Management domain (going from queued to initiating, cancelling to cancelled, etc), and from external events from the workflow execution engine itself (Nextflow at the present time). -\_#\_#\_#\_INSERT_STATE_DIAGRAM_HERE\_#\_#\_#\_ +![WES States Diagram](docs/WES%20States%20and%20Transitions.png) #### Workflow State Verifier @@ -21,13 +21,38 @@ The workflow state verifier is essentially a state machine that ensure that only \_#\_#\_#\_INSERT_DIAGRAM_HERE\_#\_#\_#\_ -#### Workflow Run State +#### Workflow Management Run State +In order for the state verifier to work correctly, a centralized record of runs, and their last valid state, will be maintained in a database (PostgreSQL). +This state will be used as the ground truth when making any decisions regarding state transitions within Workflow Management and as the backing repository +for the Workflow Management API (TBD but this will be available to any "middleware" services as well). +### RabbitMQ Queues and How They Work -## Middleware Service Support +\_#\_#\_#\_INSERT_DIAGRAM_HERE\_#\_#\_#\_ + +## Middleware(ish) Service Support + +Workflow Management approaches to concept of middleware a little differently than a more traditional application might. Let's first look at the default case of Management +running with no middleware whatsoever. + +![Management - Standalone](docs/Managment%20Standalone.png) + +In this case, there is no concept of queuing because there would be no difference between messages being set to `QUEUED` vs `INITIALIZING` as there is no action for any service to +take between those states. The diagram shows two distinct Management deploys but this is really only for getting the point across, this would likely be a single Management instance with +the right profiles enabled. + +What if you did want to have something managing a queue, or processing templated requests, or sending notification on certain state transitions. We allow for this by enabling an +architecture where standing up services that speak to Management via it's API's is able to transition runs to any number of intermediary states `QUEUED` and `INITIALIZING` +(TBD, currently we only allow the base WES states however middleware would still be able to take any number of action before completing the transition). + +![Management - Middleware(ish)](docs/Managment%20with%20Middleware.png) + +In the diagram above you can see that the flow basically works as described. Management receives the request and queues the run immediately. A middleware service is listening on the `state.QUEUED` topic, +picks up the message for processing, and once complete sends a request to Management to initialize the run (with the updates state if applicable). Management then continues from this point just as if +it was running in standalone mode. In the future once the state transitions are configurable, any number of middleware can run in sequence or even in parallel as long as the ultimately get the message +back to management to initialize the run. -Workflow Management approaches to concept of middleware a little differently than a more traditional application might. Once a run is queued ## Tech Stack - Java 11 diff --git a/docs/Managment Standalone.png b/docs/Managment Standalone.png new file mode 100644 index 0000000000000000000000000000000000000000..730f88216cf85937d146c0ae5c90609ae78d5d89 GIT binary patch literal 127638 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

F~dlY_F`ZAsD(suCZX4jtMIyw0eM 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 literal 0 HcmV?d00001 diff --git a/docs/Managment with Middleware.png b/docs/Managment with Middleware.png new file mode 100644 index 0000000000000000000000000000000000000000..006990b2d0d30016475b2f3e89f28277d81fe91b GIT binary patch literal 163751 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�cV709lp){jCl9Wa236pYs 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 LtDnm{r-UW|KT_0c literal 0 HcmV?d00001 diff --git a/docs/WES States and Transitions.png b/docs/WES States and Transitions.png new file mode 100644 index 0000000000000000000000000000000000000000..891aa09785408e7dbf0b620e121e2972838cac11 GIT binary patch literal 200333 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�M*#_FefF{U9ksV2g<@qrHO0#5_Wh_4 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 Date: Wed, 3 Feb 2021 14:30:03 -0500 Subject: [PATCH 08/18] final tweaks for now --- README.md | 127 +++++++++++++++++++++++---- docs/management-high-level-flow.jpeg | Bin 0 -> 73230 bytes docs/state-transition-diagram.jpeg | Bin 0 -> 52441 bytes docs/wes-high-level-diagram.jpeg | Bin 0 -> 150742 bytes 4 files changed, 109 insertions(+), 18 deletions(-) create mode 100644 docs/management-high-level-flow.jpeg create mode 100644 docs/state-transition-diagram.jpeg create mode 100644 docs/wes-high-level-diagram.jpeg diff --git a/README.md b/README.md index f000d2f..93ca215 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,23 @@ which can then be processed by various "middleware" before finally hitting the i Workflow Management also handles cancelling runs and ensuring that run state transitions are valid (ie. a late received duplicate message to cancel a run will be ignored as the run is already in a state of `CANCELLING` or `CANCELLED` at that point) +Workflow Management is part of the larger Workflow Execution Service which comprises multiple services. Given that Workflow Management is composed itself of +potentially multiple instances running different components (managed with Spring profiles) and potentially multiple middleware services, we refer to this more +broadly as the Workflow Management Domain. + +![Workflow Management Domain](docs/wes-high-level-diagram.jpeg) + +The above diagram illustrates the Workflow Management domain, and it's position in the overall WES service architecture. This README will attempt to illuminate +the main concepts employed by Workflow Management as well as summarize the technologies used and how to get up and running with it as smoothly as possible. + +## Tech Stack +- Java 11 +- RabbitMQ 3.X +- PostgreSQL 13 +- [Spring Reactive Stack](https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html) +- [Reactor RabbitMQ Streams](https://pivotal.github.io/reactor-rabbitmq-streams/docs/current/) +- [Apache Avro](https://avro.apache.org/) + ## Workflow Run Lifecycle and State Diagram Workflow runs can be in a number of states as they make their way through the WES, these states can be updated by user-action (starting, cancelling), @@ -15,11 +32,66 @@ execution engine itself (Nextflow at the present time). ![WES States Diagram](docs/WES%20States%20and%20Transitions.png) -#### Workflow State Verifier - -The workflow state verifier is essentially a state machine that ensure that only valid state transitions are processed whilst invalid transitions are ignored. - -\_#\_#\_#\_INSERT_DIAGRAM_HERE\_#\_#\_#\_ +### High Level Flow (RabbitMQ Queues and How They Work) + +Communication between the services in the management domain will be backed by RabbitMQ. This is because these messages don't need to be stored permanently, +we have selective message acknowledgement, once delivery, and clear transaction support. Messages in the RabbitMQ flow will also not pollute the journal in +the workflow-relay domain, ensuring separation of concerns. + +![Management High Level Flow](docs/management-high-level-flow.jpeg) + +In addition to the separation of concerns between decision-making (transitioning states) and journaling, this approach is especially beneficial to expanding +on the functionality of the Management domain with "middleware services", something that is explained in greater detail further down this readme. + +To keep things orderly and sane, Management has a single message schema defined in using Apache AVRO, that it and all future middleware must use in order to +pass messages, a Lingua Franca of sorts. + +##### Workflow Management Message Schema + +``` +WorkflowManagementMessage { + @NonNull String runId; + @NonNull WorkflowState state; + @NonNull String workflowUrl; + @NonNull String utcTime; + String workflowType; + String workflowTypeVersion; + Map workflowParams; + EngineParameters workflowEngineParams; +} + +EngineParameters { + String defaultContainer; + String launchDir; + String projectDir; + String workDir; + String revision; + String resume; + String latest; +} + +enum WorkflowState { + UNKNOWN("UNKNOWN"), + QUEUED("QUEUED"), + INITIALIZING("INITIALIZING"), + RUNNING("RUNNING"), + PAUSED("PAUSED"), + CANCELING("CANCELING"), + CANCELED("CANCELED"), + COMPLETE("COMPLETE"), + EXECUTOR_ERROR("EXECUTOR_ERROR"), + SYSTEM_ERROR("SYSTEM_ERROR"); +} + +``` + +#### Workflow State Transition Verifier + +The "State Transition Verifier" component, which is backed by a cloud friendly storage (PSQL), is as a temporary ledger for workflow runs in management giving us a +way to lock/synchronize them. Following the state transition flow, workflows enter the ledger as `QUEUED` and leave the ledger once in one of the terminal states. +Only valid transitions in workflow state is allowed to occur so only those will be executed and/or sent to the relay-domain for journaling/indexing. + +![State Transition Diagram](docs/state-transition-diagram.jpeg) #### Workflow Management Run State @@ -27,10 +99,6 @@ In order for the state verifier to work correctly, a centralized record of runs, This state will be used as the ground truth when making any decisions regarding state transitions within Workflow Management and as the backing repository for the Workflow Management API (TBD but this will be available to any "middleware" services as well). -### RabbitMQ Queues and How They Work - -\_#\_#\_#\_INSERT_DIAGRAM_HERE\_#\_#\_#\_ - ## Middleware(ish) Service Support Workflow Management approaches to concept of middleware a little differently than a more traditional application might. Let's first look at the default case of Management @@ -51,15 +119,38 @@ architecture where standing up services that speak to Management via it's API's In the diagram above you can see that the flow basically works as described. Management receives the request and queues the run immediately. A middleware service is listening on the `state.QUEUED` topic, picks up the message for processing, and once complete sends a request to Management to initialize the run (with the updates state if applicable). Management then continues from this point just as if it was running in standalone mode. In the future once the state transitions are configurable, any number of middleware can run in sequence or even in parallel as long as the ultimately get the message -back to management to initialize the run. +back to management to initialize the run. +## Modes -## Tech Stack -- Java 11 -- RabbitMQ 3.X -- PostgreSQL 13 -- [Spring Reactive Stack](https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html) -- [Reactor RabbitMQ Streams](https://pivotal.github.io/reactor-rabbitmq-streams/docs/current/) -- [Apache Avro](https://avro.apache.org/) +TBD - Describe various run profiles (modes), what they do, etc. + +## Build + +With Maven: +```bash +mvn clean package +``` + +With Docker: +```bash +docker build . +``` + +## Run + +The uber jar can be run as a spring boot application with the following command: +```bash +java -jar target/workflow-management.jar +``` + +Or with docker: +```bash +docker run ghcr.io/icgc-argo/workflow-management +``` + +## Test -## Build and Run +```bash +mvn clean test +``` \ No newline at end of file diff --git a/docs/management-high-level-flow.jpeg b/docs/management-high-level-flow.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..a83ab89406c0fb301484cadd8eaee652c0a9ebf0 GIT binary patch literal 73230 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 literal 0 HcmV?d00001 diff --git a/docs/state-transition-diagram.jpeg b/docs/state-transition-diagram.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..7dbf9956ba43735187e614a5e07bc19998f9b99f GIT binary patch literal 52441 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\ehgplk54yp+~YVA5uByr@YV2Wmcj(( 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 z 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 J-Q|yo{{cH+q}>1j literal 0 HcmV?d00001 diff --git a/docs/wes-high-level-diagram.jpeg b/docs/wes-high-level-diagram.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..c9733162d9c5af6f8d5d9a922ef272b36f6304e6 GIT binary patch literal 150742 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 yPgzd;g;XK03PB-5@NaLjG$hvTdG2N*4Ud=#X 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 Date: Wed, 3 Feb 2021 14:45:41 -0500 Subject: [PATCH 09/18] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 93ca215..1acbc47 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Workflow Management +[![License: AGPL v3](https://img.shields.io/badge/License-AGPL%20v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0) + This service is responsible for managing the lifecycle of a workflow execution within the larger Workflow Execution System (WES). At it's simplest, Workflow Management takes a workflow request and initiates a run using the requested workflow engine (currently only supporting Nextflow). However, it is possible to configure Workflow Management to go beyond being a direct initiator and instead it can be configured to queue runs @@ -153,4 +155,4 @@ docker run ghcr.io/icgc-argo/workflow-management ```bash mvn clean test -``` \ No newline at end of file +``` From 2336b04f79abc2488363b53ab102814f8a67d49a Mon Sep 17 00:00:00 2001 From: jaserud Date: Fri, 26 Feb 2021 09:36:46 -0500 Subject: [PATCH 10/18] adds gatekeeper profile and feature (#160) * gatekeeper inital commit * make gql for gatekeeper more modular * consume weblog events * cleanup * fix field visibility and some other renaming * check weblog and map to msg * remove chechandupdateresult * revert some unneeded changes * remove local specific nextflow configs * update compose for gatekeeper * weblog from gatekeeper streams * set canceled before check * fix test, make sure they work without local containers * replace null return with optional empty * refactor to make testable and add tests * disposable manager and remove explicit query * register others with disposable manager * add comments for clarity * execute consumer check if using middleware to initialize * GqlSearchQueryArgs and more comments * Move state transition into seperate class for clear documentation. Also add comments to gatekeeperprocessortests. * add matrix to next state function docs * Revert "add matrix to next state function docs" This reverts commit 66945855 * revert * squash some bugs --- Jenkinsfile | 2 + docker-compose-gatekeeper.yaml | 20 ++ pom.xml | 22 +- .../config/app/GateKeeperDisabledConfig.java | 40 +++ .../config/app/GateKeeperTestConfig.java | 31 ++ .../rabbitmq/RabbitDisabledConfig.java} | 6 +- .../config/rabbitmq/RabbitSchemaConfig.java | 73 +++++ .../gatekeeper/model/ActiveRun.java | 48 +++ .../model/EngineParamsConverter.java | 25 ++ .../gatekeeper/repository/ActiveRunsRepo.java | 35 +++ .../gatekeeper/service/GateKeeperService.java | 170 +++++++++++ .../service/GatekeeperProcessor.java | 98 ++++++ .../gatekeeper/service/StateTransition.java | 68 +++++ .../graphql/BlockedQueryVisibility.java | 56 ++++ .../graphql/GatekeeperDataFetchers.java | 70 +++++ .../graphql/GraphQLProvider.java | 19 +- .../graphql/model/GqlPage.java | 9 + .../graphql/model/GqlSearchQueryArgs.java | 36 +++ .../graphql/model/GqlSort.java | 9 + .../graphql/model/SearchResult.java | 22 ++ .../rabbitmq/ApiProducerConfig.java | 63 ++-- .../rabbitmq/DisposableManager.java | 50 ++++ .../rabbitmq/ExecuteConsumerConfig.java | 72 ++--- .../rabbitmq/GateKeeperStreamsConfig.java | 161 ++++++++++ .../rabbitmq/WeblogEvent.java | 87 ++++++ .../rabbitmq/WfMgmtRunMsgConverters.java | 6 +- .../api_to_wes/impl/ApiProducerToWes.java | 2 +- .../util/RabbitmqUtils.java | 84 ++++++ src/main/resources/application.yml | 60 +++- src/main/resources/schema.graphql | 68 ++++- .../GateKeeperProcessorTests.java | 280 ++++++++++++++++++ .../util/TransactionUtils.java | 88 ++++++ 32 files changed, 1774 insertions(+), 106 deletions(-) create mode 100644 docker-compose-gatekeeper.yaml create mode 100644 src/main/java/org/icgc/argo/workflow_management/config/app/GateKeeperDisabledConfig.java create mode 100644 src/main/java/org/icgc/argo/workflow_management/config/app/GateKeeperTestConfig.java rename src/main/java/org/icgc/argo/workflow_management/{rabbitmq/DisabledConfig.java => config/rabbitmq/RabbitDisabledConfig.java} (91%) create mode 100644 src/main/java/org/icgc/argo/workflow_management/config/rabbitmq/RabbitSchemaConfig.java create mode 100644 src/main/java/org/icgc/argo/workflow_management/gatekeeper/model/ActiveRun.java create mode 100644 src/main/java/org/icgc/argo/workflow_management/gatekeeper/model/EngineParamsConverter.java create mode 100644 src/main/java/org/icgc/argo/workflow_management/gatekeeper/repository/ActiveRunsRepo.java create mode 100644 src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/GateKeeperService.java create mode 100644 src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/GatekeeperProcessor.java create mode 100644 src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/StateTransition.java create mode 100644 src/main/java/org/icgc/argo/workflow_management/graphql/BlockedQueryVisibility.java create mode 100644 src/main/java/org/icgc/argo/workflow_management/graphql/GatekeeperDataFetchers.java create mode 100644 src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlPage.java create mode 100644 src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlSearchQueryArgs.java create mode 100644 src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlSort.java create mode 100644 src/main/java/org/icgc/argo/workflow_management/graphql/model/SearchResult.java create mode 100644 src/main/java/org/icgc/argo/workflow_management/rabbitmq/DisposableManager.java create mode 100644 src/main/java/org/icgc/argo/workflow_management/rabbitmq/GateKeeperStreamsConfig.java create mode 100644 src/main/java/org/icgc/argo/workflow_management/rabbitmq/WeblogEvent.java create mode 100644 src/main/java/org/icgc/argo/workflow_management/util/RabbitmqUtils.java create mode 100644 src/test/java/org/icgc/argo/workflow_management/GateKeeperProcessorTests.java create mode 100644 src/test/java/org/icgc/argo/workflow_management/util/TransactionUtils.java diff --git a/Jenkinsfile b/Jenkinsfile index d5e7f51..20c44f0 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -37,6 +37,8 @@ spec: volumeMounts: - mountPath: /var/run/docker.sock name: docker-sock + - name: postgres + image: postgres:10-alpine volumes: - name: docker-sock hostPath: diff --git a/docker-compose-gatekeeper.yaml b/docker-compose-gatekeeper.yaml new file mode 100644 index 0000000..1f1ea79 --- /dev/null +++ b/docker-compose-gatekeeper.yaml @@ -0,0 +1,20 @@ +version: '3' + +services: + gatekeeper-db: + image: postgres:10-alpine + environment: + POSTGRES_DB: gatekeeperdb + POSTGRES_PASSWORD: mysecretpassword + expose: + - "5432" + ports: + - "5432:5432" + rabbitmq: + image: bitnami/rabbitmq:3.8.9 + environment: + RABBITMQ_USERNAME: user + RABBITMQ_PASSWORD: pass + ports: + - 5672:5672 + - 15672:15672 diff --git a/pom.xml b/pom.xml index 6a379c0..5c06741 100644 --- a/pom.xml +++ b/pom.xml @@ -148,12 +148,32 @@ 0.5.0 - com.pivotal.rabbitmq reactor-rabbitmq-streams-autoconfigure + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.postgresql + postgresql + 42.2.18 + + + org.testcontainers + postgresql + 1.15.2 + test + + + org.springframework.cloud + spring-cloud-starter-stream-kafka + 3.0.1.RELEASE + diff --git a/src/main/java/org/icgc/argo/workflow_management/config/app/GateKeeperDisabledConfig.java b/src/main/java/org/icgc/argo/workflow_management/config/app/GateKeeperDisabledConfig.java new file mode 100644 index 0000000..e0290d6 --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/config/app/GateKeeperDisabledConfig.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. + * You should have received a copy of the GNU Affero General Public License along with + * this program. If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.icgc.argo.workflow_management.config.app; + +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; +import org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration; +import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; +import org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +@Configuration +@Profile("!gatekeeper & !gatekeeper-test") +@EnableAutoConfiguration( + exclude = { + DataSourceAutoConfiguration.class, + DataSourceTransactionManagerAutoConfiguration.class, + HibernateJpaAutoConfiguration.class, + KafkaAutoConfiguration.class, + ContextFunctionCatalogAutoConfiguration.class + }) +public class GateKeeperDisabledConfig {} diff --git a/src/main/java/org/icgc/argo/workflow_management/config/app/GateKeeperTestConfig.java b/src/main/java/org/icgc/argo/workflow_management/config/app/GateKeeperTestConfig.java new file mode 100644 index 0000000..924a96c --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/config/app/GateKeeperTestConfig.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. + * You should have received a copy of the GNU Affero General Public License along with + * this program. If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.icgc.argo.workflow_management.config.app; + +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration; +import org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +@Configuration +@Profile("gatekeeper-test") +@EnableAutoConfiguration( + exclude = {KafkaAutoConfiguration.class, ContextFunctionCatalogAutoConfiguration.class}) +public class GateKeeperTestConfig {} diff --git a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/DisabledConfig.java b/src/main/java/org/icgc/argo/workflow_management/config/rabbitmq/RabbitDisabledConfig.java similarity index 91% rename from src/main/java/org/icgc/argo/workflow_management/rabbitmq/DisabledConfig.java rename to src/main/java/org/icgc/argo/workflow_management/config/rabbitmq/RabbitDisabledConfig.java index 9d7f19f..b79a45e 100644 --- a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/DisabledConfig.java +++ b/src/main/java/org/icgc/argo/workflow_management/config/rabbitmq/RabbitDisabledConfig.java @@ -16,14 +16,14 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.rabbitmq; +package org.icgc.argo.workflow_management.config.rabbitmq; import com.pivotal.rabbitmq.ReactiveRabbitAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; -@Profile("!api & !execute") +@Profile("!api & !execute & !gatekeeper") @Configuration @EnableAutoConfiguration(exclude = ReactiveRabbitAutoConfiguration.class) -public class DisabledConfig {} +public class RabbitDisabledConfig {} diff --git a/src/main/java/org/icgc/argo/workflow_management/config/rabbitmq/RabbitSchemaConfig.java b/src/main/java/org/icgc/argo/workflow_management/config/rabbitmq/RabbitSchemaConfig.java new file mode 100644 index 0000000..b51928d --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/config/rabbitmq/RabbitSchemaConfig.java @@ -0,0 +1,73 @@ +package org.icgc.argo.workflow_management.config.rabbitmq; + +import com.pivotal.rabbitmq.ReactiveRabbit; +import com.pivotal.rabbitmq.schema.SchemaManager; +import java.lang.reflect.Method; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.apache.avro.Schema; +import org.icgc.argo.workflow_management.rabbitmq.schema.WfMgmtRunMsg; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +/** + * Reactive RabbitMQ Streams (ver 0.0.8) doesn't register the schema by contentType when using just + * transactional consumers. It registers them via class path which causes all messages already in + * queue to be considered invalid since contentType not found. But with transactional producers, + * when it produces the message there is a check to see if the contentType exists which adds it if + * not. So when you have both working together you don't notice this, but with just consumers it + * doesn't work. This config ensures the avro schema is available via contentType + */ +@Slf4j +@Profile({"gatekeeper", "api", "execute"}) +@Configuration +public class RabbitSchemaConfig { + private static final String CONTENT_TYPE = "application/vnd.WfMgmtRunMsg+avro"; + + private final ReactiveRabbit reactiveRabbit; + private final ApplicationContext context; + + @Autowired + public RabbitSchemaConfig(ReactiveRabbit reactiveRabbit, ApplicationContext context) { + this.reactiveRabbit = reactiveRabbit; + this.context = context; + ensureSchemas(); + } + + @SneakyThrows + private void ensureSchemas() { + val schemaManager = this.reactiveRabbit.schemaManager(); + + val schema = schemaManager.fetchReadSchemaByContentType(CONTENT_TYPE); + if (schema == null) { + addClassPathSchemaToContentTypeStorage(CONTENT_TYPE, WfMgmtRunMsg.SCHEMA$); + } + } + + @SneakyThrows + private void addClassPathSchemaToContentTypeStorage(String contentType, Schema schema) { + val schemaManager = this.reactiveRabbit.schemaManager(); + + Method registerMethod = + SchemaManager.class.getDeclaredMethod( + "importRegisteredSchema", String.class, Schema.class, Integer.class); + registerMethod.setAccessible(true); + + log.info("Loading WfMgmtRunMsg AVRO Schema from classpath into registry with ContentType."); + registerMethod.invoke(schemaManager, contentType, schema, null); + + val wfMgmtRunMsgSchemaObj = schemaManager.fetchReadSchemaByContentType(contentType); + if (wfMgmtRunMsgSchemaObj.isError()) { + log.error("Cannot load {}} schema by Content Type, shutting down.", schema.getFullName()); + SpringApplication.exit(context, () -> 1); + } else { + log.info( + "Successfully loaded schema {} from classpath.", wfMgmtRunMsgSchemaObj.getFullName()); + log.info("\n\033[32m" + wfMgmtRunMsgSchemaObj.toString(true) + "\033[39m"); + } + } +} diff --git a/src/main/java/org/icgc/argo/workflow_management/gatekeeper/model/ActiveRun.java b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/model/ActiveRun.java new file mode 100644 index 0000000..1c99cc5 --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/model/ActiveRun.java @@ -0,0 +1,48 @@ +package org.icgc.argo.workflow_management.gatekeeper.model; + +import javax.persistence.*; +import lombok.*; +import org.icgc.argo.workflow_management.rabbitmq.schema.RunState; + +// TODO rename ActiveRun to Run after api is removed. +// Distinction is being made for now because there are a WesRun and this new Run type in this repo. +// This entity doesn't need to be migrated and can be easily renamed/updated when the db is clear. +@Entity(name = "activeruns") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode +public class ActiveRun { + + @Id private String runId; + private String workflowUrl; + private String workflowType; + private String workflowTypeVersion; + private String workflowParamsJsonStr; + + @Enumerated(EnumType.STRING) + private RunState state; + + @Convert(converter = EngineParamsConverter.class) + private EngineParams workflowEngineParams; + + private Long timestamp; + + @Version private Long version; + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @EqualsAndHashCode + public static class EngineParams { + private String defaultContainer; + private String revision; + private String resume; + private String launchDir; + private String projectDir; + private String workDir; + private Boolean latest; + } +} diff --git a/src/main/java/org/icgc/argo/workflow_management/gatekeeper/model/EngineParamsConverter.java b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/model/EngineParamsConverter.java new file mode 100644 index 0000000..49cef6f --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/model/EngineParamsConverter.java @@ -0,0 +1,25 @@ +package org.icgc.argo.workflow_management.gatekeeper.model; + +import com.fasterxml.jackson.databind.ObjectMapper; +import javax.persistence.AttributeConverter; +import javax.persistence.Converter; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +@Converter +@Slf4j +public class EngineParamsConverter implements AttributeConverter { + private static final ObjectMapper objectMapper = new ObjectMapper(); + + @SneakyThrows + @Override + public String convertToDatabaseColumn(ActiveRun.EngineParams engineParams) { + return objectMapper.writeValueAsString(engineParams); + } + + @SneakyThrows + @Override + public ActiveRun.EngineParams convertToEntityAttribute(String dbData) { + return objectMapper.readValue(dbData, ActiveRun.EngineParams.class); + } +} diff --git a/src/main/java/org/icgc/argo/workflow_management/gatekeeper/repository/ActiveRunsRepo.java b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/repository/ActiveRunsRepo.java new file mode 100644 index 0000000..2c725e6 --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/repository/ActiveRunsRepo.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. + * You should have received a copy of the GNU Affero General Public License along with + * this program. If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.icgc.argo.workflow_management.gatekeeper.repository; + +import java.util.Optional; +import javax.persistence.LockModeType; +import org.icgc.argo.workflow_management.gatekeeper.model.ActiveRun; +import org.springframework.context.annotation.Profile; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Lock; +import org.springframework.stereotype.Repository; + +@Profile({"gatekeeper-test", "gatekeeper"}) +@Repository +public interface ActiveRunsRepo extends JpaRepository { + + @Lock(LockModeType.OPTIMISTIC_FORCE_INCREMENT) + Optional findActiveRunByRunId(String runId); +} diff --git a/src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/GateKeeperService.java b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/GateKeeperService.java new file mode 100644 index 0000000..73d5253 --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/GateKeeperService.java @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. + * You should have received a copy of the GNU Affero General Public License along with + * this program. If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.icgc.argo.workflow_management.gatekeeper.service; + +import static org.icgc.argo.workflow_management.gatekeeper.service.StateTransition.nextState; +import static org.icgc.argo.workflow_management.rabbitmq.schema.RunState.*; + +import java.util.Optional; +import java.util.Set; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.icgc.argo.workflow_management.gatekeeper.model.ActiveRun; +import org.icgc.argo.workflow_management.gatekeeper.repository.ActiveRunsRepo; +import org.icgc.argo.workflow_management.rabbitmq.schema.RunState; +import org.icgc.argo.workflow_management.rabbitmq.schema.WfMgmtRunMsg; +import org.springframework.context.annotation.Profile; +import org.springframework.data.domain.Example; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Profile({"gatekeeper-test", "gatekeeper"}) +@Slf4j +@Service +@RequiredArgsConstructor +public class GateKeeperService { + // Run moving into terminal states is removed from db because it's at the end of its lifecycle + private static final Set TERMINAL_STATES = + Set.of(SYSTEM_ERROR, EXECUTOR_ERROR, CANCELED, COMPLETE); + + private final ActiveRunsRepo repo; + + /** + * Checks if msg is moving run to a valid next state for an active run. Returns msgs with + * nextState if allowed and null if not. + */ + @Transactional + public Optional checkWfMgmtRunMsgAndUpdate(WfMgmtRunMsg msg) { + val knownRunOpt = repo.findActiveRunByRunId(msg.getRunId()); + + // short circuit, run is new + if (knownRunOpt.isEmpty() && msg.getState().equals(QUEUED)) { + val newRun = repo.save(fromMsg(msg)); + log.debug("Active Run created: {}", newRun); + return Optional.of(msg); + } else if (knownRunOpt.isEmpty()) { + return Optional.empty(); + } + + val knownRun = knownRunOpt.get(); + val inputState = msg.getState(); + + return Optional.ofNullable(fromActiveRun(checkActiveRunAndUpdate(knownRun, inputState))); + } + + /** + * Checks if inputState is moving exsisting run to a valid next state. Returns msgs with nextState + * if allowed and null if not. + */ + @Transactional + public Optional checkWithExistingAndUpdateStateOnly( + String runId, RunState inputState) { + val knownRunOpt = repo.findActiveRunByRunId(runId); + if (knownRunOpt.isEmpty()) { + log.debug("Active Run not found, so not updated: {} {}", runId, inputState); + return Optional.empty(); + } else { + return Optional.ofNullable( + fromActiveRun(checkActiveRunAndUpdate(knownRunOpt.get(), inputState))); + } + } + + @Transactional + private ActiveRun checkActiveRunAndUpdate(ActiveRun knownRun, RunState inputState) { + val currentState = knownRun.getState(); + + // check if this is a valid state transition + val nextStateOpt = nextState(currentState, inputState); + if (nextStateOpt.isEmpty()) { + return null; + } + + val nextState = nextStateOpt.get(); + knownRun.setState(nextState); + + if (TERMINAL_STATES.contains(knownRun.getState())) { + repo.deleteById(knownRun.getRunId()); + log.debug("Active Run removed: {}", knownRun); + return knownRun; + } else { + val updatedRun = repo.save(knownRun); + log.debug("Active Run updated: {}", updatedRun); + return updatedRun; + } + } + + public Page getRuns(Pageable pageable) { + return getRuns(null, pageable); + } + + public Page getRuns(Example example, Pageable pageable) { + return example == null ? repo.findAll(pageable) : repo.findAll(example, pageable); + } + + private ActiveRun fromMsg(WfMgmtRunMsg msg) { + val msgWep = msg.getWorkflowEngineParams(); + val runWep = + ActiveRun.EngineParams.builder() + .latest(msgWep.getLatest()) + .defaultContainer(msgWep.getDefaultContainer()) + .launchDir(msgWep.getLaunchDir()) + .revision(msgWep.getRevision()) + .projectDir(msgWep.getProjectDir()) + .workDir(msgWep.getWorkDir()) + .resume(msgWep.getResume()) + .build(); + + return ActiveRun.builder() + .runId(msg.getRunId()) + .state(msg.getState()) + .workflowUrl(msg.getWorkflowUrl()) + .workflowParamsJsonStr(msg.getWorkflowParamsJsonStr()) + .workflowEngineParams(runWep) + .timestamp(msg.getTimestamp()) + .build(); + } + + private WfMgmtRunMsg fromActiveRun(ActiveRun activeRun) { + if (activeRun == null) return null; + + val msgWep = activeRun.getWorkflowEngineParams(); + val runWep = + org.icgc.argo.workflow_management.rabbitmq.schema.EngineParams.newBuilder() + .setLatest(msgWep.getLatest()) + .setDefaultContainer(msgWep.getDefaultContainer()) + .setLaunchDir(msgWep.getLaunchDir()) + .setRevision(msgWep.getRevision()) + .setProjectDir(msgWep.getProjectDir()) + .setWorkDir(msgWep.getWorkDir()) + .setResume(msgWep.getResume()) + .build(); + + return WfMgmtRunMsg.newBuilder() + .setRunId(activeRun.getRunId()) + .setState(activeRun.getState()) + .setWorkflowUrl(activeRun.getWorkflowUrl()) + .setWorkflowParamsJsonStr(activeRun.getWorkflowParamsJsonStr()) + .setWorkflowEngineParams(runWep) + .setTimestamp(activeRun.getTimestamp()) + .build(); + } +} diff --git a/src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/GatekeeperProcessor.java b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/GatekeeperProcessor.java new file mode 100644 index 0000000..c035fdc --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/GatekeeperProcessor.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. + * You should have received a copy of the GNU Affero General Public License along with + * this program. If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.icgc.argo.workflow_management.gatekeeper.service; + +import com.pivotal.rabbitmq.stream.Transaction; +import java.util.function.BiFunction; +import java.util.function.Function; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.icgc.argo.workflow_management.rabbitmq.schema.WfMgmtRunMsg; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; +import reactor.core.publisher.Flux; + +/** + * Functional interface taking two fluxes (one for gatekeeper input and other for weblog input + * wfmgmtrunmsgs) and returning one merged flux of allowed wfmgmtrunmsgs + */ +@Slf4j +@Profile({"gatekeeper", "gatekeeper-test"}) +@Component +@RequiredArgsConstructor +public class GatekeeperProcessor + implements BiFunction< + Flux>, + Flux>, + Flux>> { + private final GateKeeperService service; + + @Override + public Flux> apply( + Flux> msgFluxFromGatekeeperInput, + Flux> msgFluxFromWeblog) { + return Flux.merge( + msgFluxFromGatekeeperInput.transform(getGateKeeperInputMsgTransformer()), + msgFluxFromWeblog.transform(getWeblogInputMsgsTransformer())); + } + + private Function>, Flux>> + getWeblogInputMsgsTransformer() { + return transactionFlux -> + transactionFlux + .doOnNext(tx -> log.debug("GateKeeperConsumer Received: " + tx.get())) + .handle( + (tx, sink) -> { + val msg = tx.get(); + // WeblogEvents only change run state in gatekeeper service, not other params + val allowedMsg = + service.checkWithExistingAndUpdateStateOnly(msg.getRunId(), msg.getState()); + + if (allowedMsg.isEmpty()) { + tx.reject(); + log.debug("WeblogConsumer - Gatekeeper Rejected: {}, YOU SHALL NOT PASS!", msg); + return; + } + + sink.next(tx.map(allowedMsg.get())); + }); + } + + private Function>, Flux>> + getGateKeeperInputMsgTransformer() { + return fluxOfInterest -> + fluxOfInterest + .doOnNext(tx -> log.debug("GateKeeperConsumer Received: " + tx.get())) + .handle( + (tx, sink) -> { + val msg = tx.get(); + val allowedMsg = service.checkWfMgmtRunMsgAndUpdate(msg); + + if (allowedMsg.isEmpty()) { + tx.reject(); + log.debug( + "GateKeeperConsumer - Gatekeeper Rejected: {}, YOU SHALL NOT PASS!", msg); + return; + } + + sink.next(tx.map(allowedMsg.get())); + }); + } +} diff --git a/src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/StateTransition.java b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/StateTransition.java new file mode 100644 index 0000000..bef4322 --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/StateTransition.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. + * You should have received a copy of the GNU Affero General Public License along with + * this program. If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.icgc.argo.workflow_management.gatekeeper.service; + +import static org.icgc.argo.workflow_management.rabbitmq.schema.RunState.*; +import static org.icgc.argo.workflow_management.rabbitmq.schema.RunState.COMPLETE; + +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import lombok.experimental.UtilityClass; +import org.icgc.argo.workflow_management.rabbitmq.schema.RunState; + +/** + * When updating a Run using a RunMsg state, we need to check whether that run is allowed to go into + * that state. For example a CANCELLING run can become CANCELLED but never INITIALIZING. With all of + * these rules, we can create a graph of allowed state transitions where the nodes are the state of + * Run and the edges are the state in the msg See state transition graph here: + * https://github.com/icgc-argo/workflow-management/blob/develop/docs/WES%20States%20and%20Transitions.png + */ +@UtilityClass +public class StateTransition { + private static final Map> RUN_TO_INPUT_STATE_LOOKUP = + Map.of( + QUEUED, Set.of(INITIALIZING, CANCELING, CANCELED, SYSTEM_ERROR), + INITIALIZING, Set.of(RUNNING, CANCELING, CANCELED, EXECUTOR_ERROR, SYSTEM_ERROR), + CANCELING, Set.of(CANCELED, EXECUTOR_ERROR, SYSTEM_ERROR), + RUNNING, Set.of(SYSTEM_ERROR, EXECUTOR_ERROR, CANCELED, CANCELING, COMPLETE)); + + /** + * This function applies the rules of our state graph. It takes the current Run RunState and an + * input RunState trying to change the run. Then it returns the next state or an empty optional if + * no valid next state. + * + * @param currentState The current Runstate. + * @param inputState The input RunState trying to change the current RunState. + * @return Optional containing valid nextState or empty if there are none. + */ + public static Optional nextState(RunState currentState, RunState inputState) { + if (currentState.equals(RunState.QUEUED) & inputState.equals(RunState.CANCELING)) { + // For QUEUED and inputState of CANCELING, nextState is CANCELED + return Optional.of(RunState.CANCELED); + } else if (RUN_TO_INPUT_STATE_LOOKUP.get(currentState).contains(inputState)) { + // For all other cases where currentState has a valid inputState, the nextState is the + // inputState + return Optional.of(inputState); + } else { + // No valid next state + return Optional.empty(); + } + } +} diff --git a/src/main/java/org/icgc/argo/workflow_management/graphql/BlockedQueryVisibility.java b/src/main/java/org/icgc/argo/workflow_management/graphql/BlockedQueryVisibility.java new file mode 100644 index 0000000..99b8cfc --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/graphql/BlockedQueryVisibility.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. + * You should have received a copy of the GNU Affero General Public License along with + * this program. If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.icgc.argo.workflow_management.graphql; + +import static java.util.stream.Collectors.toUnmodifiableList; + +import graphql.schema.GraphQLFieldDefinition; +import graphql.schema.GraphQLFieldsContainer; +import graphql.schema.visibility.GraphqlFieldVisibility; +import java.util.List; +import lombok.Builder; +import lombok.Singular; + +/** + * GraphqlFieldVisibility implementation that can be used to hide query level fields from the + * GraphQL schema during RuntimeWiring. Simple create a new builder of this class and add fields to + * bock with `blockedQueryField()` + * + *

More info on Field Visibility: https://www.graphql-java.com/documentation/v16/fieldvisibility/ + */ +@Builder +public class BlockedQueryVisibility implements GraphqlFieldVisibility { + @Singular private final List blockedQueryFields; + + @Override + public List getFieldDefinitions(GraphQLFieldsContainer fieldsContainer) { + if (fieldsContainer.getName().equalsIgnoreCase("Query")) { + return fieldsContainer.getFieldDefinitions().stream() + .filter(fd -> !blockedQueryFields.contains(fd.getName())) + .collect(toUnmodifiableList()); + } + return fieldsContainer.getFieldDefinitions(); + } + + @Override + public GraphQLFieldDefinition getFieldDefinition( + GraphQLFieldsContainer fieldsContainer, String fieldName) { + return fieldsContainer.getFieldDefinition(fieldName); + } +} diff --git a/src/main/java/org/icgc/argo/workflow_management/graphql/GatekeeperDataFetchers.java b/src/main/java/org/icgc/argo/workflow_management/graphql/GatekeeperDataFetchers.java new file mode 100644 index 0000000..a32d73c --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/graphql/GatekeeperDataFetchers.java @@ -0,0 +1,70 @@ +package org.icgc.argo.workflow_management.graphql; + +import static java.util.stream.Collectors.toList; +import static org.icgc.argo.workflow_management.util.JacksonUtils.convertValue; + +import graphql.schema.DataFetcher; +import lombok.val; +import org.icgc.argo.workflow_management.gatekeeper.model.ActiveRun; +import org.icgc.argo.workflow_management.gatekeeper.service.GateKeeperService; +import org.icgc.argo.workflow_management.graphql.model.GqlSearchQueryArgs; +import org.icgc.argo.workflow_management.graphql.model.SearchResult; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Profile; +import org.springframework.data.domain.Example; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Component; + +@Component +public class GatekeeperDataFetchers { + + @Bean + @Profile("gatekeeper") + @Qualifier("activeRunsDataFetcher") + public DataFetcher getActiveRunsDataFetcher(GateKeeperService gateKeeperService) { + return environment -> { + val args = convertValue(environment.getArguments(), GqlSearchQueryArgs.class); + + val page = args.getPage(); + val activeRunExample = args.getExample(); + val sorts = args.getSorts(); + + val sortable = + Sort.by( + sorts.stream() + .map( + s -> + new Sort.Order( + s.getOrder().equalsIgnoreCase("asc") + ? Sort.Direction.ASC + : Sort.Direction.DESC, + s.getFieldName())) + .collect(toList())); + + val pageable = + page == null + ? PageRequest.of(0, 10, sortable) + : PageRequest.of(page.getFrom(), page.getSize(), sortable); + + Page result; + if (activeRunExample == null) { + result = gateKeeperService.getRuns(pageable); + } else { + val example = Example.of(activeRunExample); + result = gateKeeperService.getRuns(example, pageable); + } + + return new SearchResult<>(result.getContent(), result.hasNext(), result.getTotalElements()); + }; + } + + @Bean + @Profile("!gatekeeper") + @Qualifier("activeRunsDataFetcher") + public DataFetcher getActiveRunsDisabledDataFetcher() { + return environment -> null; + } +} diff --git a/src/main/java/org/icgc/argo/workflow_management/graphql/GraphQLProvider.java b/src/main/java/org/icgc/argo/workflow_management/graphql/GraphQLProvider.java index 667341a..46997bd 100644 --- a/src/main/java/org/icgc/argo/workflow_management/graphql/GraphQLProvider.java +++ b/src/main/java/org/icgc/argo/workflow_management/graphql/GraphQLProvider.java @@ -25,25 +25,22 @@ import com.google.common.io.Resources; import graphql.GraphQL; import graphql.scalars.ExtendedScalars; +import graphql.schema.DataFetcher; import graphql.schema.GraphQLSchema; import graphql.schema.idl.RuntimeWiring; import java.io.IOException; import java.net.URL; import javax.annotation.PostConstruct; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Service; @Service +@RequiredArgsConstructor public class GraphQLProvider { private final MutationDataFetcher mutationDataFetcher; + private final DataFetcher activeRunsDataFetcher; private GraphQL graphQL; - private GraphQLSchema graphQLSchema; - - @Autowired - public GraphQLProvider(MutationDataFetcher mutationDataFetcher) { - this.mutationDataFetcher = mutationDataFetcher; - } @Bean public GraphQL graphQL() { @@ -54,7 +51,7 @@ public GraphQL graphQL() { public void init() throws IOException { URL url = Resources.getResource("schema.graphql"); String sdl = Resources.toString(url, Charsets.UTF_8); - graphQLSchema = buildSchema(sdl); + GraphQLSchema graphQLSchema = buildSchema(sdl); this.graphQL = GraphQL.newGraphQL(graphQLSchema).build(); } @@ -66,6 +63,12 @@ private RuntimeWiring buildWiring() { return RuntimeWiring.newRuntimeWiring() .scalar(ExtendedScalars.Json) .type(newTypeWiring("Mutation").dataFetchers(mutationDataFetcher.mutationResolvers())) + .type(newTypeWiring("Query").dataFetcher("activeRuns", activeRunsDataFetcher)) + // Field visibility hides from schema, but they are executable + .fieldVisibility( + BlockedQueryVisibility.builder() + .blockedQueryField("activeRuns") // TODO make visible after api is removed + .build()) .build(); } } diff --git a/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlPage.java b/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlPage.java new file mode 100644 index 0000000..213dddb --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlPage.java @@ -0,0 +1,9 @@ +package org.icgc.argo.workflow_management.graphql.model; + +import lombok.Data; + +@Data +public class GqlPage { + Integer from; + Integer size; +} diff --git a/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlSearchQueryArgs.java b/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlSearchQueryArgs.java new file mode 100644 index 0000000..701e306 --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlSearchQueryArgs.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. + * You should have received a copy of the GNU Affero General Public License along with + * this program. If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.icgc.argo.workflow_management.graphql.model; + +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.codehaus.jackson.annotate.JsonIgnoreProperties; +import org.icgc.argo.workflow_management.gatekeeper.model.ActiveRun; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@JsonIgnoreProperties(ignoreUnknown = true) +public class GqlSearchQueryArgs { + ActiveRun example; + GqlPage page; + List sorts; +} diff --git a/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlSort.java b/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlSort.java new file mode 100644 index 0000000..7ae8d66 --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlSort.java @@ -0,0 +1,9 @@ +package org.icgc.argo.workflow_management.graphql.model; + +import lombok.Data; + +@Data +public class GqlSort { + String fieldName; + String order; +} diff --git a/src/main/java/org/icgc/argo/workflow_management/graphql/model/SearchResult.java b/src/main/java/org/icgc/argo/workflow_management/graphql/model/SearchResult.java new file mode 100644 index 0000000..a9c59c4 --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/graphql/model/SearchResult.java @@ -0,0 +1,22 @@ +package org.icgc.argo.workflow_management.graphql.model; + +import java.util.List; +import lombok.Value; + +@Value +public class SearchResult { + List content; + Info info; + + public SearchResult(List content, Boolean hasNextFrom, Long totalHits) { + this.content = content; + this.info = new Info(hasNextFrom, totalHits, content.size()); + } + + @Value + public static class Info { + Boolean hasNextFrom; + Long totalHits; + Integer contentCount; + } +} diff --git a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/ApiProducerConfig.java b/src/main/java/org/icgc/argo/workflow_management/rabbitmq/ApiProducerConfig.java index 159849f..8f13d6a 100644 --- a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/ApiProducerConfig.java +++ b/src/main/java/org/icgc/argo/workflow_management/rabbitmq/ApiProducerConfig.java @@ -18,17 +18,19 @@ package org.icgc.argo.workflow_management.rabbitmq; +import static org.icgc.argo.workflow_management.rabbitmq.DisposableManager.API_PRODCUER; +import static org.icgc.argo.workflow_management.util.RabbitmqUtils.createTransProducerStream; + import com.pivotal.rabbitmq.RabbitEndpointService; import com.pivotal.rabbitmq.source.OnDemandSource; import com.pivotal.rabbitmq.source.Sender; -import com.pivotal.rabbitmq.source.Source; -import com.pivotal.rabbitmq.topology.ExchangeType; -import java.util.function.Function; +import javax.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import lombok.val; +import org.icgc.argo.workflow_management.config.rabbitmq.RabbitSchemaConfig; import org.icgc.argo.workflow_management.rabbitmq.schema.WfMgmtRunMsg; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; @@ -36,7 +38,9 @@ @Slf4j @Profile("api") +@AutoConfigureAfter(RabbitSchemaConfig.class) @Configuration +@RequiredArgsConstructor public class ApiProducerConfig { @Value("${api.producer.topology.queueName}") private String queueName; @@ -48,37 +52,17 @@ public class ApiProducerConfig { private String[] topicRoutingKeys; private final RabbitEndpointService rabbit; + private final DisposableManager disposableManager; + private final OnDemandSource sink = new OnDemandSource<>("apiSource"); - @Autowired - public ApiProducerConfig(RabbitEndpointService rabbit) { - this.rabbit = rabbit; + @PostConstruct + public void init() { + disposableManager.registerDisposable(API_PRODCUER, this::createWfMgmtRunMsgProducer); } - @Bean - public Disposable produceWfMgmtRunMsg(Source apiSourceMsgs) { - val dlxName = topicExchangeName + "-dlx"; - val dlqName = queueName + "-dlq"; - return rabbit - .declareTopology( - topologyBuilder -> - topologyBuilder - .declareExchange(dlxName) - .and() - .declareQueue(dlqName) - .boundTo(dlxName) - .and() - .declareExchange(topicExchangeName) - .type(ExchangeType.topic) - .and() - .declareQueue(queueName) - .boundTo(topicExchangeName, topicRoutingKeys) - .withDeadLetterExchange(dlxName)) - .createTransactionalProducerStream(WfMgmtRunMsg.class) - .route() - .toExchange(topicExchangeName) - .withRoutingKey(routingKeySelector()) - .then() - .send(apiSourceMsgs.source()) + private Disposable createWfMgmtRunMsgProducer() { + return createTransProducerStream(rabbit, topicExchangeName, queueName, topicRoutingKeys) + .send(sink.source()) .subscribe( tx -> { log.debug("ApiProducer sent WfMgmtRunMsg: {}", tx.get()); @@ -87,16 +71,7 @@ public Disposable produceWfMgmtRunMsg(Source apiSourceMsgs) { } @Bean - OnDemandSource source() { - return new OnDemandSource<>("source"); - } - - @Bean - Sender sender(OnDemandSource source) { - return source; - } - - Function routingKeySelector() { - return msg -> msg.getState().toString(); + Sender sender() { + return sink; } } diff --git a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/DisposableManager.java b/src/main/java/org/icgc/argo/workflow_management/rabbitmq/DisposableManager.java new file mode 100644 index 0000000..0759198 --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/rabbitmq/DisposableManager.java @@ -0,0 +1,50 @@ +/// * +// * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved +// * +// * This program and the accompanying materials are made available under the terms of the GNU +// Affero General Public License v3.0. +// * You should have received a copy of the GNU Affero General Public License along with +// * this program. If not, see . +// * +// * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +// * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +// * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +// * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +// * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// */ + +package org.icgc.argo.workflow_management.rabbitmq; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Callable; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.icgc.argo.workflow_management.config.rabbitmq.RabbitSchemaConfig; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import reactor.core.Disposable; + +@Slf4j +@Profile({"gatekeeper", "api", "execute"}) +@AutoConfigureAfter(RabbitSchemaConfig.class) +@Configuration +public class DisposableManager { + public static final String API_PRODCUER = "apiProducer"; + public static final String EXECUTE_CONSUMER = "executeConsumer"; + public static final String GATEKEEPER_PRODUCER = "gatekeeperProducer"; + + private final Map disposablesRegistry = + Collections.synchronizedMap(new HashMap<>()); + + @SneakyThrows + public void registerDisposable(String name, Callable disposableCallable) { + this.disposablesRegistry.put(name, disposableCallable.call()); + } +} diff --git a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/ExecuteConsumerConfig.java b/src/main/java/org/icgc/argo/workflow_management/rabbitmq/ExecuteConsumerConfig.java index 44d9f81..09dd6c1 100644 --- a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/ExecuteConsumerConfig.java +++ b/src/main/java/org/icgc/argo/workflow_management/rabbitmq/ExecuteConsumerConfig.java @@ -18,30 +18,37 @@ package org.icgc.argo.workflow_management.rabbitmq; +import static org.icgc.argo.workflow_management.rabbitmq.DisposableManager.EXECUTE_CONSUMER; import static org.icgc.argo.workflow_management.rabbitmq.WfMgmtRunMsgConverters.createRunParams; import static org.icgc.argo.workflow_management.rabbitmq.WfMgmtRunMsgConverters.createWfMgmtEvent; +import static org.icgc.argo.workflow_management.util.RabbitmqUtils.createTransConsumerStream; import com.pivotal.rabbitmq.RabbitEndpointService; import com.pivotal.rabbitmq.stream.Transaction; -import com.pivotal.rabbitmq.topology.ExchangeType; +import java.time.Duration; import java.util.function.BiConsumer; import java.util.function.Consumer; +import javax.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import lombok.val; +import org.icgc.argo.workflow_management.config.rabbitmq.RabbitSchemaConfig; import org.icgc.argo.workflow_management.rabbitmq.schema.RunState; import org.icgc.argo.workflow_management.rabbitmq.schema.WfMgmtRunMsg; import org.icgc.argo.workflow_management.service.wes.WebLogEventSender; import org.icgc.argo.workflow_management.service.wes.WorkflowExecutionService; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import reactor.core.Disposable; +import reactor.util.retry.RetrySpec; @Profile("execute") @Slf4j +@AutoConfigureAfter(RabbitSchemaConfig.class) @Configuration +@RequiredArgsConstructor public class ExecuteConsumerConfig { @Value("${execute.consumer.topology.queueName}") private String queueName; @@ -52,65 +59,48 @@ public class ExecuteConsumerConfig { @Value("${execute.consumer.topology.topicRoutingKeys}") private String[] topicRoutingKeys; + @Value("${execute.initializingByMiddleware}") + private Boolean initializingByMiddleware; + private final WebLogEventSender webLogEventSender; private final WorkflowExecutionService wes; private final RabbitEndpointService rabbit; + private final DisposableManager disposableManager; - @Autowired - public ExecuteConsumerConfig( - WorkflowExecutionService wes, - RabbitEndpointService rabbit, - WebLogEventSender webLogEventSender) { - this.wes = wes; - this.rabbit = rabbit; - this.webLogEventSender = webLogEventSender; + @PostConstruct + public void init() { + disposableManager.registerDisposable( + EXECUTE_CONSUMER, this::createWfMgmtRunMsgForExecuteConsumer); } - @Bean - public Disposable wfMgmtRunMsgForExecuteConsumer() { - val dlxName = topicExchangeName + "-dlx"; - val dlqName = queueName + "-dlq"; - return rabbit - .declareTopology( - topologyBuilder -> - topologyBuilder - .declareExchange(dlxName) - .and() - .declareQueue(dlqName) - .boundTo(dlxName) - .and() - .declareExchange(topicExchangeName) - .type(ExchangeType.topic) - .and() - .declareQueue(queueName) - .boundTo(topicExchangeName, topicRoutingKeys) - .withDeadLetterExchange(dlxName)) - .createTransactionalConsumerStream(queueName, WfMgmtRunMsg.class) + private Disposable createWfMgmtRunMsgForExecuteConsumer() { + return createTransConsumerStream(rabbit, topicExchangeName, queueName, topicRoutingKeys) .receive() .doOnNext(consumeAndExecuteInitializeOrCancel()) .onErrorContinue(handleError()) .subscribe(); } - public Consumer> consumeAndExecuteInitializeOrCancel() { + private Consumer> consumeAndExecuteInitializeOrCancel() { return tx -> { val msg = tx.get(); log.debug("WfMgmtRunMsg received: {}", msg); - if (msg.getState().equals(RunState.CANCELING)) { - wes.cancel(msg.getRunId()) + if ((initializingByMiddleware.equals(false) && msg.getState().equals(RunState.QUEUED)) + || (initializingByMiddleware.equals(true) && msg.getState().equals(RunState.INITIALIZING))) { + val runParams = createRunParams(msg); + wes.run(runParams) .subscribe( runsResponse -> { - log.info("Cancelled: {}", runsResponse); + log.info("Initialized: {}", msg); tx.commit(); }); - } else if (msg.getState().equals(RunState.INITIALIZING)) { - val runParams = createRunParams(msg); - - wes.run(runParams) + } else if (msg.getState().equals(RunState.CANCELING)) { + wes.cancel(msg.getRunId()) + .retryWhen(RetrySpec.backoff(3, Duration.ofMinutes(3))) .subscribe( runsResponse -> { - log.info("Initialized: {}", msg); + log.info("Cancelled: {}", runsResponse); tx.commit(); }); } else { @@ -120,7 +110,7 @@ public Consumer> consumeAndExecuteInitializeOrCancel() }; } - public BiConsumer handleError() { + private BiConsumer handleError() { return (t, tx) -> { t.printStackTrace(); log.error("Error occurred with: {}", tx); diff --git a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/GateKeeperStreamsConfig.java b/src/main/java/org/icgc/argo/workflow_management/rabbitmq/GateKeeperStreamsConfig.java new file mode 100644 index 0000000..9352a47 --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/rabbitmq/GateKeeperStreamsConfig.java @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. + * You should have received a copy of the GNU Affero General Public License along with + * this program. If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.icgc.argo.workflow_management.rabbitmq; + +import static org.icgc.argo.workflow_management.rabbitmq.DisposableManager.GATEKEEPER_PRODUCER; +import static org.icgc.argo.workflow_management.rabbitmq.WfMgmtRunMsgConverters.createWfMgmtEvent; +import static org.icgc.argo.workflow_management.util.RabbitmqUtils.createTransConsumerStream; +import static org.icgc.argo.workflow_management.util.RabbitmqUtils.createTransProducerStream; + +import com.fasterxml.jackson.databind.JsonNode; +import com.pivotal.rabbitmq.RabbitEndpointService; +import com.pivotal.rabbitmq.source.OnDemandSource; +import com.pivotal.rabbitmq.stream.Transaction; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import javax.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.icgc.argo.workflow_management.config.rabbitmq.RabbitSchemaConfig; +import org.icgc.argo.workflow_management.gatekeeper.service.GatekeeperProcessor; +import org.icgc.argo.workflow_management.rabbitmq.schema.RunState; +import org.icgc.argo.workflow_management.rabbitmq.schema.WfMgmtRunMsg; +import org.icgc.argo.workflow_management.service.wes.WebLogEventSender; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import reactor.core.Disposable; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@Slf4j +@Profile("gatekeeper") +@AutoConfigureAfter(RabbitSchemaConfig.class) +@Configuration +@RequiredArgsConstructor +public class GateKeeperStreamsConfig { + private static final String ROUTING_KEY = "#"; + + private static final Set WEBLOG_EVENTS_OUTSIDE_MGMT = + Set.of(RunState.COMPLETE, RunState.EXECUTOR_ERROR, RunState.RUNNING, RunState.SYSTEM_ERROR); + + private static final Set RUN_STATES_TO_WEBLOG = + Set.of(RunState.QUEUED, RunState.CANCELED); + + @Value("${gatekeeper.producer.topology.queueName}") + private String producerDefaultQueueName; + + @Value("${gatekeeper.producer.topology.topicExchangeName}") + private String producerTopicExchangeName; + + @Value("${gatekeeper.consumer.topology.topicExchangeName}") + private String consumerTopicExchangeName; + + @Value("${gatekeeper.consumer.topology.queueName}") + private String consumerQueueName; + + private final RabbitEndpointService rabbit; + private final GatekeeperProcessor processor; + private final WebLogEventSender webLogEventSender; + private final DisposableManager disposableManager; + + private final OnDemandSource weblogSourceSink = + new OnDemandSource<>("weblogSourceSink"); + + @PostConstruct + public void init() { + disposableManager.registerDisposable(GATEKEEPER_PRODUCER, this::createGatekeeperProducer); + } + + /** + * Disposable that takes input messages, passes them through gatekeeper processor and produces the + * msgs that gatekeeper processor allowed to pass. + */ + private Disposable createGatekeeperProducer() { + val gatekeeperInputMsgsFlux = createGatekeeperInputFlux(); + + val weblogInputMsgsFlux = weblogSourceSink.source(); + + val processedFlux = + processor + .apply(gatekeeperInputMsgsFlux, weblogInputMsgsFlux) + .flatMap( + tx -> { + if (RUN_STATES_TO_WEBLOG.contains(tx.get().getState())) { + return webLogEventSender + .sendWfMgmtEvent(createWfMgmtEvent(tx.get())) + .thenReturn(tx); + } + return Mono.just(tx); + }) + .onErrorContinue(handleError()); + + return createTransProducerStream( + rabbit, producerTopicExchangeName, producerDefaultQueueName, ROUTING_KEY) + .send(processedFlux) + .onErrorContinue(handleError()) + .subscribe( + tx -> { + log.debug("GateKeeperProducer Sent: {}", tx.get()); + tx.commit(); + }); + } + + /** + * Functional bean consuming kafka weblog events from outside mgmt domain and sending messages for + * to weblogSourceSink + */ + @Bean + public Consumer weblogConsumer() { + return event -> { + val weblogEvent = new WeblogEvent(event); + if (WEBLOG_EVENTS_OUTSIDE_MGMT.contains(weblogEvent.getRunState())) { + log.debug("WeblogConsumer received: {}", event); + weblogSourceSink.send(weblogEvent.asRunMsg()); + } + }; + } + + /** Flux of input messages into gatekeeper */ + private Flux> createGatekeeperInputFlux() { + return createTransConsumerStream( + rabbit, consumerTopicExchangeName, consumerQueueName, ROUTING_KEY) + .receive(); + } + + private BiConsumer handleError() { + return (t, tx) -> { + t.printStackTrace(); + log.error("Error occurred with: {}", tx); + if (tx instanceof Transaction && ((Transaction) tx).get() instanceof WfMgmtRunMsg) { + val msg = (WfMgmtRunMsg) ((Transaction) tx).get(); + msg.setState(RunState.SYSTEM_ERROR); + log.info("SYSTEM_ERROR: {}", msg); + webLogEventSender.sendWfMgmtEventAsync(createWfMgmtEvent(msg)); + ((Transaction) tx).reject(); + } else { + log.error("Can't get WfMgmtRunMsg, transaction is lost!"); + } + }; + } +} diff --git a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/WeblogEvent.java b/src/main/java/org/icgc/argo/workflow_management/rabbitmq/WeblogEvent.java new file mode 100644 index 0000000..bd3e4f6 --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/rabbitmq/WeblogEvent.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. + * You should have received a copy of the GNU Affero General Public License along with + * this program. If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.icgc.argo.workflow_management.rabbitmq; + +import static javax.xml.bind.DatatypeConverter.parseDateTime; + +import com.fasterxml.jackson.databind.JsonNode; +import lombok.Getter; +import lombok.NonNull; +import lombok.val; +import org.icgc.argo.workflow_management.rabbitmq.schema.EngineParams; +import org.icgc.argo.workflow_management.rabbitmq.schema.RunState; +import org.icgc.argo.workflow_management.rabbitmq.schema.WfMgmtRunMsg; + +@Getter +public class WeblogEvent { + private final String runId; + private final RunState runState; + private final String utcTime; + + public WeblogEvent(JsonNode event) { + String runId = ""; + RunState runState = RunState.UNKNOWN; + if (!event.path("metadata").path("workflow").isMissingNode()) { + // NEXTFLOW event + runId = event.get("runName").asText(); + + val eventString = event.get("event").asText(); + val success = event.get("metadata").get("workflow").get("success").asBoolean(); + runState = fromNextflowEventAndSuccess(eventString, success); + } else if (event.has("workflowUrl") + && event.has("runId") + && event.has("event") + && event.has("utcTime")) { + // WFMGMT event + runId = event.get("runId").asText(); + + val eventString = event.get("event").asText(); + runState = RunState.valueOf(eventString); + } + + this.runId = runId; + this.runState = runState; + this.utcTime = event.get("utcTime").asText(); + } + + private RunState fromNextflowEventAndSuccess( + @NonNull String nextflowEvent, @NonNull boolean success) { + if (nextflowEvent.equalsIgnoreCase("started")) { + return RunState.RUNNING; + } else if (nextflowEvent.equalsIgnoreCase("completed") && success) { + return RunState.COMPLETE; + } else if ((nextflowEvent.equalsIgnoreCase("completed") && !success) + || nextflowEvent.equalsIgnoreCase("failed") + || nextflowEvent.equalsIgnoreCase("error")) { + return RunState.EXECUTOR_ERROR; + } else { + return RunState.UNKNOWN; + } + } + + public WfMgmtRunMsg asRunMsg() { + val timeStamp = parseDateTime(utcTime).getTime().toInstant().toEpochMilli(); + return WfMgmtRunMsg.newBuilder() + .setRunId(runId) + .setState(runState) + .setWorkflowEngineParams(EngineParams.newBuilder().build()) + .setTimestamp(timeStamp) + .build(); + } +} diff --git a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/WfMgmtRunMsgConverters.java b/src/main/java/org/icgc/argo/workflow_management/rabbitmq/WfMgmtRunMsgConverters.java index f80dc28..e9bc75d 100644 --- a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/WfMgmtRunMsgConverters.java +++ b/src/main/java/org/icgc/argo/workflow_management/rabbitmq/WfMgmtRunMsgConverters.java @@ -71,6 +71,7 @@ public static WfMgmtRunMsg createWfMgmtRunMsg(String runId, RunState state) { .setRunId(runId) .setTimestamp(Instant.now().toEpochMilli()) .setState(state) + .setWorkflowEngineParams(EngineParams.newBuilder().build()) .build(); } @@ -103,7 +104,10 @@ public static RunParams createRunParams(WfMgmtRunMsg msg) { public static WfManagementEvent createWfMgmtEvent(WfMgmtRunMsg msg) { val msgWep = msg.getWorkflowEngineParams(); - val params = readValue(msg.getWorkflowParamsJsonStr(), Map.class); + val params = + msg.getWorkflowParamsJsonStr() != null + ? readValue(msg.getWorkflowParamsJsonStr(), Map.class) + : Map.of(); val wepBuilder = WorkflowEngineParams.builder() diff --git a/src/main/java/org/icgc/argo/workflow_management/service/api_to_wes/impl/ApiProducerToWes.java b/src/main/java/org/icgc/argo/workflow_management/service/api_to_wes/impl/ApiProducerToWes.java index 8118ce1..065a0b5 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/api_to_wes/impl/ApiProducerToWes.java +++ b/src/main/java/org/icgc/argo/workflow_management/service/api_to_wes/impl/ApiProducerToWes.java @@ -47,7 +47,7 @@ public ApiProducerToWes(Sender sender) { @Override public Mono run(RunsRequest runsRequest) { val runId = generateWesRunId(); - val msg = createWfMgmtRunMsg(runId, runsRequest, RunState.INITIALIZING); + val msg = createWfMgmtRunMsg(runId, runsRequest, RunState.QUEUED); return Mono.just(msg).flatMap(sender::send).map(o -> new RunsResponse(runId)); } diff --git a/src/main/java/org/icgc/argo/workflow_management/util/RabbitmqUtils.java b/src/main/java/org/icgc/argo/workflow_management/util/RabbitmqUtils.java new file mode 100644 index 0000000..5cc28f7 --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/util/RabbitmqUtils.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. + * You should have received a copy of the GNU Affero General Public License along with + * this program. If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.icgc.argo.workflow_management.util; + +import com.pivotal.rabbitmq.RabbitEndpointService; +import com.pivotal.rabbitmq.stream.TransactionalConsumerStream; +import com.pivotal.rabbitmq.stream.TransactionalProducerStream; +import com.pivotal.rabbitmq.topology.ExchangeType; +import java.util.function.Function; +import lombok.experimental.UtilityClass; +import lombok.val; +import org.icgc.argo.workflow_management.rabbitmq.schema.WfMgmtRunMsg; + +@UtilityClass +public class RabbitmqUtils { + + public static TransactionalProducerStream createTransProducerStream( + RabbitEndpointService rabbit, String topicName, String queueName, String... routingKey) { + val dlxName = topicName + "-dlx"; + val dlqName = queueName + "-dlq"; + return rabbit + .declareTopology( + topologyBuilder -> + topologyBuilder + .declareExchange(dlxName) + .and() + .declareQueue(dlqName) + .boundTo(dlxName) + .and() + .declareExchange(topicName) + .type(ExchangeType.topic) + .and() + .declareQueue(queueName) + .boundTo(topicName, routingKey) + .withDeadLetterExchange(dlxName)) + .createTransactionalProducerStream(WfMgmtRunMsg.class) + .route() + .toExchange(topicName) + .withRoutingKey(routingKeySelector()) + .then(); + } + + public static TransactionalConsumerStream createTransConsumerStream( + RabbitEndpointService rabbit, String topicName, String queueName, String... routingKey) { + val dlxName = topicName + "-dlx"; + val dlqName = queueName + "-dlq"; + return rabbit + .declareTopology( + topologyBuilder -> + topologyBuilder + .declareExchange(dlxName) + .and() + .declareQueue(dlqName) + .boundTo(dlxName) + .and() + .declareExchange(topicName) + .type(ExchangeType.topic) + .and() + .declareQueue(queueName) + .boundTo(topicName, routingKey) + .withDeadLetterExchange(dlxName)) + .createTransactionalConsumerStream(queueName, WfMgmtRunMsg.class); + } + + Function routingKeySelector() { + return msg -> msg.getState().toString(); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index f4ac122..ddb2ca2 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -44,7 +44,7 @@ secret: tokenUri: http://localhost:8080/oauth/token --- -spring.profiles: api,execute +spring.profiles: api,execute,gatekeeper rabbit: default-endpoint-name: standalone @@ -59,13 +59,61 @@ rabbit: spring.profiles: api api.producer.topology: - queueName: "execute-queue" - topicExchangeName: "execute" - topicRoutingKeys: "INITIALIZING, CANCELLING" # comma separated Array of keys + queueName: "gatekeeper-in-queue" + topicExchangeName: "gatekeeper-in" + topicRoutingKeys: "#" # comma separated Array of keys + --- spring.profiles: execute execute.consumer.topology: queueName: "execute-queue" - topicExchangeName: "execute" - topicRoutingKeys: "INITIALIZING, CANCELLING" # comma separated Array of keys + topicExchangeName: "gatekeeper-out" + topicRoutingKeys: "INITIALIZING, CANCELING" # comma separated Array of keys + +execute.initializingByMiddleware: true + +--- +spring.profiles: gatekeeper + +gatekeeper.consumer.topology: + queueName: "gatekeeper-in-queue" + topicExchangeName: "gatekeeper-in" + +gatekeeper.producer.topology: + queueName: "gatekeeper-out-default-queue" + topicExchangeName: "gatekeeper-out" + +spring.cloud.stream: + function.definition: weblogConsumer + bindings: + weblogConsumer-in-0: + group: mgmt-weblogConsumer + destination: weblog # kafka topic to listen to + binder: kafka + kafka: + binder.brokers: localhost:9092 + bindings: + weblogConsumer-in-0: + consumer: + enableDlq: true + dlqName: weblog-in-0_dlq + autoCommitOnError: true + autoCommitOffset: true +# resetOffsets: true +# startOffset: earliest + +spring.datasource: + url: jdbc:postgresql://localhost:5432/gatekeeperdb + username: postgres + password: mysecretpassword +spring.jpa: + hibernate: + ddl-auto: update + +--- +spring.profiles: gatekeeper-test + +spring.jpa: + hibernate: + ddl-auto: create-drop diff --git a/src/main/resources/schema.graphql b/src/main/resources/schema.graphql index 539b7ad..1378bf4 100644 --- a/src/main/resources/schema.graphql +++ b/src/main/resources/schema.graphql @@ -23,8 +23,74 @@ input RunsRequest { tags: JSON } - type Mutation { startRun(request: RunsRequest!): RunsResponse cancelRun(runId: ID!): RunsResponse } + +type SearchResultInfo { + contentCount: String! + hasNextFrom: String! + totalHits: String! +} + +type EngineParameters { + launchDir: String + projectDir: String + resume: String + revision: String + workDir: String + defaultContainer: String + latest: String +} + +type ActiveRun { + runId: String! + state: String! + workflowUrl: String! + workflowType: String + workflowTypeVersion: String + workflowParamsJsonStr: String + workflowEngineParams: EngineParameters! + timestamp: String! +} + +input Example { + runId: String + state: String + workflowUrl: String + workflowType: String + workflowTypeVersion: String + workflowParamsJsonStr: String + timestamp: String +} + +type ActiveRunsSearchResult { + content: [ActiveRun!] + info: SearchResultInfo! +} + +enum SortOrder { + asc, + desc +} + +enum SortField { + runId, + state, + timestamp +} + +input Page { + size: Int! + from: Int! +} + +input Sort { + fieldName: SortField! + order: SortOrder! +} + +type Query { + activeRuns(example: Example, page: Page, sorts: [Sort]): ActiveRunsSearchResult +} diff --git a/src/test/java/org/icgc/argo/workflow_management/GateKeeperProcessorTests.java b/src/test/java/org/icgc/argo/workflow_management/GateKeeperProcessorTests.java new file mode 100644 index 0000000..0b87321 --- /dev/null +++ b/src/test/java/org/icgc/argo/workflow_management/GateKeeperProcessorTests.java @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. + * You should have received a copy of the GNU Affero General Public License along with + * this program. If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.icgc.argo.workflow_management; + +import static org.icgc.argo.workflow_management.rabbitmq.WfMgmtRunMsgConverters.createWfMgmtRunMsg; +import static org.icgc.argo.workflow_management.util.TransactionUtils.*; +import static org.icgc.argo.workflow_management.util.WesUtils.generateWesRunId; +import static org.junit.Assert.*; + +import com.pivotal.rabbitmq.stream.Transaction; +import java.time.Duration; +import lombok.Builder; +import lombok.Value; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.icgc.argo.workflow_management.gatekeeper.service.GatekeeperProcessor; +import org.icgc.argo.workflow_management.rabbitmq.schema.RunState; +import org.icgc.argo.workflow_management.rabbitmq.schema.WfMgmtRunMsg; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.util.TestPropertyValues; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.testcontainers.containers.PostgreSQLContainer; +import reactor.core.publisher.Flux; +import reactor.test.StepVerifier; +import reactor.test.publisher.TestPublisher; + +/** + * Collection of tests testing RunMsgs and their states as they pass through the + * GateKeeperProcessor. Each test sends msgs sequentially (via two testpublisher for the two input + * flux) into the GateKeeperProcessor and the output is asserted as expected. + */ +@Slf4j +@ActiveProfiles("gatekeeper-test") +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest +@ContextConfiguration(initializers = {GateKeeperProcessorTests.Initializer.class}) +public class GateKeeperProcessorTests { + + @ClassRule + public static PostgreSQLContainer postgreSQLContainer = + new PostgreSQLContainer("postgres:10-alpine") + .withDatabaseName("gatekeeperdb") + .withUsername("test") + .withPassword("test"); + + @Autowired GatekeeperProcessor processor; + + /** + * Testing given two in flux, assert expected out flux: gatekeeperInFlux + * :---QUEUED---INITIALIZING--------> | | weblogInFlux + * :-----|-------------|-------RUNNING---COMPLETED-----> | | | | gatekeeperOutFlux + * :---QUEUED---INITIALIZING---RUNNING---COMPLETED-----> + */ + @Test + public void testStreamsHappyPath() { + val runId = generateWesRunId(); + buildAndAssertValidSequentialMsgsAreProcessed( + runId, + RunStateWrapper.builder().runState(RunState.QUEUED).from(MsgFrom.RABBIT_QUEUE).build(), + RunStateWrapper.builder() + .runState(RunState.INITIALIZING) + .from(MsgFrom.RABBIT_QUEUE) + .build(), + RunStateWrapper.builder().runState(RunState.RUNNING).from(MsgFrom.WEBLOG).build(), + RunStateWrapper.builder().runState(RunState.COMPLETE).from(MsgFrom.WEBLOG).build()); + } + + /** + * Testing given two in flux, assert expected out flux: gatekeeperInFlux + * :---QUEUED---INITIALIZING--------> | | weblogInFlux + * :-----|-------------|-------RUNNING---EXECUTOR_ERROR-----> | | | | gatekeeperOutFlux + * :---QUEUED---INITIALIZING---RUNNING---EXECUTOR_ERROR-----> + */ + @Test + public void testStreamsSadPathWithExecutorError() { + val runId = generateWesRunId(); + buildAndAssertValidSequentialMsgsAreProcessed( + runId, + RunStateWrapper.builder().runState(RunState.QUEUED).from(MsgFrom.RABBIT_QUEUE).build(), + RunStateWrapper.builder() + .runState(RunState.INITIALIZING) + .from(MsgFrom.RABBIT_QUEUE) + .build(), + RunStateWrapper.builder().runState(RunState.RUNNING).from(MsgFrom.WEBLOG).build(), + RunStateWrapper.builder().runState(RunState.EXECUTOR_ERROR).from(MsgFrom.WEBLOG).build()); + } + + /** + * Testing given two in flux, assert expected out flux: gatekeeperInFlux + * :---QUEUED---INITIALIZING--------> | | weblogInFlux + * :-----|----------|----------RUNNING---SYSTEM_ERROR-----> | | | | gatekeeperOutFlux + * :---QUEUED---INITIALIZING---RUNNING---SYSTEM_ERROR-----> + */ + @Test + public void testStreamsSadPathWithSystemError() { + val runId = generateWesRunId(); + buildAndAssertValidSequentialMsgsAreProcessed( + runId, + RunStateWrapper.builder().runState(RunState.QUEUED).from(MsgFrom.RABBIT_QUEUE).build(), + RunStateWrapper.builder() + .runState(RunState.INITIALIZING) + .from(MsgFrom.RABBIT_QUEUE) + .build(), + RunStateWrapper.builder().runState(RunState.RUNNING).from(MsgFrom.WEBLOG).build(), + RunStateWrapper.builder().runState(RunState.SYSTEM_ERROR).from(MsgFrom.WEBLOG).build()); + } + + /** + * Testing given two in flux, assert expected out flux: gatekeeperInFlux + * :---QUEUED---INITIALIZING-------------INITIALIZING-----> | | | weblogInFlux + * :-----|-----------|---------RUNNING--------|---------COMPLETED-----> | | | === | + * gatekeeperOutFlux :---QUEUED---INITIALIZING---RUNNING-----------------COMPLETED-----> + */ + @Test + public void testInvalidMsgsAreRejected() { + val runId = generateWesRunId(); + val gatekeeperInput = TestPublisher.>create(); + val weblogInput = TestPublisher.>create(); + + val gatekeeperOutFlux = + processor + .apply(gatekeeperInput.flux(), weblogInput.flux()) + .timeout(Duration.ofSeconds(300)); + + val invalidMsg = createWfMgmtRunMsgTransaction(runId, RunState.INITIALIZING); + + // before running test msg is not rejected, its just in queue + assertFalse(isRejected(invalidMsg)); + + StepVerifier.create(gatekeeperOutFlux) + .then(() -> gatekeeperInput.next(createWfMgmtRunMsgTransaction(runId, RunState.QUEUED))) + .expectNextMatches(tx -> tx.get().getState().equals(RunState.QUEUED)) + .then( + () -> gatekeeperInput.next(createWfMgmtRunMsgTransaction(runId, RunState.INITIALIZING))) + .expectNextMatches(tx -> tx.get().getState().equals(RunState.INITIALIZING)) + .then(() -> weblogInput.next(createWfMgmtRunMsgTransaction(runId, RunState.RUNNING))) + .expectNextMatches(tx -> tx.get().getState().equals(RunState.RUNNING)) + .then(() -> weblogInput.next(invalidMsg)) // won't be found on nextMatch since rejected + .then(() -> weblogInput.next(createWfMgmtRunMsgTransaction(runId, RunState.COMPLETE))) + .expectNextMatches(tx -> tx.get().getState().equals(RunState.COMPLETE)) + .then( + () -> { + gatekeeperInput.complete(); + weblogInput.complete(); + }) + .expectComplete() + .verifyThenAssertThat() + .hasNotDroppedElements() + .hasNotDroppedErrors() + .hasNotDiscardedElements(); + + // after running invalid msg has been rejected + assertTrue(isRejected(invalidMsg)); + } + + /** + * Testing given two in flux, assert expected out flux: gatekeeperInFlux + * :---QUEUED---CANCELING---> | | weblogInFlux :-----|-----------|------> | | gatekeeperOutFlux + * :---QUEUED---CANCELED----> + */ + @Test + public void testCancellingQueued() { + val runId = generateWesRunId(); + val gatekeeperInput = TestPublisher.>create(); + val weblogInputFlux = Flux.>just(); + + val gatekeeperOutFlux = + processor.apply(gatekeeperInput.flux(), weblogInputFlux).timeout(Duration.ofSeconds(300)); + + StepVerifier.create(gatekeeperOutFlux) + .then(() -> gatekeeperInput.next(createWfMgmtRunMsgTransaction(runId, RunState.QUEUED))) + .expectNextMatches(tx -> tx.get().getState().equals(RunState.QUEUED)) + .then(() -> gatekeeperInput.next(createWfMgmtRunMsgTransaction(runId, RunState.CANCELING))) + .expectNextMatches(tx -> tx.get().getState().equals(RunState.CANCELED)) + .then(gatekeeperInput::complete) + .expectComplete() + .verifyThenAssertThat() + .hasNotDroppedElements() + .hasNotDroppedErrors() + .hasNotDiscardedElements(); + } + + // Util function to build common tests which assert that a sequence of valid msgs are processed + // and allowed + private void buildAndAssertValidSequentialMsgsAreProcessed( + String runId, RunStateWrapper... sequenceOfStatesToGenerateAndCheck) { + // ** prepare fluxes for GateKeeperProcessor + val gatekeeperInput = TestPublisher.>create(); + val weblogInput = TestPublisher.>create(); + val gatekeeperOutFlux = + processor + .apply(gatekeeperInput.flux(), weblogInput.flux()) + .timeout(Duration.ofSeconds(300)); + + // ** construct step verifier + StepVerifier.Step> stepVerifier = + StepVerifier.create(gatekeeperOutFlux); + for (final RunStateWrapper runStateWrapper : sequenceOfStatesToGenerateAndCheck) { + TestPublisher> publisherToUse; + if (runStateWrapper.from.equals(MsgFrom.RABBIT_QUEUE)) { + publisherToUse = gatekeeperInput; + } else { + publisherToUse = weblogInput; + } + + // add runState in the sequence to step verifier, as a publish.next then assertNext + stepVerifier = + stepVerifier + .then( + () -> + publisherToUse.next( + createWfMgmtRunMsgTransaction(runId, runStateWrapper.getRunState()))) + .assertNext(tx -> assertEquals(tx.get().getState(), runStateWrapper.getRunState())); + } + + // ** run step verifier + stepVerifier + .then( + () -> { + gatekeeperInput.complete(); + weblogInput.complete(); + }) + .expectComplete() + .verifyThenAssertThat() + .hasNotDroppedElements() + .hasNotDroppedErrors() + .hasNotDiscardedElements(); + } + + private Transaction createWfMgmtRunMsgTransaction(String runId, RunState state) { + return wrapWithTransaction(createWfMgmtRunMsg(runId, state)); + } + + static class Initializer + implements ApplicationContextInitializer { + public void initialize(ConfigurableApplicationContext configurableApplicationContext) { + TestPropertyValues.of( + "spring.datasource.url=" + postgreSQLContainer.getJdbcUrl(), + "spring.datasource.username=" + postgreSQLContainer.getUsername(), + "spring.datasource.password=" + postgreSQLContainer.getPassword()) + .applyTo(configurableApplicationContext.getEnvironment()); + } + } + + @Value + @Builder + static class RunStateWrapper { + RunState runState; + MsgFrom from; + } + + enum MsgFrom { + WEBLOG, + RABBIT_QUEUE + } +} diff --git a/src/test/java/org/icgc/argo/workflow_management/util/TransactionUtils.java b/src/test/java/org/icgc/argo/workflow_management/util/TransactionUtils.java new file mode 100644 index 0000000..b4251da --- /dev/null +++ b/src/test/java/org/icgc/argo/workflow_management/util/TransactionUtils.java @@ -0,0 +1,88 @@ +package org.icgc.argo.workflow_management.util; + +import com.pivotal.rabbitmq.stream.Transaction; +import com.pivotal.rabbitmq.stream.Transactional; +import java.lang.reflect.Field; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; +import lombok.SneakyThrows; +import lombok.experimental.UtilityClass; +import lombok.val; + +@UtilityClass +public final class TransactionUtils { + private static final Field receivedRejectedField = getReceivedRejectedField(); + private static final Field receivedRequeuedField = getReceivedRequeuedField(); + private static final Field committedField = getCommittedField(); + + @SneakyThrows + public static Transaction wrapWithTransaction(T obj) { + final Consumer NOOP = something -> {}; + return new Transactional<>( + new Transactional.Identifier("componentTest", 0), obj, NOOP, NOOP, NOOP); + } + + @SneakyThrows + public static Boolean isRejected(Object transaction) { + return receivedRejectedFieldValue(transaction).get() + && !receivedRequeuedFieldValue(transaction).get() + && committedFieldValue(transaction); + } + + @SneakyThrows + public static Boolean isRequeued(Object transaction) { + return !receivedRejectedFieldValue(transaction).get() + && receivedRequeuedFieldValue(transaction).get() + && committedFieldValue(transaction); + } + + @SneakyThrows + public static Boolean isAcknowledged(Object transaction) { + return !receivedRejectedFieldValue(transaction).get() + && !receivedRequeuedFieldValue(transaction).get() + && committedFieldValue(transaction); + } + + @SneakyThrows + public static Boolean isNotAcknowledged(Object transaction) { + return !receivedRejectedFieldValue(transaction).get() + && !receivedRequeuedFieldValue(transaction).get() + && !committedFieldValue(transaction); + } + + @SneakyThrows + private static AtomicBoolean receivedRejectedFieldValue(Object transaction) { + return (AtomicBoolean) receivedRejectedField.get(transaction); + } + + @SneakyThrows + private static AtomicBoolean receivedRequeuedFieldValue(Object transaction) { + return (AtomicBoolean) receivedRequeuedField.get(transaction); + } + + @SneakyThrows + private static Boolean committedFieldValue(Object transaction) { + return (Boolean) committedField.get(transaction); + } + + @SneakyThrows + private static Field getReceivedRejectedField() { + val receivedRejectedField = Transactional.class.getDeclaredField("receivedRejected"); + receivedRejectedField.setAccessible(true); + return receivedRejectedField; + } + + @SneakyThrows + private static Field getReceivedRequeuedField() { + val receivedRequeuedField = Transactional.class.getDeclaredField("receivedRequeued"); + receivedRequeuedField.setAccessible(true); + return receivedRequeuedField; + } + + @SneakyThrows + private static Field getCommittedField() { + val committedField = Transactional.class.getDeclaredField("committed"); + committedField.setAccessible(true); + return committedField; + } +} From be160e66af2a8640a3a71d41a182dca756411444 Mon Sep 17 00:00:00 2001 From: jaserud Date: Tue, 16 Mar 2021 12:59:33 -0400 Subject: [PATCH 11/18] remove api and reorganize packages (#162) * remove api and reorganize packages * remove postgres from Jenkinsfile * put back nextflow prop, del streams prop --- Jenkinsfile | 2 - pom.xml | 21 +- .../config/app/GateKeeperDisabledConfig.java | 2 +- ...eKeeperTestConfig.java => TestConfig.java} | 11 +- .../config/rabbitmq/RabbitDisabledConfig.java | 29 -- .../config/rabbitmq/RabbitSchemaConfig.java | 4 +- .../config/secret/ApiKeyConfig.java | 4 +- .../config/secret/NoSecretProviderConfig.java | 4 +- .../config/secret/OAuth2TokenConfig.java | 4 +- .../exception/GlobalExceptionHandler.java | 234 ----------- .../graphql/GatekeeperDataFetchers.java | 85 ++++ .../graphql/GraphQLProvider.java | 13 +- .../graphql/model/GqlPage.java} | 14 +- .../graphql/model/GqlSearchQueryArgs.java | 6 +- .../graphql/model/GqlSort.java} | 22 +- .../graphql/model/SearchResult.java} | 29 +- .../model/EngineParamsConverter.java | 8 +- .../model/{ActiveRun.java => Run.java} | 9 +- .../gatekeeper/repository/ActiveRunsRepo.java | 8 +- .../gatekeeper/service/GateKeeperService.java | 63 +-- .../service/GatekeeperProcessor.java | 4 +- .../gatekeeper/service/StateTransition.java | 6 +- .../AddReactiveContextInputCustomizer.java | 57 --- .../graphql/BlockedQueryVisibility.java | 56 --- .../graphql/GatekeeperDataFetchers.java | 70 ---- .../graphql/MutationDataFetcher.java | 94 ----- .../graphql/model/GqlPage.java | 9 - .../graphql/model/GqlSort.java | 9 - .../graphql/model/SearchResult.java | 22 -- .../properties/Swagger2Properties.java | 98 ----- .../rabbitmq/ApiProducerConfig.java | 77 ---- .../rabbitmq/DisposableManager.java | 50 --- .../service/api_to_wes/ApiToWesService.java | 38 -- .../api_to_wes/impl/ApiProducerToWes.java | 59 --- .../service/api_to_wes/impl/DirectToWes.java | 64 --- .../DisposableManager.java} | 28 +- .../GateKeeperStreamsConfig.java | 18 +- .../wes => streams}/WebLogEventSender.java | 7 +- .../WesConsumerConfig.java} | 64 +-- .../wes => streams}/model/NextflowEvent.java | 2 +- .../model}/WeblogEvent.java | 8 +- .../model/WfManagementEvent.java | 4 +- .../wes => streams}/model/WorkflowEvent.java | 3 +- .../utils}/RabbitmqUtils.java | 4 +- .../utils}/WfMgmtRunMsgConverters.java | 41 +- .../{service => }/wes/NextflowService.java | 18 +- .../wes/NextflowWorkflowMonitor.java | 11 +- .../wes/WorkflowExecutionService.java | 6 +- .../wes/controller/RunsApi.java | 101 ----- .../controller/impl/RunsApiController.java | 53 --- .../wes/controller/model/RunsRequest.java | 48 --- .../wes/model/KubernetesPhase.java | 2 +- .../wes/model/NextflowMetadata.java | 2 +- .../wes/model/NextflowWorkflowMetadata.java | 2 +- .../{service => }/wes/model/RunParams.java | 3 +- .../{controller => }/model/RunsResponse.java | 6 +- .../{service => }/wes/model/WesState.java | 2 +- .../model/WorkflowEngineParams.java | 4 +- .../wes/properties/NextflowProperties.java | 2 +- .../{ => wes}/secret/SecretProvider.java | 2 +- .../{ => wes}/secret/impl/ApiKeyProvider.java | 4 +- .../secret/impl/NoSecretProvider.java | 4 +- .../impl/OAuth2BearerTokenProvider.java | 4 +- src/main/resources/application.yml | 30 +- src/main/resources/avro/WfMgmtRunMsg.avsc | 2 +- src/main/resources/schema.graphql | 36 +- .../ConditionalPutMapTest.java | 5 - .../ErrorHandlingTests.java | 371 ------------------ .../GateKeeperProcessorTests.java | 8 +- .../WorkflowManagementApplicationTests.java | 2 + 70 files changed, 336 insertions(+), 1856 deletions(-) rename src/main/java/org/icgc/argo/workflow_management/config/app/{GateKeeperTestConfig.java => TestConfig.java} (86%) delete mode 100644 src/main/java/org/icgc/argo/workflow_management/config/rabbitmq/RabbitDisabledConfig.java delete mode 100644 src/main/java/org/icgc/argo/workflow_management/exception/GlobalExceptionHandler.java create mode 100644 src/main/java/org/icgc/argo/workflow_management/gatekeeper/graphql/GatekeeperDataFetchers.java rename src/main/java/org/icgc/argo/workflow_management/{ => gatekeeper}/graphql/GraphQLProvider.java (80%) rename src/main/java/org/icgc/argo/workflow_management/{graphql/model/GqlWorkflowEngineParams.java => gatekeeper/graphql/model/GqlPage.java} (74%) rename src/main/java/org/icgc/argo/workflow_management/{ => gatekeeper}/graphql/model/GqlSearchQueryArgs.java (91%) rename src/main/java/org/icgc/argo/workflow_management/{exception/model/ErrorResponse.java => gatekeeper/graphql/model/GqlSort.java} (72%) rename src/main/java/org/icgc/argo/workflow_management/{graphql/model/GqlRunsRequest.java => gatekeeper/graphql/model/SearchResult.java} (71%) rename src/main/java/org/icgc/argo/workflow_management/gatekeeper/model/{ActiveRun.java => Run.java} (70%) delete mode 100644 src/main/java/org/icgc/argo/workflow_management/graphql/AddReactiveContextInputCustomizer.java delete mode 100644 src/main/java/org/icgc/argo/workflow_management/graphql/BlockedQueryVisibility.java delete mode 100644 src/main/java/org/icgc/argo/workflow_management/graphql/GatekeeperDataFetchers.java delete mode 100644 src/main/java/org/icgc/argo/workflow_management/graphql/MutationDataFetcher.java delete mode 100644 src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlPage.java delete mode 100644 src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlSort.java delete mode 100644 src/main/java/org/icgc/argo/workflow_management/graphql/model/SearchResult.java delete mode 100644 src/main/java/org/icgc/argo/workflow_management/properties/Swagger2Properties.java delete mode 100644 src/main/java/org/icgc/argo/workflow_management/rabbitmq/ApiProducerConfig.java delete mode 100644 src/main/java/org/icgc/argo/workflow_management/rabbitmq/DisposableManager.java delete mode 100644 src/main/java/org/icgc/argo/workflow_management/service/api_to_wes/ApiToWesService.java delete mode 100644 src/main/java/org/icgc/argo/workflow_management/service/api_to_wes/impl/ApiProducerToWes.java delete mode 100644 src/main/java/org/icgc/argo/workflow_management/service/api_to_wes/impl/DirectToWes.java rename src/main/java/org/icgc/argo/workflow_management/{properties/WebfluxProperties.java => streams/DisposableManager.java} (64%) rename src/main/java/org/icgc/argo/workflow_management/{rabbitmq => streams}/GateKeeperStreamsConfig.java (89%) rename src/main/java/org/icgc/argo/workflow_management/{service/wes => streams}/WebLogEventSender.java (93%) rename src/main/java/org/icgc/argo/workflow_management/{rabbitmq/ExecuteConsumerConfig.java => streams/WesConsumerConfig.java} (66%) rename src/main/java/org/icgc/argo/workflow_management/{service/wes => streams}/model/NextflowEvent.java (96%) rename src/main/java/org/icgc/argo/workflow_management/{rabbitmq => streams/model}/WeblogEvent.java (92%) rename src/main/java/org/icgc/argo/workflow_management/{service/wes => streams}/model/WfManagementEvent.java (92%) rename src/main/java/org/icgc/argo/workflow_management/{service/wes => streams}/model/WorkflowEvent.java (91%) rename src/main/java/org/icgc/argo/workflow_management/{util => streams/utils}/RabbitmqUtils.java (96%) rename src/main/java/org/icgc/argo/workflow_management/{rabbitmq => streams/utils}/WfMgmtRunMsgConverters.java (71%) rename src/main/java/org/icgc/argo/workflow_management/{service => }/wes/NextflowService.java (96%) rename src/main/java/org/icgc/argo/workflow_management/{service => }/wes/NextflowWorkflowMonitor.java (91%) rename src/main/java/org/icgc/argo/workflow_management/{service => }/wes/WorkflowExecutionService.java (86%) delete mode 100644 src/main/java/org/icgc/argo/workflow_management/wes/controller/RunsApi.java delete mode 100644 src/main/java/org/icgc/argo/workflow_management/wes/controller/impl/RunsApiController.java delete mode 100644 src/main/java/org/icgc/argo/workflow_management/wes/controller/model/RunsRequest.java rename src/main/java/org/icgc/argo/workflow_management/{service => }/wes/model/KubernetesPhase.java (95%) rename src/main/java/org/icgc/argo/workflow_management/{service => }/wes/model/NextflowMetadata.java (95%) rename src/main/java/org/icgc/argo/workflow_management/{service => }/wes/model/NextflowWorkflowMetadata.java (98%) rename src/main/java/org/icgc/argo/workflow_management/{service => }/wes/model/RunParams.java (91%) rename src/main/java/org/icgc/argo/workflow_management/wes/{controller => }/model/RunsResponse.java (87%) rename src/main/java/org/icgc/argo/workflow_management/{service => }/wes/model/WesState.java (96%) rename src/main/java/org/icgc/argo/workflow_management/wes/{controller => }/model/WorkflowEngineParams.java (90%) rename src/main/java/org/icgc/argo/workflow_management/{service => }/wes/properties/NextflowProperties.java (96%) rename src/main/java/org/icgc/argo/workflow_management/{ => wes}/secret/SecretProvider.java (96%) rename src/main/java/org/icgc/argo/workflow_management/{ => wes}/secret/impl/ApiKeyProvider.java (94%) rename src/main/java/org/icgc/argo/workflow_management/{ => wes}/secret/impl/NoSecretProvider.java (93%) rename src/main/java/org/icgc/argo/workflow_management/{ => wes}/secret/impl/OAuth2BearerTokenProvider.java (96%) delete mode 100644 src/test/java/org/icgc/argo/workflow_management/ErrorHandlingTests.java diff --git a/Jenkinsfile b/Jenkinsfile index 20c44f0..d5e7f51 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -37,8 +37,6 @@ spec: volumeMounts: - mountPath: /var/run/docker.sock name: docker-sock - - name: postgres - image: postgres:10-alpine volumes: - name: docker-sock hostPath: diff --git a/pom.xml b/pom.xml index 5c06741..08cfa0d 100644 --- a/pom.xml +++ b/pom.xml @@ -39,7 +39,7 @@ 11 3.0.0-SNAPSHOT - 0.0.8 + 0.0.7 @@ -77,23 +77,6 @@ spring-boot-starter-actuator - - - io.springfox - springfox-swagger2 - ${springfox.version} - - - io.springfox - springfox-spring-webflux - ${springfox.version} - - - io.springfox - springfox-swagger-ui - ${springfox.version} - - io.fabric8 kubernetes-client @@ -181,7 +164,7 @@ com.pivotal.rabbitmq reactor-rabbitmq-streams - 0.0.7 + ${reactor-rabbitmq-streams.version} pom import diff --git a/src/main/java/org/icgc/argo/workflow_management/config/app/GateKeeperDisabledConfig.java b/src/main/java/org/icgc/argo/workflow_management/config/app/GateKeeperDisabledConfig.java index e0290d6..b93442b 100644 --- a/src/main/java/org/icgc/argo/workflow_management/config/app/GateKeeperDisabledConfig.java +++ b/src/main/java/org/icgc/argo/workflow_management/config/app/GateKeeperDisabledConfig.java @@ -28,7 +28,7 @@ import org.springframework.context.annotation.Profile; @Configuration -@Profile("!gatekeeper & !gatekeeper-test") +@Profile("!gatekeeper") @EnableAutoConfiguration( exclude = { DataSourceAutoConfiguration.class, diff --git a/src/main/java/org/icgc/argo/workflow_management/config/app/GateKeeperTestConfig.java b/src/main/java/org/icgc/argo/workflow_management/config/app/TestConfig.java similarity index 86% rename from src/main/java/org/icgc/argo/workflow_management/config/app/GateKeeperTestConfig.java rename to src/main/java/org/icgc/argo/workflow_management/config/app/TestConfig.java index 924a96c..a50013c 100644 --- a/src/main/java/org/icgc/argo/workflow_management/config/app/GateKeeperTestConfig.java +++ b/src/main/java/org/icgc/argo/workflow_management/config/app/TestConfig.java @@ -18,6 +18,7 @@ package org.icgc.argo.workflow_management.config.app; +import com.pivotal.rabbitmq.ReactiveRabbitAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration; import org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration; @@ -25,7 +26,11 @@ import org.springframework.context.annotation.Profile; @Configuration -@Profile("gatekeeper-test") +@Profile("test") @EnableAutoConfiguration( - exclude = {KafkaAutoConfiguration.class, ContextFunctionCatalogAutoConfiguration.class}) -public class GateKeeperTestConfig {} + exclude = { + KafkaAutoConfiguration.class, + ContextFunctionCatalogAutoConfiguration.class, + ReactiveRabbitAutoConfiguration.class + }) +public class TestConfig {} diff --git a/src/main/java/org/icgc/argo/workflow_management/config/rabbitmq/RabbitDisabledConfig.java b/src/main/java/org/icgc/argo/workflow_management/config/rabbitmq/RabbitDisabledConfig.java deleted file mode 100644 index b79a45e..0000000 --- a/src/main/java/org/icgc/argo/workflow_management/config/rabbitmq/RabbitDisabledConfig.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved - * - * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. - * You should have received a copy of the GNU Affero General Public License along with - * this program. If not, see . - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.icgc.argo.workflow_management.config.rabbitmq; - -import com.pivotal.rabbitmq.ReactiveRabbitAutoConfiguration; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; - -@Profile("!api & !execute & !gatekeeper") -@Configuration -@EnableAutoConfiguration(exclude = ReactiveRabbitAutoConfiguration.class) -public class RabbitDisabledConfig {} diff --git a/src/main/java/org/icgc/argo/workflow_management/config/rabbitmq/RabbitSchemaConfig.java b/src/main/java/org/icgc/argo/workflow_management/config/rabbitmq/RabbitSchemaConfig.java index b51928d..22ff30c 100644 --- a/src/main/java/org/icgc/argo/workflow_management/config/rabbitmq/RabbitSchemaConfig.java +++ b/src/main/java/org/icgc/argo/workflow_management/config/rabbitmq/RabbitSchemaConfig.java @@ -7,7 +7,7 @@ import lombok.extern.slf4j.Slf4j; import lombok.val; import org.apache.avro.Schema; -import org.icgc.argo.workflow_management.rabbitmq.schema.WfMgmtRunMsg; +import org.icgc.argo.workflow_management.streams.schema.WfMgmtRunMsg; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.context.ApplicationContext; @@ -23,7 +23,7 @@ * doesn't work. This config ensures the avro schema is available via contentType */ @Slf4j -@Profile({"gatekeeper", "api", "execute"}) +@Profile("!test") @Configuration public class RabbitSchemaConfig { private static final String CONTENT_TYPE = "application/vnd.WfMgmtRunMsg+avro"; diff --git a/src/main/java/org/icgc/argo/workflow_management/config/secret/ApiKeyConfig.java b/src/main/java/org/icgc/argo/workflow_management/config/secret/ApiKeyConfig.java index 85ad85f..98e95df 100644 --- a/src/main/java/org/icgc/argo/workflow_management/config/secret/ApiKeyConfig.java +++ b/src/main/java/org/icgc/argo/workflow_management/config/secret/ApiKeyConfig.java @@ -18,8 +18,8 @@ package org.icgc.argo.workflow_management.config.secret; -import org.icgc.argo.workflow_management.secret.SecretProvider; -import org.icgc.argo.workflow_management.secret.impl.ApiKeyProvider; +import org.icgc.argo.workflow_management.wes.secret.SecretProvider; +import org.icgc.argo.workflow_management.wes.secret.impl.ApiKeyProvider; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/src/main/java/org/icgc/argo/workflow_management/config/secret/NoSecretProviderConfig.java b/src/main/java/org/icgc/argo/workflow_management/config/secret/NoSecretProviderConfig.java index 7e0f57c..f667f3f 100644 --- a/src/main/java/org/icgc/argo/workflow_management/config/secret/NoSecretProviderConfig.java +++ b/src/main/java/org/icgc/argo/workflow_management/config/secret/NoSecretProviderConfig.java @@ -18,8 +18,8 @@ package org.icgc.argo.workflow_management.config.secret; -import org.icgc.argo.workflow_management.secret.SecretProvider; -import org.icgc.argo.workflow_management.secret.impl.NoSecretProvider; +import org.icgc.argo.workflow_management.wes.secret.SecretProvider; +import org.icgc.argo.workflow_management.wes.secret.impl.NoSecretProvider; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; diff --git a/src/main/java/org/icgc/argo/workflow_management/config/secret/OAuth2TokenConfig.java b/src/main/java/org/icgc/argo/workflow_management/config/secret/OAuth2TokenConfig.java index 1840a81..2cb3373 100644 --- a/src/main/java/org/icgc/argo/workflow_management/config/secret/OAuth2TokenConfig.java +++ b/src/main/java/org/icgc/argo/workflow_management/config/secret/OAuth2TokenConfig.java @@ -18,8 +18,8 @@ package org.icgc.argo.workflow_management.config.secret; -import org.icgc.argo.workflow_management.secret.SecretProvider; -import org.icgc.argo.workflow_management.secret.impl.OAuth2BearerTokenProvider; +import org.icgc.argo.workflow_management.wes.secret.SecretProvider; +import org.icgc.argo.workflow_management.wes.secret.impl.OAuth2BearerTokenProvider; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/src/main/java/org/icgc/argo/workflow_management/exception/GlobalExceptionHandler.java b/src/main/java/org/icgc/argo/workflow_management/exception/GlobalExceptionHandler.java deleted file mode 100644 index d6e0617..0000000 --- a/src/main/java/org/icgc/argo/workflow_management/exception/GlobalExceptionHandler.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved - * - * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. - * You should have received a copy of the GNU Affero General Public License along with - * this program. If not, see . - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.icgc.argo.workflow_management.exception; - -import static com.google.common.base.Strings.isNullOrEmpty; -import static java.lang.String.format; -import static org.icgc.argo.workflow_management.util.JacksonUtils.toJsonString; -import static org.springframework.http.HttpStatus.BAD_REQUEST; -import static org.springframework.http.HttpStatus.CONFLICT; -import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; -import static org.springframework.http.HttpStatus.NOT_FOUND; -import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY; -import static org.springframework.http.MediaType.APPLICATION_JSON; - -import lombok.extern.slf4j.Slf4j; -import lombok.val; -import nextflow.exception.AbortOperationException; -import nextflow.exception.AbortRunException; -import nextflow.exception.AbortSignalException; -import nextflow.exception.ConfigParseException; -import nextflow.exception.DuplicateChannelNameException; -import nextflow.exception.DuplicateModuleIncludeException; -import nextflow.exception.DuplicateProcessInvocation; -import nextflow.exception.FailedGuardException; -import nextflow.exception.IllegalConfigException; -import nextflow.exception.IllegalDirectiveException; -import nextflow.exception.IllegalFileException; -import nextflow.exception.IllegalInvocationException; -import nextflow.exception.IllegalModulePath; -import nextflow.exception.MissingFileException; -import nextflow.exception.MissingLibraryException; -import nextflow.exception.MissingModuleComponentException; -import nextflow.exception.MissingValueException; -import nextflow.exception.ProcessFailedException; -import nextflow.exception.ProcessStageException; -import nextflow.exception.ProcessSubmitException; -import nextflow.exception.ProcessTemplateException; -import nextflow.exception.ProcessUnrecoverableException; -import nextflow.exception.ScriptCompilationException; -import nextflow.exception.ScriptRuntimeException; -import nextflow.exception.StopSplitIterationException; -import org.icgc.argo.workflow_management.exception.model.ErrorResponse; -import org.icgc.argo.workflow_management.util.Reflections; -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.reactive.function.client.WebClientResponseException; -import org.springframework.web.server.ResponseStatusException; -import org.springframework.web.server.ServerWebExchange; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -@Slf4j -@ControllerAdvice -public class GlobalExceptionHandler { - - @ResponseBody - @ResponseStatus(NOT_FOUND) - @ExceptionHandler({ - MissingFileException.class, - MissingLibraryException.class, - MissingModuleComponentException.class, - MissingValueException.class - }) - public Mono handleNextflowNotFound(Throwable t) { - return getNextflowErrorResponse(t, NOT_FOUND); - } - - @ResponseBody - @ResponseStatus(CONFLICT) - @ExceptionHandler({ - DuplicateChannelNameException.class, - DuplicateModuleIncludeException.class, - DuplicateProcessInvocation.class - }) - public Mono handleNextflowConflict(Throwable t) { - return getNextflowErrorResponse(t, CONFLICT); - } - - @ResponseBody - @ResponseStatus(BAD_REQUEST) - @ExceptionHandler({ - IllegalConfigException.class, - IllegalDirectiveException.class, - IllegalFileException.class, - IllegalInvocationException.class, - IllegalModulePath.class - }) - public Mono handleNextflowBadRequest(Throwable t) { - return getNextflowErrorResponse(t, BAD_REQUEST); - } - - @ResponseBody - @ResponseStatus(UNPROCESSABLE_ENTITY) - @ExceptionHandler({AbortOperationException.class}) - public Mono handleNextflowUnprocessableEntity(Throwable t) { - return getNextflowErrorResponse(t, UNPROCESSABLE_ENTITY); - } - - @ResponseBody - @ResponseStatus(INTERNAL_SERVER_ERROR) - @ExceptionHandler({ - AbortRunException.class, - ConfigParseException.class, - AbortSignalException.class, - FailedGuardException.class, - ProcessFailedException.class, - ProcessStageException.class, - ProcessSubmitException.class, - ProcessTemplateException.class, - ProcessUnrecoverableException.class, - ScriptCompilationException.class, - ScriptRuntimeException.class, - StopSplitIterationException.class - }) - public Mono handleNextflowInternalServerError(Throwable t) { - return getNextflowErrorResponse(t, INTERNAL_SERVER_ERROR); - } - - @ExceptionHandler(WebClientResponseException.class) - public Mono handleWebclientResponseException( - ServerWebExchange exchange, WebClientResponseException t) { - return handleGenericException(exchange, t, t.getStatusCode()); - } - - @ExceptionHandler(ResponseStatusException.class) - public Mono handleResponseStatusException( - ServerWebExchange exchange, ResponseStatusException t) { - return handleGenericException(exchange, t, t.getStatus()); - } - - @ExceptionHandler(Throwable.class) - public Mono handleAllOtherExceptions(ServerWebExchange exchange, Throwable t) { - val timestamp = System.currentTimeMillis(); - return Reflections.findResponseStatusAnnotation(t.getClass()) - .map(x -> handleResponseStatus(exchange, t, x, timestamp)) - .orElseGet(() -> handleGenericException(exchange, t, INTERNAL_SERVER_ERROR, timestamp)); - } - - private static Mono handleGenericException( - ServerWebExchange exchange, Throwable t, HttpStatus httpStatus) { - return handleGenericException(exchange, t, httpStatus, System.currentTimeMillis()); - } - - private static Mono handleGenericException( - ServerWebExchange exchange, Throwable t, HttpStatus httpStatus, long timestamp) { - log.error( - "{}[{}] exception @{}: exceptionType='{}' message='{}'", - httpStatus.getReasonPhrase(), - httpStatus.value(), - timestamp, - t.getClass().getSimpleName(), - t.getMessage()); - return processGenericException(exchange, t.getMessage(), httpStatus, timestamp); - } - - private static Mono handleResponseStatus( - ServerWebExchange exchange, Throwable t, ResponseStatus responseStatus, long timestamp) { - val reason = extractReason(responseStatus); - val httpStatus = extractHttpStatus(responseStatus); - final String message = - isNullOrEmpty(t.getMessage()) ? (isNullOrEmpty(reason) ? null : reason) : t.getMessage(); - log.error( - "{}[{}] exception @{}: exceptionType='{}' message='{}'", - httpStatus.getReasonPhrase(), - httpStatus.value(), - timestamp, - t.getClass().getSimpleName(), - message); - return processGenericException(exchange, message, httpStatus, timestamp); - } - - private static Mono processGenericException( - ServerWebExchange exchange, String message, HttpStatus httpStatus, long timestamp) { - val serverHttpResponse = exchange.getResponse(); - val errorResponse = buildErrorResponse(message, httpStatus, timestamp); - val errorResponseString = toJsonString(errorResponse); - serverHttpResponse.setStatusCode(httpStatus); - serverHttpResponse.getHeaders().setContentType(APPLICATION_JSON); - val dataBuffer = serverHttpResponse.bufferFactory().wrap(errorResponseString.getBytes()); - return serverHttpResponse.writeWith(Flux.just(dataBuffer)); - } - - private static Mono getNextflowErrorResponse(Throwable t, HttpStatus httpStatus) { - val timestamp = System.currentTimeMillis(); - log.error( - "{}[{}] exception @{}: NextflowExceptionType='{}' message='{}'", - httpStatus.getReasonPhrase(), - httpStatus.value(), - timestamp, - t.getClass().getSimpleName(), - t.getMessage()); - return buildErrorResponseMono(t.getMessage(), httpStatus, timestamp); - } - - private static Mono buildErrorResponseMono( - String message, HttpStatus status, long timestamp) { - return Mono.just(buildErrorResponse(message, status, timestamp)); - } - - private static ErrorResponse buildErrorResponse( - String message, HttpStatus status, long timestamp) { - return ErrorResponse.builder() - .msg(format("[@%s]: %s", timestamp, message)) - .statusCode(status.value()) - .build(); - } - - private static HttpStatus extractHttpStatus(ResponseStatus r) { - return r.value(); - } - - private static String extractReason(ResponseStatus r) { - return r.reason(); - } -} diff --git a/src/main/java/org/icgc/argo/workflow_management/gatekeeper/graphql/GatekeeperDataFetchers.java b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/graphql/GatekeeperDataFetchers.java new file mode 100644 index 0000000..086c941 --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/graphql/GatekeeperDataFetchers.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. + * You should have received a copy of the GNU Affero General Public License along with + * this program. If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.icgc.argo.workflow_management.gatekeeper.graphql; + +import static java.util.stream.Collectors.toList; +import static org.icgc.argo.workflow_management.util.JacksonUtils.convertValue; + +import graphql.schema.DataFetcher; +import lombok.val; +import org.icgc.argo.workflow_management.gatekeeper.graphql.model.GqlSearchQueryArgs; +import org.icgc.argo.workflow_management.gatekeeper.graphql.model.SearchResult; +import org.icgc.argo.workflow_management.gatekeeper.service.GateKeeperService; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Profile; +import org.springframework.data.domain.Example; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Component; + +@Component +public class GatekeeperDataFetchers { + + @Bean + @Profile("gatekeeper") + @Qualifier("runsDataFetcher") + public DataFetcher getActiveRunsDataFetcher(GateKeeperService gateKeeperService) { + return environment -> { + val args = convertValue(environment.getArguments(), GqlSearchQueryArgs.class); + + val page = args.getPage(); + val runExample = args.getExample(); + val sorts = args.getSorts(); + + val sortable = + sorts == null + ? Sort.unsorted() + : Sort.by( + sorts.stream() + .map( + s -> + new Sort.Order( + s.getOrder().equalsIgnoreCase("asc") + ? Sort.Direction.ASC + : Sort.Direction.DESC, + s.getFieldName())) + .collect(toList())); + + val pageable = + page == null + ? PageRequest.of(0, 10, sortable) + : PageRequest.of(page.getFrom(), page.getSize(), sortable); + + val result = + runExample == null + ? gateKeeperService.getRuns(pageable) + : gateKeeperService.getRuns(Example.of(runExample), pageable); + + return new SearchResult<>(result.getContent(), result.hasNext(), result.getTotalElements()); + }; + } + + @Bean + @Profile("!gatekeeper") + @Qualifier("runsDataFetcher") + public DataFetcher getActiveRunsDisabledDataFetcher() { + return environment -> null; + } +} diff --git a/src/main/java/org/icgc/argo/workflow_management/graphql/GraphQLProvider.java b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/graphql/GraphQLProvider.java similarity index 80% rename from src/main/java/org/icgc/argo/workflow_management/graphql/GraphQLProvider.java rename to src/main/java/org/icgc/argo/workflow_management/gatekeeper/graphql/GraphQLProvider.java index 46997bd..ca50233 100644 --- a/src/main/java/org/icgc/argo/workflow_management/graphql/GraphQLProvider.java +++ b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/graphql/GraphQLProvider.java @@ -16,7 +16,7 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.graphql; +package org.icgc.argo.workflow_management.gatekeeper.graphql; import static graphql.schema.idl.TypeRuntimeWiring.newTypeWiring; @@ -38,8 +38,7 @@ @Service @RequiredArgsConstructor public class GraphQLProvider { - private final MutationDataFetcher mutationDataFetcher; - private final DataFetcher activeRunsDataFetcher; + private final DataFetcher runsDataFetcher; private GraphQL graphQL; @Bean @@ -62,13 +61,7 @@ private GraphQLSchema buildSchema(String sdl) { private RuntimeWiring buildWiring() { return RuntimeWiring.newRuntimeWiring() .scalar(ExtendedScalars.Json) - .type(newTypeWiring("Mutation").dataFetchers(mutationDataFetcher.mutationResolvers())) - .type(newTypeWiring("Query").dataFetcher("activeRuns", activeRunsDataFetcher)) - // Field visibility hides from schema, but they are executable - .fieldVisibility( - BlockedQueryVisibility.builder() - .blockedQueryField("activeRuns") // TODO make visible after api is removed - .build()) + .type(newTypeWiring("Query").dataFetcher("runs", runsDataFetcher)) .build(); } } diff --git a/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlWorkflowEngineParams.java b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/graphql/model/GqlPage.java similarity index 74% rename from src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlWorkflowEngineParams.java rename to src/main/java/org/icgc/argo/workflow_management/gatekeeper/graphql/model/GqlPage.java index 7e67710..16ef0cb 100644 --- a/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlWorkflowEngineParams.java +++ b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/graphql/model/GqlPage.java @@ -16,12 +16,12 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.graphql.model; +package org.icgc.argo.workflow_management.gatekeeper.graphql.model; -import com.fasterxml.jackson.databind.annotation.JsonNaming; -import org.codehaus.jackson.annotate.JsonIgnoreProperties; -import org.icgc.argo.workflow_management.wes.controller.model.WorkflowEngineParams; +import lombok.Data; -@JsonNaming() -@JsonIgnoreProperties(ignoreUnknown = true) -public class GqlWorkflowEngineParams extends WorkflowEngineParams {} +@Data +public class GqlPage { + Integer from; + Integer size; +} diff --git a/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlSearchQueryArgs.java b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/graphql/model/GqlSearchQueryArgs.java similarity index 91% rename from src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlSearchQueryArgs.java rename to src/main/java/org/icgc/argo/workflow_management/gatekeeper/graphql/model/GqlSearchQueryArgs.java index 701e306..eef33e0 100644 --- a/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlSearchQueryArgs.java +++ b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/graphql/model/GqlSearchQueryArgs.java @@ -16,21 +16,21 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.graphql.model; +package org.icgc.argo.workflow_management.gatekeeper.graphql.model; import java.util.List; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.codehaus.jackson.annotate.JsonIgnoreProperties; -import org.icgc.argo.workflow_management.gatekeeper.model.ActiveRun; +import org.icgc.argo.workflow_management.gatekeeper.model.Run; @Data @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) public class GqlSearchQueryArgs { - ActiveRun example; + Run example; GqlPage page; List sorts; } diff --git a/src/main/java/org/icgc/argo/workflow_management/exception/model/ErrorResponse.java b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/graphql/model/GqlSort.java similarity index 72% rename from src/main/java/org/icgc/argo/workflow_management/exception/model/ErrorResponse.java rename to src/main/java/org/icgc/argo/workflow_management/gatekeeper/graphql/model/GqlSort.java index f6f33e5..eabd0b8 100644 --- a/src/main/java/org/icgc/argo/workflow_management/exception/model/ErrorResponse.java +++ b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/graphql/model/GqlSort.java @@ -16,24 +16,12 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.exception.model; +package org.icgc.argo.workflow_management.gatekeeper.graphql.model; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; -import lombok.*; +import lombok.Data; @Data -@Builder -@ToString -@NoArgsConstructor -@AllArgsConstructor -@EqualsAndHashCode -@ApiModel(description = "Standard error response") -public class ErrorResponse { - - @JsonProperty("msg") - private String msg; - - @JsonProperty("status_code") - private Integer statusCode; +public class GqlSort { + String fieldName; + String order; } diff --git a/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlRunsRequest.java b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/graphql/model/SearchResult.java similarity index 71% rename from src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlRunsRequest.java rename to src/main/java/org/icgc/argo/workflow_management/gatekeeper/graphql/model/SearchResult.java index cf507d7..37e91a7 100644 --- a/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlRunsRequest.java +++ b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/graphql/model/SearchResult.java @@ -16,16 +16,25 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.graphql.model; +package org.icgc.argo.workflow_management.gatekeeper.graphql.model; -import com.fasterxml.jackson.databind.annotation.JsonNaming; -import lombok.Data; -import org.codehaus.jackson.annotate.JsonIgnoreProperties; -import org.icgc.argo.workflow_management.wes.controller.model.RunsRequest; +import java.util.List; +import lombok.Value; -@Data -@JsonNaming() -@JsonIgnoreProperties(ignoreUnknown = true) -public class GqlRunsRequest extends RunsRequest { - private GqlWorkflowEngineParams workflowEngineParams = new GqlWorkflowEngineParams(); +@Value +public class SearchResult { + List content; + Info info; + + public SearchResult(List content, Boolean hasNextFrom, Long totalHits) { + this.content = content; + this.info = new Info(hasNextFrom, totalHits, content.size()); + } + + @Value + public static class Info { + Boolean hasNextFrom; + Long totalHits; + Integer contentCount; + } } diff --git a/src/main/java/org/icgc/argo/workflow_management/gatekeeper/model/EngineParamsConverter.java b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/model/EngineParamsConverter.java index 49cef6f..8a4353e 100644 --- a/src/main/java/org/icgc/argo/workflow_management/gatekeeper/model/EngineParamsConverter.java +++ b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/model/EngineParamsConverter.java @@ -8,18 +8,18 @@ @Converter @Slf4j -public class EngineParamsConverter implements AttributeConverter { +public class EngineParamsConverter implements AttributeConverter { private static final ObjectMapper objectMapper = new ObjectMapper(); @SneakyThrows @Override - public String convertToDatabaseColumn(ActiveRun.EngineParams engineParams) { + public String convertToDatabaseColumn(Run.EngineParams engineParams) { return objectMapper.writeValueAsString(engineParams); } @SneakyThrows @Override - public ActiveRun.EngineParams convertToEntityAttribute(String dbData) { - return objectMapper.readValue(dbData, ActiveRun.EngineParams.class); + public Run.EngineParams convertToEntityAttribute(String dbData) { + return objectMapper.readValue(dbData, Run.EngineParams.class); } } diff --git a/src/main/java/org/icgc/argo/workflow_management/gatekeeper/model/ActiveRun.java b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/model/Run.java similarity index 70% rename from src/main/java/org/icgc/argo/workflow_management/gatekeeper/model/ActiveRun.java rename to src/main/java/org/icgc/argo/workflow_management/gatekeeper/model/Run.java index 1c99cc5..78b05a1 100644 --- a/src/main/java/org/icgc/argo/workflow_management/gatekeeper/model/ActiveRun.java +++ b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/model/Run.java @@ -2,18 +2,15 @@ import javax.persistence.*; import lombok.*; -import org.icgc.argo.workflow_management.rabbitmq.schema.RunState; +import org.icgc.argo.workflow_management.streams.schema.RunState; -// TODO rename ActiveRun to Run after api is removed. -// Distinction is being made for now because there are a WesRun and this new Run type in this repo. -// This entity doesn't need to be migrated and can be easily renamed/updated when the db is clear. -@Entity(name = "activeruns") +@Entity(name = "runs") @Data @Builder @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode -public class ActiveRun { +public class Run { @Id private String runId; private String workflowUrl; diff --git a/src/main/java/org/icgc/argo/workflow_management/gatekeeper/repository/ActiveRunsRepo.java b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/repository/ActiveRunsRepo.java index 2c725e6..fe54676 100644 --- a/src/main/java/org/icgc/argo/workflow_management/gatekeeper/repository/ActiveRunsRepo.java +++ b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/repository/ActiveRunsRepo.java @@ -20,16 +20,16 @@ import java.util.Optional; import javax.persistence.LockModeType; -import org.icgc.argo.workflow_management.gatekeeper.model.ActiveRun; +import org.icgc.argo.workflow_management.gatekeeper.model.Run; import org.springframework.context.annotation.Profile; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Lock; import org.springframework.stereotype.Repository; -@Profile({"gatekeeper-test", "gatekeeper"}) +@Profile("gatekeeper") @Repository -public interface ActiveRunsRepo extends JpaRepository { +public interface ActiveRunsRepo extends JpaRepository { @Lock(LockModeType.OPTIMISTIC_FORCE_INCREMENT) - Optional findActiveRunByRunId(String runId); + Optional findActiveRunByRunId(String runId); } diff --git a/src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/GateKeeperService.java b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/GateKeeperService.java index 73d5253..fea1396 100644 --- a/src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/GateKeeperService.java +++ b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/GateKeeperService.java @@ -19,17 +19,18 @@ package org.icgc.argo.workflow_management.gatekeeper.service; import static org.icgc.argo.workflow_management.gatekeeper.service.StateTransition.nextState; -import static org.icgc.argo.workflow_management.rabbitmq.schema.RunState.*; +import static org.icgc.argo.workflow_management.streams.schema.RunState.*; import java.util.Optional; import java.util.Set; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import lombok.val; -import org.icgc.argo.workflow_management.gatekeeper.model.ActiveRun; +import org.icgc.argo.workflow_management.gatekeeper.model.Run; import org.icgc.argo.workflow_management.gatekeeper.repository.ActiveRunsRepo; -import org.icgc.argo.workflow_management.rabbitmq.schema.RunState; -import org.icgc.argo.workflow_management.rabbitmq.schema.WfMgmtRunMsg; +import org.icgc.argo.workflow_management.streams.schema.EngineParams; +import org.icgc.argo.workflow_management.streams.schema.RunState; +import org.icgc.argo.workflow_management.streams.schema.WfMgmtRunMsg; import org.springframework.context.annotation.Profile; import org.springframework.data.domain.Example; import org.springframework.data.domain.Page; @@ -37,7 +38,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -@Profile({"gatekeeper-test", "gatekeeper"}) +@Profile("gatekeeper") @Slf4j @Service @RequiredArgsConstructor @@ -58,7 +59,7 @@ public Optional checkWfMgmtRunMsgAndUpdate(WfMgmtRunMsg msg) { // short circuit, run is new if (knownRunOpt.isEmpty() && msg.getState().equals(QUEUED)) { - val newRun = repo.save(fromMsg(msg)); + val newRun = repo.save(runFromMsg(msg)); log.debug("Active Run created: {}", newRun); return Optional.of(msg); } else if (knownRunOpt.isEmpty()) { @@ -66,9 +67,13 @@ public Optional checkWfMgmtRunMsgAndUpdate(WfMgmtRunMsg msg) { } val knownRun = knownRunOpt.get(); + // update parmas from msg + knownRun.setWorkflowEngineParams(runEngParamFromMsg(msg.getWorkflowEngineParams())); + knownRun.setWorkflowParamsJsonStr(msg.getWorkflowParamsJsonStr()); + val inputState = msg.getState(); - return Optional.ofNullable(fromActiveRun(checkActiveRunAndUpdate(knownRun, inputState))); + return Optional.ofNullable(msgFromRun(checkActiveRunAndUpdate(knownRun, inputState))); } /** @@ -84,12 +89,12 @@ public Optional checkWithExistingAndUpdateStateOnly( return Optional.empty(); } else { return Optional.ofNullable( - fromActiveRun(checkActiveRunAndUpdate(knownRunOpt.get(), inputState))); + msgFromRun(checkActiveRunAndUpdate(knownRunOpt.get(), inputState))); } } @Transactional - private ActiveRun checkActiveRunAndUpdate(ActiveRun knownRun, RunState inputState) { + private Run checkActiveRunAndUpdate(Run knownRun, RunState inputState) { val currentState = knownRun.getState(); // check if this is a valid state transition @@ -112,18 +117,18 @@ private ActiveRun checkActiveRunAndUpdate(ActiveRun knownRun, RunState inputStat } } - public Page getRuns(Pageable pageable) { + public Page getRuns(Pageable pageable) { return getRuns(null, pageable); } - public Page getRuns(Example example, Pageable pageable) { + public Page getRuns(Example example, Pageable pageable) { return example == null ? repo.findAll(pageable) : repo.findAll(example, pageable); } - private ActiveRun fromMsg(WfMgmtRunMsg msg) { + private Run runFromMsg(WfMgmtRunMsg msg) { val msgWep = msg.getWorkflowEngineParams(); val runWep = - ActiveRun.EngineParams.builder() + Run.EngineParams.builder() .latest(msgWep.getLatest()) .defaultContainer(msgWep.getDefaultContainer()) .launchDir(msgWep.getLaunchDir()) @@ -133,7 +138,7 @@ private ActiveRun fromMsg(WfMgmtRunMsg msg) { .resume(msgWep.getResume()) .build(); - return ActiveRun.builder() + return Run.builder() .runId(msg.getRunId()) .state(msg.getState()) .workflowUrl(msg.getWorkflowUrl()) @@ -143,12 +148,12 @@ private ActiveRun fromMsg(WfMgmtRunMsg msg) { .build(); } - private WfMgmtRunMsg fromActiveRun(ActiveRun activeRun) { - if (activeRun == null) return null; + private WfMgmtRunMsg msgFromRun(Run run) { + if (run == null) return null; - val msgWep = activeRun.getWorkflowEngineParams(); + val msgWep = run.getWorkflowEngineParams(); val runWep = - org.icgc.argo.workflow_management.rabbitmq.schema.EngineParams.newBuilder() + EngineParams.newBuilder() .setLatest(msgWep.getLatest()) .setDefaultContainer(msgWep.getDefaultContainer()) .setLaunchDir(msgWep.getLaunchDir()) @@ -159,12 +164,24 @@ private WfMgmtRunMsg fromActiveRun(ActiveRun activeRun) { .build(); return WfMgmtRunMsg.newBuilder() - .setRunId(activeRun.getRunId()) - .setState(activeRun.getState()) - .setWorkflowUrl(activeRun.getWorkflowUrl()) - .setWorkflowParamsJsonStr(activeRun.getWorkflowParamsJsonStr()) + .setRunId(run.getRunId()) + .setState(run.getState()) + .setWorkflowUrl(run.getWorkflowUrl()) + .setWorkflowParamsJsonStr(run.getWorkflowParamsJsonStr()) .setWorkflowEngineParams(runWep) - .setTimestamp(activeRun.getTimestamp()) + .setTimestamp(run.getTimestamp()) + .build(); + } + + private Run.EngineParams runEngParamFromMsg(EngineParams msgWep) { + return Run.EngineParams.builder() + .latest(msgWep.getLatest()) + .defaultContainer(msgWep.getDefaultContainer()) + .launchDir(msgWep.getLaunchDir()) + .revision(msgWep.getRevision()) + .projectDir(msgWep.getProjectDir()) + .workDir(msgWep.getWorkDir()) + .resume(msgWep.getResume()) .build(); } } diff --git a/src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/GatekeeperProcessor.java b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/GatekeeperProcessor.java index c035fdc..6d4f10d 100644 --- a/src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/GatekeeperProcessor.java +++ b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/GatekeeperProcessor.java @@ -24,7 +24,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import lombok.val; -import org.icgc.argo.workflow_management.rabbitmq.schema.WfMgmtRunMsg; +import org.icgc.argo.workflow_management.streams.schema.WfMgmtRunMsg; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component; import reactor.core.publisher.Flux; @@ -34,7 +34,7 @@ * wfmgmtrunmsgs) and returning one merged flux of allowed wfmgmtrunmsgs */ @Slf4j -@Profile({"gatekeeper", "gatekeeper-test"}) +@Profile("gatekeeper") @Component @RequiredArgsConstructor public class GatekeeperProcessor diff --git a/src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/StateTransition.java b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/StateTransition.java index bef4322..c769c07 100644 --- a/src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/StateTransition.java +++ b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/StateTransition.java @@ -18,14 +18,14 @@ package org.icgc.argo.workflow_management.gatekeeper.service; -import static org.icgc.argo.workflow_management.rabbitmq.schema.RunState.*; -import static org.icgc.argo.workflow_management.rabbitmq.schema.RunState.COMPLETE; +import static org.icgc.argo.workflow_management.streams.schema.RunState.*; +import static org.icgc.argo.workflow_management.streams.schema.RunState.COMPLETE; import java.util.Map; import java.util.Optional; import java.util.Set; import lombok.experimental.UtilityClass; -import org.icgc.argo.workflow_management.rabbitmq.schema.RunState; +import org.icgc.argo.workflow_management.streams.schema.RunState; /** * When updating a Run using a RunMsg state, we need to check whether that run is allowed to go into diff --git a/src/main/java/org/icgc/argo/workflow_management/graphql/AddReactiveContextInputCustomizer.java b/src/main/java/org/icgc/argo/workflow_management/graphql/AddReactiveContextInputCustomizer.java deleted file mode 100644 index cb65054..0000000 --- a/src/main/java/org/icgc/argo/workflow_management/graphql/AddReactiveContextInputCustomizer.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved - * - * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. - * You should have received a copy of the GNU Affero General Public License along with - * this program. If not, see . - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.icgc.argo.workflow_management.graphql; - -import graphql.ExecutionInput; -import graphql.spring.web.reactive.ExecutionInputCustomizer; -import lombok.extern.slf4j.Slf4j; -import org.springframework.context.annotation.Primary; -import org.springframework.context.annotation.Profile; -import org.springframework.security.core.context.ReactiveSecurityContextHolder; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.stereotype.Component; -import org.springframework.web.server.ServerWebExchange; -import reactor.core.publisher.Mono; - -// This class is a work around for this issue: -// https://github.com/graphql-java/graphql-java-spring/issues/8 -// The problem at a high level is that the graphql-java engine looses the ReactiveSecurityContext -// when it executes async. -// This work around, adds the security context to the graphql execution context so it's not lost and -// can be used for auth check. -// This only occurs if auth is enabled. - -@Slf4j -@Component -@Primary -@Profile("secure") -public class AddReactiveContextInputCustomizer implements ExecutionInputCustomizer { - @Override - public Mono customizeExecutionInput( - ExecutionInput executionInput, ServerWebExchange serverWebExchange) { - log.debug("Adding Reactive Security Context To Execution Input"); - Mono securityContextMono = ReactiveSecurityContextHolder.getContext(); - - return securityContextMono - .map( - securityContext -> - executionInput.transform(builder -> builder.context(securityContext))) - .switchIfEmpty(Mono.just(executionInput)); - } -} diff --git a/src/main/java/org/icgc/argo/workflow_management/graphql/BlockedQueryVisibility.java b/src/main/java/org/icgc/argo/workflow_management/graphql/BlockedQueryVisibility.java deleted file mode 100644 index 99b8cfc..0000000 --- a/src/main/java/org/icgc/argo/workflow_management/graphql/BlockedQueryVisibility.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved - * - * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. - * You should have received a copy of the GNU Affero General Public License along with - * this program. If not, see . - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.icgc.argo.workflow_management.graphql; - -import static java.util.stream.Collectors.toUnmodifiableList; - -import graphql.schema.GraphQLFieldDefinition; -import graphql.schema.GraphQLFieldsContainer; -import graphql.schema.visibility.GraphqlFieldVisibility; -import java.util.List; -import lombok.Builder; -import lombok.Singular; - -/** - * GraphqlFieldVisibility implementation that can be used to hide query level fields from the - * GraphQL schema during RuntimeWiring. Simple create a new builder of this class and add fields to - * bock with `blockedQueryField()` - * - *

More info on Field Visibility: https://www.graphql-java.com/documentation/v16/fieldvisibility/ - */ -@Builder -public class BlockedQueryVisibility implements GraphqlFieldVisibility { - @Singular private final List blockedQueryFields; - - @Override - public List getFieldDefinitions(GraphQLFieldsContainer fieldsContainer) { - if (fieldsContainer.getName().equalsIgnoreCase("Query")) { - return fieldsContainer.getFieldDefinitions().stream() - .filter(fd -> !blockedQueryFields.contains(fd.getName())) - .collect(toUnmodifiableList()); - } - return fieldsContainer.getFieldDefinitions(); - } - - @Override - public GraphQLFieldDefinition getFieldDefinition( - GraphQLFieldsContainer fieldsContainer, String fieldName) { - return fieldsContainer.getFieldDefinition(fieldName); - } -} diff --git a/src/main/java/org/icgc/argo/workflow_management/graphql/GatekeeperDataFetchers.java b/src/main/java/org/icgc/argo/workflow_management/graphql/GatekeeperDataFetchers.java deleted file mode 100644 index a32d73c..0000000 --- a/src/main/java/org/icgc/argo/workflow_management/graphql/GatekeeperDataFetchers.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.icgc.argo.workflow_management.graphql; - -import static java.util.stream.Collectors.toList; -import static org.icgc.argo.workflow_management.util.JacksonUtils.convertValue; - -import graphql.schema.DataFetcher; -import lombok.val; -import org.icgc.argo.workflow_management.gatekeeper.model.ActiveRun; -import org.icgc.argo.workflow_management.gatekeeper.service.GateKeeperService; -import org.icgc.argo.workflow_management.graphql.model.GqlSearchQueryArgs; -import org.icgc.argo.workflow_management.graphql.model.SearchResult; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Profile; -import org.springframework.data.domain.Example; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Sort; -import org.springframework.stereotype.Component; - -@Component -public class GatekeeperDataFetchers { - - @Bean - @Profile("gatekeeper") - @Qualifier("activeRunsDataFetcher") - public DataFetcher getActiveRunsDataFetcher(GateKeeperService gateKeeperService) { - return environment -> { - val args = convertValue(environment.getArguments(), GqlSearchQueryArgs.class); - - val page = args.getPage(); - val activeRunExample = args.getExample(); - val sorts = args.getSorts(); - - val sortable = - Sort.by( - sorts.stream() - .map( - s -> - new Sort.Order( - s.getOrder().equalsIgnoreCase("asc") - ? Sort.Direction.ASC - : Sort.Direction.DESC, - s.getFieldName())) - .collect(toList())); - - val pageable = - page == null - ? PageRequest.of(0, 10, sortable) - : PageRequest.of(page.getFrom(), page.getSize(), sortable); - - Page result; - if (activeRunExample == null) { - result = gateKeeperService.getRuns(pageable); - } else { - val example = Example.of(activeRunExample); - result = gateKeeperService.getRuns(example, pageable); - } - - return new SearchResult<>(result.getContent(), result.hasNext(), result.getTotalElements()); - }; - } - - @Bean - @Profile("!gatekeeper") - @Qualifier("activeRunsDataFetcher") - public DataFetcher getActiveRunsDisabledDataFetcher() { - return environment -> null; - } -} diff --git a/src/main/java/org/icgc/argo/workflow_management/graphql/MutationDataFetcher.java b/src/main/java/org/icgc/argo/workflow_management/graphql/MutationDataFetcher.java deleted file mode 100644 index dc208be..0000000 --- a/src/main/java/org/icgc/argo/workflow_management/graphql/MutationDataFetcher.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved - * - * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. - * You should have received a copy of the GNU Affero General Public License along with - * this program. If not, see . - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.icgc.argo.workflow_management.graphql; - -import static org.icgc.argo.workflow_management.util.JacksonUtils.convertValue; - -import com.google.common.collect.ImmutableMap; -import graphql.schema.DataFetcher; -import graphql.schema.DataFetchingEnvironment; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.function.Function; -import lombok.NonNull; -import lombok.val; -import org.icgc.argo.workflow_management.graphql.model.GqlRunsRequest; -import org.icgc.argo.workflow_management.service.api_to_wes.ApiToWesService; -import org.icgc.argo.workflow_management.wes.controller.model.RunsRequest; -import org.icgc.argo.workflow_management.wes.controller.model.RunsResponse; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.core.context.ReactiveSecurityContextHolder; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.stereotype.Component; -import reactor.core.publisher.Mono; - -@Component -public class MutationDataFetcher { - - @NonNull private final MonoDataFetcher cancelRunResolver; - @NonNull private final MonoDataFetcher startRunResolver; - - @Autowired - public MutationDataFetcher(ApiToWesService apiToWesService) { - cancelRunResolver = - env -> { - val args = env.getArguments(); - String runId = String.valueOf(args.get("runId")); - return apiToWesService.cancel(runId); - }; - - startRunResolver = - env -> { - val args = env.getArguments(); - - val requestMap = ImmutableMap.builder(); - - if (args.get("request") != null) - requestMap.putAll((Map) args.get("request")); - - RunsRequest runsRequest = convertValue(requestMap.build(), GqlRunsRequest.class); - return apiToWesService.run(runsRequest); - }; - } - - public Map mutationResolvers() { - return Map.of( - "cancelRun", securityContextAddedFetcher(cancelRunResolver), - "startRun", securityContextAddedFetcher(startRunResolver)); - } - - private DataFetcher> securityContextAddedFetcher( - MonoDataFetcher monoDataFetcher) { - return environment -> { - // add reactive security context to mono subscriberContext so subscribers (i.e. method - // security) have access - if (environment.getContext() instanceof SecurityContext) { - SecurityContext context = environment.getContext(); - return monoDataFetcher - .apply(environment) - .subscriberContext( - ReactiveSecurityContextHolder.withSecurityContext(Mono.just(context))) - .toFuture(); - } - return monoDataFetcher.apply(environment).toFuture(); - }; - } - - interface MonoDataFetcher extends Function> {} -} diff --git a/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlPage.java b/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlPage.java deleted file mode 100644 index 213dddb..0000000 --- a/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlPage.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.icgc.argo.workflow_management.graphql.model; - -import lombok.Data; - -@Data -public class GqlPage { - Integer from; - Integer size; -} diff --git a/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlSort.java b/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlSort.java deleted file mode 100644 index 7ae8d66..0000000 --- a/src/main/java/org/icgc/argo/workflow_management/graphql/model/GqlSort.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.icgc.argo.workflow_management.graphql.model; - -import lombok.Data; - -@Data -public class GqlSort { - String fieldName; - String order; -} diff --git a/src/main/java/org/icgc/argo/workflow_management/graphql/model/SearchResult.java b/src/main/java/org/icgc/argo/workflow_management/graphql/model/SearchResult.java deleted file mode 100644 index a9c59c4..0000000 --- a/src/main/java/org/icgc/argo/workflow_management/graphql/model/SearchResult.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.icgc.argo.workflow_management.graphql.model; - -import java.util.List; -import lombok.Value; - -@Value -public class SearchResult { - List content; - Info info; - - public SearchResult(List content, Boolean hasNextFrom, Long totalHits) { - this.content = content; - this.info = new Info(hasNextFrom, totalHits, content.size()); - } - - @Value - public static class Info { - Boolean hasNextFrom; - Long totalHits; - Integer contentCount; - } -} diff --git a/src/main/java/org/icgc/argo/workflow_management/properties/Swagger2Properties.java b/src/main/java/org/icgc/argo/workflow_management/properties/Swagger2Properties.java deleted file mode 100644 index 2cfcf69..0000000 --- a/src/main/java/org/icgc/argo/workflow_management/properties/Swagger2Properties.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved - * - * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. - * You should have received a copy of the GNU Affero General Public License along with - * this program. If not, see . - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.icgc.argo.workflow_management.properties; - -import com.fasterxml.classmate.ResolvedType; -import com.fasterxml.classmate.TypeResolver; -import com.fasterxml.classmate.types.ResolvedArrayType; -import lombok.Getter; -import lombok.Setter; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Primary; -import org.springframework.stereotype.Component; -import org.springframework.web.method.HandlerMethod; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import springfox.documentation.builders.PathSelectors; -import springfox.documentation.builders.RequestHandlerSelectors; -import springfox.documentation.service.ApiInfo; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spring.web.plugins.Docket; -import springfox.documentation.spring.web.readers.operation.HandlerMethodResolver; -import springfox.documentation.swagger2.annotations.EnableSwagger2WebFlux; - -@Configuration -@EnableSwagger2WebFlux -public class Swagger2Properties { - - @Bean - public Docket api(SwaggerProperties properties) { - return new Docket(DocumentationType.SWAGGER_2) - .select() - .apis( - RequestHandlerSelectors.basePackage("org.icgc.argo.workflow_management.wes.controller")) - .paths(PathSelectors.any()) - .build() - .host(properties.host) - .apiInfo(apiInfo()); - } - - @Component - @ConfigurationProperties(prefix = "swagger") - class SwaggerProperties { - /** Specify host if workflow management is running behind proxy. */ - @Setter @Getter private String host = ""; - } - - ApiInfo apiInfo() { - return new ApiInfo( - "Workflow Management", - "Workflow Management API Documentation", - "0.0.2", - "", - "contact@overture.bio", - "", - ""); - } - - @Bean - @Primary - public HandlerMethodResolver fluxMethodResolver(TypeResolver resolver) { - // Inject our own HandlerMethodResolver to unpack Mono/Flux types to their bound types - return new HandlerMethodResolver(resolver) { - @Override - public ResolvedType methodReturnType(HandlerMethod handlerMethod) { - ResolvedType retType = super.methodReturnType(handlerMethod); - - while (retType.getErasedType() == Mono.class || retType.getErasedType() == Flux.class) { - if (retType.getErasedType() == Flux.class) { - ResolvedType type = retType.getTypeBindings().getBoundType(0); - retType = new ResolvedArrayType(type.getErasedType(), type.getTypeBindings(), type); - } else { - retType = retType.getTypeBindings().getBoundType(0); - } - } - - return retType; - } - }; - } -} diff --git a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/ApiProducerConfig.java b/src/main/java/org/icgc/argo/workflow_management/rabbitmq/ApiProducerConfig.java deleted file mode 100644 index 8f13d6a..0000000 --- a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/ApiProducerConfig.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved - * - * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. - * You should have received a copy of the GNU Affero General Public License along with - * this program. If not, see . - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.icgc.argo.workflow_management.rabbitmq; - -import static org.icgc.argo.workflow_management.rabbitmq.DisposableManager.API_PRODCUER; -import static org.icgc.argo.workflow_management.util.RabbitmqUtils.createTransProducerStream; - -import com.pivotal.rabbitmq.RabbitEndpointService; -import com.pivotal.rabbitmq.source.OnDemandSource; -import com.pivotal.rabbitmq.source.Sender; -import javax.annotation.PostConstruct; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.icgc.argo.workflow_management.config.rabbitmq.RabbitSchemaConfig; -import org.icgc.argo.workflow_management.rabbitmq.schema.WfMgmtRunMsg; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; -import reactor.core.Disposable; - -@Slf4j -@Profile("api") -@AutoConfigureAfter(RabbitSchemaConfig.class) -@Configuration -@RequiredArgsConstructor -public class ApiProducerConfig { - @Value("${api.producer.topology.queueName}") - private String queueName; - - @Value("${api.producer.topology.topicExchangeName}") - private String topicExchangeName; - - @Value("${api.producer.topology.topicRoutingKeys}") - private String[] topicRoutingKeys; - - private final RabbitEndpointService rabbit; - private final DisposableManager disposableManager; - private final OnDemandSource sink = new OnDemandSource<>("apiSource"); - - @PostConstruct - public void init() { - disposableManager.registerDisposable(API_PRODCUER, this::createWfMgmtRunMsgProducer); - } - - private Disposable createWfMgmtRunMsgProducer() { - return createTransProducerStream(rabbit, topicExchangeName, queueName, topicRoutingKeys) - .send(sink.source()) - .subscribe( - tx -> { - log.debug("ApiProducer sent WfMgmtRunMsg: {}", tx.get()); - tx.commit(); - }); - } - - @Bean - Sender sender() { - return sink; - } -} diff --git a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/DisposableManager.java b/src/main/java/org/icgc/argo/workflow_management/rabbitmq/DisposableManager.java deleted file mode 100644 index 0759198..0000000 --- a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/DisposableManager.java +++ /dev/null @@ -1,50 +0,0 @@ -/// * -// * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved -// * -// * This program and the accompanying materials are made available under the terms of the GNU -// Affero General Public License v3.0. -// * You should have received a copy of the GNU Affero General Public License along with -// * this program. If not, see . -// * -// * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -// * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -// * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -// * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -// * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -// * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -// * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -// * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// */ - -package org.icgc.argo.workflow_management.rabbitmq; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.Callable; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.icgc.argo.workflow_management.config.rabbitmq.RabbitSchemaConfig; -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; -import reactor.core.Disposable; - -@Slf4j -@Profile({"gatekeeper", "api", "execute"}) -@AutoConfigureAfter(RabbitSchemaConfig.class) -@Configuration -public class DisposableManager { - public static final String API_PRODCUER = "apiProducer"; - public static final String EXECUTE_CONSUMER = "executeConsumer"; - public static final String GATEKEEPER_PRODUCER = "gatekeeperProducer"; - - private final Map disposablesRegistry = - Collections.synchronizedMap(new HashMap<>()); - - @SneakyThrows - public void registerDisposable(String name, Callable disposableCallable) { - this.disposablesRegistry.put(name, disposableCallable.call()); - } -} diff --git a/src/main/java/org/icgc/argo/workflow_management/service/api_to_wes/ApiToWesService.java b/src/main/java/org/icgc/argo/workflow_management/service/api_to_wes/ApiToWesService.java deleted file mode 100644 index 14d1a02..0000000 --- a/src/main/java/org/icgc/argo/workflow_management/service/api_to_wes/ApiToWesService.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved - * - * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. - * You should have received a copy of the GNU Affero General Public License along with - * this program. If not, see . - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.icgc.argo.workflow_management.service.api_to_wes; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import org.icgc.argo.workflow_management.wes.controller.model.RunsRequest; -import org.icgc.argo.workflow_management.wes.controller.model.RunsResponse; -import org.springframework.security.access.prepost.PreAuthorize; -import reactor.core.publisher.Mono; - -public interface ApiToWesService { - @HasQueryAndMutationAccess - Mono run(RunsRequest runsRequest); - - @HasQueryAndMutationAccess - Mono cancel(String runId); - - @Retention(RetentionPolicy.RUNTIME) - @PreAuthorize("@queryAndMutationScopeChecker.apply(authentication)") - @interface HasQueryAndMutationAccess {} -} diff --git a/src/main/java/org/icgc/argo/workflow_management/service/api_to_wes/impl/ApiProducerToWes.java b/src/main/java/org/icgc/argo/workflow_management/service/api_to_wes/impl/ApiProducerToWes.java deleted file mode 100644 index 065a0b5..0000000 --- a/src/main/java/org/icgc/argo/workflow_management/service/api_to_wes/impl/ApiProducerToWes.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved - * - * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. - * You should have received a copy of the GNU Affero General Public License along with - * this program. If not, see . - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.icgc.argo.workflow_management.service.api_to_wes.impl; - -import static org.icgc.argo.workflow_management.rabbitmq.WfMgmtRunMsgConverters.createWfMgmtRunMsg; -import static org.icgc.argo.workflow_management.util.WesUtils.generateWesRunId; - -import com.pivotal.rabbitmq.source.Sender; -import lombok.val; -import org.icgc.argo.workflow_management.rabbitmq.schema.RunState; -import org.icgc.argo.workflow_management.rabbitmq.schema.WfMgmtRunMsg; -import org.icgc.argo.workflow_management.service.api_to_wes.ApiToWesService; -import org.icgc.argo.workflow_management.wes.controller.model.RunsRequest; -import org.icgc.argo.workflow_management.wes.controller.model.RunsResponse; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Profile; -import org.springframework.stereotype.Service; -import reactor.core.publisher.Mono; - -@Profile("api") -@Service -public class ApiProducerToWes implements ApiToWesService { - - private final Sender sender; - - @Autowired - public ApiProducerToWes(Sender sender) { - this.sender = sender; - } - - @Override - public Mono run(RunsRequest runsRequest) { - val runId = generateWesRunId(); - val msg = createWfMgmtRunMsg(runId, runsRequest, RunState.QUEUED); - return Mono.just(msg).flatMap(sender::send).map(o -> new RunsResponse(runId)); - } - - @Override - public Mono cancel(String runId) { - val event = createWfMgmtRunMsg(runId, RunState.CANCELING); - return Mono.just(event).flatMap(sender::send).map(o -> new RunsResponse(runId)); - } -} diff --git a/src/main/java/org/icgc/argo/workflow_management/service/api_to_wes/impl/DirectToWes.java b/src/main/java/org/icgc/argo/workflow_management/service/api_to_wes/impl/DirectToWes.java deleted file mode 100644 index 5f89214..0000000 --- a/src/main/java/org/icgc/argo/workflow_management/service/api_to_wes/impl/DirectToWes.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved - * - * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. - * You should have received a copy of the GNU Affero General Public License along with - * this program. If not, see . - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.icgc.argo.workflow_management.service.api_to_wes.impl; - -import static org.icgc.argo.workflow_management.util.WesUtils.generateWesRunId; - -import lombok.val; -import org.icgc.argo.workflow_management.service.api_to_wes.ApiToWesService; -import org.icgc.argo.workflow_management.service.wes.WorkflowExecutionService; -import org.icgc.argo.workflow_management.service.wes.model.RunParams; -import org.icgc.argo.workflow_management.wes.controller.model.RunsRequest; -import org.icgc.argo.workflow_management.wes.controller.model.RunsResponse; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Profile; -import org.springframework.stereotype.Service; -import reactor.core.publisher.Mono; - -// Default setup uses no rabbitmq configs setup, so talk directly to WES -@Profile("!api & !execute") -@Service -public class DirectToWes implements ApiToWesService { - - private final WorkflowExecutionService wes; - - @Autowired - public DirectToWes(WorkflowExecutionService wes) { - this.wes = wes; - } - - @Override - public Mono run(RunsRequest runsRequest) { - // create run config from request - val runConfig = - RunParams.builder() - .workflowUrl(runsRequest.getWorkflowUrl()) - .workflowParams(runsRequest.getWorkflowParams()) - .workflowEngineParams(runsRequest.getWorkflowEngineParams()) - .runId(generateWesRunId()) - .build(); - - return wes.run(runConfig); - } - - @Override - public Mono cancel(String runId) { - return wes.cancel(runId); - } -} diff --git a/src/main/java/org/icgc/argo/workflow_management/properties/WebfluxProperties.java b/src/main/java/org/icgc/argo/workflow_management/streams/DisposableManager.java similarity index 64% rename from src/main/java/org/icgc/argo/workflow_management/properties/WebfluxProperties.java rename to src/main/java/org/icgc/argo/workflow_management/streams/DisposableManager.java index e429079..2bb4067 100644 --- a/src/main/java/org/icgc/argo/workflow_management/properties/WebfluxProperties.java +++ b/src/main/java/org/icgc/argo/workflow_management/streams/DisposableManager.java @@ -16,24 +16,26 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.properties; +package org.icgc.argo.workflow_management.streams; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Callable; +import lombok.SneakyThrows; import org.springframework.context.annotation.Configuration; -import org.springframework.web.reactive.config.ResourceHandlerRegistry; -import org.springframework.web.reactive.config.WebFluxConfigurer; +import reactor.core.Disposable; @Configuration -public class WebfluxProperties implements WebFluxConfigurer { +public class DisposableManager { + public static final String WES_CONSUMER = "WESConsumer"; + public static final String GATEKEEPER_PRODUCER = "gatekeeperProducer"; - @Override - public void addResourceHandlers(ResourceHandlerRegistry registry) { + private final Map disposablesRegistry = + Collections.synchronizedMap(new HashMap<>()); - registry - .addResourceHandler("/swagger-ui.html**") - .addResourceLocations("classpath:/META-INF/resources/"); - - registry - .addResourceHandler("/webjars/**") - .addResourceLocations("classpath:/META-INF/resources/webjars/"); + @SneakyThrows + public void registerDisposable(String name, Callable disposableCallable) { + this.disposablesRegistry.put(name, disposableCallable.call()); } } diff --git a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/GateKeeperStreamsConfig.java b/src/main/java/org/icgc/argo/workflow_management/streams/GateKeeperStreamsConfig.java similarity index 89% rename from src/main/java/org/icgc/argo/workflow_management/rabbitmq/GateKeeperStreamsConfig.java rename to src/main/java/org/icgc/argo/workflow_management/streams/GateKeeperStreamsConfig.java index 9352a47..e996cd1 100644 --- a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/GateKeeperStreamsConfig.java +++ b/src/main/java/org/icgc/argo/workflow_management/streams/GateKeeperStreamsConfig.java @@ -16,12 +16,12 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.rabbitmq; +package org.icgc.argo.workflow_management.streams; -import static org.icgc.argo.workflow_management.rabbitmq.DisposableManager.GATEKEEPER_PRODUCER; -import static org.icgc.argo.workflow_management.rabbitmq.WfMgmtRunMsgConverters.createWfMgmtEvent; -import static org.icgc.argo.workflow_management.util.RabbitmqUtils.createTransConsumerStream; -import static org.icgc.argo.workflow_management.util.RabbitmqUtils.createTransProducerStream; +import static org.icgc.argo.workflow_management.streams.DisposableManager.GATEKEEPER_PRODUCER; +import static org.icgc.argo.workflow_management.streams.utils.RabbitmqUtils.createTransConsumerStream; +import static org.icgc.argo.workflow_management.streams.utils.RabbitmqUtils.createTransProducerStream; +import static org.icgc.argo.workflow_management.streams.utils.WfMgmtRunMsgConverters.createWfMgmtEvent; import com.fasterxml.jackson.databind.JsonNode; import com.pivotal.rabbitmq.RabbitEndpointService; @@ -36,9 +36,9 @@ import lombok.val; import org.icgc.argo.workflow_management.config.rabbitmq.RabbitSchemaConfig; import org.icgc.argo.workflow_management.gatekeeper.service.GatekeeperProcessor; -import org.icgc.argo.workflow_management.rabbitmq.schema.RunState; -import org.icgc.argo.workflow_management.rabbitmq.schema.WfMgmtRunMsg; -import org.icgc.argo.workflow_management.service.wes.WebLogEventSender; +import org.icgc.argo.workflow_management.streams.model.WeblogEvent; +import org.icgc.argo.workflow_management.streams.schema.RunState; +import org.icgc.argo.workflow_management.streams.schema.WfMgmtRunMsg; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.context.annotation.Bean; @@ -49,7 +49,7 @@ import reactor.core.publisher.Mono; @Slf4j -@Profile("gatekeeper") +@Profile("gatekeeper & !test") @AutoConfigureAfter(RabbitSchemaConfig.class) @Configuration @RequiredArgsConstructor diff --git a/src/main/java/org/icgc/argo/workflow_management/service/wes/WebLogEventSender.java b/src/main/java/org/icgc/argo/workflow_management/streams/WebLogEventSender.java similarity index 93% rename from src/main/java/org/icgc/argo/workflow_management/service/wes/WebLogEventSender.java rename to src/main/java/org/icgc/argo/workflow_management/streams/WebLogEventSender.java index 0e3d54d..f5e2917 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/wes/WebLogEventSender.java +++ b/src/main/java/org/icgc/argo/workflow_management/streams/WebLogEventSender.java @@ -16,7 +16,7 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.service.wes; +package org.icgc.argo.workflow_management.streams; import static org.icgc.argo.workflow_management.util.JacksonUtils.toJsonString; @@ -27,7 +27,10 @@ import lombok.val; import nextflow.Const; import nextflow.extension.Bolts; -import org.icgc.argo.workflow_management.service.wes.model.*; +import org.icgc.argo.workflow_management.streams.model.NextflowEvent; +import org.icgc.argo.workflow_management.streams.model.WfManagementEvent; +import org.icgc.argo.workflow_management.streams.model.WorkflowEvent; +import org.icgc.argo.workflow_management.wes.model.*; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; import org.springframework.stereotype.Service; diff --git a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/ExecuteConsumerConfig.java b/src/main/java/org/icgc/argo/workflow_management/streams/WesConsumerConfig.java similarity index 66% rename from src/main/java/org/icgc/argo/workflow_management/rabbitmq/ExecuteConsumerConfig.java rename to src/main/java/org/icgc/argo/workflow_management/streams/WesConsumerConfig.java index 09dd6c1..facab4e 100644 --- a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/ExecuteConsumerConfig.java +++ b/src/main/java/org/icgc/argo/workflow_management/streams/WesConsumerConfig.java @@ -16,12 +16,12 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.rabbitmq; +package org.icgc.argo.workflow_management.streams; -import static org.icgc.argo.workflow_management.rabbitmq.DisposableManager.EXECUTE_CONSUMER; -import static org.icgc.argo.workflow_management.rabbitmq.WfMgmtRunMsgConverters.createRunParams; -import static org.icgc.argo.workflow_management.rabbitmq.WfMgmtRunMsgConverters.createWfMgmtEvent; -import static org.icgc.argo.workflow_management.util.RabbitmqUtils.createTransConsumerStream; +import static org.icgc.argo.workflow_management.streams.DisposableManager.WES_CONSUMER; +import static org.icgc.argo.workflow_management.streams.utils.RabbitmqUtils.createTransConsumerStream; +import static org.icgc.argo.workflow_management.streams.utils.WfMgmtRunMsgConverters.createRunParams; +import static org.icgc.argo.workflow_management.streams.utils.WfMgmtRunMsgConverters.createWfMgmtEvent; import com.pivotal.rabbitmq.RabbitEndpointService; import com.pivotal.rabbitmq.stream.Transaction; @@ -33,10 +33,9 @@ import lombok.extern.slf4j.Slf4j; import lombok.val; import org.icgc.argo.workflow_management.config.rabbitmq.RabbitSchemaConfig; -import org.icgc.argo.workflow_management.rabbitmq.schema.RunState; -import org.icgc.argo.workflow_management.rabbitmq.schema.WfMgmtRunMsg; -import org.icgc.argo.workflow_management.service.wes.WebLogEventSender; -import org.icgc.argo.workflow_management.service.wes.WorkflowExecutionService; +import org.icgc.argo.workflow_management.streams.schema.RunState; +import org.icgc.argo.workflow_management.streams.schema.WfMgmtRunMsg; +import org.icgc.argo.workflow_management.wes.WorkflowExecutionService; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.context.annotation.Configuration; @@ -44,24 +43,21 @@ import reactor.core.Disposable; import reactor.util.retry.RetrySpec; -@Profile("execute") @Slf4j +@Profile("!test") @AutoConfigureAfter(RabbitSchemaConfig.class) @Configuration @RequiredArgsConstructor -public class ExecuteConsumerConfig { - @Value("${execute.consumer.topology.queueName}") +public class WesConsumerConfig { + @Value("${wes.consumer.topology.queueName}") private String queueName; - @Value("${execute.consumer.topology.topicExchangeName}") + @Value("${wes.consumer.topology.topicExchangeName}") private String topicExchangeName; - @Value("${execute.consumer.topology.topicRoutingKeys}") + @Value("${wes.consumer.topology.topicRoutingKeys}") private String[] topicRoutingKeys; - @Value("${execute.initializingByMiddleware}") - private Boolean initializingByMiddleware; - private final WebLogEventSender webLogEventSender; private final WorkflowExecutionService wes; private final RabbitEndpointService rabbit; @@ -69,15 +65,14 @@ public class ExecuteConsumerConfig { @PostConstruct public void init() { - disposableManager.registerDisposable( - EXECUTE_CONSUMER, this::createWfMgmtRunMsgForExecuteConsumer); + disposableManager.registerDisposable(WES_CONSUMER, this::createWfMgmtRunMsgForExecuteConsumer); } private Disposable createWfMgmtRunMsgForExecuteConsumer() { return createTransConsumerStream(rabbit, topicExchangeName, queueName, topicRoutingKeys) .receive() .doOnNext(consumeAndExecuteInitializeOrCancel()) - .onErrorContinue(handleError()) + .onErrorContinue(handleRabbitStreamError()) .subscribe(); } @@ -86,10 +81,10 @@ private Consumer> consumeAndExecuteInitializeOrCancel( val msg = tx.get(); log.debug("WfMgmtRunMsg received: {}", msg); - if ((initializingByMiddleware.equals(false) && msg.getState().equals(RunState.QUEUED)) - || (initializingByMiddleware.equals(true) && msg.getState().equals(RunState.INITIALIZING))) { + if (msg.getState().equals(RunState.INITIALIZING)) { val runParams = createRunParams(msg); wes.run(runParams) + .onErrorContinue(handleWesError(tx)) .subscribe( runsResponse -> { log.info("Initialized: {}", msg); @@ -98,6 +93,7 @@ private Consumer> consumeAndExecuteInitializeOrCancel( } else if (msg.getState().equals(RunState.CANCELING)) { wes.cancel(msg.getRunId()) .retryWhen(RetrySpec.backoff(3, Duration.ofMinutes(3))) + .onErrorContinue(handleWesError(tx)) .subscribe( runsResponse -> { log.info("Cancelled: {}", runsResponse); @@ -110,19 +106,35 @@ private Consumer> consumeAndExecuteInitializeOrCancel( }; } - private BiConsumer handleError() { + private BiConsumer handleRabbitStreamError() { return (t, tx) -> { t.printStackTrace(); log.error("Error occurred with: {}", tx); if (tx instanceof Transaction && ((Transaction) tx).get() instanceof WfMgmtRunMsg) { val msg = (WfMgmtRunMsg) ((Transaction) tx).get(); msg.setState(RunState.SYSTEM_ERROR); - log.info("SYSTEM_ERROR: {}", msg); + log.info("Rabbit stream SYSTEM_ERROR msg: {}", msg); + webLogEventSender.sendWfMgmtEventAsync(createWfMgmtEvent(msg)); + ((Transaction) tx).reject(); + } else { + log.error("Transaction is lost, nothing to ack!"); + } + }; + } + + private BiConsumer handleWesError(Transaction tx) { + return (t, obj) -> { + t.printStackTrace(); + log.error("Error occurred with: {}", obj); + if (tx.get() instanceof WfMgmtRunMsg) { + val msg = (WfMgmtRunMsg) tx.get(); + msg.setState(RunState.SYSTEM_ERROR); webLogEventSender.sendWfMgmtEventAsync(createWfMgmtEvent(msg)); - ((Transaction) tx).commit(); + log.error("WES SYSTEM_ERROR msg: {}", msg); } else { - log.error("Can't get WfMgmtRunMsg, transaction is lost!"); + log.error("Can't get WfMgmtRunMsg, nothing to weblog with here!"); } + tx.reject(); }; } } diff --git a/src/main/java/org/icgc/argo/workflow_management/service/wes/model/NextflowEvent.java b/src/main/java/org/icgc/argo/workflow_management/streams/model/NextflowEvent.java similarity index 96% rename from src/main/java/org/icgc/argo/workflow_management/service/wes/model/NextflowEvent.java rename to src/main/java/org/icgc/argo/workflow_management/streams/model/NextflowEvent.java index 0f5b59b..99070d1 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/wes/model/NextflowEvent.java +++ b/src/main/java/org/icgc/argo/workflow_management/streams/model/NextflowEvent.java @@ -16,7 +16,7 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.service.wes.model; +package org.icgc.argo.workflow_management.streams.model; import lombok.Getter; import lombok.NonNull; diff --git a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/WeblogEvent.java b/src/main/java/org/icgc/argo/workflow_management/streams/model/WeblogEvent.java similarity index 92% rename from src/main/java/org/icgc/argo/workflow_management/rabbitmq/WeblogEvent.java rename to src/main/java/org/icgc/argo/workflow_management/streams/model/WeblogEvent.java index bd3e4f6..596ff34 100644 --- a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/WeblogEvent.java +++ b/src/main/java/org/icgc/argo/workflow_management/streams/model/WeblogEvent.java @@ -16,7 +16,7 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.rabbitmq; +package org.icgc.argo.workflow_management.streams.model; import static javax.xml.bind.DatatypeConverter.parseDateTime; @@ -24,9 +24,9 @@ import lombok.Getter; import lombok.NonNull; import lombok.val; -import org.icgc.argo.workflow_management.rabbitmq.schema.EngineParams; -import org.icgc.argo.workflow_management.rabbitmq.schema.RunState; -import org.icgc.argo.workflow_management.rabbitmq.schema.WfMgmtRunMsg; +import org.icgc.argo.workflow_management.streams.schema.EngineParams; +import org.icgc.argo.workflow_management.streams.schema.RunState; +import org.icgc.argo.workflow_management.streams.schema.WfMgmtRunMsg; @Getter public class WeblogEvent { diff --git a/src/main/java/org/icgc/argo/workflow_management/service/wes/model/WfManagementEvent.java b/src/main/java/org/icgc/argo/workflow_management/streams/model/WfManagementEvent.java similarity index 92% rename from src/main/java/org/icgc/argo/workflow_management/service/wes/model/WfManagementEvent.java rename to src/main/java/org/icgc/argo/workflow_management/streams/model/WfManagementEvent.java index f77bcb2..e567fe4 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/wes/model/WfManagementEvent.java +++ b/src/main/java/org/icgc/argo/workflow_management/streams/model/WfManagementEvent.java @@ -16,12 +16,12 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.service.wes.model; +package org.icgc.argo.workflow_management.streams.model; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import java.util.Map; import lombok.*; -import org.icgc.argo.workflow_management.wes.controller.model.WorkflowEngineParams; +import org.icgc.argo.workflow_management.wes.model.WorkflowEngineParams; @Data @Builder diff --git a/src/main/java/org/icgc/argo/workflow_management/service/wes/model/WorkflowEvent.java b/src/main/java/org/icgc/argo/workflow_management/streams/model/WorkflowEvent.java similarity index 91% rename from src/main/java/org/icgc/argo/workflow_management/service/wes/model/WorkflowEvent.java rename to src/main/java/org/icgc/argo/workflow_management/streams/model/WorkflowEvent.java index 5a3a2f1..c5add20 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/wes/model/WorkflowEvent.java +++ b/src/main/java/org/icgc/argo/workflow_management/streams/model/WorkflowEvent.java @@ -16,11 +16,12 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.service.wes.model; +package org.icgc.argo.workflow_management.streams.model; import lombok.Builder; import lombok.NonNull; import lombok.Value; +import org.icgc.argo.workflow_management.wes.model.NextflowMetadata; @Value @Builder diff --git a/src/main/java/org/icgc/argo/workflow_management/util/RabbitmqUtils.java b/src/main/java/org/icgc/argo/workflow_management/streams/utils/RabbitmqUtils.java similarity index 96% rename from src/main/java/org/icgc/argo/workflow_management/util/RabbitmqUtils.java rename to src/main/java/org/icgc/argo/workflow_management/streams/utils/RabbitmqUtils.java index 5cc28f7..3766ff6 100644 --- a/src/main/java/org/icgc/argo/workflow_management/util/RabbitmqUtils.java +++ b/src/main/java/org/icgc/argo/workflow_management/streams/utils/RabbitmqUtils.java @@ -16,7 +16,7 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.util; +package org.icgc.argo.workflow_management.streams.utils; import com.pivotal.rabbitmq.RabbitEndpointService; import com.pivotal.rabbitmq.stream.TransactionalConsumerStream; @@ -25,7 +25,7 @@ import java.util.function.Function; import lombok.experimental.UtilityClass; import lombok.val; -import org.icgc.argo.workflow_management.rabbitmq.schema.WfMgmtRunMsg; +import org.icgc.argo.workflow_management.streams.schema.WfMgmtRunMsg; @UtilityClass public class RabbitmqUtils { diff --git a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/WfMgmtRunMsgConverters.java b/src/main/java/org/icgc/argo/workflow_management/streams/utils/WfMgmtRunMsgConverters.java similarity index 71% rename from src/main/java/org/icgc/argo/workflow_management/rabbitmq/WfMgmtRunMsgConverters.java rename to src/main/java/org/icgc/argo/workflow_management/streams/utils/WfMgmtRunMsgConverters.java index e9bc75d..f4b4e07 100644 --- a/src/main/java/org/icgc/argo/workflow_management/rabbitmq/WfMgmtRunMsgConverters.java +++ b/src/main/java/org/icgc/argo/workflow_management/streams/utils/WfMgmtRunMsgConverters.java @@ -16,7 +16,7 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.rabbitmq; +package org.icgc.argo.workflow_management.streams.utils; import static org.icgc.argo.workflow_management.util.JacksonUtils.*; @@ -29,42 +29,15 @@ import lombok.val; import nextflow.Const; import nextflow.extension.Bolts; -import org.icgc.argo.workflow_management.rabbitmq.schema.EngineParams; -import org.icgc.argo.workflow_management.rabbitmq.schema.RunState; -import org.icgc.argo.workflow_management.rabbitmq.schema.WfMgmtRunMsg; -import org.icgc.argo.workflow_management.service.wes.model.RunParams; -import org.icgc.argo.workflow_management.service.wes.model.WfManagementEvent; -import org.icgc.argo.workflow_management.wes.controller.model.RunsRequest; -import org.icgc.argo.workflow_management.wes.controller.model.WorkflowEngineParams; +import org.icgc.argo.workflow_management.streams.model.WfManagementEvent; +import org.icgc.argo.workflow_management.streams.schema.EngineParams; +import org.icgc.argo.workflow_management.streams.schema.RunState; +import org.icgc.argo.workflow_management.streams.schema.WfMgmtRunMsg; +import org.icgc.argo.workflow_management.wes.model.RunParams; +import org.icgc.argo.workflow_management.wes.model.WorkflowEngineParams; @UtilityClass public class WfMgmtRunMsgConverters { - public static WfMgmtRunMsg createWfMgmtRunMsg( - String runId, RunsRequest runsRequest, RunState state) { - val requestWep = runsRequest.getWorkflowEngineParams(); - - val msgWep = - EngineParams.newBuilder() - .setLatest(requestWep.getLatest()) - .setDefaultContainer(requestWep.getDefaultContainer()) - .setLaunchDir(requestWep.getLaunchDir()) - .setRevision(requestWep.getRevision()) - .setProjectDir(requestWep.getProjectDir()) - .setWorkDir(requestWep.getWorkDir()); - - if (requestWep.getResume() != null) { - msgWep.setResume(requestWep.getResume().toString()); - } - - return WfMgmtRunMsg.newBuilder() - .setRunId(runId) - .setState(state) - .setWorkflowUrl(runsRequest.getWorkflowUrl()) - .setWorkflowParamsJsonStr(toJsonString(runsRequest.getWorkflowParams())) - .setWorkflowEngineParams(msgWep.build()) - .setTimestamp(Instant.now().toEpochMilli()) - .build(); - } public static WfMgmtRunMsg createWfMgmtRunMsg(String runId, RunState state) { return WfMgmtRunMsg.newBuilder() diff --git a/src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowService.java b/src/main/java/org/icgc/argo/workflow_management/wes/NextflowService.java similarity index 96% rename from src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowService.java rename to src/main/java/org/icgc/argo/workflow_management/wes/NextflowService.java index fdcdc11..8060adc 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowService.java +++ b/src/main/java/org/icgc/argo/workflow_management/wes/NextflowService.java @@ -16,11 +16,10 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.service.wes; +package org.icgc.argo.workflow_management.wes; import static java.lang.String.format; import static java.util.Objects.nonNull; -import static org.icgc.argo.workflow_management.service.wes.model.KubernetesPhase.*; import static org.icgc.argo.workflow_management.util.NextflowConfigFile.createNextflowConfigFile; import static org.icgc.argo.workflow_management.util.ParamsFile.createParamsFile; import static org.icgc.argo.workflow_management.util.Reflections.createWithReflection; @@ -45,11 +44,12 @@ import nextflow.script.ScriptBinding; import org.icgc.argo.workflow_management.exception.NextflowRunException; import org.icgc.argo.workflow_management.exception.ReflectionUtilsException; -import org.icgc.argo.workflow_management.secret.SecretProvider; -import org.icgc.argo.workflow_management.service.wes.model.*; -import org.icgc.argo.workflow_management.service.wes.properties.NextflowProperties; +import org.icgc.argo.workflow_management.streams.WebLogEventSender; import org.icgc.argo.workflow_management.util.ConditionalPutMap; -import org.icgc.argo.workflow_management.wes.controller.model.RunsResponse; +import org.icgc.argo.workflow_management.wes.model.*; +import org.icgc.argo.workflow_management.wes.model.RunsResponse; +import org.icgc.argo.workflow_management.wes.properties.NextflowProperties; +import org.icgc.argo.workflow_management.wes.secret.SecretProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import reactor.core.publisher.Mono; @@ -175,13 +175,13 @@ private DefaultKubernetesClient createWorkflowRunK8sClient() { private String cancelRun(@NonNull String runId) { val state = getPhase(runId); - if (state.equals(FAILED)) { + if (state.equals(KubernetesPhase.FAILED)) { return handleFailedPod(runId); } // can only cancel when executor pod is in running or failed state // so throw an exception if not either of those two states - if (!state.equals(RUNNING)) { + if (!state.equals(KubernetesPhase.RUNNING)) { throw new RuntimeException( format( "Executor pod %s is in %s state, can only cancel a running workflow.", runId, state)); @@ -217,7 +217,7 @@ private KubernetesPhase getPhase(String runId) { () -> new RuntimeException( format("Cannot find executor pod with runId: %s.", runId))); - return valueOf(executorPod.getStatus().getPhase().toUpperCase()); + return KubernetesPhase.valueOf(executorPod.getStatus().getPhase().toUpperCase()); } private String handleFailedPod(String podName) { diff --git a/src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowWorkflowMonitor.java b/src/main/java/org/icgc/argo/workflow_management/wes/NextflowWorkflowMonitor.java similarity index 91% rename from src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowWorkflowMonitor.java rename to src/main/java/org/icgc/argo/workflow_management/wes/NextflowWorkflowMonitor.java index f4bb378..81bdcbb 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/wes/NextflowWorkflowMonitor.java +++ b/src/main/java/org/icgc/argo/workflow_management/wes/NextflowWorkflowMonitor.java @@ -16,11 +16,11 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.service.wes; +package org.icgc.argo.workflow_management.wes; import static java.lang.String.format; import static java.time.OffsetDateTime.now; -import static org.icgc.argo.workflow_management.service.wes.NextflowService.NEXTFLOW_PREFIX; +import static org.icgc.argo.workflow_management.wes.NextflowService.NEXTFLOW_PREFIX; import io.fabric8.kubernetes.api.model.DoneablePod; import io.fabric8.kubernetes.api.model.Pod; @@ -31,9 +31,10 @@ import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import lombok.val; -import org.icgc.argo.workflow_management.service.wes.model.KubernetesPhase; -import org.icgc.argo.workflow_management.service.wes.model.NextflowEvent; -import org.icgc.argo.workflow_management.service.wes.model.NextflowMetadata; +import org.icgc.argo.workflow_management.streams.WebLogEventSender; +import org.icgc.argo.workflow_management.streams.model.NextflowEvent; +import org.icgc.argo.workflow_management.wes.model.KubernetesPhase; +import org.icgc.argo.workflow_management.wes.model.NextflowMetadata; @Slf4j @AllArgsConstructor diff --git a/src/main/java/org/icgc/argo/workflow_management/service/wes/WorkflowExecutionService.java b/src/main/java/org/icgc/argo/workflow_management/wes/WorkflowExecutionService.java similarity index 86% rename from src/main/java/org/icgc/argo/workflow_management/service/wes/WorkflowExecutionService.java rename to src/main/java/org/icgc/argo/workflow_management/wes/WorkflowExecutionService.java index b76eb7a..2a0d46b 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/wes/WorkflowExecutionService.java +++ b/src/main/java/org/icgc/argo/workflow_management/wes/WorkflowExecutionService.java @@ -16,10 +16,10 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.service.wes; +package org.icgc.argo.workflow_management.wes; -import org.icgc.argo.workflow_management.service.wes.model.RunParams; -import org.icgc.argo.workflow_management.wes.controller.model.RunsResponse; +import org.icgc.argo.workflow_management.wes.model.RunParams; +import org.icgc.argo.workflow_management.wes.model.RunsResponse; import reactor.core.publisher.Mono; public interface WorkflowExecutionService { diff --git a/src/main/java/org/icgc/argo/workflow_management/wes/controller/RunsApi.java b/src/main/java/org/icgc/argo/workflow_management/wes/controller/RunsApi.java deleted file mode 100644 index 25e6f55..0000000 --- a/src/main/java/org/icgc/argo/workflow_management/wes/controller/RunsApi.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved - * - * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. - * You should have received a copy of the GNU Affero General Public License along with - * this program. If not, see . - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.icgc.argo.workflow_management.wes.controller; - -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; -import javax.validation.Valid; -import org.icgc.argo.workflow_management.exception.model.ErrorResponse; -import org.icgc.argo.workflow_management.wes.controller.model.RunsRequest; -import org.icgc.argo.workflow_management.wes.controller.model.RunsResponse; -import org.springframework.web.bind.annotation.RequestBody; -import reactor.core.publisher.Mono; - -@Api(value = "WorkflowExecutionService", tags = "WorkflowExecutionService") -public interface RunsApi { - - @ApiOperation( - value = "Run a workflow", - nickname = "runs", - notes = - "This endpoint creates a new workflow run and returns a runId to monitor its progress.\n\n" - + "The workflow_attachment is part of the GA4GH WES API Standard however we currently not supporting it as of this release.\n\n" - + "The workflow_url is the workflow GitHub repository URL (ex. icgc-argo/nextflow-dna-seq-alignment) that is accessible by the WES endpoint.\n\n" - + "The workflow_params JSON object specifies the input parameters for a workflow. The exact format of the JSON object depends on the conventions of the workflow.\n\n" - + "The workflow_engine_parameters JSON object specifies additional run-time arguments to the workflow engine (ie. specific workflow version, resuming a workflow, etc.)" - + "The workflow_type is the type of workflow language, currently this WES API supports \"nextflow\" only.\n\n" - + "The workflow_type_version is the version of the workflow language to run the workflow against and must be one supported by this WES instance.\n", - response = RunsResponse.class, - tags = { - "WorkflowExecutionService", - }) - @ApiResponses( - value = { - @ApiResponse(code = 200, message = "", response = RunsResponse.class), - @ApiResponse( - code = 401, - message = "The request is unauthorized.", - response = ErrorResponse.class), - @ApiResponse( - code = 403, - message = "The requester is not authorized to perform this action.", - response = ErrorResponse.class), - @ApiResponse( - code = 404, - message = "The requested workflow run not found.", - response = ErrorResponse.class), - @ApiResponse( - code = 500, - message = "An unexpected error occurred.", - response = ErrorResponse.class) - }) - Mono postRun(@Valid @RequestBody RunsRequest runsRequest); - - @ApiOperation( - value = "Cancel a running workflow", - nickname = "cancel run", - notes = " ", - response = RunsResponse.class, - tags = { - "WorkflowExecutionService", - }) - @ApiResponses( - value = { - @ApiResponse(code = 200, message = "", response = RunsResponse.class), - @ApiResponse( - code = 401, - message = "The request is unauthorized.", - response = ErrorResponse.class), - @ApiResponse( - code = 403, - message = "The requester is not authorized to perform this action.", - response = ErrorResponse.class), - @ApiResponse( - code = 404, - message = "The requested workflow run not found.", - response = ErrorResponse.class), - @ApiResponse( - code = 500, - message = "An unexpected error occurred.", - response = ErrorResponse.class) - }) - Mono cancelRun(@Valid @RequestBody String runId); -} diff --git a/src/main/java/org/icgc/argo/workflow_management/wes/controller/impl/RunsApiController.java b/src/main/java/org/icgc/argo/workflow_management/wes/controller/impl/RunsApiController.java deleted file mode 100644 index ee87f7c..0000000 --- a/src/main/java/org/icgc/argo/workflow_management/wes/controller/impl/RunsApiController.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved - * - * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. - * You should have received a copy of the GNU Affero General Public License along with - * this program. If not, see . - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.icgc.argo.workflow_management.wes.controller.impl; - -import javax.validation.Valid; -import org.icgc.argo.workflow_management.service.api_to_wes.ApiToWesService; -import org.icgc.argo.workflow_management.wes.controller.RunsApi; -import org.icgc.argo.workflow_management.wes.controller.model.RunsRequest; -import org.icgc.argo.workflow_management.wes.controller.model.RunsResponse; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; -import reactor.core.publisher.Mono; - -@RestController -@RequestMapping("/runs") -public class RunsApiController implements RunsApi { - - /** Dependencies */ - private final ApiToWesService apiToWesService; - - @Autowired - public RunsApiController(ApiToWesService apiToWesService) { - this.apiToWesService = apiToWesService; - } - - @PostMapping - public Mono postRun(@Valid @RequestBody RunsRequest runsRequest) { - return apiToWesService.run(runsRequest); - } - - @PostMapping( - path = "/{run_id}/cancel", - produces = {"application/json"}) - public Mono cancelRun(@Valid @PathVariable("run_id") String runId) { - return apiToWesService.cancel(runId); - } -} diff --git a/src/main/java/org/icgc/argo/workflow_management/wes/controller/model/RunsRequest.java b/src/main/java/org/icgc/argo/workflow_management/wes/controller/model/RunsRequest.java deleted file mode 100644 index 55a7027..0000000 --- a/src/main/java/org/icgc/argo/workflow_management/wes/controller/model/RunsRequest.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved - * - * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. - * You should have received a copy of the GNU Affero General Public License along with - * this program. If not, see . - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.icgc.argo.workflow_management.wes.controller.model; - -import com.fasterxml.jackson.databind.PropertyNamingStrategy; -import com.fasterxml.jackson.databind.annotation.JsonNaming; -import io.swagger.annotations.ApiModel; -import java.util.HashMap; -import java.util.Map; -import javax.validation.constraints.NotBlank; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.codehaus.jackson.annotate.JsonIgnoreProperties; - -@Data -@AllArgsConstructor -@NoArgsConstructor -@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) -@JsonIgnoreProperties(ignoreUnknown = true) -@ApiModel(description = "A JSON of required and optional fields to run a workflow") -public class RunsRequest { - @NotBlank(message = "workflow_url is a required field!") - private String workflowUrl; - - private Map workflowParams = new HashMap<>(); - private WorkflowEngineParams workflowEngineParams = new WorkflowEngineParams(); - - private String workflowType; - private String workflowTypeVersion; - private Map tags; -} diff --git a/src/main/java/org/icgc/argo/workflow_management/service/wes/model/KubernetesPhase.java b/src/main/java/org/icgc/argo/workflow_management/wes/model/KubernetesPhase.java similarity index 95% rename from src/main/java/org/icgc/argo/workflow_management/service/wes/model/KubernetesPhase.java rename to src/main/java/org/icgc/argo/workflow_management/wes/model/KubernetesPhase.java index 1a2eca5..18f1562 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/wes/model/KubernetesPhase.java +++ b/src/main/java/org/icgc/argo/workflow_management/wes/model/KubernetesPhase.java @@ -16,7 +16,7 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.service.wes.model; +package org.icgc.argo.workflow_management.wes.model; /** * Kubernetes phases */ public enum KubernetesPhase { diff --git a/src/main/java/org/icgc/argo/workflow_management/service/wes/model/NextflowMetadata.java b/src/main/java/org/icgc/argo/workflow_management/wes/model/NextflowMetadata.java similarity index 95% rename from src/main/java/org/icgc/argo/workflow_management/service/wes/model/NextflowMetadata.java rename to src/main/java/org/icgc/argo/workflow_management/wes/model/NextflowMetadata.java index acd4078..3b979a0 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/wes/model/NextflowMetadata.java +++ b/src/main/java/org/icgc/argo/workflow_management/wes/model/NextflowMetadata.java @@ -16,7 +16,7 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.service.wes.model; +package org.icgc.argo.workflow_management.wes.model; import lombok.Data; import nextflow.script.ScriptBinding.ParamsMap; diff --git a/src/main/java/org/icgc/argo/workflow_management/service/wes/model/NextflowWorkflowMetadata.java b/src/main/java/org/icgc/argo/workflow_management/wes/model/NextflowWorkflowMetadata.java similarity index 98% rename from src/main/java/org/icgc/argo/workflow_management/service/wes/model/NextflowWorkflowMetadata.java rename to src/main/java/org/icgc/argo/workflow_management/wes/model/NextflowWorkflowMetadata.java index 9860d00..2707d22 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/wes/model/NextflowWorkflowMetadata.java +++ b/src/main/java/org/icgc/argo/workflow_management/wes/model/NextflowWorkflowMetadata.java @@ -16,7 +16,7 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.service.wes.model; +package org.icgc.argo.workflow_management.wes.model; import static org.icgc.argo.workflow_management.util.Reflections.invokeDeclaredMethod; diff --git a/src/main/java/org/icgc/argo/workflow_management/service/wes/model/RunParams.java b/src/main/java/org/icgc/argo/workflow_management/wes/model/RunParams.java similarity index 91% rename from src/main/java/org/icgc/argo/workflow_management/service/wes/model/RunParams.java rename to src/main/java/org/icgc/argo/workflow_management/wes/model/RunParams.java index 45cd2bc..d6e2e6d 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/wes/model/RunParams.java +++ b/src/main/java/org/icgc/argo/workflow_management/wes/model/RunParams.java @@ -16,14 +16,13 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.service.wes.model; +package org.icgc.argo.workflow_management.wes.model; import java.util.Map; import lombok.Builder; import lombok.Data; import lombok.NonNull; import lombok.RequiredArgsConstructor; -import org.icgc.argo.workflow_management.wes.controller.model.WorkflowEngineParams; @Data @Builder diff --git a/src/main/java/org/icgc/argo/workflow_management/wes/controller/model/RunsResponse.java b/src/main/java/org/icgc/argo/workflow_management/wes/model/RunsResponse.java similarity index 87% rename from src/main/java/org/icgc/argo/workflow_management/wes/controller/model/RunsResponse.java rename to src/main/java/org/icgc/argo/workflow_management/wes/model/RunsResponse.java index 3fcf7ee..d11522a 100644 --- a/src/main/java/org/icgc/argo/workflow_management/wes/controller/model/RunsResponse.java +++ b/src/main/java/org/icgc/argo/workflow_management/wes/model/RunsResponse.java @@ -16,11 +16,10 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.wes.controller.model; +package org.icgc.argo.workflow_management.wes.model; import com.fasterxml.jackson.databind.PropertyNamingStrategy; import com.fasterxml.jackson.databind.annotation.JsonNaming; -import io.swagger.annotations.ApiModel; import javax.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Data; @@ -30,9 +29,6 @@ @AllArgsConstructor @NoArgsConstructor @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) -@ApiModel( - description = - "A successful run will return the runId which can be used to get info about that run") public class RunsResponse { @NotNull private String runId; } diff --git a/src/main/java/org/icgc/argo/workflow_management/service/wes/model/WesState.java b/src/main/java/org/icgc/argo/workflow_management/wes/model/WesState.java similarity index 96% rename from src/main/java/org/icgc/argo/workflow_management/service/wes/model/WesState.java rename to src/main/java/org/icgc/argo/workflow_management/wes/model/WesState.java index 60deaa8..2d0b290 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/wes/model/WesState.java +++ b/src/main/java/org/icgc/argo/workflow_management/wes/model/WesState.java @@ -16,7 +16,7 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.service.wes.model; +package org.icgc.argo.workflow_management.wes.model; import lombok.Getter; import lombok.NonNull; diff --git a/src/main/java/org/icgc/argo/workflow_management/wes/controller/model/WorkflowEngineParams.java b/src/main/java/org/icgc/argo/workflow_management/wes/model/WorkflowEngineParams.java similarity index 90% rename from src/main/java/org/icgc/argo/workflow_management/wes/controller/model/WorkflowEngineParams.java rename to src/main/java/org/icgc/argo/workflow_management/wes/model/WorkflowEngineParams.java index cd37828..da0a3bd 100644 --- a/src/main/java/org/icgc/argo/workflow_management/wes/controller/model/WorkflowEngineParams.java +++ b/src/main/java/org/icgc/argo/workflow_management/wes/model/WorkflowEngineParams.java @@ -16,11 +16,10 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.wes.controller.model; +package org.icgc.argo.workflow_management.wes.model; import com.fasterxml.jackson.databind.PropertyNamingStrategy; import com.fasterxml.jackson.databind.annotation.JsonNaming; -import io.swagger.annotations.ApiModel; import java.util.UUID; import lombok.AllArgsConstructor; import lombok.Builder; @@ -34,7 +33,6 @@ @NoArgsConstructor @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) @JsonIgnoreProperties(ignoreUnknown = true) -@ApiModel(description = "Describes valid workflow engine parameters (part of RunsRequest)") public class WorkflowEngineParams { private String defaultContainer; private String revision; diff --git a/src/main/java/org/icgc/argo/workflow_management/service/wes/properties/NextflowProperties.java b/src/main/java/org/icgc/argo/workflow_management/wes/properties/NextflowProperties.java similarity index 96% rename from src/main/java/org/icgc/argo/workflow_management/service/wes/properties/NextflowProperties.java rename to src/main/java/org/icgc/argo/workflow_management/wes/properties/NextflowProperties.java index e3ebbc6..a17093f 100644 --- a/src/main/java/org/icgc/argo/workflow_management/service/wes/properties/NextflowProperties.java +++ b/src/main/java/org/icgc/argo/workflow_management/wes/properties/NextflowProperties.java @@ -16,7 +16,7 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.service.wes.properties; +package org.icgc.argo.workflow_management.wes.properties; import java.util.List; import lombok.Data; diff --git a/src/main/java/org/icgc/argo/workflow_management/secret/SecretProvider.java b/src/main/java/org/icgc/argo/workflow_management/wes/secret/SecretProvider.java similarity index 96% rename from src/main/java/org/icgc/argo/workflow_management/secret/SecretProvider.java rename to src/main/java/org/icgc/argo/workflow_management/wes/secret/SecretProvider.java index 9da7c3b..17b3e12 100644 --- a/src/main/java/org/icgc/argo/workflow_management/secret/SecretProvider.java +++ b/src/main/java/org/icgc/argo/workflow_management/wes/secret/SecretProvider.java @@ -16,7 +16,7 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.secret; +package org.icgc.argo.workflow_management.wes.secret; import java.util.List; import java.util.Optional; diff --git a/src/main/java/org/icgc/argo/workflow_management/secret/impl/ApiKeyProvider.java b/src/main/java/org/icgc/argo/workflow_management/wes/secret/impl/ApiKeyProvider.java similarity index 94% rename from src/main/java/org/icgc/argo/workflow_management/secret/impl/ApiKeyProvider.java rename to src/main/java/org/icgc/argo/workflow_management/wes/secret/impl/ApiKeyProvider.java index 6deb83b..f9483ea 100644 --- a/src/main/java/org/icgc/argo/workflow_management/secret/impl/ApiKeyProvider.java +++ b/src/main/java/org/icgc/argo/workflow_management/wes/secret/impl/ApiKeyProvider.java @@ -16,13 +16,13 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.secret.impl; +package org.icgc.argo.workflow_management.wes.secret.impl; import java.util.List; import java.util.Optional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.icgc.argo.workflow_management.secret.SecretProvider; +import org.icgc.argo.workflow_management.wes.secret.SecretProvider; @Slf4j @RequiredArgsConstructor diff --git a/src/main/java/org/icgc/argo/workflow_management/secret/impl/NoSecretProvider.java b/src/main/java/org/icgc/argo/workflow_management/wes/secret/impl/NoSecretProvider.java similarity index 93% rename from src/main/java/org/icgc/argo/workflow_management/secret/impl/NoSecretProvider.java rename to src/main/java/org/icgc/argo/workflow_management/wes/secret/impl/NoSecretProvider.java index 3602b64..d354dcc 100644 --- a/src/main/java/org/icgc/argo/workflow_management/secret/impl/NoSecretProvider.java +++ b/src/main/java/org/icgc/argo/workflow_management/wes/secret/impl/NoSecretProvider.java @@ -16,12 +16,12 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.secret.impl; +package org.icgc.argo.workflow_management.wes.secret.impl; import java.util.List; import java.util.Optional; import lombok.extern.slf4j.Slf4j; -import org.icgc.argo.workflow_management.secret.SecretProvider; +import org.icgc.argo.workflow_management.wes.secret.SecretProvider; @Slf4j public class NoSecretProvider extends SecretProvider { diff --git a/src/main/java/org/icgc/argo/workflow_management/secret/impl/OAuth2BearerTokenProvider.java b/src/main/java/org/icgc/argo/workflow_management/wes/secret/impl/OAuth2BearerTokenProvider.java similarity index 96% rename from src/main/java/org/icgc/argo/workflow_management/secret/impl/OAuth2BearerTokenProvider.java rename to src/main/java/org/icgc/argo/workflow_management/wes/secret/impl/OAuth2BearerTokenProvider.java index 580f0df..01bf888 100644 --- a/src/main/java/org/icgc/argo/workflow_management/secret/impl/OAuth2BearerTokenProvider.java +++ b/src/main/java/org/icgc/argo/workflow_management/wes/secret/impl/OAuth2BearerTokenProvider.java @@ -16,7 +16,7 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.icgc.argo.workflow_management.secret.impl; +package org.icgc.argo.workflow_management.wes.secret.impl; import java.util.List; import java.util.Optional; @@ -24,7 +24,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import lombok.val; -import org.icgc.argo.workflow_management.secret.SecretProvider; +import org.icgc.argo.workflow_management.wes.secret.SecretProvider; import org.springframework.security.oauth2.client.OAuth2RestTemplate; import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails; diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index ddb2ca2..b4fa9bb 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -16,6 +16,11 @@ nextflow: secret: enabled: false +logging.level: + com.pivotal: debug + # org.springframework: debug + org.icgc.argo: debug + --- spring.profiles: secure auth: @@ -44,8 +49,6 @@ secret: tokenUri: http://localhost:8080/oauth/token --- -spring.profiles: api,execute,gatekeeper - rabbit: default-endpoint-name: standalone endpoints: @@ -55,33 +58,20 @@ rabbit: username: user password: pass ---- -spring.profiles: api - -api.producer.topology: - queueName: "gatekeeper-in-queue" - topicExchangeName: "gatekeeper-in" - topicRoutingKeys: "#" # comma separated Array of keys - ---- -spring.profiles: execute - -execute.consumer.topology: +wes.consumer.topology: queueName: "execute-queue" - topicExchangeName: "gatekeeper-out" + topicExchangeName: "mgmt-in" topicRoutingKeys: "INITIALIZING, CANCELING" # comma separated Array of keys -execute.initializingByMiddleware: true - --- spring.profiles: gatekeeper gatekeeper.consumer.topology: queueName: "gatekeeper-in-queue" - topicExchangeName: "gatekeeper-in" + topicExchangeName: "mgmt-in" gatekeeper.producer.topology: - queueName: "gatekeeper-out-default-queue" + queueName: "gatekeeper-out-default" topicExchangeName: "gatekeeper-out" spring.cloud.stream: @@ -112,7 +102,7 @@ spring.jpa: ddl-auto: update --- -spring.profiles: gatekeeper-test +spring.profiles: test spring.jpa: hibernate: diff --git a/src/main/resources/avro/WfMgmtRunMsg.avsc b/src/main/resources/avro/WfMgmtRunMsg.avsc index 0897f01..8095b1c 100644 --- a/src/main/resources/avro/WfMgmtRunMsg.avsc +++ b/src/main/resources/avro/WfMgmtRunMsg.avsc @@ -1,7 +1,7 @@ { "type": "record", "name": "WfMgmtRunMsg", - "namespace": "org.icgc.argo.workflow_management.rabbitmq.schema", + "namespace": "org.icgc.argo.workflow_management.streams.schema", "fields": [ { "name": "timestamp", diff --git a/src/main/resources/schema.graphql b/src/main/resources/schema.graphql index 1378bf4..90e970b 100644 --- a/src/main/resources/schema.graphql +++ b/src/main/resources/schema.graphql @@ -1,33 +1,5 @@ scalar JSON -type RunsResponse { - runId: ID -} - -input WorkflowEngineParams { - defaultContainer: String - revision: String - resume: ID - launchDir: String - projectDir: String - workDir: String - latest: Boolean -} - -input RunsRequest { - workflowUrl: String! - workflowEngineParams: WorkflowEngineParams - workflowParams: JSON - workflowType: String - workflowTypeVersion: String - tags: JSON -} - -type Mutation { - startRun(request: RunsRequest!): RunsResponse - cancelRun(runId: ID!): RunsResponse -} - type SearchResultInfo { contentCount: String! hasNextFrom: String! @@ -44,7 +16,7 @@ type EngineParameters { latest: String } -type ActiveRun { +type Run { runId: String! state: String! workflowUrl: String! @@ -65,8 +37,8 @@ input Example { timestamp: String } -type ActiveRunsSearchResult { - content: [ActiveRun!] +type RunsSearchResult { + content: [Run!] info: SearchResultInfo! } @@ -92,5 +64,5 @@ input Sort { } type Query { - activeRuns(example: Example, page: Page, sorts: [Sort]): ActiveRunsSearchResult + runs(example: Example, page: Page, sorts: [Sort]): RunsSearchResult } diff --git a/src/test/java/org/icgc/argo/workflow_management/ConditionalPutMapTest.java b/src/test/java/org/icgc/argo/workflow_management/ConditionalPutMapTest.java index 6610315..db27f4f 100644 --- a/src/test/java/org/icgc/argo/workflow_management/ConditionalPutMapTest.java +++ b/src/test/java/org/icgc/argo/workflow_management/ConditionalPutMapTest.java @@ -26,12 +26,7 @@ import lombok.val; import org.icgc.argo.workflow_management.util.ConditionalPutMap; import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; -@SpringBootTest -@RunWith(SpringRunner.class) public class ConditionalPutMapTest { @Test public void testConditionalPutMap() { diff --git a/src/test/java/org/icgc/argo/workflow_management/ErrorHandlingTests.java b/src/test/java/org/icgc/argo/workflow_management/ErrorHandlingTests.java deleted file mode 100644 index e258274..0000000 --- a/src/test/java/org/icgc/argo/workflow_management/ErrorHandlingTests.java +++ /dev/null @@ -1,371 +0,0 @@ -/* - * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved - * - * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. - * You should have received a copy of the GNU Affero General Public License along with - * this program. If not, see . - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.icgc.argo.workflow_management; - -import static java.lang.String.format; -import static org.hamcrest.Matchers.*; -import static org.icgc.argo.workflow_management.util.RandomGenerator.createRandomGenerator; -import static org.icgc.argo.workflow_management.util.Reflections.findResponseStatusAnnotation; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.reset; -import static org.springframework.http.HttpStatus.*; -import static org.springframework.http.MediaType.APPLICATION_JSON; -import static org.springframework.web.reactive.function.BodyInserters.fromValue; - -import com.google.common.collect.Maps; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.Optional; -import java.util.function.Supplier; -import lombok.extern.slf4j.Slf4j; -import lombok.val; -import nextflow.exception.*; -import org.icgc.argo.workflow_management.config.secret.NoSecretProviderConfig; -import org.icgc.argo.workflow_management.config.security.AuthDisabledConfig; -import org.icgc.argo.workflow_management.exception.GlobalExceptionHandler; -import org.icgc.argo.workflow_management.service.api_to_wes.ApiToWesService; -import org.icgc.argo.workflow_management.service.api_to_wes.impl.DirectToWes; -import org.icgc.argo.workflow_management.service.wes.NextflowService; -import org.icgc.argo.workflow_management.service.wes.WebLogEventSender; -import org.icgc.argo.workflow_management.service.wes.properties.NextflowProperties; -import org.icgc.argo.workflow_management.wes.controller.impl.RunsApiController; -import org.icgc.argo.workflow_management.wes.controller.model.RunsRequest; -import org.junit.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; -import org.springframework.context.annotation.Import; -import org.springframework.http.HttpStatus; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.test.web.reactive.server.WebTestClient; -import org.springframework.test.web.reactive.server.WebTestClient.ResponseSpec; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.reactive.function.client.WebClientResponseException; -import org.springframework.web.server.ResponseStatusException; - -// TODO: rtisma create test for -// https://github.com/${owner}/${repo}/blob/${branch}/${path-to-file} -@Slf4j -@Import( - value = { - NoSecretProviderConfig.class, - DirectToWes.class, - NextflowService.class, - WebLogEventSender.class, - NextflowProperties.class, - GlobalExceptionHandler.class, - AuthDisabledConfig.class - }) -@RunWith(SpringRunner.class) -@ExtendWith(SpringExtension.class) -@WebFluxTest(controllers = RunsApiController.class) -public class ErrorHandlingTests { - - @Mock private ApiToWesService apiToWesService; - - @Autowired private RunsApiController controller; - - @Autowired private WebTestClient webClient; - - private static Optional> getStringConstructor( - Class klazz) { - try { - return Optional.of(klazz.getDeclaredConstructor(String.class)); - } catch (NoSuchMethodException e) { - return Optional.empty(); - } - } - - private static boolean hasArgumentlessConstructor(Class clazz) { - try { - return clazz.getConstructor().getParameterCount() == 0; - } catch (NoSuchMethodException e) { - return false; - } - } - - /** - * Test when a Netflow exception mapped as NOT_FOUND is thrown, the server responds with an - * ErrorResponse with status NOT_FOUND - */ - @Test - public void testNotFoundErrorHandling() { - doRunRequestError(MissingFileException::new, NOT_FOUND) - .expectBody() - .jsonPath("$.status_code", NOT_FOUND); - } - - /** - * Test when a Netflow exception mapped as CONFLICT is thrown, the server responds with an - * ErrorResponse with status CONFLICT - */ - @Test - public void testConflictErrorHandling() { - doRunRequestError(DuplicateProcessInvocation::new, CONFLICT) - .expectBody() - .jsonPath("$.status_code", CONFLICT); - } - - /** - * Test when a Netflow exception mapped as BAD_REQUEST is thrown, the server responds with an - * ErrorResponse with status BAD_REQUEST - */ - @Test - public void testBadRequestErrorHandling() { - doRunRequestError(IllegalFileException::new, BAD_REQUEST) - .expectBody() - .jsonPath("$.status_code", BAD_REQUEST); - } - - /** - * Test when a Netflow exception mapped as UNPROCESSABLE_ENTITY is thrown, the server responds - * with an ErrorResponse with status UNPROCESSABLE_ENTITY - */ - @Test - public void testUnprocessableEntityErrorHandling() { - doRunRequestError(AbortOperationException::new, UNPROCESSABLE_ENTITY) - .expectBody() - .jsonPath("$.status_code", UNPROCESSABLE_ENTITY); - } - - /** - * Test when a Netflow exception mapped as INTERNAL_SERVER_ERROR is thrown, the server responds - * with an ErrorResponse with status INTERNAL_SERVER_ERROR - */ - @Test - public void testInternalServerErrorErrorHandling() { - doRunRequestError(AbortRunException::new, INTERNAL_SERVER_ERROR) - .expectBody() - .jsonPath("$.status_code", INTERNAL_SERVER_ERROR); - } - - /** - * Test when an exception of type WebClientResponseException is thrown, the server responds with - * an ErrorResponse with the associated HttpStatus - */ - @Test - public void testWebClientResponseErrorHandling() { - val rg = createRandomGenerator("randomGen1"); - val randomHttpStatus = rg.randomEnum(HttpStatus.class, HttpStatus::isError); - doRunRequestError( - () -> - WebClientResponseException.create( - randomHttpStatus.value(), randomHttpStatus.name(), null, null, null), - randomHttpStatus) - .expectBody() - .jsonPath("$.status_code", randomHttpStatus); - } - - /** - * Test when exceptions of type ResponseStatusException are thrown, the server responds with an - * ErrorResponse with the associated HttpStatus - */ - @Test - public void testResponseStatusExceptionErrorHandling() { - val rg = createRandomGenerator("randomGen1"); - val randomHttpStatus = rg.randomEnum(HttpStatus.class, HttpStatus::isError); - doRunRequestError( - () -> new ResponseStatusException(randomHttpStatus, randomHttpStatus.getReasonPhrase()), - randomHttpStatus) - .expectBody() - .jsonPath("$.status_code", randomHttpStatus); - } - - /** - * Test that when an exception annotated with @ResponseStatus(SOME_HTTP_STATUS) is thrown, a - * responds of type ErrorResponse is returned with the specified HttpStatus - */ - @Test - public void testResponseStatusAnnotation() { - runResponseStatusAnnotationTest(ResponseStatusTest1Exception.class, BANDWIDTH_LIMIT_EXCEEDED); - runResponseStatusAnnotationTest(ResponseStatusTest2Exception.class, NOT_FOUND); - } - - /** Test that an invalid RunsRequest will throw BAD_REQUEST http status errors */ - @Test - public void testInvalidRunsRequest() { - // Assert a request with all fields null returns a BAD_REQUEST - val reqAllNull = new RunsRequest(); - postRunRequestForError(reqAllNull, BAD_REQUEST) - .expectBody() - .jsonPath("$.status_code") - .isEqualTo(BAD_REQUEST.value()) - .jsonPath("$.msg") - .value(containsString("workflow_url is a required field!")); - - // Assert a request with only the workflowParams field defined returns a BAD_REQUEST - val reqWorkflowUrlUndefined = new RunsRequest(); - reqWorkflowUrlUndefined.setWorkflowParams(Maps.newHashMap()); - postRunRequestForError(reqWorkflowUrlUndefined, BAD_REQUEST) - .expectBody() - .jsonPath("$.status_code") - .isEqualTo(BAD_REQUEST.value()) - .jsonPath("$.msg") - .value(containsString("workflow_url is a required field!")); - - // Assert a request with the workflowParams fields defined, - // and an empty string for the workflowUrl return a BAD_REQUEST - val reqWorkflowUrlEmpty = new RunsRequest(); - reqWorkflowUrlEmpty.setWorkflowParams(Maps.newHashMap()); - reqWorkflowUrlEmpty.setWorkflowUrl(""); - postRunRequestForError(reqWorkflowUrlEmpty, BAD_REQUEST) - .expectBody() - .jsonPath("$.status_code") - .isEqualTo(BAD_REQUEST.value()) - .jsonPath("$.msg") - .value(containsString("workflow_url is a required field!")); - } - - /** - * Ensure exceptions NOT defined in the CustomErrorHandler are handled as INTERNAL_SERVER_ERROR - * errors - */ - @Test - public void testUnhandledException() { - // Set up request - val req = new RunsRequest(); - req.setWorkflowUrl("sdf"); - req.setWorkflowParams(Maps.newHashMap()); - - setup(SomeUnhandledTestException::new); - - // Assert an INTERNAL_SERVER_ERROR is thrown for the custom unhandled exception - postRunRequestForError(req, INTERNAL_SERVER_ERROR) - .expectStatus() - .isEqualTo(INTERNAL_SERVER_ERROR) - .expectBody() - .jsonPath("$.status_code") - .isEqualTo(INTERNAL_SERVER_ERROR.value()) - .jsonPath("$.msg") - .value(not(emptyOrNullString())); - } - - private ResponseSpec postRunRequest(RunsRequest r) { - return webClient - .post() - .uri("/runs") - .contentType(APPLICATION_JSON) - .accept(APPLICATION_JSON) - .body(fromValue(r)) - .exchange(); - } - - private ResponseSpec postRunRequestForError(RunsRequest r, HttpStatus errorStatus) { - assertTrue(errorStatus.isError()); - return postRunRequest(r) - .expectStatus() - .isEqualTo(errorStatus) - .expectHeader() - .contentType(APPLICATION_JSON); - } - - private ResponseSpec doRunRequestError( - Supplier exceptionSupplier, HttpStatus expectedStatus) { - val req = new RunsRequest(); - req.setWorkflowUrl("sdf"); - req.setWorkflowParams(Maps.newHashMap()); - setup(exceptionSupplier); - return postRunRequestForError(req, expectedStatus); - } - - private void setup(Supplier exceptionSupplier) { - // Replace nextflowService dependency in the controller with a mock - assertNotNull( - ReflectionTestUtils.getField(controller, "apiToWesService"), - "Test setup uses reflection to inject mock into controller field, but field not found!"); - - ReflectionTestUtils.setField(controller, "apiToWesService", apiToWesService); - - // Setup the mock to throw an exception - reset(apiToWesService); - given(apiToWesService.run(Mockito.any())) - .willAnswer( - i -> { - throw exceptionSupplier.get(); - }); - } - - private void setupSingleStringConstructor( - Class klazz, Constructor exceptionConstructor) { - setup( - () -> { - try { - return exceptionConstructor.newInstance("something"); - } catch (IllegalAccessException | InstantiationException | InvocationTargetException e) { - fail(format("Could not instantiate '%s'", klazz.getSimpleName())); - return null; - } - }); - } - - private void runResponseStatusAnnotationTest( - Class exceptionClass, HttpStatus expectedErrorStatus) { - val req = new RunsRequest(); - req.setWorkflowUrl("sdf"); - req.setWorkflowParams(Maps.newHashMap()); - - // Check the exception class used in this test has a single string argument constructor - val result = getStringConstructor(exceptionClass); - assertTrue( - result.isPresent(), - format( - "The class '%s' does not contain a constructor that takes a single String argument", - exceptionClass.getSimpleName())); - - // Check the exeption class used in this test is annotated with ResponseStatus - assertTrue( - findResponseStatusAnnotation(exceptionClass).isPresent(), - format( - "The class '%s' does not contain the ResponseStatus annotation", - exceptionClass.getSimpleName())); - - setupSingleStringConstructor(exceptionClass, result.get()); - - postRunRequestForError(req, expectedErrorStatus) - .expectStatus() - .isEqualTo(expectedErrorStatus) - .expectBody() - .jsonPath("$.status_code") - .isEqualTo(expectedErrorStatus.value()); - } - - public static class SomeUnhandledTestException extends RuntimeException { - public SomeUnhandledTestException() {} - } - - @ResponseStatus(BANDWIDTH_LIMIT_EXCEEDED) - public static class ResponseStatusTest1Exception extends RuntimeException { - public ResponseStatusTest1Exception(String message) { - super(message); - } - } - - @ResponseStatus(NOT_FOUND) - public static class ResponseStatusTest2Exception extends Exception { - public ResponseStatusTest2Exception(String message) { - super(message); - } - } -} diff --git a/src/test/java/org/icgc/argo/workflow_management/GateKeeperProcessorTests.java b/src/test/java/org/icgc/argo/workflow_management/GateKeeperProcessorTests.java index 0b87321..78e447b 100644 --- a/src/test/java/org/icgc/argo/workflow_management/GateKeeperProcessorTests.java +++ b/src/test/java/org/icgc/argo/workflow_management/GateKeeperProcessorTests.java @@ -18,7 +18,7 @@ package org.icgc.argo.workflow_management; -import static org.icgc.argo.workflow_management.rabbitmq.WfMgmtRunMsgConverters.createWfMgmtRunMsg; +import static org.icgc.argo.workflow_management.streams.utils.WfMgmtRunMsgConverters.createWfMgmtRunMsg; import static org.icgc.argo.workflow_management.util.TransactionUtils.*; import static org.icgc.argo.workflow_management.util.WesUtils.generateWesRunId; import static org.junit.Assert.*; @@ -30,8 +30,8 @@ import lombok.extern.slf4j.Slf4j; import lombok.val; import org.icgc.argo.workflow_management.gatekeeper.service.GatekeeperProcessor; -import org.icgc.argo.workflow_management.rabbitmq.schema.RunState; -import org.icgc.argo.workflow_management.rabbitmq.schema.WfMgmtRunMsg; +import org.icgc.argo.workflow_management.streams.schema.RunState; +import org.icgc.argo.workflow_management.streams.schema.WfMgmtRunMsg; import org.junit.ClassRule; import org.junit.Test; import org.junit.runner.RunWith; @@ -54,7 +54,7 @@ * flux) into the GateKeeperProcessor and the output is asserted as expected. */ @Slf4j -@ActiveProfiles("gatekeeper-test") +@ActiveProfiles({"gatekeeper", "test"}) @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest @ContextConfiguration(initializers = {GateKeeperProcessorTests.Initializer.class}) diff --git a/src/test/java/org/icgc/argo/workflow_management/WorkflowManagementApplicationTests.java b/src/test/java/org/icgc/argo/workflow_management/WorkflowManagementApplicationTests.java index 6be4590..d737929 100644 --- a/src/test/java/org/icgc/argo/workflow_management/WorkflowManagementApplicationTests.java +++ b/src/test/java/org/icgc/argo/workflow_management/WorkflowManagementApplicationTests.java @@ -21,8 +21,10 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringRunner; +@ActiveProfiles("test") @SpringBootTest @RunWith(SpringRunner.class) public class WorkflowManagementApplicationTests { From ab175f3d959cd41438734fecd64b5b3c58ccf939 Mon Sep 17 00:00:00 2001 From: jaserud Date: Thu, 6 May 2021 10:22:12 -0400 Subject: [PATCH 12/18] Fix table schema (#164) * explicit json type on params and engineparams * update config value, stringtype=unspecified --- docker-compose-gatekeeper.yaml | 2 +- .../icgc/argo/workflow_management/gatekeeper/model/Run.java | 3 +++ src/main/resources/application.yml | 2 +- .../argo/workflow_management/GateKeeperProcessorTests.java | 4 +++- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/docker-compose-gatekeeper.yaml b/docker-compose-gatekeeper.yaml index 1f1ea79..57daeae 100644 --- a/docker-compose-gatekeeper.yaml +++ b/docker-compose-gatekeeper.yaml @@ -2,7 +2,7 @@ version: '3' services: gatekeeper-db: - image: postgres:10-alpine + image: docker.io/bitnami/postgresql:10-debian-10 environment: POSTGRES_DB: gatekeeperdb POSTGRES_PASSWORD: mysecretpassword diff --git a/src/main/java/org/icgc/argo/workflow_management/gatekeeper/model/Run.java b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/model/Run.java index 78b05a1..d741160 100644 --- a/src/main/java/org/icgc/argo/workflow_management/gatekeeper/model/Run.java +++ b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/model/Run.java @@ -16,12 +16,15 @@ public class Run { private String workflowUrl; private String workflowType; private String workflowTypeVersion; + + @Column(columnDefinition = "json") private String workflowParamsJsonStr; @Enumerated(EnumType.STRING) private RunState state; @Convert(converter = EngineParamsConverter.class) + @Column(columnDefinition = "json") private EngineParams workflowEngineParams; private Long timestamp; diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index b4fa9bb..5bf876e 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -94,7 +94,7 @@ spring.cloud.stream: # startOffset: earliest spring.datasource: - url: jdbc:postgresql://localhost:5432/gatekeeperdb + url: jdbc:postgresql://localhost:5432/gatekeeperdb?stringtype=unspecified username: postgres password: mysecretpassword spring.jpa: diff --git a/src/test/java/org/icgc/argo/workflow_management/GateKeeperProcessorTests.java b/src/test/java/org/icgc/argo/workflow_management/GateKeeperProcessorTests.java index 78e447b..a68dcb3 100644 --- a/src/test/java/org/icgc/argo/workflow_management/GateKeeperProcessorTests.java +++ b/src/test/java/org/icgc/argo/workflow_management/GateKeeperProcessorTests.java @@ -259,7 +259,9 @@ static class Initializer implements ApplicationContextInitializer { public void initialize(ConfigurableApplicationContext configurableApplicationContext) { TestPropertyValues.of( - "spring.datasource.url=" + postgreSQLContainer.getJdbcUrl(), + "spring.datasource.url=" + + postgreSQLContainer.getJdbcUrl() + + "&stringtype=unspecified", "spring.datasource.username=" + postgreSQLContainer.getUsername(), "spring.datasource.password=" + postgreSQLContainer.getPassword()) .applyTo(configurableApplicationContext.getEnvironment()); From 81545f1aa048d3ac483baf5bc6a2be5463b20585 Mon Sep 17 00:00:00 2001 From: jaserud Date: Wed, 12 May 2021 09:25:44 -0400 Subject: [PATCH 13/18] refactor WesConsumerConfig and adds health check (#165) * add health check for disposables * cleanup WesConsumerConfig and optimize imports * make requested changes --- docker-compose-gatekeeper.yaml | 17 ++++ .../config/security/AuthEnabledConfig.java | 5 +- .../gatekeeper/service/StateTransition.java | 1 - .../health/DisposableHealthIndicator.java | 53 ++++++++++ .../streams/DisposableManager.java | 2 + .../streams/WebLogEventSender.java | 4 +- .../streams/WesConsumerConfig.java | 99 ++++++++----------- .../streams/utils/WfMgmtRunMsgConverters.java | 2 +- .../wes/NextflowService.java | 1 - .../GateKeeperProcessorTests.java | 3 +- 10 files changed, 124 insertions(+), 63 deletions(-) create mode 100644 src/main/java/org/icgc/argo/workflow_management/health/DisposableHealthIndicator.java diff --git a/docker-compose-gatekeeper.yaml b/docker-compose-gatekeeper.yaml index 57daeae..fcea1e3 100644 --- a/docker-compose-gatekeeper.yaml +++ b/docker-compose-gatekeeper.yaml @@ -18,3 +18,20 @@ services: ports: - 5672:5672 - 15672:15672 + zookeeper: + image: wurstmeister/zookeeper + ports: + - "2181:2181" + broker: + image: wurstmeister/kafka:2.13-2.6.0 + hostname: broker + container_name: broker + depends_on: + - zookeeper + ports: + - "9092:9092" + environment: + KAFKA_ADVERTISED_HOST_NAME: localhost + KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 + volumes: + - /var/run/docker.sock:/var/run/docker.sock diff --git a/src/main/java/org/icgc/argo/workflow_management/config/security/AuthEnabledConfig.java b/src/main/java/org/icgc/argo/workflow_management/config/security/AuthEnabledConfig.java index aacf934..66326a4 100644 --- a/src/main/java/org/icgc/argo/workflow_management/config/security/AuthEnabledConfig.java +++ b/src/main/java/org/icgc/argo/workflow_management/config/security/AuthEnabledConfig.java @@ -27,7 +27,10 @@ import java.security.KeyFactory; import java.security.interfaces.RSAPublicKey; import java.security.spec.X509EncodedKeySpec; -import java.util.*; +import java.util.Base64; +import java.util.Collection; +import java.util.Map; +import java.util.Objects; import java.util.function.Function; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; diff --git a/src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/StateTransition.java b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/StateTransition.java index c769c07..590fa19 100644 --- a/src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/StateTransition.java +++ b/src/main/java/org/icgc/argo/workflow_management/gatekeeper/service/StateTransition.java @@ -19,7 +19,6 @@ package org.icgc.argo.workflow_management.gatekeeper.service; import static org.icgc.argo.workflow_management.streams.schema.RunState.*; -import static org.icgc.argo.workflow_management.streams.schema.RunState.COMPLETE; import java.util.Map; import java.util.Optional; diff --git a/src/main/java/org/icgc/argo/workflow_management/health/DisposableHealthIndicator.java b/src/main/java/org/icgc/argo/workflow_management/health/DisposableHealthIndicator.java new file mode 100644 index 0000000..d3b5417 --- /dev/null +++ b/src/main/java/org/icgc/argo/workflow_management/health/DisposableHealthIndicator.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2021 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of the GNU Affero General Public License v3.0. + * You should have received a copy of the GNU Affero General Public License along with + * this program. If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.icgc.argo.workflow_management.health; + +import lombok.RequiredArgsConstructor; +import lombok.val; +import org.icgc.argo.workflow_management.streams.DisposableManager; +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.ReactiveHealthIndicator; +import org.springframework.boot.actuate.health.Status; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@Component +@RequiredArgsConstructor +public class DisposableHealthIndicator implements ReactiveHealthIndicator { + + private final DisposableManager disposableManager; + + @Bean + public Mono health() { + return Flux.fromIterable(disposableManager.getDisposablesRegistry().entrySet()) + .reduce( + Health.up(), + (healthBuilder, entry) -> { + val disposed = entry.getValue().isDisposed(); + if (disposed) { + healthBuilder.status(Status.DOWN); + } + healthBuilder.withDetail(entry.getKey(), disposed); + return healthBuilder; + }) + .map(Health.Builder::build); + } +} diff --git a/src/main/java/org/icgc/argo/workflow_management/streams/DisposableManager.java b/src/main/java/org/icgc/argo/workflow_management/streams/DisposableManager.java index 2bb4067..dc4bc0d 100644 --- a/src/main/java/org/icgc/argo/workflow_management/streams/DisposableManager.java +++ b/src/main/java/org/icgc/argo/workflow_management/streams/DisposableManager.java @@ -22,6 +22,7 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.Callable; +import lombok.Getter; import lombok.SneakyThrows; import org.springframework.context.annotation.Configuration; import reactor.core.Disposable; @@ -31,6 +32,7 @@ public class DisposableManager { public static final String WES_CONSUMER = "WESConsumer"; public static final String GATEKEEPER_PRODUCER = "gatekeeperProducer"; + @Getter private final Map disposablesRegistry = Collections.synchronizedMap(new HashMap<>()); diff --git a/src/main/java/org/icgc/argo/workflow_management/streams/WebLogEventSender.java b/src/main/java/org/icgc/argo/workflow_management/streams/WebLogEventSender.java index f5e2917..7e3daa8 100644 --- a/src/main/java/org/icgc/argo/workflow_management/streams/WebLogEventSender.java +++ b/src/main/java/org/icgc/argo/workflow_management/streams/WebLogEventSender.java @@ -30,7 +30,9 @@ import org.icgc.argo.workflow_management.streams.model.NextflowEvent; import org.icgc.argo.workflow_management.streams.model.WfManagementEvent; import org.icgc.argo.workflow_management.streams.model.WorkflowEvent; -import org.icgc.argo.workflow_management.wes.model.*; +import org.icgc.argo.workflow_management.wes.model.NextflowMetadata; +import org.icgc.argo.workflow_management.wes.model.RunParams; +import org.icgc.argo.workflow_management.wes.model.WesState; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; import org.springframework.stereotype.Service; diff --git a/src/main/java/org/icgc/argo/workflow_management/streams/WesConsumerConfig.java b/src/main/java/org/icgc/argo/workflow_management/streams/WesConsumerConfig.java index facab4e..c6175d7 100644 --- a/src/main/java/org/icgc/argo/workflow_management/streams/WesConsumerConfig.java +++ b/src/main/java/org/icgc/argo/workflow_management/streams/WesConsumerConfig.java @@ -27,7 +27,6 @@ import com.pivotal.rabbitmq.stream.Transaction; import java.time.Duration; import java.util.function.BiConsumer; -import java.util.function.Consumer; import javax.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -41,6 +40,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import reactor.core.Disposable; +import reactor.core.publisher.Mono; import reactor.util.retry.RetrySpec; @Slf4j @@ -71,70 +71,55 @@ public void init() { private Disposable createWfMgmtRunMsgForExecuteConsumer() { return createTransConsumerStream(rabbit, topicExchangeName, queueName, topicRoutingKeys) .receive() - .doOnNext(consumeAndExecuteInitializeOrCancel()) - .onErrorContinue(handleRabbitStreamError()) + // consume each tx msg and flatMap into publisher of Mono. + // Mono is used so reactor can manage subscriptions and publisher signals. + .flatMap(this::consumeMessageAndExecuteInitializeOrCancel) + // Continue on error so disposable doesn't die. + // The tx commit/reject is handled in the flatmap so no need to worry about that here + .onErrorContinue(catchStreamError()) + .log(WES_CONSUMER) .subscribe(); } - private Consumer> consumeAndExecuteInitializeOrCancel() { - return tx -> { - val msg = tx.get(); - log.debug("WfMgmtRunMsg received: {}", msg); - - if (msg.getState().equals(RunState.INITIALIZING)) { - val runParams = createRunParams(msg); - wes.run(runParams) - .onErrorContinue(handleWesError(tx)) - .subscribe( - runsResponse -> { - log.info("Initialized: {}", msg); - tx.commit(); - }); - } else if (msg.getState().equals(RunState.CANCELING)) { - wes.cancel(msg.getRunId()) - .retryWhen(RetrySpec.backoff(3, Duration.ofMinutes(3))) - .onErrorContinue(handleWesError(tx)) - .subscribe( - runsResponse -> { - log.info("Cancelled: {}", runsResponse); - tx.commit(); - }); - } else { - log.debug("Ignoring: {}", msg); - tx.commit(); - } - }; + private Mono consumeMessageAndExecuteInitializeOrCancel(Transaction tx) { + val msg = tx.get(); + log.debug("WfMgmtRunMsg received: {}", msg); + + if (msg.getState().equals(RunState.INITIALIZING)) { + return wes.run(createRunParams(msg)) + .flatMap(runsResponse -> commitTx("Initialized", tx)) + .onErrorResume(t -> rejectAndWeblogTx(t, tx)); + } else if (msg.getState().equals(RunState.CANCELING)) { + return wes.cancel(msg.getRunId()) + .retryWhen(RetrySpec.backoff(3, Duration.ofMinutes(3))) + .flatMap(runsResponse -> commitTx("Cancelled", tx)) + .onErrorResume(t -> rejectAndWeblogTx(t, tx)); + } else { + return commitTx("Ignored", tx); + } } - private BiConsumer handleRabbitStreamError() { - return (t, tx) -> { - t.printStackTrace(); - log.error("Error occurred with: {}", tx); - if (tx instanceof Transaction && ((Transaction) tx).get() instanceof WfMgmtRunMsg) { - val msg = (WfMgmtRunMsg) ((Transaction) tx).get(); - msg.setState(RunState.SYSTEM_ERROR); - log.info("Rabbit stream SYSTEM_ERROR msg: {}", msg); - webLogEventSender.sendWfMgmtEventAsync(createWfMgmtEvent(msg)); - ((Transaction) tx).reject(); - } else { - log.error("Transaction is lost, nothing to ack!"); - } - }; + private Mono commitTx(String actionMsg, Transaction tx) { + log.info(actionMsg, tx.get()); + tx.commit(); + return Mono.just(true); + } + + private Mono rejectAndWeblogTx(Throwable t, Transaction tx) { + val msg = tx.get(); + msg.setState(RunState.SYSTEM_ERROR); + + log.error("Error occurred", t); + log.error("WES SYSTEM_ERROR msg: {}", msg); + tx.reject(); + + return webLogEventSender.sendWfMgmtEvent(createWfMgmtEvent(msg)).thenReturn(false); } - private BiConsumer handleWesError(Transaction tx) { + private BiConsumer catchStreamError() { return (t, obj) -> { - t.printStackTrace(); - log.error("Error occurred with: {}", obj); - if (tx.get() instanceof WfMgmtRunMsg) { - val msg = (WfMgmtRunMsg) tx.get(); - msg.setState(RunState.SYSTEM_ERROR); - webLogEventSender.sendWfMgmtEventAsync(createWfMgmtEvent(msg)); - log.error("WES SYSTEM_ERROR msg: {}", msg); - } else { - log.error("Can't get WfMgmtRunMsg, nothing to weblog with here!"); - } - tx.reject(); + log.error("WesConsumer stream error", t); + log.error("WesConsumer stream error object {}", obj); }; } } diff --git a/src/main/java/org/icgc/argo/workflow_management/streams/utils/WfMgmtRunMsgConverters.java b/src/main/java/org/icgc/argo/workflow_management/streams/utils/WfMgmtRunMsgConverters.java index f4b4e07..77545c2 100644 --- a/src/main/java/org/icgc/argo/workflow_management/streams/utils/WfMgmtRunMsgConverters.java +++ b/src/main/java/org/icgc/argo/workflow_management/streams/utils/WfMgmtRunMsgConverters.java @@ -18,7 +18,7 @@ package org.icgc.argo.workflow_management.streams.utils; -import static org.icgc.argo.workflow_management.util.JacksonUtils.*; +import static org.icgc.argo.workflow_management.util.JacksonUtils.readValue; import java.time.Instant; import java.util.Date; diff --git a/src/main/java/org/icgc/argo/workflow_management/wes/NextflowService.java b/src/main/java/org/icgc/argo/workflow_management/wes/NextflowService.java index 8060adc..d3eaf8c 100644 --- a/src/main/java/org/icgc/argo/workflow_management/wes/NextflowService.java +++ b/src/main/java/org/icgc/argo/workflow_management/wes/NextflowService.java @@ -47,7 +47,6 @@ import org.icgc.argo.workflow_management.streams.WebLogEventSender; import org.icgc.argo.workflow_management.util.ConditionalPutMap; import org.icgc.argo.workflow_management.wes.model.*; -import org.icgc.argo.workflow_management.wes.model.RunsResponse; import org.icgc.argo.workflow_management.wes.properties.NextflowProperties; import org.icgc.argo.workflow_management.wes.secret.SecretProvider; import org.springframework.beans.factory.annotation.Autowired; diff --git a/src/test/java/org/icgc/argo/workflow_management/GateKeeperProcessorTests.java b/src/test/java/org/icgc/argo/workflow_management/GateKeeperProcessorTests.java index a68dcb3..f603101 100644 --- a/src/test/java/org/icgc/argo/workflow_management/GateKeeperProcessorTests.java +++ b/src/test/java/org/icgc/argo/workflow_management/GateKeeperProcessorTests.java @@ -19,7 +19,8 @@ package org.icgc.argo.workflow_management; import static org.icgc.argo.workflow_management.streams.utils.WfMgmtRunMsgConverters.createWfMgmtRunMsg; -import static org.icgc.argo.workflow_management.util.TransactionUtils.*; +import static org.icgc.argo.workflow_management.util.TransactionUtils.isRejected; +import static org.icgc.argo.workflow_management.util.TransactionUtils.wrapWithTransaction; import static org.icgc.argo.workflow_management.util.WesUtils.generateWesRunId; import static org.junit.Assert.*; From 78f82077d3f59581c4ea9c46d6146621aeb28337 Mon Sep 17 00:00:00 2001 From: jaserud Date: Wed, 12 May 2021 12:21:56 -0400 Subject: [PATCH 14/18] remove producers default and DL queue+excahnge (#166) --- .../streams/GateKeeperStreamsConfig.java | 12 ++++-------- .../streams/WesConsumerConfig.java | 6 +++--- .../streams/utils/RabbitmqUtils.java | 17 +++-------------- src/main/resources/application.yml | 19 +++++++++---------- 4 files changed, 19 insertions(+), 35 deletions(-) diff --git a/src/main/java/org/icgc/argo/workflow_management/streams/GateKeeperStreamsConfig.java b/src/main/java/org/icgc/argo/workflow_management/streams/GateKeeperStreamsConfig.java index e996cd1..00c4754 100644 --- a/src/main/java/org/icgc/argo/workflow_management/streams/GateKeeperStreamsConfig.java +++ b/src/main/java/org/icgc/argo/workflow_management/streams/GateKeeperStreamsConfig.java @@ -62,16 +62,13 @@ public class GateKeeperStreamsConfig { private static final Set RUN_STATES_TO_WEBLOG = Set.of(RunState.QUEUED, RunState.CANCELED); - @Value("${gatekeeper.producer.topology.queueName}") - private String producerDefaultQueueName; - - @Value("${gatekeeper.producer.topology.topicExchangeName}") + @Value("${gatekeeper.producer.topicExchange}") private String producerTopicExchangeName; - @Value("${gatekeeper.consumer.topology.topicExchangeName}") + @Value("${gatekeeper.consumer.topicExchange}") private String consumerTopicExchangeName; - @Value("${gatekeeper.consumer.topology.queueName}") + @Value("${gatekeeper.consumer.queue}") private String consumerQueueName; private final RabbitEndpointService rabbit; @@ -110,8 +107,7 @@ private Disposable createGatekeeperProducer() { }) .onErrorContinue(handleError()); - return createTransProducerStream( - rabbit, producerTopicExchangeName, producerDefaultQueueName, ROUTING_KEY) + return createTransProducerStream(rabbit, producerTopicExchangeName) .send(processedFlux) .onErrorContinue(handleError()) .subscribe( diff --git a/src/main/java/org/icgc/argo/workflow_management/streams/WesConsumerConfig.java b/src/main/java/org/icgc/argo/workflow_management/streams/WesConsumerConfig.java index c6175d7..e753540 100644 --- a/src/main/java/org/icgc/argo/workflow_management/streams/WesConsumerConfig.java +++ b/src/main/java/org/icgc/argo/workflow_management/streams/WesConsumerConfig.java @@ -49,13 +49,13 @@ @Configuration @RequiredArgsConstructor public class WesConsumerConfig { - @Value("${wes.consumer.topology.queueName}") + @Value("${wes.consumer.queue}") private String queueName; - @Value("${wes.consumer.topology.topicExchangeName}") + @Value("${wes.consumer.topicExchange}") private String topicExchangeName; - @Value("${wes.consumer.topology.topicRoutingKeys}") + @Value("${wes.consumer.topicRoutingKeys}") private String[] topicRoutingKeys; private final WebLogEventSender webLogEventSender; diff --git a/src/main/java/org/icgc/argo/workflow_management/streams/utils/RabbitmqUtils.java b/src/main/java/org/icgc/argo/workflow_management/streams/utils/RabbitmqUtils.java index 3766ff6..6f7dfcb 100644 --- a/src/main/java/org/icgc/argo/workflow_management/streams/utils/RabbitmqUtils.java +++ b/src/main/java/org/icgc/argo/workflow_management/streams/utils/RabbitmqUtils.java @@ -31,24 +31,13 @@ public class RabbitmqUtils { public static TransactionalProducerStream createTransProducerStream( - RabbitEndpointService rabbit, String topicName, String queueName, String... routingKey) { - val dlxName = topicName + "-dlx"; - val dlqName = queueName + "-dlq"; + RabbitEndpointService rabbit, String topicName) { return rabbit .declareTopology( topologyBuilder -> topologyBuilder - .declareExchange(dlxName) - .and() - .declareQueue(dlqName) - .boundTo(dlxName) - .and() .declareExchange(topicName) - .type(ExchangeType.topic) - .and() - .declareQueue(queueName) - .boundTo(topicName, routingKey) - .withDeadLetterExchange(dlxName)) + .type(ExchangeType.topic)) .createTransactionalProducerStream(WfMgmtRunMsg.class) .route() .toExchange(topicName) @@ -58,7 +47,7 @@ public static TransactionalProducerStream createTransProducerStrea public static TransactionalConsumerStream createTransConsumerStream( RabbitEndpointService rabbit, String topicName, String queueName, String... routingKey) { - val dlxName = topicName + "-dlx"; + val dlxName = queueName + "-dlx"; val dlqName = queueName + "-dlq"; return rabbit .declareTopology( diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 5bf876e..4e0b149 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -58,21 +58,20 @@ rabbit: username: user password: pass -wes.consumer.topology: - queueName: "execute-queue" - topicExchangeName: "mgmt-in" - topicRoutingKeys: "INITIALIZING, CANCELING" # comma separated Array of keys +wes.consumer: + queue: "execute-queue" + topicExchange: "gatekeeper-out" + topicRoutingKeys: "INITIALIZING, CANCELING" # comma separated Array of keys --- spring.profiles: gatekeeper -gatekeeper.consumer.topology: - queueName: "gatekeeper-in-queue" - topicExchangeName: "mgmt-in" +gatekeeper.consumer: + queue: "gatekeeper-in-queue" + topicExchange: "gatekeeper-in" -gatekeeper.producer.topology: - queueName: "gatekeeper-out-default" - topicExchangeName: "gatekeeper-out" +gatekeeper.producer: + topicExchange: "gatekeeper-out" spring.cloud.stream: function.definition: weblogConsumer From 5d5517457593b5b3a73c6b490cdbaff0b45aca01 Mon Sep 17 00:00:00 2001 From: Yelizar Alturmessov Date: Fri, 9 Jul 2021 15:14:41 -0400 Subject: [PATCH 15/18] Jenkinsfile update Replace docker socket mount with docker host env vars. --- Jenkinsfile | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index d5e7f51..749bb2b 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -34,14 +34,10 @@ spec: - name: docker image: docker:18-git tty: true - volumeMounts: - - mountPath: /var/run/docker.sock - name: docker-sock + env: + - name: DOCKER_HOST + value: tcp://localhost:2375 volumes: - - name: docker-sock - hostPath: - path: /var/run/docker.sock - type: File - name: docker-graph-storage emptyDir: {} """ From 646d5fd95372e897ad30b0ec65e61b9b75c969ba Mon Sep 17 00:00:00 2001 From: Yelizar Alturmessov Date: Fri, 16 Jul 2021 15:30:18 -0400 Subject: [PATCH 16/18] Jenkinsfile update Set explicit UIDs for containers. --- Jenkinsfile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 749bb2b..80d771b 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -22,7 +22,8 @@ spec: - name: dind-daemon image: docker:18.06-dind securityContext: - privileged: true + privileged: true + runAsUser: 0 volumeMounts: - name: docker-graph-storage mountPath: /var/lib/docker @@ -37,6 +38,8 @@ spec: env: - name: DOCKER_HOST value: tcp://localhost:2375 + securityContext: + runAsUser: 1000 volumes: - name: docker-graph-storage emptyDir: {} From 3165483aad8cbeff55f7eb380cd284a4adcedaa6 Mon Sep 17 00:00:00 2001 From: Dusan Andric Date: Mon, 19 Jul 2021 15:34:14 -0400 Subject: [PATCH 17/18] docker home dir for jenkins --- Jenkinsfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index 80d771b..fb40b50 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -38,6 +38,8 @@ spec: env: - name: DOCKER_HOST value: tcp://localhost:2375 + - name: HOME + value: /home/jenkins/agent securityContext: runAsUser: 1000 volumes: From 503f496a15fcd4b2f7e046669f45c6d37d63f413 Mon Sep 17 00:00:00 2001 From: Dusan Andric Date: Mon, 19 Jul 2021 15:45:54 -0400 Subject: [PATCH 18/18] 3.0.0 release --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 08cfa0d..75aa758 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ org.icgc.argo workflow-management - 2.12.0-SNAPSHOT + 3.0.0 workflow-management ARGO Workflow Management