Skip to content

Commit

Permalink
feat(orchestrator): add OpenAPI v2 implementations (#1182)
Browse files Browse the repository at this point in the history
* Implement getWorkflowOverviewById (v2)

Signed-off-by: Gloria Ciavarrini <[email protected]>

* Implementation of getWorkflows (v2)

Signed-off-by: Gloria Ciavarrini <[email protected]>

* Implementation of getWorkflowById (v2)

Signed-off-by: Gloria Ciavarrini <[email protected]>

* Implementation of getInstances (v2)

Signed-off-by: Gloria Ciavarrini <[email protected]>

* Implementation of getInstancesById (v2)

Signed-off-by: Gloria Ciavarrini <[email protected]>

* Definition of getWorkflowResults (v2)

Signed-off-by: Gloria Ciavarrini <[email protected]>

* Definition of getWorkflowStatuses (v2)

Signed-off-by: Gloria Ciavarrini <[email protected]>

* Refactor: use namespaces for api versions

Signed-off-by: Gloria Ciavarrini <[email protected]>

* Definition of executeWorkflow (v2)

Signed-off-by: Gloria Ciavarrini <[email protected]>

* Implementation of executeWorkflow (v2)

Signed-off-by: Kamlesh Panchal <[email protected]>

Refactoring

Signed-off-by: Gloria Ciavarrini <[email protected]>

* Implementation of createWorkflow (v2)

Signed-off-by: Gloria Ciavarrini <[email protected]>

* Definition of abortWorkflow (v2)

Signed-off-by: Gloria Ciavarrini <[email protected]>

* Implementation of abortWorkflow (v2)

Signed-off-by: Jude Niroshan <[email protected]>

Refactoring

Signed-off-by: Gloria Ciavarrini <[email protected]>

* Implementation of getWorkflowResults (v2)

Signed-off-by: Kamlesh Panchal <[email protected]>

Refactoring

Signed-off-by: Gloria Ciavarrini <[email protected]>

* Implementation of getWorkflowSpecs (v2)

Signed-off-by: Gloria Ciavarrini <[email protected]>

* fix(orchestrator): remove enum types from openapi types.ts
FLPATH-947
https://issues.redhat.com/browse/FLPATH-947

Signed-off-by: Yaron Dayagi <[email protected]>

Fix sonarcloud issue `"switch" statements should have at least 3 "case"
clauses`

Signed-off-by: Gloria Ciavarrini <[email protected]>

* Implementation of getWorkflowStatuses (v2)

Signed-off-by: Gloria Ciavarrini <[email protected]>

* Add autogenerated api doc

Signed-off-by: Gloria Ciavarrini <[email protected]>

* Fix: rename getWorkflowsOverview (v1 and v2)

Signed-off-by: Gloria Ciavarrini <[email protected]>

* Unit Test: getWorkflowOverview (v2)

Signed-off-by: Gloria Ciavarrini <[email protected]>

* Unit Test: getWorkflowOverviewById (v2)

Signed-off-by: Gloria Ciavarrini <[email protected]>

* Unit Test: getWorkflowSpecs (v2)

Signed-off-by: Gloria Ciavarrini <[email protected]>

* Unit Test: getWorkflowById (v2)

Signed-off-by: Gloria Ciavarrini <[email protected]>

* Fix: typo

Signed-off-by: Gloria Ciavarrini <[email protected]>

* Fix: use ternary conditional operator

Signed-off-by: Gloria Ciavarrini <[email protected]>

---------

Signed-off-by: Gloria Ciavarrini <[email protected]>
Co-authored-by: Kamlesh Panchal <[email protected]>
Co-authored-by: Jude Niroshan <[email protected]>
Co-authored-by: Yaron Dayagi <[email protected]>
  • Loading branch information
4 people authored Feb 20, 2024
1 parent 9724e27 commit 43ac2f3
Show file tree
Hide file tree
Showing 20 changed files with 4,541 additions and 197 deletions.
1 change: 1 addition & 0 deletions plugins/orchestrator-backend/dist-dynamic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"openapi-types": "^12.1.3",
"winston": "^3.11.0",
"yn": "^5.0.0",
"moment": "^2.29.4",
"js-yaml": "^4.1.0"
},
"devDependencies": {},
Expand Down
5 changes: 5 additions & 0 deletions plugins/orchestrator-backend/dist-dynamic/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,11 @@ mock-json-schema@^1.0.7:
dependencies:
lodash "^4.17.21"

