diff --git a/.changeset/little-fans-do.md b/.changeset/little-fans-do.md new file mode 100644 index 00000000..933ce244 --- /dev/null +++ b/.changeset/little-fans-do.md @@ -0,0 +1,5 @@ +--- +'@gradientedge/cdk-utils-azure': patch +--- + +Adding contructs to resolve storage accounts and event grid system topics diff --git a/packages/azure/src/services/eventgrid/main.ts b/packages/azure/src/services/eventgrid/main.ts index cae3d9b0..64e2ea2f 100644 --- a/packages/azure/src/services/eventgrid/main.ts +++ b/packages/azure/src/services/eventgrid/main.ts @@ -4,6 +4,7 @@ import { EventSubscription, GetSystemTopicResult, getTopicOutput, + getSystemTopicOutput, SystemTopic, SystemTopicEventSubscription, TlsVersion, @@ -19,6 +20,7 @@ import { EventgridSystemTopicProps, EventgridTopicProps, ResolveEventgridTopicProps, + ResolveEventgridSystemTopicProps, } from './types.js' /** @@ -218,4 +220,34 @@ export class AzureEventgridManager { { parent: scope, ...resourceOptions } ) } + + /** + * @summary Method to resolve an existing eventgrid system topic + * @param id scoped id of the resource + * @param scope scope in which this resource is defined + * @param props eventgrid system topic properties + * @param resourceOptions Optional settings to control resource behaviour + * @see [Pulumi Azure Native Event Grid System Topic Lookup]{@link https://www.pulumi.com/registry/packages/azure-native/api-docs/eventgrid/getsystemtopic/} + */ + public resolveEventgridSystemTopic( + id: string, + scope: CommonAzureConstruct, + props: ResolveEventgridSystemTopicProps, + resourceOptions?: ResourceOptions + ) { + if (!props) throw new Error(`Props undefined for ${id}`) + + return getSystemTopicOutput( + { + systemTopicName: + props.systemTopicName ?? + scope.resourceNameFormatter.format( + props.systemTopicName, + scope.props.resourceNameOptions?.eventGridSystemTopic + ), + resourceGroupName: props.resourceGroupName ?? scope.resourceNameFormatter.format(scope.props.resourceGroupName), + }, + { parent: scope, ...resourceOptions } + ) + } } diff --git a/packages/azure/src/services/eventgrid/types.ts b/packages/azure/src/services/eventgrid/types.ts index fde642b3..d060d197 100644 --- a/packages/azure/src/services/eventgrid/types.ts +++ b/packages/azure/src/services/eventgrid/types.ts @@ -1,5 +1,6 @@ import { EventSubscriptionArgs, + GetSystemTopicOutputArgs, GetTopicOutputArgs, SystemTopicArgs, SystemTopicEventSubscriptionArgs, @@ -40,3 +41,10 @@ export interface EventgridSystemTopicEventSubscriptionProps extends SystemTopicE * @category Interface */ export interface ResolveEventgridTopicProps extends GetTopicOutputArgs {} + +/** + * Properties for resolving an existing EventGrid system topic + * @see [Pulumi Azure Native Event Grid System Topic]{@link https://www.pulumi.com/registry/packages/azure-native/api-docs/eventgrid/systemtopic/} + * @category Interface + */ +export interface ResolveEventgridSystemTopicProps extends GetSystemTopicOutputArgs {} diff --git a/packages/azure/src/services/storage/main.ts b/packages/azure/src/services/storage/main.ts index 73eaaa1f..3ed770d5 100644 --- a/packages/azure/src/services/storage/main.ts +++ b/packages/azure/src/services/storage/main.ts @@ -2,6 +2,8 @@ import { Blob, BlobContainer, BlobServiceProperties, + getStorageAccountOutput, + getBlobContainerOutput, HttpProtocol, Kind, listStorageAccountSAS, @@ -23,6 +25,8 @@ import { CommonAzureConstruct } from '../../common/index.js' import { ContainerSasTokenProps, ManagementPolicyProps, + ResolveStorageAccountProps, + ResolveStorageContainerProps, StorageAccountProps, StorageBlobProps, StorageContainerProps, @@ -269,4 +273,55 @@ export class AzureStorageManager { return new Table(`${id}`, props, { parent: scope, ...resourceOptions }) } + + /** + * @param id scoped id of the resource + * @param scope scope in which this resource is defined + * @param props storage account properties + * @param resourceOptions Optional settings to control resource behaviour + * @see [Pulumi Azure Native Storage Table]{@link https://www.pulumi.com/registry/packages/azure-native/api-docs/storage/table/} + */ + public resolveStorageAccount( + id: string, + scope: CommonAzureConstruct, + props: ResolveStorageAccountProps, + resourceOptions?: ResourceOptions + ) { + return getStorageAccountOutput( + { + accountName: scope.resourceNameFormatter.format( + props.accountName?.toString(), + scope.props.resourceNameOptions?.storageAccount + ), + resourceGroupName: props.resourceGroupName ?? scope.resourceNameFormatter.format(scope.props.resourceGroupName), + }, + { parent: scope, ...resourceOptions } + ) + } + + /** + * @param id scoped id of the resource + * @param scope scope in which this resource is defined + * @param props storage account container properties + * @param resourceOptions Optional settings to control resource behaviour + + */ + public resolveStorageContainer( + id: string, + scope: CommonAzureConstruct, + props: ResolveStorageContainerProps, + resourceOptions?: ResourceOptions + ) { + return getBlobContainerOutput( + { + accountName: scope.resourceNameFormatter.format( + props.accountName?.toString(), + scope.props.resourceNameOptions?.storageAccount + ), + containerName: props.containerName, + resourceGroupName: props.resourceGroupName ?? scope.resourceNameFormatter.format(scope.props.resourceGroupName), + }, + { parent: scope, ...resourceOptions } + ) + } } diff --git a/packages/azure/src/services/storage/types.ts b/packages/azure/src/services/storage/types.ts index 60c5cbe3..2b644285 100644 --- a/packages/azure/src/services/storage/types.ts +++ b/packages/azure/src/services/storage/types.ts @@ -2,6 +2,8 @@ import { BlobArgs, BlobContainerArgs, BlobServicePropertiesArgs, + GetStorageAccountOutputArgs, + GetBlobContainerOutputArgs, ListStorageAccountSASArgs, ManagementPolicyArgs, StorageAccountArgs, @@ -70,3 +72,17 @@ export interface ContainerSasTokenProps extends ListStorageAccountSASArgs { /** SAS expiry date in 'YYYY-MM-DD' format; defaults to 7 days from now */ expiry?: string } + +/** + * Properties for resolving an existing Storage account + * @see [Pulumi Azure Native Event Grid Topic]{@link https://www.pulumi.com/registry/packages/azure-native/api-docs/storage/getstorageaccount/} + * @category Interface + */ +export interface ResolveStorageAccountProps extends GetStorageAccountOutputArgs {} + +/** + * Properties for resolving an existing Storage account container + * @see [Pulumi Azure Native Event Grid Topic]{@link https://www.pulumi.com/registry/packages/azure-native/api-docs/storage/getstorageaccount/} + * @category Interface + */ +export interface ResolveStorageContainerProps extends GetBlobContainerOutputArgs {} diff --git a/packages/azure/test/services/eventgrid-manager.test.ts b/packages/azure/test/services/eventgrid-manager.test.ts index 55cc132c..a258afc1 100644 --- a/packages/azure/test/services/eventgrid-manager.test.ts +++ b/packages/azure/test/services/eventgrid-manager.test.ts @@ -279,6 +279,16 @@ describe('TestAzureEventgridConstruct - Props Undefined', () => { stack.construct.eventgridManager.resolveEventgridTopic('test-resolve-err', stack.construct, undefined as any) }).toThrow('Props undefined for test-resolve-err') }) + + test('resolveEventgridSystemTopic throws when props are undefined', () => { + expect(() => { + stack.construct.eventgridManager.resolveEventgridSystemTopic( + 'test-system-resolve-err', + stack.construct, + undefined as any + ) + }).toThrow('Props undefined for test-system-resolve-err') + }) }) /* --- Tests for default value fallback branches --- */ @@ -287,6 +297,9 @@ class TestMinimalEventgridConstruct extends CommonAzureConstruct { eventgridTopic: Topic eventgridSubscription: EventSubscription eventgridSystemTopic: SystemTopic + eventgridSystemEventSubscription: SystemTopicEventSubscription + resolvedEventgridTopic: pulumi.Output + resolvedEventgridSystemTopic: pulumi.Output constructor(name: string, props: TestAzureStackProps) { super(name, props) @@ -297,7 +310,6 @@ class TestMinimalEventgridConstruct extends CommonAzureConstruct { this, { topicName: 'test-minimal-eg-topic', - resourceGroupName: 'test-rg-dev', } as any ) @@ -322,11 +334,42 @@ class TestMinimalEventgridConstruct extends CommonAzureConstruct { this, { systemTopicName: 'test-minimal-eg-sys-topic', - resourceGroupName: 'test-rg-dev', source: '/subscriptions/test-sub/resourceGroups/test-rg-dev/providers/Microsoft.Storage/storageAccounts/testsa', topicType: 'Microsoft.Storage.StorageAccounts', } as any ) + + // System topic subscription with minimal props - exercises resourceGroupName fallback + this.eventgridSystemEventSubscription = this.eventgridManager.createEventgridSystemTopicEventSubscription( + `test-minimal-eg-sys-sub-${this.props.stage}`, + this, + { + eventSubscriptionName: 'test-minimal-eg-sys-sub', + scope: + '/subscriptions/test-sub/resourceGroups/test-rg-dev/providers/Microsoft.EventGrid/systemTopics/test-minimal-eg-sys-topic-dev', + destination: { + endpointType: 'WebHook', + properties: { endpointUrl: 'https://test.example.com/webhook' }, + }, + } as any, + this.eventgridSystemTopic + ) + + this.resolvedEventgridTopic = this.eventgridManager.resolveEventgridTopic( + `test-resolved-eg-topic-${this.props.stage}`, + this, + { + topicName: 'test-minimal-eg-topic', + } as any + ) + + this.resolvedEventgridSystemTopic = this.eventgridManager.resolveEventgridSystemTopic( + `test-resolved-eg-sys-topic-${this.props.stage}`, + this, + { + systemTopicName: 'test-minimal-eg-sys-topic', + } as any + ) } } @@ -359,6 +402,26 @@ describe('TestAzureEventgridConstruct - Default Values', () => { ) }) + test('eventgrid topic uses default data residency boundary when not provided', async () => { + await outputToPromise( + pulumi + .all([minimalEventgridStack.construct.eventgridTopic.dataResidencyBoundary]) + .apply(([dataResidencyBoundary]) => { + expect(dataResidencyBoundary).toEqual('WithinGeopair') + }) + ) + }) + + test('eventgrid topic uses default minimum tls version when not provided', async () => { + await outputToPromise( + pulumi + .all([minimalEventgridStack.construct.eventgridTopic.minimumTlsVersionAllowed]) + .apply(([minimumTlsVersionAllowed]) => { + expect(minimumTlsVersionAllowed).toEqual('1.2') + }) + ) + }) + test('eventgrid subscription uses default eventDeliverySchema when not provided', async () => { await outputToPromise( pulumi.all([minimalEventgridStack.construct.eventgridSubscription.eventDeliverySchema]).apply(([schema]) => { @@ -391,4 +454,24 @@ describe('TestAzureEventgridConstruct - Default Values', () => { }) ) }) + + test('resolve eventgrid topic uses formatted topic name and default resource group name from scope', async () => { + await outputToPromise( + pulumi.output(minimalEventgridStack.construct.resolvedEventgridTopic).apply(resolvedEventgridTopic => { + expect((resolvedEventgridTopic as any).topicName).toEqual('test-minimal-eg-topic-dev') + expect((resolvedEventgridTopic as any).resourceGroupName).toEqual('test-rg-dev') + }) + ) + }) + + test('resolve eventgrid system topic uses provided system topic name and default resource group name from scope', async () => { + await outputToPromise( + pulumi + .output(minimalEventgridStack.construct.resolvedEventgridSystemTopic) + .apply(resolvedEventgridSystemTopic => { + expect((resolvedEventgridSystemTopic as any).systemTopicName).toEqual('test-minimal-eg-sys-topic') + expect((resolvedEventgridSystemTopic as any).resourceGroupName).toEqual('test-rg-dev') + }) + ) + }) })