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(scheduler-targets): add support for universal target #32341

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
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
40 changes: 40 additions & 0 deletions packages/@aws-cdk/aws-scheduler-targets-alpha/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ The following targets are supported:
9. `targets.KinesisDataFirehosePutRecord`: [Put a record to a Kinesis Data Firehose](#put-a-record-to-a-kinesis-data-firehose)
10. `targets.CodePipelineStartPipelineExecution`: [Start a CodePipeline execution](#start-a-codepipeline-execution)
11. `targets.SageMakerStartPipelineExecution`: [Start a SageMaker pipeline execution](#start-a-sagemaker-pipeline-execution)
12. `targets.AwsApi`: [Invoke a wider set of AWS API](#invoke-a-wider-set-of-aws-api)

## Invoke a Lambda function

Expand Down Expand Up @@ -312,3 +313,42 @@ new Schedule(this, 'Schedule', {
}),
});
```

## Invoke a wider set of AWS API

Use the `AwsApi` target to invoke AWS API.

The code snippet below creates an event rule with AWS API as the target which is
called at midnight every day by EventBridge Scheduler.

```ts
new Schedule(this, 'Schedule', {
schedule: ScheduleExpression.cron({
minute: '0',
hour: '0',
}),
target: new targets.AwsApi({
service: 'rds',
action: 'stopDBCluster',
input: ScheduleTargetInput.fromObject({
DbClusterIdentifier: 'my-db',
}),
}),
});
```

The `service` is must be in lower case and the `action` is must be in camelCase.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The `service` is must be in lower case and the `action` is must be in camelCase.
The `service` must be in lower case and the `action` is must be in camelCase.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad, fixed.
209f6ea


You can also set any Action and Resource in the EventBridge Scheduler's IAM Policy by specifying `iamAction` and `iamResources`.

```ts
new Schedule(this, 'Schedule', {
schedule: ScheduleExpression.rate(Duration.minutes(60)),
target: new targets.AwsApi({
service: 'lambda',
action: 'invoke',
iamAction: 'lambda:InvokeFunction',
iamResources: ['arn:aws:lambda:us-east-1:111111111111:function:my-function'],
}),
});
```
111 changes: 111 additions & 0 deletions packages/@aws-cdk/aws-scheduler-targets-alpha/lib/aws-api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { IScheduleTarget } from '@aws-cdk/aws-scheduler-alpha';
import { Aws, Token } from 'aws-cdk-lib';
import { IRole, PolicyStatement } from 'aws-cdk-lib/aws-iam';
import { awsSdkToIamAction } from 'aws-cdk-lib/custom-resources/lib/helpers-internal';
import { ScheduleTargetBase, ScheduleTargetBaseProps } from './target';

/**
* AWS read-only API action name prefixes that are not supported by EventBridge Scheduler.
*
* @see https://docs.aws.amazon.com/scheduler/latest/UserGuide/managing-targets-universal.html
*/
const NOT_SUPPORTED_ACTION_PREFIX = [
'get',
'describe',
'list',
'poll',
'receive',
'search',
'scan',
'query',
'select',
'read',
'lookup',
'discover',
'validate',
'batchGet',
'batchDescribe',
'batchRead',
'transactGet',
'adminGet',
'adminList',
'testMigration',
'retrieve',
'testConnection',
'translateDocument',
'isAuthorized',
'invokeModel',
];

/**
* Properties for a AWS API Target
*/
export interface AwsApiProps extends ScheduleTargetBaseProps {
/**
* The AWS service to call.
*
* This must be in lowercase.
*/
readonly service: string;

/**
* The API action to call.
*
* You cannot use read-only API actions such as common GET operations.
* For more information, see the {@link https://docs.aws.amazon.com/scheduler/latest/UserGuide/managing-targets-universal.html}.
*
* ALso, This must be in camelCase.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* ALso, This must be in camelCase.
* Also, This must be in camelCase.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.
7b4a4ec

*/
readonly action: string;

/**
* The resource ARNs for the IAM statement that will be added to
* the execution role's policy to allow the scheduler to make the API call.
*
* @default - ['*']
*/
readonly iamResources?: string[];

/**
* The action for the IAM statement that will be added to
* the execution role's policy to allow the scheduler to make the API call.
*
* Use in the case where the IAM action name does not match with the
* API service/action name, e.g. `s3:listObjectV2` requires `s3:ListBucket`.
*
* @default - service:action
*/
readonly iamAction?: string;
}

/**
* Send an event to an AWS EventBridge by AWS EventBridge Scheduler.
*/
export class AwsApi extends ScheduleTargetBase implements IScheduleTarget {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A class name of Universal might be nice to match the RFC and userguide:

https://github.com/aws/aws-cdk-rfcs/blob/main/text/0474-event-bridge-scheduler-l2.md

Universal target automatically create an IAM role if you do not specify your own IAM role. However, in comparison with templated targets, for universal targets you must grant the required IAM permissions yourself.

const target = new targets.Universal('sqs', 'CreateQueue', { input: input });

https://docs.aws.amazon.com/scheduler/latest/UserGuide/managing-targets-universal.html

A universal target is a customizable set of parameters that allow you to invoke a wider set of API operation for many AWS services.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missed the RFC document.
Changed construct name to Universal.
319ae62#diff-e0a0ad08b68d00bc54d5c89f36ff0a08cb03f762ddd7768cae6ff2ea4edebcc5

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please change the description in this PR?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see:

Added AwsAPI constructs targeting AWS APIs.

constructor(
private readonly props: AwsApiProps,
) {
const service = props.service;
const action = props.action;

if (!Token.isUnresolved(service) && service !== service.toLowerCase()) {
throw new Error(`API service must be lowercase, got: ${service}`);
}
if (!Token.isUnresolved(action) && !action.startsWith(action[0]?.toLowerCase())) {
throw new Error(`API action must be camelCase, got: ${action}`);
}
if (!Token.isUnresolved(action) && NOT_SUPPORTED_ACTION_PREFIX.some(prefix => action.startsWith(prefix))) {
throw new Error(`Read-only API action is not supported by EventBridge Scheduler: ${service}:${action}`);
}

const arn = `arn:${Aws.PARTITION}:scheduler:::aws-sdk:${service}:${action}`;
super(props, arn);
}

protected addTargetActionToRole(role: IRole): void {
role.addToPrincipalPolicy(new PolicyStatement({
actions: [this.props.iamAction ?? awsSdkToIamAction(this.props.service, this.props.action)],
resources: this.props.iamResources ?? ['*'],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any cases where more than one action is required?

For example: S3 put with KMS key.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There may be cases where conditions are also needed...?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that could be the case.
Added an array of PolicyStatemants to the props.

}));
}
}
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-scheduler-targets-alpha/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export * from './sns-publish';
export * from './sqs-send-message';
export * from './stepfunctions-start-execution';
export * from './target';
export * from './aws-api';
Loading
Loading