Skip to content
This repository has been archived by the owner on Jul 23, 2024. It is now read-only.

Commit

Permalink
MTA Assessment Workflow
Browse files Browse the repository at this point in the history
This is an assessment workflow which is based on the Migration Analysis
infra workflow.
The main differne is that the checker of that workflow downloads the
html report and tries to extract a table of scores of issues found by
the analysis. The ProcessAnalysisTask has a predicate passed in the
constructor to test against the scores of the analysis and based on that
the task returns the passOption or the defaultOption. The passOption is
the next flow to invoke, that should be the move2kube.

The flow is roughly:

Start
  -
Infra flow start
  -
submit analysis report
  -
End

Start
  -
Checker flow start
  -
check report is ready
  -
switch (is ready?)
  yes -> go to parse
  no  -> go to check report is ready
  -
parse
  -
switch (match incidents on predicate)
  true - return pass option (move2kube)
  false - return default option
  -
End

Signed-off-by: Roy Golan <rgolan@redhat.com>
  • Loading branch information
rgolangh committed Jun 6, 2023
1 parent b44ac9b commit e67fa39
Show file tree
Hide file tree
Showing 15 changed files with 494 additions and 120 deletions.
2 changes: 1 addition & 1 deletion parodos-model-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,4 @@
</plugin>
</plugins>
</build>
</project>
</project>
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
package com.redhat.parodos.tasks.migrationtoolkit;

import java.net.URI;
import java.util.List;

import com.redhat.parodos.workflow.exception.MissingParameterException;
import com.redhat.parodos.workflow.parameter.WorkParameter;
import com.redhat.parodos.workflow.parameter.WorkParameterType;
import com.redhat.parodos.workflow.task.infrastructure.BaseInfrastructureWorkFlowTask;
import com.redhat.parodos.workflows.work.DefaultWorkReport;
import com.redhat.parodos.workflows.work.WorkContext;
import com.redhat.parodos.workflows.work.WorkReport;
import com.redhat.parodos.workflows.work.WorkStatus;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;

