Skip to content

Commit 890c4c5

Browse files
authored
feat(aws-s3): Adding Intelligent Tiering to Bucket (#18013)
Allows users to add Intelligent Tiering to their s3 buckets. Modelling of CfnBucket was done before. Fixes #16191 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 65414c6 commit 890c4c5

8 files changed

+380
-16
lines changed

packages/@aws-cdk/aws-s3/README.md

+19-2
Original file line numberDiff line numberDiff line change
@@ -480,15 +480,32 @@ by deploying with CDK version `1.126.0` or later **before** switching this value
480480

481481
```ts
482482
const bucket = new s3.Bucket(this, 'MyBucket', {
483-
transferAcceleration: true,
483+
transferAcceleration: true,
484484
});
485485
```
486486

487487
To access the bucket that is enabled for Transfer Acceleration, you must use a special endpoint. The URL can be generated using method `transferAccelerationUrlForObject`:
488488

489489
```ts
490490
const bucket = new s3.Bucket(this, 'MyBucket', {
491-
transferAcceleration: true,
491+
transferAcceleration: true,
492492
});
493493
bucket.transferAccelerationUrlForObject('objectname');
494494
```
495+
496+
## Intelligent Tiering
497+
498+
[Intelligent Tiering](https://docs.aws.amazon.com/AmazonS3/latest/userguide/intelligent-tiering.html) can be configured to automatically move files to glacier:
499+
500+
```ts
501+
new s3.Bucket(this, 'MyBucket', {
502+
intelligentTieringConfigurations: [{
503+
name: 'foo',
504+
prefix: 'folder/name',
505+
archiveAccessTierTime: cdk.Duration.days(90),
506+
deepArchiveAccessTierTime: cdk.Duration.days(180),
507+
tags: [{key: 'tagname', value: 'tagvalue'}]
508+
}],
509+
});
510+
511+
```

packages/@aws-cdk/aws-s3/lib/bucket.ts

+160-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import * as iam from '@aws-cdk/aws-iam';
55
import * as kms from '@aws-cdk/aws-kms';
66
import {
77
Fn, IResource, Lazy, RemovalPolicy, Resource, ResourceProps, Stack, Token,
8-
CustomResource, CustomResourceProvider, CustomResourceProviderRuntime, FeatureFlags, Tags,
8+
CustomResource, CustomResourceProvider, CustomResourceProviderRuntime, FeatureFlags, Tags, Duration,
99
} from '@aws-cdk/core';
1010
import * as cxapi from '@aws-cdk/cx-api';
1111
import { Construct } from 'constructs';
@@ -1222,6 +1222,48 @@ export enum ObjectOwnership {
12221222
*/
12231223
OBJECT_WRITER = 'ObjectWriter',
12241224
}
1225+
/**
1226+
* The intelligent tiering configuration.
1227+
*/
1228+
export interface IntelligentTieringConfiguration {
1229+
/**
1230+
* Configuration name
1231+
*/
1232+
readonly name: string;
1233+
1234+
1235+
/**
1236+
* Add a filter to limit the scope of this configuration to a single prefix.
1237+
*
1238+
* @default this configuration will apply to **all** objects in the bucket.
1239+
*/
1240+
readonly prefix?: string;
1241+
1242+
/**
1243+
* You can limit the scope of this rule to the key value pairs added below.
1244+
*
1245+
* @default No filtering will be performed on tags
1246+
*/
1247+
readonly tags?: Tag[];
1248+
1249+
/**
1250+
* When enabled, Intelligent-Tiering will automatically move objects that
1251+
* haven’t been accessed for a minimum of 90 days to the Archive Access tier.
1252+
*
1253+
* @default Objects will not move to Glacier
1254+
*/
1255+
readonly archiveAccessTierTime?: Duration;
1256+
1257+
/**
1258+
* When enabled, Intelligent-Tiering will automatically move objects that
1259+
* haven’t been accessed for a minimum of 180 days to the Deep Archive Access
1260+
* tier.
1261+
*
1262+
* @default Objects will not move to Glacier Deep Access
1263+
*/
1264+
readonly deepArchiveAccessTierTime?: Duration;
1265+
}
1266+
12251267
export interface BucketProps {
12261268
/**
12271269
* The kind of server-side encryption to apply to this bucket.
@@ -1418,6 +1460,31 @@ export interface BucketProps {
14181460
* @default false
14191461
*/
14201462
readonly transferAcceleration?: boolean;
1463+
1464+
/**
1465+
* Inteligent Tiering Configurations
1466+
*
1467+
* @see https://docs.aws.amazon.com/AmazonS3/latest/userguide/intelligent-tiering.html
1468+
*
1469+
* @default No Intelligent Tiiering Configurations.
1470+
*/
1471+
readonly intelligentTieringConfigurations?: IntelligentTieringConfiguration[];
1472+
}
1473+
1474+
1475+
/**
1476+
* Tag
1477+
*/
1478+
export interface Tag {
1479+
1480+
/**
1481+
* key to e tagged
1482+
*/
1483+
readonly key: string;
1484+
/**
1485+
* additional value
1486+
*/
1487+
readonly value: string;
14211488
}
14221489

14231490
/**
@@ -1585,6 +1652,7 @@ export class Bucket extends BucketBase {
15851652
inventoryConfigurations: Lazy.any({ produce: () => this.parseInventoryConfiguration() }),
15861653
ownershipControls: this.parseOwnershipControls(props),
15871654
accelerateConfiguration: props.transferAcceleration ? { accelerationStatus: 'Enabled' } : undefined,
1655+
intelligentTieringConfigurations: this.parseTieringConfig(props),
15881656
});
15891657
this._resource = resource;
15901658

@@ -1887,6 +1955,35 @@ export class Bucket extends BucketBase {
18871955
};
18881956
}
18891957

1958+
private parseTieringConfig({ intelligentTieringConfigurations }: BucketProps): CfnBucket.IntelligentTieringConfigurationProperty[] | undefined {
1959+
if (!intelligentTieringConfigurations) {
1960+
return undefined;
1961+
}
1962+
1963+
return intelligentTieringConfigurations.map(config => {
1964+
const tierings = [];
1965+
if (config.archiveAccessTierTime) {
1966+
tierings.push({
1967+
accessTier: 'ARCHIVE_ACCESS',
1968+
days: config.archiveAccessTierTime.toDays({ integral: true }),
1969+
});
1970+
}
1971+
if (config.deepArchiveAccessTierTime) {
1972+
tierings.push({
1973+
accessTier: 'DEEP_ARCHIVE_ACCESS',
1974+
days: config.deepArchiveAccessTierTime.toDays({ integral: true }),
1975+
});
1976+
}
1977+
return {
1978+
id: config.name,
1979+
prefix: config.prefix,
1980+
status: 'Enabled',
1981+
tagFilters: config.tags,
1982+
tierings: tierings,
1983+
};
1984+
});
1985+
}
1986+
18901987
private renderWebsiteConfiguration(props: BucketProps): CfnBucket.WebsiteConfigurationProperty | undefined {
18911988
if (!props.websiteErrorDocument && !props.websiteIndexDocument && !props.websiteRedirect && !props.websiteRoutingRules) {
18921989
return undefined;
@@ -2057,6 +2154,7 @@ export enum BucketEncryption {
20572154

20582155
/**
20592156
* Notification event types.
2157+
* @link https://docs.aws.amazon.com/AmazonS3/latest/userguide/notification-how-to-event-types-and-destinations.html#supported-notification-event-types
20602158
*/
20612159
export enum EventType {
20622160
/**
@@ -2208,6 +2306,67 @@ export enum EventType {
22082306
* by replication metrics.
22092307
*/
22102308
REPLICATION_OPERATION_NOT_TRACKED = 's3:Replication:OperationNotTracked',
2309+
2310+
/**
2311+
* By using the LifecycleExpiration event types, you can receive a notification
2312+
* when Amazon S3 deletes an object based on your S3 Lifecycle configuration.
2313+
*/
2314+
LIFECYCLE_EXPIRATION = 's3:LifecycleExpiration:*',
2315+
2316+
/**
2317+
* The s3:LifecycleExpiration:Delete event type notifies you when an object
2318+
* in an unversioned bucket is deleted.
2319+
* It also notifies you when an object version is permanently deleted by an
2320+
* S3 Lifecycle configuration.
2321+
*/
2322+
LIFECYCLE_EXPIRATION_DELETE = 's3:LifecycleExpiration:Delete',
2323+
2324+
/**
2325+
* The s3:LifecycleExpiration:DeleteMarkerCreated event type notifies you
2326+
* when S3 Lifecycle creates a delete marker when a current version of an
2327+
* object in versioned bucket is deleted.
2328+
*/
2329+
LIFECYCLE_EXPIRATION_DELETE_MARKER_CREATED = 's3:LifecycleExpiration:DeleteMarkerCreated',
2330+
2331+
/**
2332+
* You receive this notification event when an object is transitioned to
2333+
* another Amazon S3 storage class by an S3 Lifecycle configuration.
2334+
*/
2335+
LIFECYCLE_TRANSITION = 's3:LifecycleTransition',
2336+
2337+
/**
2338+
* You receive this notification event when an object within the
2339+
* S3 Intelligent-Tiering storage class moved to the Archive Access tier or
2340+
* Deep Archive Access tier.
2341+
*/
2342+
INTELLIGENT_TIERING = 's3:IntelligentTiering',
2343+
2344+
/**
2345+
* By using the ObjectTagging event types, you can enable notification when
2346+
* an object tag is added or deleted from an object.
2347+
*/
2348+
OBJECT_TAGGING = 's3:ObjectTagging:*',
2349+
2350+
/**
2351+
* The s3:ObjectTagging:Put event type notifies you when a tag is PUT on an
2352+
* object or an existing tag is updated.
2353+
2354+
*/
2355+
OBJECT_TAGGING_PUT = 's3:ObjectTagging:Put',
2356+
2357+
/**
2358+
* The s3:ObjectTagging:Delete event type notifies you when a tag is removed
2359+
* from an object.
2360+
*/
2361+
OBJECT_TAGGING_DELETE = 's3:ObjectTagging:Delete',
2362+
2363+
/**
2364+
* You receive this notification event when an ACL is PUT on an object or when
2365+
* an existing ACL is changed.
2366+
* An event is not generated when a request results in no change to an
2367+
* object’s ACL.
2368+
*/
2369+
OBJECT_ACL_PUT = 's3:ObjectAcl:Put',
22112370
}
22122371

22132372
export interface NotificationKeyFilter {

packages/@aws-cdk/aws-s3/test/bucket.test.ts

+138-1
Original file line numberDiff line numberDiff line change
@@ -2671,7 +2671,144 @@ describe('bucket', () => {
26712671
},
26722672
},
26732673
});
2674+
});
2675+
2676+
test('bucket with intelligent tiering turned on', () => {
2677+
const stack = new cdk.Stack();
2678+
new s3.Bucket(stack, 'MyBucket', {
2679+
intelligentTieringConfigurations: [{
2680+
name: 'foo',
2681+
}],
2682+
});
2683+
2684+
expect(stack).toMatchTemplate({
2685+
'Resources': {
2686+
'MyBucketF68F3FF0': {
2687+
'Type': 'AWS::S3::Bucket',
2688+
'Properties': {
2689+
'IntelligentTieringConfigurations': [
2690+
{
2691+
'Id': 'foo',
2692+
'Status': 'Enabled',
2693+
'Tierings': [],
2694+
},
2695+
],
2696+
},
2697+
'DeletionPolicy': 'Retain',
2698+
'UpdateReplacePolicy': 'Retain',
2699+
},
2700+
},
2701+
});
2702+
});
2703+
2704+
test('bucket with intelligent tiering turned on with archive access', () => {
2705+
const stack = new cdk.Stack();
2706+
new s3.Bucket(stack, 'MyBucket', {
2707+
intelligentTieringConfigurations: [{
2708+
name: 'foo',
2709+
archiveAccessTierTime: cdk.Duration.days(90),
2710+
}],
2711+
});
2712+
2713+
expect(stack).toMatchTemplate({
2714+
'Resources': {
2715+
'MyBucketF68F3FF0': {
2716+
'Type': 'AWS::S3::Bucket',
2717+
'Properties': {
2718+
'IntelligentTieringConfigurations': [
2719+
{
2720+
'Id': 'foo',
2721+
'Status': 'Enabled',
2722+
'Tierings': [{
2723+
'AccessTier': 'ARCHIVE_ACCESS',
2724+
'Days': 90,
2725+
}],
2726+
},
2727+
],
2728+
},
2729+
'DeletionPolicy': 'Retain',
2730+
'UpdateReplacePolicy': 'Retain',
2731+
},
2732+
},
2733+
});
2734+
});
2735+
2736+
test('bucket with intelligent tiering turned on with deep archive access', () => {
2737+
const stack = new cdk.Stack();
2738+
new s3.Bucket(stack, 'MyBucket', {
2739+
intelligentTieringConfigurations: [{
2740+
name: 'foo',
2741+
deepArchiveAccessTierTime: cdk.Duration.days(180),
2742+
}],
2743+
});
26742744

2745+
expect(stack).toMatchTemplate({
2746+
'Resources': {
2747+
'MyBucketF68F3FF0': {
2748+
'Type': 'AWS::S3::Bucket',
2749+
'Properties': {
2750+
'IntelligentTieringConfigurations': [
2751+
{
2752+
'Id': 'foo',
2753+
'Status': 'Enabled',
2754+
'Tierings': [{
2755+
'AccessTier': 'DEEP_ARCHIVE_ACCESS',
2756+
'Days': 180,
2757+
}],
2758+
},
2759+
],
2760+
},
2761+
'DeletionPolicy': 'Retain',
2762+
'UpdateReplacePolicy': 'Retain',
2763+
},
2764+
},
2765+
});
2766+
});
2767+
2768+
test('bucket with intelligent tiering turned on with all properties', () => {
2769+
const stack = new cdk.Stack();
2770+
new s3.Bucket(stack, 'MyBucket', {
2771+
intelligentTieringConfigurations: [{
2772+
name: 'foo',
2773+
prefix: 'bar',
2774+
archiveAccessTierTime: cdk.Duration.days(90),
2775+
deepArchiveAccessTierTime: cdk.Duration.days(180),
2776+
tags: [{ key: 'test', value: 'bazz' }],
2777+
}],
2778+
});
26752779

2780+
expect(stack).toMatchTemplate({
2781+
'Resources': {
2782+
'MyBucketF68F3FF0': {
2783+
'Type': 'AWS::S3::Bucket',
2784+
'Properties': {
2785+
'IntelligentTieringConfigurations': [
2786+
{
2787+
'Id': 'foo',
2788+
'Prefix': 'bar',
2789+
'Status': 'Enabled',
2790+
'TagFilters': [
2791+
{
2792+
'Key': 'test',
2793+
'Value': 'bazz',
2794+
},
2795+
],
2796+
'Tierings': [{
2797+
'AccessTier': 'ARCHIVE_ACCESS',
2798+
'Days': 90,
2799+
},
2800+
{
2801+
'AccessTier': 'DEEP_ARCHIVE_ACCESS',
2802+
'Days': 180,
2803+
}],
2804+
},
2805+
],
2806+
},
2807+
'DeletionPolicy': 'Retain',
2808+
'UpdateReplacePolicy': 'Retain',
2809+
},
2810+
},
2811+
});
26762812
});
2677-
});
2813+
2814+
});

0 commit comments

Comments
 (0)