Skip to content

Commit

Permalink
feat(aws-s3): initial support for website hosting (#946)
Browse files Browse the repository at this point in the history
Adds basic support for website hosting for S3 buckets.
Users can specify `websiteIndexDocument` and optionally
`websiteErrorDocument` to enable website hosting.

The property `publicReadAccess` can be used to
grant public read access to the bucket (similar to
calling `grantPublicAccess`).

No support for redirects yet.
  • Loading branch information
Elad Ben-Israel authored and RomainMuller committed Oct 17, 2018
1 parent 65190f9 commit 2d3661c
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 0 deletions.
38 changes: 38 additions & 0 deletions packages/@aws-cdk/aws-s3/lib/bucket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,24 @@ export interface BucketProps {
* @default No lifecycle rules
*/
lifecycleRules?: LifecycleRule[];

/**
* The name of the index document (e.g. "index.html") for the website. Enables static website
* hosting for this bucket.
*/
websiteIndexDocument?: string;

/**
* The name of the error document (e.g. "404.html") for the website.
* `websiteIndexDocument` must also be set if this is set.
*/
websiteErrorDocument?: string;

/**
* Grants public read access to all objects in the bucket.
* Similar to calling `bucket.grantPublicAccess()`
*/
publicReadAccess?: boolean;
}

/**
Expand Down Expand Up @@ -414,6 +432,7 @@ export class Bucket extends BucketRef {
bucketEncryption,
versioningConfiguration: props.versioned ? { status: 'Enabled' } : undefined,
lifecycleConfiguration: new cdk.Token(() => this.parseLifecycleConfiguration()),
websiteConfiguration: this.renderWebsiteConfiguration(props)
});

cdk.applyRemovalPolicy(resource, props.removalPolicy);
Expand All @@ -431,6 +450,10 @@ export class Bucket extends BucketRef {
// defines a BucketNotifications construct. Notice that an actual resource will only
// be added if there are notifications added, so we don't need to condition this.
this.notifications = new BucketNotifications(this, 'Notifications', { bucket: this });

if (props.publicReadAccess) {
this.grantPublicAccess();
}
}

/**
Expand Down Expand Up @@ -598,6 +621,21 @@ export class Bucket extends BucketRef {
}));
}
}

private renderWebsiteConfiguration(props: BucketProps): cloudformation.BucketResource.WebsiteConfigurationProperty | undefined {
if (!props.websiteErrorDocument && !props.websiteIndexDocument) {
return undefined;
}

if (props.websiteErrorDocument && !props.websiteIndexDocument) {
throw new Error(`"websiteIndexDocument" is required if "websiteErrorDocument" is set`);
}

return {
indexDocument: props.websiteIndexDocument,
errorDocument: props.websiteErrorDocument
};
}
}

/**
Expand Down
38 changes: 38 additions & 0 deletions packages/@aws-cdk/aws-s3/test/test.bucket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1143,5 +1143,43 @@ export = {
}));
test.done();
}
},

'website configuration': {
'only index doc'(test: Test) {
const stack = new cdk.Stack();
new s3.Bucket(stack, 'Website', {
websiteIndexDocument: 'index2.html'
});
expect(stack).to(haveResource('AWS::S3::Bucket', {
WebsiteConfiguration: {
IndexDocument: "index2.html"
}
}));
test.done();
},
'fails if only error doc is specified'(test: Test) {
const stack = new cdk.Stack();
test.throws(() => {
new s3.Bucket(stack, 'Website', {
websiteErrorDocument: 'error.html'
});
}, /"websiteIndexDocument" is required if "websiteErrorDocument" is set/);
test.done();
},
'error and index docs'(test: Test) {
const stack = new cdk.Stack();
new s3.Bucket(stack, 'Website', {
websiteIndexDocument: 'index2.html',
websiteErrorDocument: 'error.html',
});
expect(stack).to(haveResource('AWS::S3::Bucket', {
WebsiteConfiguration: {
IndexDocument: "index2.html",
ErrorDocument: "error.html"
}
}));
test.done();
}
}
};

0 comments on commit 2d3661c

Please sign in to comment.