/**
Expand All @@ -37,21 +33,6 @@ public CreateApplicationTask(URI serverURL, String bearerToken) {
mtaClient = new MTAClient(serverURL, bearerToken);
}

@Override
public @NonNull List<WorkParameter> getWorkFlowTaskParameters() {
return List.of(
WorkParameter.builder().key("applicationName").type(WorkParameterType.TEXT).optional(false)
.description("The application name. Can be generated from the repository name").build(),
WorkParameter.builder().key("repositoryURL").type(WorkParameterType.TEXT).optional(false)
.description("The application git repository URL. Can be generated from the repository name")
.build(),
WorkParameter.builder().key("serverURL").type(WorkParameterType.TEXT).optional(true).description(
"Base URL of the MTA instance - e.g https://mta-openshift-mta.app.clustername.clusterdomain")
.build(),
WorkParameter.builder().key("bearerToken").type(WorkParameterType.TEXT).optional(true)
.description("Bearer token to authenticate server requests").build());
}

/**
* @param workContext optional context values: serverURL, and bearerToken for the
* mtaClient.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

import java.net.URI;
import java.util.List;
import java.util.function.Consumer;

import com.redhat.parodos.email.Message;
import javax.inject.Inject;

import com.redhat.parodos.notification.sdk.model.NotificationMessageCreateRequestDTO;
import com.redhat.parodos.workflow.exception.MissingParameterException;
import com.redhat.parodos.workflow.parameter.WorkParameter;
import com.redhat.parodos.workflow.parameter.WorkParameterType;
import com.redhat.parodos.workflow.task.infrastructure.BaseInfrastructureWorkFlowTask;
import com.redhat.parodos.workflow.task.infrastructure.Notifier;
import com.redhat.parodos.workflows.work.DefaultWorkReport;
import com.redhat.parodos.workflows.work.WorkContext;
import com.redhat.parodos.workflows.work.WorkReport;
Expand All @@ -35,12 +37,13 @@ public class GetAnalysisTask extends BaseInfrastructureWorkFlowTask {

private URI serverUrl;

private final Consumer<Message> messageConsumer;
@Inject
private Notifier notificationSender;

public GetAnalysisTask(URI serverURL, String bearerToken, Consumer<Message> messageConsumer) {
public GetAnalysisTask(URI serverURL, String bearerToken, Notifier notifier) {
this.serverUrl = serverURL;
this.mtaClient = new MTAClient(serverURL, bearerToken);
this.messageConsumer = messageConsumer;
this.notificationSender = notifier;
}

@Override
Expand Down Expand Up @@ -95,8 +98,8 @@ else if (result instanceof Result.Success<TaskGroup> success) {
&& success.value().tasks()[0].state().equals("Succeeded")) {
String reportURL = String.format("%s/hub/applications/%d/bucket/%s", serverUrl,
success.value().tasks()[0].application().id(), success.value().data().output());
sendEmail(reportURL, getOptionalParameterValue("email", null));
addParameter("reportURL", reportURL);
sendNotification(reportURL);
return new DefaultWorkReport(WorkStatus.COMPLETED, workContext);
}
else if ("Failed".equals(success.value().state())) {
Expand All @@ -108,13 +111,14 @@ else if ("Failed".equals(success.value().state())) {
throw new IllegalArgumentException();
}

private void sendEmail(String reportURL, String recipient) {
if (recipient == null) {
return;
}
messageConsumer.accept(new Message(recipient, "parodos-task-notification@redhat.com",
"Parodos: Analysis report is done",
String.format("The analysis report is done. Find it here %s", reportURL)));
private void sendNotification(String reportURL) {
var request = new NotificationMessageCreateRequestDTO();
request.setMessageType("text");
request.setBody("Report URL: " + reportURL);
request.subject("Migration Analysis Report Completed");
request.setUsernames(List.of("test"));
request.setGroupNames(List.of("test"));
notificationSender.send(request);
}

}
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
package com.redhat.parodos.tasks.migrationtoolkit;

import java.net.URI;
import java.util.List;

import com.redhat.parodos.workflow.exception.MissingParameterException;
import com.redhat.parodos.workflow.parameter.WorkParameter;
import com.redhat.parodos.workflow.parameter.WorkParameterType;
import com.redhat.parodos.workflow.task.infrastructure.BaseInfrastructureWorkFlowTask;
import com.redhat.parodos.workflows.work.DefaultWorkReport;
import com.redhat.parodos.workflows.work.WorkContext;
import com.redhat.parodos.workflows.work.WorkReport;
import com.redhat.parodos.workflows.work.WorkStatus;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;

/**
Expand All @@ -36,22 +32,6 @@ public GetApplicationTask(URI serverURL, String bearerToken) {
mtaClient = new MTAClient(serverURL, bearerToken);
}

@Override
public @NonNull List<WorkParameter> getWorkFlowTaskParameters() {
return List.of(
WorkParameter.builder().key("serverURL").type(WorkParameterType.TEXT).optional(true).description(
"Base URL of the MTA instance - e.g https://mta-openshift-mta.app.clustername.clusterdomain")
.build(),
WorkParameter.builder().key("bearerToken").type(WorkParameterType.TEXT).optional(true)
.description("Bearer token to authenticate server requests").build(),
WorkParameter.builder().key("applicationName").type(WorkParameterType.TEXT).optional(false).description(
"The application name as presented in the application hub. Can be generated from the repository name")
.build(),
WorkParameter.builder().key("sourceRepository").type(WorkParameterType.TEXT).optional(true).description(
"The application name as presented in the application hub. Can be generated from the repository name")
.build());
}

/**
* @param workContext optional context values: serverURL, and bearerToken for the
* mtaClient.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
package com.redhat.parodos.tasks.migrationtoolkit;

import java.net.URI;
import java.util.List;

import com.redhat.parodos.workflow.exception.MissingParameterException;
import com.redhat.parodos.workflow.parameter.WorkParameter;
import com.redhat.parodos.workflow.parameter.WorkParameterType;
import com.redhat.parodos.workflow.task.infrastructure.BaseInfrastructureWorkFlowTask;
import com.redhat.parodos.workflows.work.DefaultWorkReport;
import com.redhat.parodos.workflows.work.WorkContext;
import com.redhat.parodos.workflows.work.WorkReport;
import com.redhat.parodos.workflows.work.WorkStatus;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;

/**
Expand Down Expand Up @@ -41,19 +37,6 @@ public SubmitAnalysisTask(URI serverURL, String bearerToken) {
this.mtaClient = new MTAClient(serverURL, bearerToken);
}

@Override
public @NonNull List<WorkParameter> getWorkFlowTaskParameters() {
return List.of(
WorkParameter.builder().key("applicationName").type(WorkParameterType.TEXT).optional(false).description(
"The application name as presented in the application hub. Can be generated from the repository name")
.build(),
WorkParameter.builder().key("serverURL").type(WorkParameterType.TEXT).optional(true).description(
"Base URL of the MTA instance - e.g https://mta-openshift-mta.app.clustername.clusterdomain")
.build(),
WorkParameter.builder().key("bearerToken").type(WorkParameterType.TEXT).optional(true)
.description("Bearer token to authenticate server requests").build());
}

/**
* @param workContext optional context values: serverURL, and bearerToken for the
* mtaClient.
Expand Down
6 changes: 6 additions & 0 deletions workflow-examples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@
<artifactId>aspectjweaver</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.7.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,10 @@
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;

@Configuration
@Profile("local")
public class OcpOnboardingWorkFlowConfiguration {

// Assessment workflow
Expand Down Expand Up @@ -76,15 +78,24 @@ WorkFlowOption notSupportOption() {
.setDescription("Non-Supported Workflow Steps").build();
}

@Bean
WorkFlowOption analyzeOption() {
return new WorkFlowOption.Builder("analyzeOption", "AnalyzeApplicationAssessment")
.addToDetails("Analyze an application's source code before migrating it."
+ " Produces a containerization report by MTA")
.displayName("Migration Analysis").setDescription("Migration Analysis step").build();
}

// An AssessmentTask returns one or more WorkFlowOption wrapped in a WorkflowOptions
@Bean
OnboardingOcpAssessmentTask onboardingAssessmentTask(
@Qualifier("onboardingOcpOption") WorkFlowOption onboardingOcpOption,
@Qualifier("badRepoOption") WorkFlowOption badRepoOption,
@Qualifier("notSupportOption") WorkFlowOption notSupportOption,
@Qualifier("move2kube") WorkFlowOption move2kube) {
@Qualifier("move2kube") WorkFlowOption move2kube,
@Qualifier("analyzeOption") WorkFlowOption analyzeOption) {
return new OnboardingOcpAssessmentTask(
List.of(onboardingOcpOption, badRepoOption, notSupportOption, move2kube));
List.of(onboardingOcpOption, badRepoOption, notSupportOption, move2kube, analyzeOption));
}

// A Workflow designed to execute and return WorkflowOption(s) that can be executed
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.redhat.parodos.examples.prebuilt.migrationtoolkit;

import java.util.Iterator;
import java.util.Scanner;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class MTAAnalysisReport {

/**
* migrationIssuesReport is assumed to be valid html. MTA 6.1 should supply a CSV as
* well. Throw and exception when the parsing fails or if it can't extract data
*/
public record AnalysisIncidents(int mandatory, int optional, int potential, int cloudMandatory, int cloudOptional,
int information) {
}