moment@^2.29.4:
version "2.30.1"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae"
integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==

[email protected]:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
Expand Down
6 changes: 4 additions & 2 deletions plugins/orchestrator-backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,15 @@
"openapi-backend": "^5.10.5",
"openapi-types": "^12.1.3",
"winston": "^3.11.0",
"yn": "^5.0.0"
"yn": "^5.0.0",
"moment": "^2.29.4"
},
"devDependencies": {
"@backstage/cli": "0.23.0",
"@janus-idp/cli": "1.7.1",
"@types/express": "4.17.20",
"@types/fs-extra": "^11.0.1",
"@types/json-schema": "^7.0.12"
"@types/json-schema": "^7.0.12",
"@backstage/backend-test-utils": "^0.2.10"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import {
WorkflowOverview,
WorkflowSpecFile,
} from '@janus-idp/backstage-plugin-orchestrator-common';

import {
fakeOpenAPIV3Document,
generateTestWorkflowOverview,
generateTestWorkflowSpecs,
} from '../test-utils';
import {
mapToWorkflowOverviewDTO,
mapToWorkflowSpecFileDTO,
mapWorkflowCategoryDTOFromString,
} from './V2Mappings';

describe('scenarios to verify mapToWorkflowOverviewDTO', () => {
it('correctly maps WorkflowOverview', () => {
// Arrange
const overview: WorkflowOverview = generateTestWorkflowOverview({
category: 'assessment',
});

// Act
const result = mapToWorkflowOverviewDTO(overview);

// Assert
expect(result.workflowId).toBe(overview.workflowId);
expect(result.name).toBe(overview.name);
expect(result.uri).toBe(overview.uri);
expect(result.lastTriggeredMs).toBe(overview.lastTriggeredMs);
expect(result.lastRunStatus).toBe(overview.lastRunStatus);
expect(result.category).toBe('assessment');
expect(result.avgDurationMs).toBe(overview.avgDurationMs);
expect(result.description).toBe(overview.description);
expect(Object.keys(result).length).toBe(8);
});
});
describe('scenarios to verify mapWorkflowCategoryDTOFromString', () => {
test.each([
{ input: 'assessment', expected: 'assessment' },
{ input: 'infrastructure', expected: 'infrastructure' },
{ input: 'random category', expected: 'infrastructure' },
])('mapWorkflowCategoryDTOFromString($input)', ({ input, expected }) => {
// Arrange
const overview: WorkflowOverview = generateTestWorkflowOverview({
category: input,
});

// Act
const resultCategory = mapWorkflowCategoryDTOFromString(overview.category);

// Assert
expect(resultCategory).toBeDefined();
expect(resultCategory).toBe(expected);
});
});

describe('scenarios to verify mapToWorkflowSpecFileDTO', () => {
it('correctly maps WorkflowSpecFile', () => {
// Arrange
const specV1: WorkflowSpecFile[] = generateTestWorkflowSpecs(1);

// Act
const result = mapToWorkflowSpecFileDTO(specV1[0]);

// Assert
expect(result.path).toBeDefined();
expect(result.path).toEqual('/test/path/openapi_0.json');
expect(result.content).toBeDefined();
expect(JSON.parse(result.content)).toEqual(fakeOpenAPIV3Document());
expect(Object.keys(result).length).toBe(2);
});
});
203 changes: 203 additions & 0 deletions plugins/orchestrator-backend/src/service/api/mapping/V2Mappings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
import moment from 'moment';

import {
ASSESSMENT_WORKFLOW_TYPE,
ExecuteWorkflowResponseDTO,
ProcessInstance,
ProcessInstanceDTO,
ProcessInstanceState,
ProcessInstanceStatusDTO,
WorkflowCategory,
WorkflowCategoryDTO,
WorkflowDataDTO,
WorkflowDefinition,
WorkflowDTO,
WorkflowExecutionResponse,
WorkflowListResult,
WorkflowListResultDTO,
WorkflowOverview,
WorkflowOverviewDTO,
WorkflowSpecFile,
WorkflowSpecFileDTO,
} from '@janus-idp/backstage-plugin-orchestrator-common';

// Mapping functions
export function mapToWorkflowOverviewDTO(
overview: WorkflowOverview,
): WorkflowOverviewDTO {
return {
...overview,
category: mapWorkflowCategoryDTOFromString(overview.category),
};
}

export function mapWorkflowCategoryDTOFromString(
category?: string,
): WorkflowCategoryDTO {
return category?.toLocaleLowerCase() === 'assessment'
? 'assessment'
: 'infrastructure';
}

export function mapToWorkflowListResultDTO(
definitions: WorkflowListResult,
): WorkflowListResultDTO {
const result = {
items: definitions.items.map(def => {
return {
annotations: def.definition.annotations,
category: getWorkflowCategoryDTO(def.definition),
description: def.definition.description,
name: def.definition.name,
uri: def.uri,
id: def.definition.id,
};
}),
paginationInfo: {
limit: definitions.limit,
offset: definitions.offset,
totalCount: definitions.totalCount,
},
};
return result;
}

export function getWorkflowCategoryDTO(
definition: WorkflowDefinition | undefined,
): WorkflowCategoryDTO {
let result: WorkflowCategoryDTO = 'infrastructure';

if (
definition?.annotations?.find(
annotation => annotation === ASSESSMENT_WORKFLOW_TYPE,
)
) {
result = 'assessment';
}

return result;
}

export function mapToWorkflowDTO(
uri: string,
definition: WorkflowDefinition,
): WorkflowDTO {
return {
annotations: definition.annotations,
category: getWorkflowCategoryDTO(definition),
description: definition.description,
name: definition.name,
uri: uri,
id: definition.id,
};
}

export function mapWorkflowCategoryDTO(
category?: WorkflowCategory,
): WorkflowCategoryDTO {
if (category === WorkflowCategory.ASSESSMENT) {
return 'assessment';
}
return 'infrastructure';
}

export function getProcessInstancesDTOFromString(
state: string,
): ProcessInstanceStatusDTO {
switch (state) {
case ProcessInstanceState.Active.valueOf():
return 'Running';
case ProcessInstanceState.Error.valueOf():
return 'Error';
case ProcessInstanceState.Completed.valueOf():
return 'Completed';
case ProcessInstanceState.Aborted.valueOf():
return 'Aborted';
case ProcessInstanceState.Suspended.valueOf():
return 'Suspended';
default:
throw new Error(
'state is not one of the values of type ProcessInstanceStatusDTO',
);
}
}

export function mapToProcessInstanceDTO(
processInstance: ProcessInstance,
): ProcessInstanceDTO {
const start = moment(processInstance.start?.toString());
const end = moment(processInstance.end?.toString());
const duration = moment.duration(start.diff(end));

let variables: Record<string, unknown> | undefined;
if (typeof processInstance?.variables === 'string') {
variables = JSON.parse(processInstance?.variables);
} else {
variables = processInstance?.variables;
}

return {
category: mapWorkflowCategoryDTO(processInstance.category),
description: processInstance.description,
duration: duration.humanize(),
id: processInstance.id,
name: processInstance.processName,
// To be fixed https://issues.redhat.com/browse/FLPATH-950
// @ts-ignore
workflowdata: variables?.workflowdata,
started: start.toDate().toLocaleString(),
status: getProcessInstancesDTOFromString(processInstance.state),
workflow: processInstance.processName ?? processInstance.processId,
};
}

export function mapToExecuteWorkflowResponseDTO(
workflowId: string,
workflowExecutionResponse: WorkflowExecutionResponse,
): ExecuteWorkflowResponseDTO {
if (!workflowExecutionResponse?.id) {
throw new Error(
`Error while mapping ExecuteWorkflowResponse to ExecuteWorkflowResponseDTO for workflow with id ${workflowId}`,
);
}

return {
id: workflowExecutionResponse.id,
};
}

export function mapToGetWorkflowInstanceResults(
variables: string | Record<string, unknown>,
): WorkflowDataDTO {
if (typeof variables === 'string') {
return {
variables: variables,
};
}

let returnObject = {};
if (variables?.workflowdata) {
returnObject = {
...variables.workflowdata,
};
} else {
returnObject = {
workflowoptions: [],
};
}

return returnObject;
}

export function mapToWorkflowSpecFileDTO(
specV1: WorkflowSpecFile,
): WorkflowSpecFileDTO {
if (!specV1.content) {
throw new Error('Workflow specification content is empty');
}

return {
content: JSON.stringify(specV1.content),
path: specV1.path,
};
}
Loading

0 comments on commit 43ac2f3

Please sign in to comment.