Skip to content

Commit

Permalink
feat: exposing FlowStatus for the triggered flows. (#19)
Browse files Browse the repository at this point in the history
With this PR the library uses the new [FlowStatus](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appflow-flow.html#cfn-appflow-flow-flowstatus) field for activating/deactivating a triggered flow. 

It deprecates the use of [a custom resource](https://github.com/cdklabs/cdk-appflow/blob/a252fa11780da4b75ff0b1016199e561db874d13/src/core/flows/triggered-flow-base.ts#L23) and thus will result in changes to the generated template (less resources) with no change in the functionality.
  • Loading branch information
rpawlaszek authored Sep 14, 2023
1 parent a252fa1 commit 7bc31df
Show file tree
Hide file tree
Showing 9 changed files with 225 additions and 211 deletions.
172 changes: 143 additions & 29 deletions API.md

Large diffs are not rendered by default.

33 changes: 33 additions & 0 deletions src/core/flows/flow-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,45 @@ import { IDestination } from '../vertices/destination';
import { ISource } from '../vertices/source';

export interface IFlow extends IResource {
/**
* The ARN of the flow.
*/
readonly arn: string;

/**
* The name of the flow
*/
readonly name: string;

/**
* The type of the flow.
*/
readonly type: FlowType;

onRunStarted(id: string, options?: OnEventOptions): Rule;

onRunCompleted(id: string, options?: OnEventOptions): Rule;

/**
* @internal
*/
_addMapping(mapping: IMapping): IFlow;

/**
* @internal
*/
_addValidation(validator: IValidation): IFlow;

/**
* @internal
*/
_addTransform(transform: ITransform): IFlow;

/**
* @internal
*/
_addFilter(filter: IFilter): IFlow;

/**
* @internal
*/
Expand All @@ -51,6 +67,11 @@ export enum FlowType {
SCHEDULED = 'Scheduled'
}

export enum FlowStatus {
ACTIVE = 'Active',
SUSPENDED = 'Suspended'
}

export enum DataPullMode {
COMPLETE = 'Complete',
INCREMENTAL = 'Incremental'
Expand Down Expand Up @@ -103,13 +124,24 @@ export interface FlowProps {
export interface FlowBaseProps extends FlowProps {
readonly type: FlowType;
readonly triggerConfig?: TriggerConfig;
readonly status?: FlowStatus;
}

export abstract class FlowBase extends Resource implements IFlow {

/**
* The ARN of the flow.
*/
public readonly arn: string;

/**
* The type of the flow.
*/
public readonly type: FlowType;

/**
* The name of the flow.
*/
public readonly name: string;

private readonly mappings: CfnFlow.TaskProperty[] = [];
Expand All @@ -133,6 +165,7 @@ export abstract class FlowBase extends Resource implements IFlow {
this.name = props.name || id;
const resource = new CfnFlow(this, id, {
flowName: this.name,
flowStatus: props.status,
triggerConfig: {
triggerType: props.type,
triggerProperties: props.triggerConfig
Expand Down
3 changes: 2 additions & 1 deletion src/core/flows/on-event-flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ export class OnEventFlow extends TriggeredFlowBase implements IFlow {
super(scope, id, {
...props,
type: FlowType.EVENT,
}, props.autoActivate);
status: TriggeredFlowBase.setStatus(props.autoActivate, props.status),
});
}

public onDeactivated(id: string, options: OnEventOptions = {}) {
Expand Down
3 changes: 2 additions & 1 deletion src/core/flows/on-schedule-flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@ export class OnScheduleFlow extends TriggeredFlowBase implements IFlow {
super(scope, id, {
...props,
type: FlowType.SCHEDULED,
status: TriggeredFlowBase.setStatus(props.autoActivate, props.status),
triggerConfig: {
properties: {
schedule: props.schedule,
dataPullConfig: props.pullConfig,
properties: props.scheduleProperties,
},
},
}, props.autoActivate);
});
}

public onDeactivated(id: string, options: OnEventOptions = {}) {
Expand Down
65 changes: 34 additions & 31 deletions src/core/flows/triggered-flow-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,50 @@ Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
import { OnEventOptions, Rule } from 'aws-cdk-lib/aws-events';
import { AwsCustomResource, AwsCustomResourcePolicy, PhysicalResourceId } from 'aws-cdk-lib/custom-resources';
import { Construct } from 'constructs';
import { FlowBase, FlowBaseProps, FlowProps, IFlow } from './flow-base';
import { FlowBase, FlowBaseProps, FlowProps, FlowStatus, IFlow } from './flow-base';

export interface TriggeredFlowBaseProps extends FlowProps {
/**
* The status to set on the flow. Use this over {@link autoActivate}.
*/
readonly status?: FlowStatus;
/**
* @deprecated. This property is deprecated and will be removed in a future release. Use {@link status} instead
*/
readonly autoActivate?: boolean;
}

/**
* A base class for triggered flows.
*/
export abstract class TriggeredFlowBase extends FlowBase implements IFlow {

constructor(scope: Construct, id: string, props: FlowBaseProps, autoActivate?: boolean) {
super(scope, id, props);

if (autoActivate) {
const activatorId = `${id}Activator`;

// TODO: this is too basic. test it more to identify any potential errors/issues
const activator = new AwsCustomResource(scope, activatorId, {
onCreate: {
service: 'Appflow',
action: 'startFlow',
parameters: {
flowName: this.name,
},
physicalResourceId: PhysicalResourceId.of(activatorId),
},
onDelete: {
service: 'Appflow',
action: 'stopFlow',
parameters: {
flowName: this.name,
},
},
policy: AwsCustomResourcePolicy.fromSdkCalls({
resources: AwsCustomResourcePolicy.ANY_RESOURCE,
}),
});

activator.node.addDependency(this);
/**
*
* @param autoActivate - a boolean value indicating whether to automatically activate the flow.
* @param status - a {@link FlowStatus} value indicating the status to set on the flow.
* @returns
*/
protected static setStatus(autoActivate?: boolean, status?: FlowStatus): FlowStatus | undefined {
if (autoActivate !== undefined && status !== undefined) {
throw new Error('Cannot specify both autoActivate and status');
}

return autoActivate !== undefined ?
(autoActivate ? FlowStatus.ACTIVE : FlowStatus.SUSPENDED) :
(status !== undefined ? status : undefined);
}
/**
*
* @param scope
* @param id
* @param props
*/
constructor(scope: Construct, id: string, props: FlowBaseProps) {
super(scope, id, props);
}

public abstract onDeactivated(id: string, options?: OnEventOptions): Rule;

}
22 changes: 5 additions & 17 deletions test/core/flows/on-event-flow.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ SPDX-License-Identifier: Apache-2.0
import { Stack } from 'aws-cdk-lib';
import { Template } from 'aws-cdk-lib/assertions';
import { Bucket } from 'aws-cdk-lib/aws-s3';
import { OnEventFlow, SalesforceSource, EventBridgeDestination, EventSources, Mapping, SalesforceConnectorProfile } from '../../../src';
import { OnEventFlow, SalesforceSource, EventBridgeDestination, EventSources, Mapping, SalesforceConnectorProfile, FlowStatus } from '../../../src';

describe('OnEventFlow', () => {
test.each([{
Expand All @@ -30,7 +30,7 @@ describe('OnEventFlow', () => {
source: source,
destination: destination,
mappings: [Mapping.mapAll()],
autoActivate: true,
status: FlowStatus.ACTIVE,
});

flow.onDeactivated('OnDeactivated', namedRules ? {
Expand Down Expand Up @@ -72,6 +72,7 @@ describe('OnEventFlow', () => {
},
],
FlowName: 'OnEventFlow',
FlowStatus: 'Active',
SourceFlowConfig: {
ConnectorProfileName: 'appflow-tester',
ConnectorType: 'Salesforce',
Expand Down Expand Up @@ -148,20 +149,6 @@ describe('OnEventFlow', () => {
},
State: 'ENABLED',
});

template.resourceCountIs('Custom::AWS', 1);

template.hasResourceProperties('Custom::AWS', {
ServiceToken: {
'Fn::GetAtt': [
'AWS679f53fac002430cb0da5b7982bd22872D164C4C',
'Arn',
],
},
Create: '{"service":"Appflow","action":"startFlow","parameters":{"flowName":"OnEventFlow"},"physicalResourceId":{"id":"OnEventFlowActivator"}}',
Delete: '{"service":"Appflow","action":"stopFlow","parameters":{"flowName":"OnEventFlow"}}',
InstallLatestAwsSdk: true,
});
});

test('autoactivated flow without status and deactivation listeners renders flow definition only', () => {
Expand All @@ -182,13 +169,14 @@ describe('OnEventFlow', () => {
source: source,
destination: destination,
mappings: [Mapping.mapAll()],
autoActivate: false,
status: FlowStatus.SUSPENDED,
});

const template = Template.fromStack(stack);

template.hasResource('AWS::AppFlow::Flow', {
Properties: {
FlowStatus: 'Suspended',
DestinationFlowConfigList: [
{
ConnectorType: 'EventBridge',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,28 +79,15 @@
}
}
},
"f9346b940b724b094a16ca051c017799995fa93df6da38a0539bf7c000fee50a": {
"source": {
"path": "asset.f9346b940b724b094a16ca051c017799995fa93df6da38a0539bf7c000fee50a",
"packaging": "zip"
},
"destinations": {
"current_account-current_region": {
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
"objectKey": "f9346b940b724b094a16ca051c017799995fa93df6da38a0539bf7c000fee50a.zip",
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
}
}
},
"70e9e81a17e28b416e6cddd53c6f664013051489338e6fb4049fc03220fd5b32": {
"593c27ba9998e04fb75a5b15e6f87386ea622fd825ad3003bc96380f0567da22": {
"source": {
"path": "TestStack.template.json",
"packaging": "file"
},
"destinations": {
"current_account-current_region": {
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
"objectKey": "70e9e81a17e28b416e6cddd53c6f664013051489338e6fb4049fc03220fd5b32.json",
"objectKey": "593c27ba9998e04fb75a5b15e6f87386ea622fd825ad3003bc96380f0567da22.json",
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
}
}
Expand Down
Loading

0 comments on commit 7bc31df

Please sign in to comment.