/**
* Take the data/issue_summaries.js that contains a variable with a map of severity ->
* list of issues. Then extract the size of the list by the severity name. Parsing is
* straight forward - identify the assignment to the var and extract the value - it is
* a valid json map.
* @param jsIssuesData
* @return AnalysisIncidents
* @throws Exception - for any failure in json parsing or when there's nothing to
* parse
*/
public static AnalysisIncidents extractIncidents(String jsIssuesData) throws Exception {
Scanner scanner = new Scanner(jsIssuesData);
while (scanner.hasNextLine()) {
String s = scanner.nextLine();
// find the variable assignment WINDUP...['123'] = {$severity: [{}]}
if (s.startsWith("WINDUP_ISSUE_SUMMARIES[")) {
// extract only the json map data
s = s.replaceFirst("WINDUP_ISSUE_SUMMARIES\\[.*\\] =", "");
var mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.setSerializationInclusion(JsonInclude.Include.NON_NULL);
try {
int mandatory = 0, optional = 0, potential = 0, cloudMandatory = 0, cloudOptional = 0,
information = 0;
JsonNode jsonNode = mapper.readTree(s);
for (Iterator<String> it = jsonNode.fieldNames(); it.hasNext();) {
String severity = it.next();
switch (severity) {
case "mandatory" -> mandatory = jsonNode.get(severity).size();
case "optional" -> optional = jsonNode.get(severity).size();
case "potential" -> potential = jsonNode.get(severity).size();
case "cloud-mandatory" -> cloudMandatory = jsonNode.get(severity).size();
case "cloud-optional" -> cloudOptional = jsonNode.get(severity).size();
case "information" -> information = jsonNode.get(severity).size();
}
}
return new MTAAnalysisReport.AnalysisIncidents(mandatory, optional, potential, cloudMandatory,
cloudOptional, information);
}
catch (JsonProcessingException e) {
throw new Exception("failed extracting the incidents summary from issue_summaries.js " + e);
}
}
}
throw new Exception(
"failed extracting the incidents summary from issue_summaries.js - didn't match any line. Possibly the format changed"
+ "by MTA or wrong page is scanned. Data parsed: " + jsIssuesData);
}

}
Loading

0 comments on commit e67fa39

Please sign in to comment.