From 6b70f1fd53561f1a379ded0ca19e41bd250e9e66 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy <36202692+kaizencc@users.noreply.github.com> Date: Fri, 15 Dec 2023 07:50:56 -0500 Subject: [PATCH] chore(sqs): use ICfnQueue wherever possible (#28232) Migrate inputs of `IQueue` to `ICfnQueue` wherever possible. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../aws-appconfig-alpha/lib/extension.ts | 4 +- .../lib/sqs-queue-action.ts | 10 +- .../lib/queue-hook.ts | 8 +- .../lib/base/queue-processing-service-base.ts | 20 +-- .../aws-events-targets/lib/util.ts | 5 +- .../aws-lambda-destinations/lib/sqs.ts | 8 +- .../aws-lambda-event-sources/lib/sqs-dlq.ts | 8 +- .../aws-cdk-lib/aws-lambda/lib/function.ts | 12 +- .../aws-s3-notifications/lib/sqs.ts | 5 +- .../aws-sns-subscriptions/lib/subscription.ts | 2 + .../aws-cdk-lib/aws-sns/lib/subscription.ts | 1 - packages/aws-cdk-lib/aws-sqs/lib/policy.ts | 7 +- .../aws-cdk-lib/aws-sqs/lib/queue-base.ts | 24 +++- packages/aws-cdk-lib/aws-sqs/lib/queue.ts | 121 ++++++++++++++++-- .../lib/sqs/send-message.ts | 14 +- .../lib/sqs/send-to-queue.ts | 1 - 16 files changed, 190 insertions(+), 60 deletions(-) diff --git a/packages/@aws-cdk/aws-appconfig-alpha/lib/extension.ts b/packages/@aws-cdk/aws-appconfig-alpha/lib/extension.ts index 72f6d1bc9c739..4cf5fe044eec9 100644 --- a/packages/@aws-cdk/aws-appconfig-alpha/lib/extension.ts +++ b/packages/@aws-cdk/aws-appconfig-alpha/lib/extension.ts @@ -92,8 +92,8 @@ export class SqsDestination implements IEventDestination { public readonly type: SourceType; public readonly policyDocument?: iam.PolicyDocument; - constructor(queue: sqs.IQueue) { - this.extensionUri = queue.queueArn; + constructor(queue: sqs.ICfnQueue) { + this.extensionUri = queue.attrArn; this.type = SourceType.SQS; const policy = new iam.PolicyStatement({ effect: iam.Effect.ALLOW, diff --git a/packages/@aws-cdk/aws-iot-actions-alpha/lib/sqs-queue-action.ts b/packages/@aws-cdk/aws-iot-actions-alpha/lib/sqs-queue-action.ts index 44f222a46c6db..d678ab82e48e2 100644 --- a/packages/@aws-cdk/aws-iot-actions-alpha/lib/sqs-queue-action.ts +++ b/packages/@aws-cdk/aws-iot-actions-alpha/lib/sqs-queue-action.ts @@ -13,7 +13,7 @@ export interface SqsQueueActionProps extends CommonActionProps { * * @default false */ - readonly useBase64?: boolean + readonly useBase64?: boolean; } /** @@ -21,14 +21,14 @@ export interface SqsQueueActionProps extends CommonActionProps { */ export class SqsQueueAction implements iot.IAction { private readonly role?: iam.IRole; - private readonly queue: sqs.IQueue; + private readonly queue: sqs.ICfnQueue; private readonly useBase64?: boolean; /** * @param queue The Amazon SQS queue to which to write data. * @param props Optional properties to not use default */ - constructor(queue: sqs.IQueue, props: SqsQueueActionProps = {}) { + constructor(queue: sqs.ICfnQueue, props: SqsQueueActionProps = {}) { this.queue = queue; this.role = props.role; this.useBase64 = props.useBase64; @@ -41,13 +41,13 @@ export class SqsQueueAction implements iot.IAction { const role = this.role ?? singletonActionRole(rule); role.addToPrincipalPolicy(new iam.PolicyStatement({ actions: ['sqs:SendMessage'], - resources: [this.queue.queueArn], + resources: [this.queue.attrArn], })); return { configuration: { sqs: { - queueUrl: this.queue.queueUrl, + queueUrl: this.queue.attrQueueUrl, useBase64: this.useBase64, roleArn: role.roleArn, }, diff --git a/packages/aws-cdk-lib/aws-autoscaling-hooktargets/lib/queue-hook.ts b/packages/aws-cdk-lib/aws-autoscaling-hooktargets/lib/queue-hook.ts index 2b034604362f6..b3c591306d7d4 100644 --- a/packages/aws-cdk-lib/aws-autoscaling-hooktargets/lib/queue-hook.ts +++ b/packages/aws-cdk-lib/aws-autoscaling-hooktargets/lib/queue-hook.ts @@ -7,7 +7,9 @@ import * as sqs from '../../aws-sqs'; * Use an SQS queue as a hook target */ export class QueueHook implements autoscaling.ILifecycleHookTarget { - constructor(private readonly queue: sqs.IQueue) { + private readonly _queue: sqs.IQueue; + constructor(queue: sqs.ICfnQueue) { + this._queue = sqs.Queue.fromCfnQueue(queue); } /** @@ -18,10 +20,10 @@ export class QueueHook implements autoscaling.ILifecycleHookTarget { */ public bind(_scope: Construct, options: autoscaling.BindHookTargetOptions): autoscaling.LifecycleHookTargetConfig { const role = createRole(_scope, options.role); - this.queue.grantSendMessages(role); + this._queue.grantSendMessages(role); return { - notificationTargetArn: this.queue.queueArn, + notificationTargetArn: this._queue.attrArn, createdRole: role, }; } diff --git a/packages/aws-cdk-lib/aws-ecs-patterns/lib/base/queue-processing-service-base.ts b/packages/aws-cdk-lib/aws-ecs-patterns/lib/base/queue-processing-service-base.ts index 385caafdc0ca2..ceabcc58d6768 100644 --- a/packages/aws-cdk-lib/aws-ecs-patterns/lib/base/queue-processing-service-base.ts +++ b/packages/aws-cdk-lib/aws-ecs-patterns/lib/base/queue-processing-service-base.ts @@ -5,7 +5,7 @@ import { AwsLogDriver, BaseService, CapacityProviderStrategy, Cluster, ContainerImage, DeploymentController, DeploymentCircuitBreaker, ICluster, LogDriver, PropagatedTagSource, Secret, } from '../../../aws-ecs'; -import { IQueue, Queue } from '../../../aws-sqs'; +import * as sqs from '../../../aws-sqs'; import { CfnOutput, Duration, FeatureFlags, Stack } from '../../../core'; import * as cxapi from '../../../cx-api'; @@ -90,9 +90,9 @@ export interface QueueProcessingServiceBaseProps { * If specified and this is a FIFO queue, the queue name must end in the string '.fifo'. See * [CreateQueue](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_CreateQueue.html) * - * @default 'SQSQueue with CloudFormation-generated name' + * @default - SQS Queue with CloudFormation-generated name */ - readonly queue?: IQueue; + readonly queue?: sqs.ICfnQueue; /** * The maximum number of times that a message can be received by consumers. @@ -125,14 +125,14 @@ export interface QueueProcessingServiceBaseProps { * * @default - If the feature flag, ECS_REMOVE_DEFAULT_DESIRED_COUNT is false, the default is (desiredTaskCount * 2); if true, the default is 2. */ - readonly maxScalingCapacity?: number + readonly maxScalingCapacity?: number; /** * Minimum capacity to scale to. * * @default - If the feature flag, ECS_REMOVE_DEFAULT_DESIRED_COUNT is false, the default is the desiredTaskCount; if true, the default is 1. */ - readonly minScalingCapacity?: number + readonly minScalingCapacity?: number; /** * The intervals for scaling based on the SQS queue's ApproximateNumberOfMessagesVisible metric. @@ -230,12 +230,12 @@ export abstract class QueueProcessingServiceBase extends Construct { /** * The SQS queue that the service will process from */ - public readonly sqsQueue: IQueue; + public readonly sqsQueue: sqs.IQueue; /** * The dead letter queue for the primary SQS queue */ - public readonly deadLetterQueue?: IQueue; + public readonly deadLetterQueue?: sqs.IQueue; /** * The cluster where your service will be deployed @@ -297,12 +297,12 @@ export abstract class QueueProcessingServiceBase extends Construct { } // Create the SQS queue and it's corresponding DLQ if one is not provided if (props.queue) { - this.sqsQueue = props.queue; + this.sqsQueue = sqs.Queue.fromCfnQueue(props.queue); } else { - this.deadLetterQueue = new Queue(this, 'EcsProcessingDeadLetterQueue', { + this.deadLetterQueue = new sqs.Queue(this, 'EcsProcessingDeadLetterQueue', { retentionPeriod: props.retentionPeriod || Duration.days(14), }); - this.sqsQueue = new Queue(this, 'EcsProcessingQueue', { + this.sqsQueue = new sqs.Queue(this, 'EcsProcessingQueue', { visibilityTimeout: props.visibilityTimeout, deadLetterQueue: { queue: this.deadLetterQueue, diff --git a/packages/aws-cdk-lib/aws-events-targets/lib/util.ts b/packages/aws-cdk-lib/aws-events-targets/lib/util.ts index ab279d03f4b60..af4c834e8c49c 100644 --- a/packages/aws-cdk-lib/aws-events-targets/lib/util.ts +++ b/packages/aws-cdk-lib/aws-events-targets/lib/util.ts @@ -19,7 +19,8 @@ export interface TargetBaseProps { * * @default - no dead-letter queue */ - readonly deadLetterQueue?: sqs.IQueue; + readonly deadLetterQueue?: sqs.ICfnQueue; + /** * The maximum age of a request that Lambda sends to a function for * processing. @@ -50,7 +51,7 @@ export function bindBaseTargetConfig(props: TargetBaseProps) { let { deadLetterQueue, retryAttempts, maxEventAge } = props; return { - deadLetterConfig: deadLetterQueue ? { arn: deadLetterQueue?.queueArn } : undefined, + deadLetterConfig: deadLetterQueue ? { arn: deadLetterQueue?.attrArn } : undefined, retryPolicy: (retryAttempts !== undefined && retryAttempts >= 0) || maxEventAge ? { maximumRetryAttempts: retryAttempts, diff --git a/packages/aws-cdk-lib/aws-lambda-destinations/lib/sqs.ts b/packages/aws-cdk-lib/aws-lambda-destinations/lib/sqs.ts index 760cad5e68090..dc734a526e13b 100644 --- a/packages/aws-cdk-lib/aws-lambda-destinations/lib/sqs.ts +++ b/packages/aws-cdk-lib/aws-lambda-destinations/lib/sqs.ts @@ -6,7 +6,9 @@ import * as sqs from '../../aws-sqs'; * Use a SQS queue as a Lambda destination */ export class SqsDestination implements lambda.IDestination { - constructor(private readonly queue: sqs.IQueue) { + private readonly _queue: sqs.IQueue; + constructor(queue: sqs.ICfnQueue) { + this._queue = sqs.Queue.fromCfnQueue(queue); } /** @@ -14,10 +16,10 @@ export class SqsDestination implements lambda.IDestination { */ public bind(_scope: Construct, fn: lambda.IFunction, _options?: lambda.DestinationOptions): lambda.DestinationConfig { // deduplicated automatically - this.queue.grantSendMessages(fn); + this._queue.grantSendMessages(fn); return { - destination: this.queue.queueArn, + destination: this._queue.attrArn, }; } } diff --git a/packages/aws-cdk-lib/aws-lambda-event-sources/lib/sqs-dlq.ts b/packages/aws-cdk-lib/aws-lambda-event-sources/lib/sqs-dlq.ts index d199ea0868b40..c18a89c943e1e 100644 --- a/packages/aws-cdk-lib/aws-lambda-event-sources/lib/sqs-dlq.ts +++ b/packages/aws-cdk-lib/aws-lambda-event-sources/lib/sqs-dlq.ts @@ -5,17 +5,19 @@ import * as sqs from '../../aws-sqs'; * An SQS dead letter queue destination configuration for a Lambda event source */ export class SqsDlq implements IEventSourceDlq { - constructor(private readonly queue: sqs.IQueue) { + private readonly _queue: sqs.IQueue; + constructor(queue: sqs.ICfnQueue) { + this._queue = sqs.Queue.fromCfnQueue(queue); } /** * Returns a destination configuration for the DLQ */ public bind(_target: IEventSourceMapping, targetHandler: IFunction): DlqDestinationConfig { - this.queue.grantSendMessages(targetHandler); + this._queue.grantSendMessages(targetHandler); return { - destination: this.queue.queueArn, + destination: this._queue.attrArn, }; } } diff --git a/packages/aws-cdk-lib/aws-lambda/lib/function.ts b/packages/aws-cdk-lib/aws-lambda/lib/function.ts index 356be758b9a7c..243cdb9da27d2 100644 --- a/packages/aws-cdk-lib/aws-lambda/lib/function.ts +++ b/packages/aws-cdk-lib/aws-lambda/lib/function.ts @@ -278,7 +278,7 @@ export interface FunctionOptions extends EventInvokeConfigOptions { * * @default - SQS queue with 14 day retention period if `deadLetterQueueEnabled` is `true` */ - readonly deadLetterQueue?: sqs.IQueue; + readonly deadLetterQueue?: sqs.ICfnQueue; /** * The SNS topic to use as a DLQ. @@ -1490,12 +1490,14 @@ Environment variables can be marked for removal when used in Lambda@Edge by sett resources: [deadLetterQueue.topicArn], })); } else { - deadLetterQueue = props.deadLetterQueue || new sqs.Queue(this, 'DeadLetterQueue', { - retentionPeriod: Duration.days(14), - }); + deadLetterQueue = props.deadLetterQueue ? + sqs.Queue.fromCfnQueue(props.deadLetterQueue) : + new sqs.Queue(this, 'DeadLetterQueue', { + retentionPeriod: Duration.days(14), + }); this.addToRolePolicy(new iam.PolicyStatement({ actions: ['sqs:SendMessage'], - resources: [deadLetterQueue.queueArn], + resources: [deadLetterQueue.attrArn], })); } diff --git a/packages/aws-cdk-lib/aws-s3-notifications/lib/sqs.ts b/packages/aws-cdk-lib/aws-s3-notifications/lib/sqs.ts index 4a3739d3f904d..c1880c25e4d65 100644 --- a/packages/aws-cdk-lib/aws-s3-notifications/lib/sqs.ts +++ b/packages/aws-cdk-lib/aws-s3-notifications/lib/sqs.ts @@ -8,7 +8,10 @@ import { Annotations } from '../../core'; * Use an SQS queue as a bucket notification destination */ export class SqsDestination implements s3.IBucketNotificationDestination { - constructor(private readonly queue: sqs.IQueue) { + private readonly _queue: sqs.IQueue; + + constructor(queue: sqs.ICfnQueue) { + this._queue = sqs.Queue.fromCfnQueue(queue); } /** diff --git a/packages/aws-cdk-lib/aws-sns-subscriptions/lib/subscription.ts b/packages/aws-cdk-lib/aws-sns-subscriptions/lib/subscription.ts index cb00ef6507d53..d9d144959ec8d 100644 --- a/packages/aws-cdk-lib/aws-sns-subscriptions/lib/subscription.ts +++ b/packages/aws-cdk-lib/aws-sns-subscriptions/lib/subscription.ts @@ -11,6 +11,7 @@ export interface SubscriptionProps { * @default - all messages are delivered */ readonly filterPolicy?: { [attribute: string]: sns.SubscriptionFilter }; + /** * The filter policy that is applied on the message body. * To apply a filter policy to the message attributes, use `filterPolicy`. A maximum of one of `filterPolicyWithMessageBody` and `filterPolicy` may be used. @@ -18,6 +19,7 @@ export interface SubscriptionProps { * @default - all messages are delivered */ readonly filterPolicyWithMessageBody?: { [attribute: string]: sns.FilterOrPolicy }; + /** * Queue to be used as dead letter queue. * If not passed no dead letter queue is enabled. diff --git a/packages/aws-cdk-lib/aws-sns/lib/subscription.ts b/packages/aws-cdk-lib/aws-sns/lib/subscription.ts index 7701a5dd75def..a73cd157454c2 100644 --- a/packages/aws-cdk-lib/aws-sns/lib/subscription.ts +++ b/packages/aws-cdk-lib/aws-sns/lib/subscription.ts @@ -85,7 +85,6 @@ export interface SubscriptionProps extends SubscriptionOptions { * this class. */ export class Subscription extends Resource { - /** * The DLQ associated with this subscription if present. */ diff --git a/packages/aws-cdk-lib/aws-sqs/lib/policy.ts b/packages/aws-cdk-lib/aws-sqs/lib/policy.ts index 2a427c0522c19..eacdbee8110b3 100644 --- a/packages/aws-cdk-lib/aws-sqs/lib/policy.ts +++ b/packages/aws-cdk-lib/aws-sqs/lib/policy.ts @@ -1,6 +1,5 @@ import { Construct } from 'constructs'; -import { IQueue } from './queue-base'; -import { CfnQueuePolicy } from './sqs.generated'; +import { CfnQueuePolicy, ICfnQueue } from './sqs.generated'; import { PolicyDocument } from '../../aws-iam'; import { Resource } from '../../core'; @@ -11,7 +10,7 @@ export interface QueuePolicyProps { /** * The set of queues this policy applies to. */ - readonly queues: IQueue[]; + readonly queues: ICfnQueue[]; } /** @@ -39,7 +38,7 @@ export class QueuePolicy extends Resource { new CfnQueuePolicy(this, 'Resource', { policyDocument: this.document, - queues: props.queues.map(q => q.queueUrl), + queues: props.queues.map(q => q.attrQueueUrl), }); } diff --git a/packages/aws-cdk-lib/aws-sqs/lib/queue-base.ts b/packages/aws-cdk-lib/aws-sqs/lib/queue-base.ts index ca445daef9a5f..0298caeaa928c 100644 --- a/packages/aws-cdk-lib/aws-sqs/lib/queue-base.ts +++ b/packages/aws-cdk-lib/aws-sqs/lib/queue-base.ts @@ -3,11 +3,12 @@ import { QueuePolicy } from './policy'; import * as iam from '../../aws-iam'; import * as kms from '../../aws-kms'; import { IResource, Resource, ResourceProps } from '../../core'; +import { ICfnQueue } from './sqs.generated'; /** * Represents an SQS queue */ -export interface IQueue extends IResource { +export interface IQueue extends IResource, ICfnQueue { /** * The ARN of this queue * @attribute @@ -105,14 +106,31 @@ export interface IQueue extends IResource { * Reference to a new or existing Amazon SQS queue */ export abstract class QueueBase extends Resource implements IQueue { + /** + * The ARN of this queue + * + * @attribute + */ + public abstract readonly attrArn: string; /** * The ARN of this queue + * + * Deprecated: use attrArn */ public abstract readonly queueArn: string; /** * The URL of this queue + * + * @attribute + */ + public abstract readonly attrQueueUrl: string; + + /** + * The URL of this queue + * + * Deprecated: use attrQueueUrl */ public abstract readonly queueUrl: string; @@ -339,5 +357,5 @@ export enum QueueEncryption { * To learn more about SSE-SQS on Amazon SQS, please visit the * [Amazon SQS documentation](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-server-side-encryption.html). */ - SQS_MANAGED = 'SQS_MANAGED' -} \ No newline at end of file + SQS_MANAGED = 'SQS_MANAGED', +} diff --git a/packages/aws-cdk-lib/aws-sqs/lib/queue.ts b/packages/aws-cdk-lib/aws-sqs/lib/queue.ts index a122045571937..37442ad6cd9c7 100644 --- a/packages/aws-cdk-lib/aws-sqs/lib/queue.ts +++ b/packages/aws-cdk-lib/aws-sqs/lib/queue.ts @@ -1,10 +1,11 @@ import { Construct } from 'constructs'; import { IQueue, QueueAttributes, QueueBase, QueueEncryption } from './queue-base'; -import { CfnQueue } from './sqs.generated'; +import { ICfnQueue, CfnQueue } from './sqs.generated'; import { validateProps } from './validate-props'; import * as iam from '../../aws-iam'; import * as kms from '../../aws-kms'; -import { Duration, RemovalPolicy, Stack, Token, ArnFormat, Annotations } from '../../core'; +import { Duration, RemovalPolicy, Stack, Token, ArnFormat, Annotations, Tokenization } from '../../core'; +import { CfnReference } from '../../core/lib/private/cfn-reference'; /** * Properties for creating a new Queue @@ -15,7 +16,7 @@ export interface QueueProps { * * If specified and this is a FIFO queue, must end in the string '.fifo'. * - * @default CloudFormation-generated name + * @default - CloudFormation generated name */ readonly queueName?: string; @@ -78,7 +79,7 @@ export interface QueueProps { /** * Send messages to this queue if they were unsuccessfully dequeued a number of times. * - * @default no dead-letter queue + * @default - no dead-letter queue */ readonly deadLetterQueue?: DeadLetterQueue; @@ -102,7 +103,7 @@ export interface QueueProps { * If the 'encryptionMasterKey' property is set, 'encryption' type will be * implicitly set to "KMS". * - * @default If encryption is set to KMS and not specified, a key will be created. + * @default - If encryption is set to KMS and not specified, a key will be created. */ readonly encryptionMasterKey?: kms.IKey; @@ -227,7 +228,6 @@ export enum FifoThroughputLimit { * A new Amazon SQS queue */ export class Queue extends QueueBase { - /** * Import an existing SQS queue provided an ARN * @@ -249,8 +249,10 @@ export class Queue extends QueueBase { const queueUrl = attrs.queueUrl || `https://sqs.${parsedArn.region}.${stack.urlSuffix}/${parsedArn.account}/${queueName}`; class Import extends QueueBase { - public readonly queueArn = attrs.queueArn; // arn:aws:sqs:us-east-1:123456789012:queue1 - public readonly queueUrl = queueUrl; + public readonly attrArn = attrs.queueArn; // arn:aws:sqs:us-east-1:123456789012:queue1 + public readonly queueArn = this.attrArn; + public readonly attrQueueUrl = queueUrl; + public readonly queueUrl = this.attrQueueUrl; public readonly queueName = queueName; public readonly encryptionMasterKey = attrs.keyArn ? kms.Key.fromKeyArn(this, 'Key', attrs.keyArn) @@ -287,8 +289,96 @@ export class Queue extends QueueBase { }); } + /** + * Create a mutable `IQueue` out of a `ICfnQueue`. + */ + public static fromCfnQueue(cfnQueue: ICfnQueue): IQueue { + function isIQueue(x: any): x is IQueue { + return (x).grant !== undefined; + } + // if cfnQueue is already an IQueue, just return itself + if (isIQueue(cfnQueue)) { return cfnQueue; } + + // use a "weird" id that has a higher chance of being unique + const id = '@FromCfnQueue'; + + // if fromCfnQueue() was already called on this cfnQueue, + // return the same L2 + const existing = cfnQueue.node.tryFindChild(id); + if (existing) { + return existing; + } + + // if cfnQueue is not a CfnResource, and thus not a CfnQueue, we are in a scenario where + // cfnQueue is an ICfnQueue but NOT a CfnQueue, which shouldn't happen + if (!CfnQueue.isCfnResource(cfnQueue)) { + throw new Error('Encountered an "ICfnQueue" that is not an "IQueue" or "CfnQueue". If you have a legitimate reason for this, please open an issue at https://github.com/aws/aws-cdk/issues'); + } + const _cfnQueue = cfnQueue as CfnQueue; + + let encryptionKey: kms.IKey | undefined; + if (_cfnQueue.kmsMasterKeyId) { + if (Token.isUnresolved(_cfnQueue.kmsMasterKeyId)) { + const kmsIResolvable = Tokenization.reverse(_cfnQueue.kmsMasterKeyId); + if (kmsIResolvable instanceof CfnReference) { + const cfnElement = kmsIResolvable.target; + if (cfnElement instanceof kms.CfnKey) { + encryptionKey = kms.Key.fromCfnKey(cfnElement); + } + } + } + } + + return new class extends QueueBase { + public readonly attrArn = _cfnQueue.attrArn; + public readonly queueArn = this.attrArn; + public readonly queueName = _cfnQueue.attrQueueName; + public readonly attrQueueUrl = _cfnQueue.attrQueueUrl; + public readonly queueUrl = this.attrQueueUrl; + public readonly fifo = this.determineFifo(_cfnQueue.fifoQueue === true); + public readonly autoCreatePolicy = false; + + public readonly encryptionMasterKey = encryptionKey; + public readonly encryptionType = encryptionKey ? QueueEncryption.KMS : undefined; + + constructor() { + super(_cfnQueue, id); + + this.node.defaultChild = _cfnQueue; + } + + /** + * Determine fifo flag based on queueName and fifo attribute + */ + private determineFifo(fifo: boolean): boolean { + if (Token.isUnresolved(this.queueArn)) { + return fifo || false; + } else { + if (typeof fifo !== 'undefined') { + if (fifo && !this.queueName.endsWith('.fifo')) { + throw new Error("FIFO queue names must end in '.fifo'"); + } + if (!fifo && this.queueName.endsWith('.fifo')) { + throw new Error("Non-FIFO queue name may not end in '.fifo'"); + } + } + return this.queueName.endsWith('.fifo') ? true : false; + } + } + }(); + } + + /** + * The ARN of this queue + * + * @attribute + */ + public readonly attrArn: string; + /** * The ARN of this queue + * + * Deprecated: use attrArn */ public readonly queueArn: string; @@ -299,6 +389,15 @@ export class Queue extends QueueBase { /** * The URL of this queue + * + * @attribute + */ + public readonly attrQueueUrl: string; + + /** + * The URL of this queue + * + * Deprecated: use attrQueueUrl */ public readonly queueUrl: string; @@ -356,13 +455,15 @@ export class Queue extends QueueBase { }); queue.applyRemovalPolicy(props.removalPolicy ?? RemovalPolicy.DESTROY); - this.queueArn = this.getResourceArnAttribute(queue.attrArn, { + this.attrArn = this.getResourceArnAttribute(queue.attrArn, { service: 'sqs', resource: this.physicalName, }); + this.queueArn = this.attrArn; this.queueName = this.getResourceNameAttribute(queue.attrQueueName); this.encryptionMasterKey = encryptionMasterKey; - this.queueUrl = queue.ref; + this.attrQueueUrl = queue.ref; + this.queueUrl = this.attrQueueUrl; this.deadLetterQueue = props.deadLetterQueue; this.encryptionType = encryptionType; diff --git a/packages/aws-cdk-lib/aws-stepfunctions-tasks/lib/sqs/send-message.ts b/packages/aws-cdk-lib/aws-stepfunctions-tasks/lib/sqs/send-message.ts index 38903d1789739..57f5a55bdcd93 100644 --- a/packages/aws-cdk-lib/aws-stepfunctions-tasks/lib/sqs/send-message.ts +++ b/packages/aws-cdk-lib/aws-stepfunctions-tasks/lib/sqs/send-message.ts @@ -9,11 +9,10 @@ import { integrationResourceArn, validatePatternSupported } from '../private/tas * Properties for sending a message to an SQS queue */ export interface SqsSendMessageProps extends sfn.TaskStateBaseProps { - /** * The SQS queue that messages will be sent to */ - readonly queue: sqs.IQueue + readonly queue: sqs.ICfnQueue; /** * The text message to send to the queue. @@ -55,7 +54,6 @@ export interface SqsSendMessageProps extends sfn.TaskStateBaseProps { * */ export class SqsSendMessage extends sfn.TaskStateBase { - private static readonly SUPPORTED_INTEGRATION_PATTERNS: sfn.IntegrationPattern[] = [ sfn.IntegrationPattern.REQUEST_RESPONSE, sfn.IntegrationPattern.WAIT_FOR_TASK_TOKEN, @@ -65,6 +63,7 @@ export class SqsSendMessage extends sfn.TaskStateBase { protected readonly taskPolicies?: iam.PolicyStatement[]; private readonly integrationPattern: sfn.IntegrationPattern; + private readonly queue: sqs.IQueue; constructor(scope: Construct, id: string, private readonly props: SqsSendMessageProps) { super(scope, id, props); @@ -81,17 +80,18 @@ export class SqsSendMessage extends sfn.TaskStateBase { this.taskPolicies = [ new iam.PolicyStatement({ actions: ['sqs:SendMessage'], - resources: [this.props.queue.queueArn], + resources: [this.props.queue.attrArn], }), ]; + this.queue = sqs.Queue.fromCfnQueue(props.queue); // sending to an encrypted queue requires // permissions on the associated kms key - if (this.props.queue.encryptionMasterKey) { + if (this.queue.encryptionMasterKey) { this.taskPolicies.push( new iam.PolicyStatement({ actions: ['kms:Decrypt', 'kms:GenerateDataKey*'], - resources: [this.props.queue.encryptionMasterKey.keyArn], + resources: [this.queue.encryptionMasterKey.keyArn], })); } } @@ -106,7 +106,7 @@ export class SqsSendMessage extends sfn.TaskStateBase { return { Resource: integrationResourceArn('sqs', 'sendMessage', this.integrationPattern), Parameters: sfn.FieldUtils.renderObject({ - QueueUrl: this.props.queue.queueUrl, + QueueUrl: this.queue.attrQueueUrl, MessageBody: this.props.messageBody.value, DelaySeconds: this.props.delay?.toSeconds(), MessageDeduplicationId: this.props.messageDeduplicationId, diff --git a/packages/aws-cdk-lib/aws-stepfunctions-tasks/lib/sqs/send-to-queue.ts b/packages/aws-cdk-lib/aws-stepfunctions-tasks/lib/sqs/send-to-queue.ts index f1ebe96dd76e6..d77f89b9c4584 100644 --- a/packages/aws-cdk-lib/aws-stepfunctions-tasks/lib/sqs/send-to-queue.ts +++ b/packages/aws-cdk-lib/aws-stepfunctions-tasks/lib/sqs/send-to-queue.ts @@ -60,7 +60,6 @@ export interface SendToQueueProps { * @deprecated Use `SqsSendMessage` */ export class SendToQueue implements sfn.IStepFunctionsTask { - private readonly integrationPattern: sfn.ServiceIntegrationPattern; constructor(private readonly queue: sqs.IQueue, private readonly props: SendToQueueProps) {