From c3372b794405c566230ec0cfd1d18614827205aa Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Mon, 3 Sep 2018 11:02:56 +0200 Subject: [PATCH] fix(aws-logs): add export()/import() capabilities (#630) LogGroups and LogStreams can now be exported and imported. ALSO IN THIS COMMIT - All exports() for other resources would run afoul of ClassCastException in Java. Wrap all `FnImportValue`s in the right type to avoid this. - The addition of some convenience methods to the `Arn` class flushed out a number of places where we were using some other `Token`-derived value in places where `Arn`s were expected. --- .../lib/certificate-ref.ts | 2 +- packages/@aws-cdk/aws-cloudtrail/lib/index.ts | 4 +- .../@aws-cdk/aws-codebuild/lib/project.ts | 4 +- .../@aws-cdk/aws-codecommit/lib/repository.ts | 2 +- .../@aws-cdk/aws-ec2/lib/security-group.ts | 2 +- packages/@aws-cdk/aws-ec2/lib/vpc-ref.ts | 8 +- packages/@aws-cdk/aws-events/lib/rule-ref.ts | 2 +- packages/@aws-cdk/aws-kinesis/lib/stream.ts | 17 +-- packages/@aws-cdk/aws-kms/lib/key.ts | 2 +- packages/@aws-cdk/aws-kms/test/integ.key.ts | 4 +- .../@aws-cdk/aws-lambda/lib/lambda-ref.ts | 4 +- .../aws-logs/lib/cross-account-destination.ts | 4 +- packages/@aws-cdk/aws-logs/lib/log-group.ts | 134 +++++++++++++----- packages/@aws-cdk/aws-logs/lib/log-stream.ts | 59 +++++++- .../@aws-cdk/aws-logs/lib/metric-filter.ts | 4 +- .../aws-logs/lib/subscription-filter.ts | 6 +- .../@aws-cdk/aws-logs/test/test.loggroup.ts | 18 ++- .../aws-logs/test/test.subscriptionfilter.ts | 4 +- packages/@aws-cdk/aws-rds/lib/cluster-ref.ts | 18 +-- .../aws-route53/lib/hosted-zone-ref.ts | 2 +- packages/@aws-cdk/aws-s3/lib/bucket.ts | 6 +- .../notifications-resource-handler.ts | 2 +- .../aws-s3/test/notification-dests.ts | 2 +- packages/@aws-cdk/aws-sns/lib/topic-ref.ts | 4 +- packages/@aws-cdk/aws-sqs/lib/queue-ref.ts | 6 +- .../@aws-cdk/cdk/lib/cloudformation/arn.ts | 14 ++ .../cdk/lib/cloudformation/permission.ts | 2 +- 27 files changed, 237 insertions(+), 99 deletions(-) diff --git a/packages/@aws-cdk/aws-certificatemanager/lib/certificate-ref.ts b/packages/@aws-cdk/aws-certificatemanager/lib/certificate-ref.ts index 76d8d9b687e77..4d5e9b1974ea0 100644 --- a/packages/@aws-cdk/aws-certificatemanager/lib/certificate-ref.ts +++ b/packages/@aws-cdk/aws-certificatemanager/lib/certificate-ref.ts @@ -19,7 +19,7 @@ export abstract class CertificateRef extends Construct { */ public export(): CertificateRefProps { return { - certificateArn: new Output(this, 'Arn', { value: this.certificateArn }).makeImportValue() + certificateArn: new CertificateArn(new Output(this, 'Arn', { value: this.certificateArn }).makeImportValue()) }; } } diff --git a/packages/@aws-cdk/aws-cloudtrail/lib/index.ts b/packages/@aws-cdk/aws-cloudtrail/lib/index.ts index 0fc363819d073..dd5360c3c5741 100644 --- a/packages/@aws-cdk/aws-cloudtrail/lib/index.ts +++ b/packages/@aws-cdk/aws-cloudtrail/lib/index.ts @@ -147,11 +147,11 @@ export class CloudTrail extends cdk.Construct { const logGroup = new logs.cloudformation.LogGroupResource(this, "LogGroup", { retentionInDays: props.cloudWatchLogsRetentionTimeDays || LogRetention.OneYear }); - this.cloudWatchLogsGroupArn = logGroup.ref; + this.cloudWatchLogsGroupArn = logGroup.logGroupArn; const logsRole = new iam.Role(this, 'LogsRole', {assumedBy: new cdk.ServicePrincipal(cloudTrailPrincipal) }); - const streamArn = new cdk.FnConcat(this.cloudWatchLogsGroupArn, ":log-stream:*"); + const streamArn = new cdk.Arn(new cdk.FnConcat(this.cloudWatchLogsGroupArn, ":log-stream:*")); logsRole.addToPolicy(new cdk.PolicyStatement() .addActions("logs:PutLogEvents", "logs:CreateLogStream") .addResource(streamArn)); diff --git a/packages/@aws-cdk/aws-codebuild/lib/project.ts b/packages/@aws-cdk/aws-codebuild/lib/project.ts index 23a70fb82ef38..99fca662b8866 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/project.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/project.ts @@ -73,7 +73,7 @@ export abstract class ProjectRef extends cdk.Construct implements events.IEventR */ public export(): ProjectRefProps { return { - projectName: new cdk.Output(this, 'ProjectName', { value: this.projectName }).makeImportValue(), + projectName: new ProjectName(new cdk.Output(this, 'ProjectName', { value: this.projectName }).makeImportValue()), }; } @@ -482,7 +482,7 @@ export class Project extends ProjectRef { resourceName: new cdk.FnConcat('/aws/codebuild/', this.projectName), }); - const logGroupStarArn = new cdk.FnConcat(logGroupArn, ':*'); + const logGroupStarArn = new cdk.Arn(new cdk.FnConcat(logGroupArn, ':*')); const p = new cdk.PolicyStatement(); p.allow(); diff --git a/packages/@aws-cdk/aws-codecommit/lib/repository.ts b/packages/@aws-cdk/aws-codecommit/lib/repository.ts index 152a7ff82d4b1..5171cfa755289 100644 --- a/packages/@aws-cdk/aws-codecommit/lib/repository.ts +++ b/packages/@aws-cdk/aws-codecommit/lib/repository.ts @@ -51,7 +51,7 @@ export abstract class RepositoryRef extends cdk.Construct { */ public export(): RepositoryRefProps { return { - repositoryName: new cdk.Output(this, 'RepositoryName', { value: this.repositoryName }).makeImportValue(), + repositoryName: new RepositoryName(new cdk.Output(this, 'RepositoryName', { value: this.repositoryName }).makeImportValue()), }; } diff --git a/packages/@aws-cdk/aws-ec2/lib/security-group.ts b/packages/@aws-cdk/aws-ec2/lib/security-group.ts index 0204439d1d74b..88aceba456bf1 100644 --- a/packages/@aws-cdk/aws-ec2/lib/security-group.ts +++ b/packages/@aws-cdk/aws-ec2/lib/security-group.ts @@ -63,7 +63,7 @@ export abstract class SecurityGroupRef extends Construct implements ISecurityGro */ public export(): SecurityGroupRefProps { return { - securityGroupId: new Output(this, 'SecurityGroupId', { value: this.securityGroupId }).makeImportValue() + securityGroupId: new SecurityGroupId(new Output(this, 'SecurityGroupId', { value: this.securityGroupId }).makeImportValue()) }; } diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc-ref.ts b/packages/@aws-cdk/aws-ec2/lib/vpc-ref.ts index 7ad02e46ca69f..e3fa76df0dc33 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc-ref.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc-ref.ts @@ -61,12 +61,14 @@ export abstract class VpcNetworkRef extends Construct implements IDependable { * Export this VPC from the stack */ public export(): VpcNetworkRefProps { + // tslint:disable:max-line-length return { - vpcId: new Output(this, 'VpcId', { value: this.vpcId }).makeImportValue(), + vpcId: new VPCId(new Output(this, 'VpcId', { value: this.vpcId }).makeImportValue()), availabilityZones: this.publicSubnets.map(s => s.availabilityZone), - publicSubnetIds: new StringListOutput(this, 'PublicSubnetIDs', { values: this.publicSubnets.map(s => s.subnetId) }).makeImportValues(), - privateSubnetIds: new StringListOutput(this, 'PrivateSubnetIDs', { values: this.privateSubnets.map(s => s.subnetId) }).makeImportValues(), + publicSubnetIds: new StringListOutput(this, 'PublicSubnetIDs', { values: this.publicSubnets.map(s => s.subnetId) }).makeImportValues().map(x => new SubnetId(x)), + privateSubnetIds: new StringListOutput(this, 'PrivateSubnetIDs', { values: this.privateSubnets.map(s => s.subnetId) }).makeImportValues().map(x => new SubnetId(x)), }; + // tslint:enable:max-line-length } } diff --git a/packages/@aws-cdk/aws-events/lib/rule-ref.ts b/packages/@aws-cdk/aws-events/lib/rule-ref.ts index b0527900eeb1b..4a0a8478e562f 100644 --- a/packages/@aws-cdk/aws-events/lib/rule-ref.ts +++ b/packages/@aws-cdk/aws-events/lib/rule-ref.ts @@ -29,7 +29,7 @@ export abstract class EventRuleRef extends Construct { */ public export(): EventRuleRefProps { return { - eventRuleArn: new Output(this, 'RuleArn', { value: this.ruleArn }).makeImportValue() + eventRuleArn: new RuleArn(new Output(this, 'RuleArn', { value: this.ruleArn }).makeImportValue()) }; } } diff --git a/packages/@aws-cdk/aws-kinesis/lib/stream.ts b/packages/@aws-cdk/aws-kinesis/lib/stream.ts index ad244663a5d24..19eae41cc3338 100644 --- a/packages/@aws-cdk/aws-kinesis/lib/stream.ts +++ b/packages/@aws-cdk/aws-kinesis/lib/stream.ts @@ -75,15 +75,10 @@ export abstract class StreamRef extends cdk.Construct implements logs.ILogSubscr * Exports this stream from the stack. */ public export(): StreamRefProps { - const streamArn = new cdk.Output(this, 'StreamArn', { value: this.streamArn }).makeImportValue(); - if (this.encryptionKey) { - return { - streamArn, - encryptionKey: this.encryptionKey.export() - }; - } else { - return { streamArn }; - } + return { + streamArn: new StreamArn(new cdk.Output(this, 'StreamArn', { value: this.streamArn }).makeImportValue()), + encryptionKey: this.encryptionKey ? this.encryptionKey.export() : undefined, + }; } /** @@ -170,7 +165,7 @@ export abstract class StreamRef extends cdk.Construct implements logs.ILogSubscr ); } - public logSubscriptionDestination(sourceLogGroup: logs.LogGroup): logs.LogSubscriptionDestination { + public logSubscriptionDestination(sourceLogGroup: logs.LogGroupRef): logs.LogSubscriptionDestination { // Following example from https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/SubscriptionFilters.html#DestinationKinesisExample if (!this.cloudWatchLogsRole) { // Create a role to be assumed by CWL that can write to this stream and pass itself. @@ -200,7 +195,7 @@ export abstract class StreamRef extends cdk.Construct implements logs.ILogSubscr /** * Generate a CloudWatch Logs Destination and return the properties in the form o a subscription destination */ - private crossAccountLogSubscriptionDestination(sourceLogGroup: logs.LogGroup): logs.LogSubscriptionDestination { + private crossAccountLogSubscriptionDestination(sourceLogGroup: logs.LogGroupRef): logs.LogSubscriptionDestination { const sourceStack = cdk.Stack.find(sourceLogGroup); const thisStack = cdk.Stack.find(this); diff --git a/packages/@aws-cdk/aws-kms/lib/key.ts b/packages/@aws-cdk/aws-kms/lib/key.ts index b84a3a2e813fc..c73bc7e1afe18 100644 --- a/packages/@aws-cdk/aws-kms/lib/key.ts +++ b/packages/@aws-cdk/aws-kms/lib/key.ts @@ -74,7 +74,7 @@ export abstract class EncryptionKeyRef extends Construct { */ public export(): EncryptionKeyRefProps { return { - keyArn: new Output(this, 'KeyArn').makeImportValue() + keyArn: new KeyArn(new Output(this, 'KeyArn').makeImportValue()) }; } } diff --git a/packages/@aws-cdk/aws-kms/test/integ.key.ts b/packages/@aws-cdk/aws-kms/test/integ.key.ts index 169cd428be370..48c27231d6d91 100644 --- a/packages/@aws-cdk/aws-kms/test/integ.key.ts +++ b/packages/@aws-cdk/aws-kms/test/integ.key.ts @@ -1,4 +1,4 @@ -import { App, AwsAccountId, PolicyStatement, Stack } from '@aws-cdk/cdk'; +import { App, Arn, AwsAccountId, PolicyStatement, Stack } from '@aws-cdk/cdk'; import { EncryptionKey } from '../lib'; const app = new App(process.argv); @@ -10,7 +10,7 @@ const key = new EncryptionKey(stack, 'MyKey'); key.addToResourcePolicy(new PolicyStatement() .addAllResources() .addAction('kms:encrypt') - .addAwsPrincipal(new AwsAccountId())); + .addAwsPrincipal(new Arn(new AwsAccountId()))); key.addAlias('alias/bar'); diff --git a/packages/@aws-cdk/aws-lambda/lib/lambda-ref.ts b/packages/@aws-cdk/aws-lambda/lib/lambda-ref.ts index 089270bbaaa93..559794eb6112d 100644 --- a/packages/@aws-cdk/aws-lambda/lib/lambda-ref.ts +++ b/packages/@aws-cdk/aws-lambda/lib/lambda-ref.ts @@ -238,7 +238,7 @@ export abstract class FunctionRef extends cdk.Construct return this.metric('Throttles', { statistic: 'sum', ...props }); } - public logSubscriptionDestination(sourceLogGroup: logs.LogGroup): logs.LogSubscriptionDestination { + public logSubscriptionDestination(sourceLogGroup: logs.LogGroupRef): logs.LogSubscriptionDestination { const arn = sourceLogGroup.logGroupArn; if (this.logSubscriptionDestinationPolicyAddedFor.indexOf(arn) === -1) { @@ -260,7 +260,7 @@ export abstract class FunctionRef extends cdk.Construct */ public export(): FunctionRefProps { return { - functionArn: new cdk.Output(this, 'FunctionArn', { value: this.functionArn }).makeImportValue(), + functionArn: new FunctionArn(new cdk.Output(this, 'FunctionArn', { value: this.functionArn }).makeImportValue()), }; } diff --git a/packages/@aws-cdk/aws-logs/lib/cross-account-destination.ts b/packages/@aws-cdk/aws-logs/lib/cross-account-destination.ts index d5a4bb0d5ca8e..cf29d3bc08e64 100644 --- a/packages/@aws-cdk/aws-logs/lib/cross-account-destination.ts +++ b/packages/@aws-cdk/aws-logs/lib/cross-account-destination.ts @@ -1,6 +1,6 @@ import iam = require('@aws-cdk/aws-iam'); import cdk = require('@aws-cdk/cdk'); -import { LogGroup } from './log-group'; +import { LogGroupRef } from './log-group'; import { cloudformation, DestinationArn, DestinationName } from './logs.generated'; import { ILogSubscriptionDestination, LogSubscriptionDestination } from './subscription-filter'; @@ -78,7 +78,7 @@ export class CrossAccountDestination extends cdk.Construct implements ILogSubscr this.policyDocument.addStatement(statement); } - public logSubscriptionDestination(_sourceLogGroup: LogGroup): LogSubscriptionDestination { + public logSubscriptionDestination(_sourceLogGroup: LogGroupRef): LogSubscriptionDestination { return { arn: this.destinationArn }; } diff --git a/packages/@aws-cdk/aws-logs/lib/log-group.ts b/packages/@aws-cdk/aws-logs/lib/log-group.ts index f7810b6d5d9fe..cd909091ea092 100644 --- a/packages/@aws-cdk/aws-logs/lib/log-group.ts +++ b/packages/@aws-cdk/aws-logs/lib/log-group.ts @@ -6,7 +6,87 @@ import { IFilterPattern } from './pattern'; import { ILogSubscriptionDestination, SubscriptionFilter } from './subscription-filter'; /** - * Properties for a new LogGroup + * Properties for importing a LogGroup + */ +export interface LogGroupRefProps { + logGroupArn: LogGroupArn; +} + +/** + * An CloudWatch Log Group + */ +export abstract class LogGroupRef extends cdk.Construct { + /** + * Import an existing LogGroup + */ + public static import(parent: cdk.Construct, id: string, props: LogGroupRefProps): LogGroupRef { + return new ImportedLogGroup(parent, id, props); + } + + /** + * The ARN of this log group + */ + public abstract readonly logGroupArn: LogGroupArn; + + /** + * The name of this log group + */ + public abstract readonly logGroupName: LogGroupName; + + /** + * Create a new Log Stream for this Log Group + * + * @param parent Parent construct + * @param id Unique identifier for the construct in its parent + * @param props Properties for creating the LogStream + */ + public newStream(parent: cdk.Construct, id: string, props: NewLogStreamProps = {}): LogStream { + return new LogStream(parent, id, { + logGroup: this, + ...props + }); + } + + /** + * Create a new Subscription Filter on this Log Group + * + * @param parent Parent construct + * @param id Unique identifier for the construct in its parent + * @param props Properties for creating the SubscriptionFilter + */ + public newSubscriptionFilter(parent: cdk.Construct, id: string, props: NewSubscriptionFilterProps): SubscriptionFilter { + return new SubscriptionFilter(parent, id, { + logGroup: this, + ...props + }); + } + + /** + * Create a new Metric Filter on this Log Group + * + * @param parent Parent construct + * @param id Unique identifier for the construct in its parent + * @param props Properties for creating the MetricFilter + */ + public newMetricFilter(parent: cdk.Construct, id: string, props: NewMetricFilterProps): MetricFilter { + return new MetricFilter(parent, id, { + logGroup: this, + ...props + }); + } + + /** + * Export this LogGroup + */ + public export(): LogGroupRefProps { + return { + logGroupArn: new LogGroupArn(new cdk.Output(this, 'LogGroupArn', { value: this.logGroupArn }).makeImportValue()) + }; + } +} + +/** + * Properties for a LogGroup */ export interface LogGroupProps { /** @@ -39,9 +119,9 @@ export interface LogGroupProps { } /** - * A new CloudWatch Log Group + * Define a CloudWatch Log Group */ -export class LogGroup extends cdk.Construct { +export class LogGroup extends LogGroupRef { /** * The ARN of this log group */ @@ -75,47 +155,27 @@ export class LogGroup extends cdk.Construct { this.logGroupArn = resource.logGroupArn; this.logGroupName = resource.ref; } +} +/** + * An imported CloudWatch Log Group + */ +class ImportedLogGroup extends LogGroupRef { /** - * Create a new Log Stream for this Log Group - * - * @param parent Parent construct - * @param id Unique identifier for the construct in its parent - * @param props Properties for creating the LogStream + * The ARN of this log group */ - public newStream(parent: cdk.Construct, id: string, props: NewLogStreamProps = {}): LogStream { - return new LogStream(parent, id, { - logGroup: this, - ...props - }); - } + public readonly logGroupArn: LogGroupArn; /** - * Create a new Subscription Filter on this Log Group - * - * @param parent Parent construct - * @param id Unique identifier for the construct in its parent - * @param props Properties for creating the SubscriptionFilter + * The name of this log group */ - public newSubscriptionFilter(parent: cdk.Construct, id: string, props: NewSubscriptionFilterProps): SubscriptionFilter { - return new SubscriptionFilter(parent, id, { - logGroup: this, - ...props - }); - } + public readonly logGroupName: LogGroupName; - /** - * Create a new Metric Filter on this Log Group - * - * @param parent Parent construct - * @param id Unique identifier for the construct in its parent - * @param props Properties for creating the MetricFilter - */ - public newMetricFilter(parent: cdk.Construct, id: string, props: NewMetricFilterProps): MetricFilter { - return new MetricFilter(parent, id, { - logGroup: this, - ...props - }); + constructor(parent: cdk.Construct, id: string, props: LogGroupRefProps) { + super(parent, id); + + this.logGroupArn = props.logGroupArn; + this.logGroupName = new LogGroupName(props.logGroupArn.resourceNameComponent(':')); } } diff --git a/packages/@aws-cdk/aws-logs/lib/log-stream.ts b/packages/@aws-cdk/aws-logs/lib/log-stream.ts index e9937fadcb2b3..583f0bf92eacb 100644 --- a/packages/@aws-cdk/aws-logs/lib/log-stream.ts +++ b/packages/@aws-cdk/aws-logs/lib/log-stream.ts @@ -1,15 +1,48 @@ import cdk = require('@aws-cdk/cdk'); -import { LogGroup } from './log-group'; +import { LogGroupRef } from './log-group'; import { cloudformation, LogStreamName } from './logs.generated'; /** - * Properties for a new LogStream + * Properties for importing a LogStream + */ +export interface LogStreamRefProps { + logStreamName: LogStreamName; +} + +/** + * A Log Stream in a Log Group + */ +export abstract class LogStreamRef extends cdk.Construct { + /** + * Import an existing LogGroup + */ + public static import(parent: cdk.Construct, id: string, props: LogStreamRefProps): LogStreamRef { + return new ImportedLogStream(parent, id, props); + } + + /** + * The name of this log stream + */ + public abstract readonly logStreamName: LogStreamName; + + /** + * Export this LogStream + */ + public export(): LogStreamRefProps { + return { + logStreamName: new LogStreamName(new cdk.Output(this, 'LogStreamName', { value: this.logStreamName }).makeImportValue()) + }; + } +} + +/** + * Properties for a LogStream */ export interface LogStreamProps { /** * The log group to create a log stream for. */ - logGroup: LogGroup; + logGroup: LogGroupRef; /** * The name of the log stream to create. @@ -35,9 +68,9 @@ export interface LogStreamProps { } /** - * A new Log Stream in a Log Group + * Define a Log Stream in a Log Group */ -export class LogStream extends cdk.Construct { +export class LogStream extends LogStreamRef { /** * The name of this log stream */ @@ -57,4 +90,20 @@ export class LogStream extends cdk.Construct { this.logStreamName = resource.ref; } +} + +/** + * An imported LogStream + */ +class ImportedLogStream extends LogStreamRef { + /** + * The name of this log stream + */ + public readonly logStreamName: LogStreamName; + + constructor(parent: cdk.Construct, id: string, props: LogStreamRefProps) { + super(parent, id); + + this.logStreamName = props.logStreamName; + } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-logs/lib/metric-filter.ts b/packages/@aws-cdk/aws-logs/lib/metric-filter.ts index bcb64c7ddd73b..c9828bcb3dd03 100644 --- a/packages/@aws-cdk/aws-logs/lib/metric-filter.ts +++ b/packages/@aws-cdk/aws-logs/lib/metric-filter.ts @@ -1,5 +1,5 @@ import cdk = require('@aws-cdk/cdk'); -import { LogGroup } from './log-group'; +import { LogGroupRef } from './log-group'; import { cloudformation } from './logs.generated'; import { IFilterPattern } from './pattern'; @@ -10,7 +10,7 @@ export interface MetricFilterProps { /** * The log group to create the filter on. */ - logGroup: LogGroup; + logGroup: LogGroupRef; /** * Pattern to search for log events. diff --git a/packages/@aws-cdk/aws-logs/lib/subscription-filter.ts b/packages/@aws-cdk/aws-logs/lib/subscription-filter.ts index 8a489f507f5e9..949b6984ee3b5 100644 --- a/packages/@aws-cdk/aws-logs/lib/subscription-filter.ts +++ b/packages/@aws-cdk/aws-logs/lib/subscription-filter.ts @@ -1,6 +1,6 @@ import iam = require('@aws-cdk/aws-iam'); import cdk = require('@aws-cdk/cdk'); -import { LogGroup } from './log-group'; +import { LogGroupRef } from './log-group'; import { cloudformation } from './logs.generated'; import { IFilterPattern } from './pattern'; @@ -18,7 +18,7 @@ export interface ILogSubscriptionDestination { * The destination may reconfigure its own permissions in response to this * function call. */ - logSubscriptionDestination(sourceLogGroup: LogGroup): LogSubscriptionDestination; + logSubscriptionDestination(sourceLogGroup: LogGroupRef): LogSubscriptionDestination; } /** @@ -45,7 +45,7 @@ export interface SubscriptionFilterProps { /** * The log group to create the subscription on. */ - logGroup: LogGroup; + logGroup: LogGroupRef; /** * The destination to send the filtered events to. diff --git a/packages/@aws-cdk/aws-logs/test/test.loggroup.ts b/packages/@aws-cdk/aws-logs/test/test.loggroup.ts index b46532584501c..c3990056e9357 100644 --- a/packages/@aws-cdk/aws-logs/test/test.loggroup.ts +++ b/packages/@aws-cdk/aws-logs/test/test.loggroup.ts @@ -1,7 +1,7 @@ import { expect, haveResource, matchTemplate } from '@aws-cdk/assert'; import { Stack } from '@aws-cdk/cdk'; import { Test } from 'nodeunit'; -import { LogGroup } from '../lib'; +import { LogGroup, LogGroupRef } from '../lib'; export = { 'fixed retention'(test: Test) { @@ -75,6 +75,22 @@ export = { } })); + test.done(); + }, + + 'export/import'(test: Test) { + // GIVEN + const stack1 = new Stack(); + const lg = new LogGroup(stack1, 'LogGroup'); + const stack2 = new Stack(); + + // WHEN + const imported = LogGroupRef.import(stack2, 'Import', lg.export()); + imported.newStream(stack2, 'MakeMeAStream'); + + // THEN + expect(stack2).to(haveResource('AWS::Logs::LogStream', {})); + test.done(); } }; diff --git a/packages/@aws-cdk/aws-logs/test/test.subscriptionfilter.ts b/packages/@aws-cdk/aws-logs/test/test.subscriptionfilter.ts index f2eef7139cb82..607425d03ef2c 100644 --- a/packages/@aws-cdk/aws-logs/test/test.subscriptionfilter.ts +++ b/packages/@aws-cdk/aws-logs/test/test.subscriptionfilter.ts @@ -1,7 +1,7 @@ import { expect, haveResource } from '@aws-cdk/assert'; import { Arn, Stack } from '@aws-cdk/cdk'; import { Test } from 'nodeunit'; -import { FilterPattern, ILogSubscriptionDestination, LogGroup, SubscriptionFilter } from '../lib'; +import { FilterPattern, ILogSubscriptionDestination, LogGroup, LogGroupRef, SubscriptionFilter } from '../lib'; export = { 'trivial instantiation'(test: Test) { @@ -28,7 +28,7 @@ export = { }; class FakeDestination implements ILogSubscriptionDestination { - public logSubscriptionDestination(_sourceLogGroup: LogGroup) { + public logSubscriptionDestination(_sourceLogGroup: LogGroupRef) { return { arn: new Arn('arn:bogus'), }; diff --git a/packages/@aws-cdk/aws-rds/lib/cluster-ref.ts b/packages/@aws-cdk/aws-rds/lib/cluster-ref.ts index c2affde36ffae..6711cc455d873 100644 --- a/packages/@aws-cdk/aws-rds/lib/cluster-ref.ts +++ b/packages/@aws-cdk/aws-rds/lib/cluster-ref.ts @@ -52,16 +52,17 @@ export abstract class DatabaseClusterRef extends cdk.Construct implements ec2.IC * Export a Database Cluster for importing in another stack */ public export(): DatabaseClusterRefProps { + // tslint:disable:max-line-length return { - port: new cdk.Output(this, 'Port', { value: this.clusterEndpoint.port, }).makeImportValue(), - securityGroupId: new cdk.Output(this, 'SecurityGroupId', { value: this.securityGroupId, }).makeImportValue(), - clusterIdentifier: new cdk.Output(this, 'ClusterIdentifier', { value: this.clusterIdentifier, }).makeImportValue(), - instanceIdentifiers: new cdk.StringListOutput(this, 'InstanceIdentifiers', { values: this.instanceIdentifiers }).makeImportValues(), - clusterEndpointAddress: new cdk.Output(this, 'ClusterEndpointAddress', { value: this.clusterEndpoint.hostname, }).makeImportValue(), - readerEndpointAddress: new cdk.Output(this, 'ReaderEndpointAddress', { value: this.readerEndpoint.hostname, }).makeImportValue(), - // tslint:disable-next-line:max-line-length - instanceEndpointAddresses: new cdk.StringListOutput(this, 'InstanceEndpointAddresses', { values: this.instanceEndpoints.map(e => e.hostname) }).makeImportValues(), + port: new DBClusterEndpointPort(new cdk.Output(this, 'Port', { value: this.clusterEndpoint.port, }).makeImportValue()), + securityGroupId: new ec2.SecurityGroupId(new cdk.Output(this, 'SecurityGroupId', { value: this.securityGroupId, }).makeImportValue()), + clusterIdentifier: new DBClusterName(new cdk.Output(this, 'ClusterIdentifier', { value: this.clusterIdentifier, }).makeImportValue()), + instanceIdentifiers: new cdk.StringListOutput(this, 'InstanceIdentifiers', { values: this.instanceIdentifiers }).makeImportValues().map(x => new DBInstanceId(x)), + clusterEndpointAddress: new DBClusterEndpointAddress(new cdk.Output(this, 'ClusterEndpointAddress', { value: this.clusterEndpoint.hostname, }).makeImportValue()), + readerEndpointAddress: new DBClusterEndpointAddress(new cdk.Output(this, 'ReaderEndpointAddress', { value: this.readerEndpoint.hostname, }).makeImportValue()), + instanceEndpointAddresses: new cdk.StringListOutput(this, 'InstanceEndpointAddresses', { values: this.instanceEndpoints.map(e => e.hostname) }).makeImportValues().map(x => new DBClusterEndpointAddress(x)), }; + // tslint:enable:max-line-length } } @@ -88,6 +89,7 @@ export interface DatabaseClusterRefProps { * Identifier for the instances */ instanceIdentifiers: DBInstanceId[]; + // Actual underlying type: DBInstanceId[], but we have to type it more loosely for Java's benefit. /** * Cluster endpoint address diff --git a/packages/@aws-cdk/aws-route53/lib/hosted-zone-ref.ts b/packages/@aws-cdk/aws-route53/lib/hosted-zone-ref.ts index 185c33acadeb7..c1f216506eda7 100644 --- a/packages/@aws-cdk/aws-route53/lib/hosted-zone-ref.ts +++ b/packages/@aws-cdk/aws-route53/lib/hosted-zone-ref.ts @@ -24,7 +24,7 @@ export abstract class HostedZoneRef extends Construct { */ public export(): HostedZoneRefProps { return { - hostedZoneId: new Output(this, 'HostedZoneId', { value: this.hostedZoneId }).makeImportValue(), + hostedZoneId: new HostedZoneId(new Output(this, 'HostedZoneId', { value: this.hostedZoneId }).makeImportValue()), zoneName: this.zoneName, }; } diff --git a/packages/@aws-cdk/aws-s3/lib/bucket.ts b/packages/@aws-cdk/aws-s3/lib/bucket.ts index a11565634aea6..e4c94dab2f489 100644 --- a/packages/@aws-cdk/aws-s3/lib/bucket.ts +++ b/packages/@aws-cdk/aws-s3/lib/bucket.ts @@ -96,8 +96,8 @@ export abstract class BucketRef extends cdk.Construct { */ public export(): BucketRefProps { return { - bucketArn: new cdk.Output(this, 'BucketArn', { value: this.bucketArn }).makeImportValue(), - bucketName: new cdk.Output(this, 'BucketName', { value: this.bucketName }).makeImportValue(), + bucketArn: new BucketArn(new cdk.Output(this, 'BucketArn', { value: this.bucketArn }).makeImportValue()), + bucketName: new BucketName(new cdk.Output(this, 'BucketName', { value: this.bucketName }).makeImportValue()), }; } @@ -176,7 +176,7 @@ export abstract class BucketRef extends cdk.Construct { * */ public arnForObjects(...keyPattern: any[]): cdk.Arn { - return new cdk.FnConcat(this.bucketArn, '/', ...keyPattern); + return new cdk.Arn(new cdk.FnConcat(this.bucketArn, '/', ...keyPattern)); } /** diff --git a/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource-handler.ts b/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource-handler.ts index 38f2195f9fd71..37ad42e21f308 100644 --- a/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource-handler.ts +++ b/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource-handler.ts @@ -77,7 +77,7 @@ export class NotificationsResourceHandler extends cdk.Construct { } }); - this.functionArn = resource.getAtt('Arn'); + this.functionArn = new cdk.Arn(resource.getAtt('Arn')); } } diff --git a/packages/@aws-cdk/aws-s3/test/notification-dests.ts b/packages/@aws-cdk/aws-s3/test/notification-dests.ts index c49367c35db53..d25776297b5d1 100644 --- a/packages/@aws-cdk/aws-s3/test/notification-dests.ts +++ b/packages/@aws-cdk/aws-s3/test/notification-dests.ts @@ -24,7 +24,7 @@ export class Topic extends cdk.Construct implements s3notifications.IBucketNotif } }); - this.topicArn = topicArn; + this.topicArn = new cdk.Arn(topicArn); } public asBucketNotificationDestination(bucketArn: cdk.Arn, bucketId: string): s3notifications.BucketNotificationDestinationProps { diff --git a/packages/@aws-cdk/aws-sns/lib/topic-ref.ts b/packages/@aws-cdk/aws-sns/lib/topic-ref.ts index 07ffdf18430dd..f4e43206b82eb 100644 --- a/packages/@aws-cdk/aws-sns/lib/topic-ref.ts +++ b/packages/@aws-cdk/aws-sns/lib/topic-ref.ts @@ -47,8 +47,8 @@ export abstract class TopicRef extends cdk.Construct implements events.IEventRul */ public export(): TopicRefProps { return { - topicArn: new cdk.Output(this, 'TopicArn', { value: this.topicArn }).makeImportValue(), - topicName: new cdk.Output(this, 'TopicName', { value: this.topicName }).makeImportValue(), + topicArn: new TopicArn(new cdk.Output(this, 'TopicArn', { value: this.topicArn }).makeImportValue()), + topicName: new TopicName(new cdk.Output(this, 'TopicName', { value: this.topicName }).makeImportValue()), }; } diff --git a/packages/@aws-cdk/aws-sqs/lib/queue-ref.ts b/packages/@aws-cdk/aws-sqs/lib/queue-ref.ts index debc98296cdc3..9d9728fef03fc 100644 --- a/packages/@aws-cdk/aws-sqs/lib/queue-ref.ts +++ b/packages/@aws-cdk/aws-sqs/lib/queue-ref.ts @@ -49,10 +49,10 @@ export abstract class QueueRef extends cdk.Construct implements s3n.IBucketNotif */ public export(): QueueRefProps { return { - queueArn: new cdk.Output(this, 'QueueArn', { value: this.queueArn }).makeImportValue(), - queueUrl: new cdk.Output(this, 'QueueUrl', { value: this.queueUrl }).makeImportValue(), + queueArn: new QueueArn(new cdk.Output(this, 'QueueArn', { value: this.queueArn }).makeImportValue()), + queueUrl: new QueueUrl(new cdk.Output(this, 'QueueUrl', { value: this.queueUrl }).makeImportValue()), keyArn: this.encryptionMasterKey - ? new cdk.Output(this, 'KeyArn', { value: this.encryptionMasterKey.keyArn }).makeImportValue() + ? new kms.KeyArn(new cdk.Output(this, 'KeyArn', { value: this.encryptionMasterKey.keyArn }).makeImportValue()) : undefined }; } diff --git a/packages/@aws-cdk/cdk/lib/cloudformation/arn.ts b/packages/@aws-cdk/cdk/lib/cloudformation/arn.ts index 30981b7edab34..07b6a3192ab69 100644 --- a/packages/@aws-cdk/cdk/lib/cloudformation/arn.ts +++ b/packages/@aws-cdk/cdk/lib/cloudformation/arn.ts @@ -183,6 +183,20 @@ export class Arn extends Token { return { partition, service, region, account, resource, resourceName, sep }; } } + + /** + * Return a Token that represents the resource component of the ARN + */ + public resourceComponent(sep: string = '/'): Token { + return Arn.parseToken(this, sep).resource; + } + + /** + * Return a Token that represents the resource Name component of the ARN + */ + public resourceNameComponent(sep: string = '/'): Token { + return Arn.parseToken(this, sep, true).resourceName!; + } } export interface ArnComponents { diff --git a/packages/@aws-cdk/cdk/lib/cloudformation/permission.ts b/packages/@aws-cdk/cdk/lib/cloudformation/permission.ts index 3dd1610d4c2a5..c1ce5f3f7e0cd 100644 --- a/packages/@aws-cdk/cdk/lib/cloudformation/permission.ts +++ b/packages/@aws-cdk/cdk/lib/cloudformation/permission.ts @@ -85,7 +85,7 @@ export class ArnPrincipal extends PolicyPrincipal { export class AccountPrincipal extends ArnPrincipal { constructor(public readonly accountId: any) { - super(new FnConcat('arn:', new AwsPartition(), ':iam::', accountId, ':root')); + super(new Arn(new FnConcat('arn:', new AwsPartition(), ':iam::', accountId, ':root'))); } }