Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(orchestrator): add OpenAPI v2 implementations #1182

Merged
merged 25 commits into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
757b740
Implement getWorkflowOverviewById (v2)
gciavarrini Feb 2, 2024
da459f6
Implementation of getWorkflows (v2)
gciavarrini Feb 2, 2024
71cf743
Implementation of getWorkflowById (v2)
gciavarrini Feb 2, 2024
051399f
Implementation of getInstances (v2)
gciavarrini Feb 15, 2024
d672cdb
Implementation of getInstancesById (v2)
gciavarrini Feb 15, 2024
30df0ed
Definition of getWorkflowResults (v2)
gciavarrini Feb 5, 2024
a6812d2
Definition of getWorkflowStatuses (v2)
gciavarrini Feb 5, 2024
d827a70
Refactor: use namespaces for api versions
gciavarrini Feb 5, 2024
f864e0f
Definition of executeWorkflow (v2)
gciavarrini Feb 5, 2024
811b91a
Implementation of executeWorkflow (v2)
rhkp Feb 5, 2024
711e904
Implementation of createWorkflow (v2)
gciavarrini Feb 5, 2024
b492f12
Definition of abortWorkflow (v2)
gciavarrini Feb 5, 2024
008b03a
Implementation of abortWorkflow (v2)
jude-at-redhat Feb 6, 2024
92038d2
Implementation of getWorkflowResults (v2)
rhkp Feb 7, 2024
bfd94b2
Implementation of getWorkflowSpecs (v2)
gciavarrini Feb 5, 2024
970ab58
fix(orchestrator): remove enum types from openapi types.ts
ydayagi Feb 8, 2024
9da2827
Implementation of getWorkflowStatuses (v2)
gciavarrini Feb 9, 2024
ce5f3e1
Add autogenerated api doc
gciavarrini Feb 2, 2024
c5164fc
Fix: rename getWorkflowsOverview (v1 and v2)
gciavarrini Feb 16, 2024
4a41c09
Unit Test: getWorkflowOverview (v2)
gciavarrini Feb 16, 2024
eada0ad
Unit Test: getWorkflowOverviewById (v2)
gciavarrini Feb 12, 2024
d84addf
Unit Test: getWorkflowSpecs (v2)
gciavarrini Feb 16, 2024
1588fc3
Unit Test: getWorkflowById (v2)
gciavarrini Feb 16, 2024
ac5ac96
Fix: typo
gciavarrini Feb 20, 2024
834302f
Fix: use ternary conditional operator
gciavarrini Feb 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading