diff --git a/packages/@aws-cdk/aws-scheduler-alpha/.eslintrc.js b/packages/@aws-cdk/aws-scheduler-alpha/.eslintrc.js new file mode 100644 index 0000000000000..2a2c7498774d0 --- /dev/null +++ b/packages/@aws-cdk/aws-scheduler-alpha/.eslintrc.js @@ -0,0 +1,6 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; + +baseConfig.rules['import/no-extraneous-dependencies'] = ['error', { devDependencies: true, peerDependencies: true }]; + +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-scheduler-alpha/.gitignore b/packages/@aws-cdk/aws-scheduler-alpha/.gitignore new file mode 100644 index 0000000000000..4b4c1e6d4716a --- /dev/null +++ b/packages/@aws-cdk/aws-scheduler-alpha/.gitignore @@ -0,0 +1,24 @@ +*.d.ts +*.generated.ts +*.js +*.js.map +*.snk +.jsii +.jsii.gz +.LAST_BUILD +.LAST_PACKAGE +nyc.config.js +.nyc_output +.vscode +.types-compat +coverage +dist +tsconfig.json +!.eslintrc.js +!jest.config.js + +junit.xml +!**/*.snapshot/**/asset.*/*.js +!**/*.snapshot/**/asset.*/*.d.ts + +!**/*.snapshot/**/asset.*/** diff --git a/packages/@aws-cdk/aws-scheduler-alpha/.npmignore b/packages/@aws-cdk/aws-scheduler-alpha/.npmignore new file mode 100644 index 0000000000000..39a19f1bc4c14 --- /dev/null +++ b/packages/@aws-cdk/aws-scheduler-alpha/.npmignore @@ -0,0 +1,39 @@ +# The basics +*.ts +*.tgz +*.snk +!*.d.ts +!*.js +test/ +**/test/** + +# Coverage +coverage +.nyc_output +.nycrc + +# Build gear +build-tools +dist +scripts +.LAST_BUILD +.LAST_PACKAGE + +tsconfig.json +*.tsbuildinfo + +!.jsii +!.jsii.gz +.eslintrc.js + +# exclude cdk artifacts +**/cdk.out +junit.xml + +!*.lit.ts + +# exclude source maps as they only work locally +*.map + +# Nested node_modules +aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/node_modules diff --git a/packages/@aws-cdk/aws-scheduler-alpha/LICENSE b/packages/@aws-cdk/aws-scheduler-alpha/LICENSE new file mode 100644 index 0000000000000..9b722c65c5481 --- /dev/null +++ b/packages/@aws-cdk/aws-scheduler-alpha/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/@aws-cdk/aws-scheduler-alpha/NOTICE b/packages/@aws-cdk/aws-scheduler-alpha/NOTICE new file mode 100644 index 0000000000000..a27b7dd317649 --- /dev/null +++ b/packages/@aws-cdk/aws-scheduler-alpha/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/aws-scheduler-alpha/README.md b/packages/@aws-cdk/aws-scheduler-alpha/README.md new file mode 100644 index 0000000000000..171cecdf66854 --- /dev/null +++ b/packages/@aws-cdk/aws-scheduler-alpha/README.md @@ -0,0 +1,138 @@ +# Amazon EventBridge Scheduler Construct Library + + +--- + +![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge) + +> The APIs of higher level constructs in this module are experimental and under active development. +> They are subject to non-backward compatible changes or removal in any future version. These are +> not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be +> announced in the release notes. This means that while you may use them, you may need to update +> your source code when upgrading to a newer version of this package. + +--- + + + +[Amazon EventBridge Scheduler](https://aws.amazon.com/blogs/compute/introducing-amazon-eventbridge-scheduler/) is a feature from Amazon EventBridge +that allows you to create, run, and manage scheduled tasks at scale. With EventBridge Scheduler, you can schedule one-time or recurrently tens +of millions of tasks across many AWS services without provisioning or managing underlying infrastructure. + +1. **Schedule**: A schedule is the main resource you create, configure, and manage using Amazon EventBridge Scheduler. Every schedule has a schedule expression that determines when, and with what frequency, the schedule runs. EventBridge Scheduler supports three types of schedules: rate, cron, and one-time schedules. When you create a schedule, you configure a target for the schedule to invoke. +2. **Targets**: A target is an API operation that EventBridge Scheduler calls on your behalf every time your schedule runs. EventBridge Scheduler +supports two types of targets: templated targets and universal targets. Templated targets invoke common API operations across a core groups of +services. For example, EventBridge Scheduler supports templated targets for invoking AWS Lambda Function or starting execution of Step Function state +machine. For API operations that are not supported by templated targets you can use customizeable universal targets. Universal targets support calling +more than 6,000 API operations across over 270 AWS services. +3. **Schedule Group**: A schedule group is an Amazon EventBridge Scheduler resource that you use to organize your schedules. Your AWS account comes +with a default scheduler group. A new schedule will always be added to a scheduling group. If you do not provide a scheduling group to add to, it +will be added to the default scheduling group. You can create up to 500 schedule groups in your AWS account. Groups can be used to organize the +schedules logically, access the schedule metrics and manage permissions at group granularity (see details below). Scheduling groups support tagging: +with EventBridge Scheduler, you apply tags to schedule groups, not to individual schedules to organize your resources. + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. It allows you to define Event Bridge Schedules. + +> This module is in active development. Some features may not be implemented yet. + +## Defining a schedule + +TODO: Schedule is not yet implemented. See section in [L2 Event Bridge Scheduler RFC](https://github.com/aws/aws-cdk-rfcs/blob/master/text/0474-event-bridge-scheduler-l2.md) + +### Schedule Expressions + +You can choose from three schedule types when configuring your schedule: rate-based, cron-based, and one-time schedules. + +Both rate-based and cron-based schedules are recurring schedules. You can configure each recurring schedule type using a schedule expression. For +cron-based schedule you can specify a time zone in which EventBridge Scheduler evaluates the expression. + + +> ScheduleExpression should be used together with class Schedule, which is not yet implemented. + +[comment]: <> (TODO: Switch to `ts` once Schedule is implemented) + +```text +const rateBasedSchedule = new Schedule(this, 'Schedule', { + scheduleExpression: ScheduleExpression.rate(Duration.minutes(10)), + target, + description: 'This is a test rate-based schedule', +}); + +const cronBasedSchedule = new Schedule(this, 'Schedule', { + scheduleExpression: ScheduleExpression.cron({ + minute: '0', + hour: '23', + day: '20', + month: '11', + timeZone: TimeZone.AMERICA_NEW_YORK, + }), + target, + description: 'This is a test cron-based schedule that will run at 11:00 PM, on day 20 of the month, only in November in New York timezone', +}); +``` + +A one-time schedule is a schedule that invokes a target only once. You configure a one-time schedule when by specifying the time of the day, date, +and time zone in which EventBridge Scheduler evaluates the schedule. + +[comment]: <> (TODO: Switch to `ts` once Schedule is implemented) + +```text +const oneTimeSchedule = new Schedule(this, 'Schedule', { + scheduleExpression: ScheduleExpression.at( + new Date(2022, 10, 20, 19, 20, 23), + TimeZone.AMERICA_NEW_YORK, + ), + target, + description: 'This is a one-time schedule in New York timezone', +}); +``` + +### Grouping Schedules + +TODO: Group is not yet implemented. See section in [L2 Event Bridge Scheduler RFC](https://github.com/aws/aws-cdk-rfcs/blob/master/text/0474-event-bridge-scheduler-l2.md) + +## Scheduler Targets + +TODO: Scheduler Targets Module is not yet implemented. See section in [L2 Event Bridge Scheduler RFC](https://github.com/aws/aws-cdk-rfcs/blob/master/text/0474-event-bridge-scheduler-l2.md) + +### Input + +TODO: Target Input is not yet implemented. See section in [L2 Event Bridge Scheduler RFC](https://github.com/aws/aws-cdk-rfcs/blob/master/text/0474-event-bridge-scheduler-l2.md) + + +### Specifying Execution Role + +TODO: Not yet implemented. See section in [L2 Event Bridge Scheduler RFC](https://github.com/aws/aws-cdk-rfcs/blob/master/text/0474-event-bridge-scheduler-l2.md) + +### Cross-account and cross-region targets + +Executing cross-account and cross-region targets are not supported yet. + +### Specifying Encryption key + +TODO: Not yet implemented. See section in [L2 Event Bridge Scheduler RFC](https://github.com/aws/aws-cdk-rfcs/blob/master/text/0474-event-bridge-scheduler-l2.md) + +## Error-handling + +TODO: Not yet implemented. See section in [L2 Event Bridge Scheduler RFC](https://github.com/aws/aws-cdk-rfcs/blob/master/text/0474-event-bridge-scheduler-l2.md) + +## Overriding Target Properties + +TODO: Not yet implemented. See section in [L2 Event Bridge Scheduler RFC](https://github.com/aws/aws-cdk-rfcs/blob/master/text/0474-event-bridge-scheduler-l2.md) + + +## Monitoring + +You can monitor Amazon EventBridge Scheduler using CloudWatch, which collects raw data +and processes it into readable, near real-time metrics. EventBridge Scheduler emits +a set of metrics for all schedules, and an additional set of metrics for schedules that +have an associated dead-letter queue (DLQ). If you configure a DLQ for your schedule, +EventBridge Scheduler publishes additional metrics when your schedule exhausts its retry policy. + +### Metrics for all schedules + +TODO: Not yet implemented. See section in [L2 Event Bridge Scheduler RFC](https://github.com/aws/aws-cdk-rfcs/blob/master/text/0474-event-bridge-scheduler-l2.md) + +### Metrics for a Group + +TODO: Not yet implemented. See section in [L2 Event Bridge Scheduler RFC](https://github.com/aws/aws-cdk-rfcs/blob/master/text/0474-event-bridge-scheduler-l2.md) diff --git a/packages/@aws-cdk/aws-scheduler-alpha/jest.config.js b/packages/@aws-cdk/aws-scheduler-alpha/jest.config.js new file mode 100644 index 0000000000000..7ea6abe8036b2 --- /dev/null +++ b/packages/@aws-cdk/aws-scheduler-alpha/jest.config.js @@ -0,0 +1,10 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = { + ...baseConfig, + coverageThreshold: { + global: { + ...baseConfig.coverageThreshold.global, + branches: 60, + }, + }, + };; diff --git a/packages/@aws-cdk/aws-scheduler-alpha/lib/index.ts b/packages/@aws-cdk/aws-scheduler-alpha/lib/index.ts new file mode 100644 index 0000000000000..c00ab258ae963 --- /dev/null +++ b/packages/@aws-cdk/aws-scheduler-alpha/lib/index.ts @@ -0,0 +1 @@ +export * from './schedule-expression'; \ No newline at end of file diff --git a/packages/@aws-cdk/aws-scheduler-alpha/lib/schedule-expression.ts b/packages/@aws-cdk/aws-scheduler-alpha/lib/schedule-expression.ts new file mode 100644 index 0000000000000..89aa1f9205dae --- /dev/null +++ b/packages/@aws-cdk/aws-scheduler-alpha/lib/schedule-expression.ts @@ -0,0 +1,95 @@ +import { Duration, TimeZone } from 'aws-cdk-lib'; +import * as events from 'aws-cdk-lib/aws-events'; + +/** + * ScheduleExpression for EventBridge Schedule + * + * You can choose from three schedule types when configuring your schedule: rate-based, cron-based, and one-time schedules. + * Both rate-based and cron-based schedules are recurring schedules. + * + * @see https://docs.aws.amazon.com/scheduler/latest/UserGuide/schedule-types.html + */ +export abstract class ScheduleExpression { + /** + * Construct a one-time schedule from a date. + * + * @param date The date and time to use. The millisecond part will be ignored. + * @param timeZone The time zone to use for interpreting the date. Default: - UTC + */ + public static at(date: Date, timeZone?: TimeZone): ScheduleExpression { + try { + const literal = date.toISOString().split('.')[0]; + return new LiteralScheduleExpression(`at(${literal})`, timeZone ?? TimeZone.ETC_UTC); + } catch (e) { + if (e instanceof RangeError) { + throw new Error('Invalid date'); + } + throw e; + } + } + + /** + * Construct a schedule from a literal schedule expression + * @param expression The expression to use. Must be in a format that EventBridge will recognize + * @param timeZone The time zone to use for interpreting the expression. Default: - UTC + */ + public static expression(expression: string, timeZone?: TimeZone): ScheduleExpression { + return new LiteralScheduleExpression(expression, timeZone ?? TimeZone.ETC_UTC); + } + + /** + * Construct a recurring schedule from an interval and a time unit + * + * Rates may be defined with any unit of time, but when converted into minutes, the duration must be a positive whole number of minutes. + */ + public static rate(duration: Duration): ScheduleExpression { + const schedule = events.Schedule.rate(duration); + return new LiteralScheduleExpression(schedule.expressionString); + } + + /** + * Create a recurring schedule from a set of cron fields and time zone. + */ + public static cron(options: CronOptionsWithTimezone): ScheduleExpression { + const { timeZone, ...cronOptions } = options; + const schedule = events.Schedule.cron(cronOptions); + return new LiteralScheduleExpression(schedule.expressionString, timeZone); + } + + /** + * Retrieve the expression for this schedule + */ + public abstract readonly expressionString: string; + + /** + * Retrieve the expression for this schedule + */ + public abstract readonly timeZone?: TimeZone; + + protected constructor() {} +} + +/** + * Options to configure a cron expression + * + * All fields are strings so you can use complex expressions. Absence of + * a field implies '*' or '?', whichever one is appropriate. + * + * @see https://docs.aws.amazon.com/eventbridge/latest/userguide/scheduled-events.html#cron-expressions + */ +export interface CronOptionsWithTimezone extends events.CronOptions { + /** + * The timezone to run the schedule in + * + * @default - TimeZone.ETC_UTC + */ + readonly timeZone?: TimeZone; +} + +const DEFAULT_TIMEZONE = TimeZone.ETC_UTC; + +class LiteralScheduleExpression extends ScheduleExpression { + constructor(public readonly expressionString: string, public readonly timeZone: TimeZone = DEFAULT_TIMEZONE) { + super(); + } +} diff --git a/packages/@aws-cdk/aws-scheduler-alpha/package.json b/packages/@aws-cdk/aws-scheduler-alpha/package.json new file mode 100644 index 0000000000000..0dd7f971c0784 --- /dev/null +++ b/packages/@aws-cdk/aws-scheduler-alpha/package.json @@ -0,0 +1,119 @@ +{ + "name": "@aws-cdk/aws-scheduler-alpha", + "version": "0.0.0", + "description": "The CDK Construct Library for Amazon Scheduler", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "targets": { + "java": { + "package": "software.amazon.awscdk.services.scheduler.alpha", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "scheduler-alpha" + } + }, + "dotnet": { + "namespace": "Amazon.CDK.AWS.Scheduler.Alpha", + "packageId": "Amazon.CDK.AWS.Scheduler.Alpha", + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/main/logo/default-256-dark.png" + }, + "python": { + "distName": "aws-cdk.aws-scheduler-alpha", + "module": "aws_cdk.aws_scheduler_alpha", + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 2" + ] + }, + "go": { + "moduleName": "github.com/aws/aws-cdk-go", + "packageName": "awscdkscheduleralpha" + } + }, + "projectReferences": true, + "metadata": { + "jsii": { + "rosetta": { + "strict": true + } + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-scheduler-alpha" + }, + "homepage": "https://github.com/aws/aws-cdk", + "scripts": { + "build": "cdk-build", + "integ": "integ-runner", + "lint": "cdk-lint", + "package": "cdk-package", + "awslint": "cdk-awslint", + "pkglint": "pkglint -f", + "test": "cdk-test", + "watch": "cdk-watch", + "compat": "cdk-compat", + "build+test": "yarn build && yarn test", + "build+test+package": "yarn build+test && yarn package", + "rosetta:extract": "yarn --silent jsii-rosetta extract", + "build+extract": "yarn build && yarn rosetta:extract", + "build+test+extract": "yarn build+test && yarn rosetta:extract" + }, + "cdk-build": { + "env": { + "AWSLINT_BASE_CONSTRUCT": true + } + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "aws-scheduler" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/integ-runner": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^29.5.1", + "aws-cdk-lib": "0.0.0", + "constructs": "^10.0.0" + }, + "dependencies": {}, + "peerDependencies": { + "aws-cdk-lib": "^0.0.0", + "constructs": "^10.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "stability": "experimental", + "maturity": "experimental", + "awscdkio": { + "announce": false + }, + "publishConfig": { + "tag": "latest" + }, + "awslint": { + "exclude": [ + "*:*" + ] + }, + "pkglint": { + "exclude": [ + "naming/package-matches-directory", + "assert/assert-dependency" + ] + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-scheduler-alpha/rosetta/default.ts-fixture b/packages/@aws-cdk/aws-scheduler-alpha/rosetta/default.ts-fixture new file mode 100644 index 0000000000000..71131d04c63a3 --- /dev/null +++ b/packages/@aws-cdk/aws-scheduler-alpha/rosetta/default.ts-fixture @@ -0,0 +1,17 @@ +// Fixture with packages imported, but nothing else +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as kms from 'aws-cdk-lib/aws-kms'; +import * as sqs from 'aws-cdk-lib/aws-sqs'; +import * as cloudwatch from 'aws-cdk-lib/aws-cloudwatch'; +import { App, Stack, TimeZone, Duration } from 'aws-cdk-lib'; +import { ScheduleExpression } from '@aws-cdk/aws-scheduler-alpha'; + +class Fixture extends cdk.Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + /// here + } +} diff --git a/packages/@aws-cdk/aws-scheduler-alpha/test/schedule-expression.test.ts b/packages/@aws-cdk/aws-scheduler-alpha/test/schedule-expression.test.ts new file mode 100644 index 0000000000000..06fdb794ca600 --- /dev/null +++ b/packages/@aws-cdk/aws-scheduler-alpha/test/schedule-expression.test.ts @@ -0,0 +1,164 @@ +import { Duration, Lazy, Stack, TimeZone } from 'aws-cdk-lib'; +import { ScheduleExpression } from '../lib'; + +describe('schedule expression', () => { + test('cron expressions day and dow are mutex: given weekday', () => { + // Run every 10 minutes Monday through Friday + expect('cron(0/10 * ? * MON-FRI *)').toEqual(ScheduleExpression.cron({ + minute: '0/10', + weekDay: 'MON-FRI', + }).expressionString); + }); + + test('cron expressions day and dow are mutex: given month day', () => { + // Run at 8:00 am (UTC) every 1st day of the month + expect('cron(0 8 1 * ? *)').toEqual(ScheduleExpression.cron({ + minute: '0', + hour: '8', + day: '1', + }).expressionString); + }); + + test('cron expressions day and dow are mutex: given neither', () => { + // Run at 10:00 am (UTC) every day + expect('cron(0 10 * * ? *)').toEqual(ScheduleExpression.cron({ + minute: '0', + hour: '10', + }).expressionString); + }); + + test('cron expressions saves timezone', () => { + expect(TimeZone.EUROPE_LONDON).toEqual(ScheduleExpression.cron( + { + minute: '0', + hour: '10', + timeZone: TimeZone.EUROPE_LONDON, + }).timeZone); + }); + + test('cron expressions timezone is UTC if not specified', () => { + expect(TimeZone.ETC_UTC).toEqual(ScheduleExpression.cron( + { + minute: '0', + hour: '10', + }).timeZone); + }); + + test('rate cannot be 0', () => { + expect(() => { + ScheduleExpression.rate(Duration.days(0)); + }).toThrow(/Duration cannot be 0/); + }); + + test('rate cannot be negative', () => { + expect(() => { + ScheduleExpression.rate(Duration.minutes(-2)); + }).toThrow(/Duration amounts cannot be negative/); + }); + + test('rate can be from a token', () => { + const stack = new Stack(); + const lazyDuration = Duration.minutes(Lazy.number({ produce: () => 5 })); + const rate = ScheduleExpression.rate(lazyDuration); + expect('rate(5 minutes)').toEqual(stack.resolve(rate).expressionString); + }); + + test('rate can be in minutes', () => { + expect('rate(10 minutes)').toEqual( + ScheduleExpression.rate(Duration.minutes(10)) + .expressionString); + }); + + test('rate can be in days', () => { + expect('rate(10 days)').toEqual( + ScheduleExpression.rate(Duration.days(10)) + .expressionString); + }); + + test('rate can be in hours', () => { + expect('rate(10 hours)').toEqual( + ScheduleExpression.rate(Duration.hours(10)) + .expressionString); + }); + + test('rate can be in seconds', () => { + expect('rate(2 minutes)').toEqual( + ScheduleExpression.rate(Duration.seconds(120)) + .expressionString); + }); + + test('rate must not be in seconds when specified as a token', () => { + expect(() => { + ScheduleExpression.rate(Duration.seconds(Lazy.number({ produce: () => 5 }))); + }).toThrow(/Allowed units for scheduling/); + }); + + test('one-time expression string has expected date', () => { + const x = ScheduleExpression.at(new Date(2022, 10, 20, 19, 20, 23)); + expect(x.expressionString).toEqual('at(2022-11-20T19:20:23)'); + }); + + test('one-time expression time zone is UTC if not provided', () => { + const x = ScheduleExpression.at(new Date(2022, 10, 20, 19, 20, 23)); + expect(x.timeZone).toEqual(TimeZone.ETC_UTC); + }); + + test('one-time expression has expected time zone if provided', () => { + const x = ScheduleExpression.at(new Date(2022, 10, 20, 19, 20, 23), TimeZone.EUROPE_LONDON); + expect(x.expressionString).toEqual('at(2022-11-20T19:20:23)'); + expect(x.timeZone).toEqual(TimeZone.EUROPE_LONDON); + }); + + test('one-time expression milliseconds ignored', () => { + const x = ScheduleExpression.at(new Date(Date.UTC(2022, 10, 20, 19, 20, 23, 111))); + expect(x.expressionString).toEqual('at(2022-11-20T19:20:23)'); + }); + + test('one-time expression with invalid date throws', () => { + expect(() => ScheduleExpression.at(new Date('13-20-1969'))).toThrowError('Invalid date'); + }); +}); + +describe('fractional minutes checks', () => { + test('rate cannot be a fractional amount of minutes (defined with seconds)', () => { + expect(() => { + ScheduleExpression.rate(Duration.seconds(150)); + }).toThrow(/cannot be converted into a whole number of/); + }); + + test('rate cannot be a fractional amount of minutes (defined with minutes)', () => { + expect(()=> { + ScheduleExpression.rate(Duration.minutes(5/3)); + }).toThrow(/must be a whole number of/); + }); + + test('rate cannot be a fractional amount of minutes (defined with hours)', () => { + expect(()=> { + ScheduleExpression.rate(Duration.hours(1.03)); + }).toThrow(/cannot be converted into a whole number of/); + }); + + test('rate cannot be less than 1 minute (defined with seconds)', () => { + expect(() => { + ScheduleExpression.rate(Duration.seconds(30)); + }).toThrow(/'30 seconds' cannot be converted into a whole number of minutes./); + }); + + test('rate cannot be less than 1 minute (defined with minutes as fractions)', () => { + expect(() => { + ScheduleExpression.rate(Duration.minutes(1/2)); + }).toThrow(/must be a whole number of/); + }); + + test('rate cannot be less than 1 minute (defined with minutes as decimals)', () => { + expect(() => { + ScheduleExpression.rate(Duration.minutes(0.25)); + }).toThrow(/must be a whole number of/); + }); + + test('rate can be in minutes', () => { + expect('rate(10 minutes)').toEqual( + ScheduleExpression.rate(Duration.minutes(10)) + .expressionString); + }); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-scheduler-alpha/tsconfig.dev.json b/packages/@aws-cdk/aws-scheduler-alpha/tsconfig.dev.json new file mode 100644 index 0000000000000..4470bb29bf6da --- /dev/null +++ b/packages/@aws-cdk/aws-scheduler-alpha/tsconfig.dev.json @@ -0,0 +1,38 @@ +{ + "$": "Config file for ts-node", + "ts-node": { + "preferTsExts": true + }, + "compilerOptions": { + "alwaysStrict": true, + "experimentalDecorators": true, + "incremental": true, + "lib": [ + "es2020" + ], + "module": "CommonJS", + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "strictNullChecks": true, + "strictPropertyInitialization": true, + "stripInternal": false, + "target": "ES2020", + "composite": false, + "tsBuildInfoFile": "tsconfig.dev.tsbuildinfo" + }, + "include": [ + "**/*.ts" + ], + "exclude": [ + "node_modules", + ".types-compat", + "**/*.d.ts" + ] +}