@gradientedge/cdk-utils-azure 2.47.0 → 2.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/construct/event-handler/main.d.ts +99 -3
- package/dist/src/construct/event-handler/main.js +167 -14
- package/dist/src/construct/event-handler/types.d.ts +46 -7
- package/dist/src/services/authorisation/constants.d.ts +3 -1
- package/dist/src/services/authorisation/constants.js +2 -0
- package/dist/src/services/servicebus/main.d.ts +10 -1
- package/dist/src/services/servicebus/main.js +14 -1
- package/dist/src/services/servicebus/types.d.ts +8 -1
- package/package.json +1 -1
|
@@ -3,8 +3,36 @@ import { Output } from '@pulumi/pulumi';
|
|
|
3
3
|
import { AzureFunctionApp } from '../function-app/index.js';
|
|
4
4
|
import { AzureEventHandlerProps, EventHandlerEventGridSubscription, EventHandlerServiceBus } from './types.js';
|
|
5
5
|
/**
|
|
6
|
-
* Provides a construct to create and deploy an Azure EventGrid Event Handler with Service Bus integration
|
|
6
|
+
* Provides a construct to create and deploy an Azure EventGrid Event Handler with Service Bus integration.
|
|
7
|
+
*
|
|
8
|
+
* ## Service Bus configuration
|
|
9
|
+
*
|
|
10
|
+
* The construct manages a Service Bus namespace and queue. Each can independently be created by the
|
|
11
|
+
* construct or resolved from existing Azure resources via the `namespace.useExisting` and
|
|
12
|
+
* `queue.useExisting` flags on {@link EventHandlerServiceBusProps}:
|
|
13
|
+
*
|
|
14
|
+
* | `namespace.useExisting` | `queue.useExisting` | Behaviour |
|
|
15
|
+
* |---|---|---|
|
|
16
|
+
* | `false` | `false` | Create both — the default. Used by single-purpose stacks that own the whole Service Bus surface. |
|
|
17
|
+
* | `true` | `false` | Look up the namespace, create a new queue under it. Use this when one namespace is provisioned by a shared infrastructure stack and multiple event-handler stacks each provision their own queue under it. |
|
|
18
|
+
* | `true` | `true` | Look up both. Cross-stack pattern where the producer/owner of the queue is a different stack (e.g. `WebhookEventHandler` consuming a queue created by `WebhookGateway`). |
|
|
19
|
+
* | `false` | `true` | **Invalid** — construct-time error. You cannot resolve an existing queue under a namespace the construct is creating. |
|
|
20
|
+
*
|
|
21
|
+
* The top-level `serviceBus.useExisting` flag is retained as a deprecated alias that sets both
|
|
22
|
+
* per-resource flags to the same value, so existing callers continue to work unchanged.
|
|
23
|
+
*
|
|
24
|
+
* ## Authorization and the `EVENT_INGEST_SERVICE_BUS` connection string
|
|
25
|
+
*
|
|
26
|
+
* When the construct owns the queue (`queue.useExisting=false`), it provisions a per-queue
|
|
27
|
+
* authorization rule named `listen-send` (scoped to the queue) with `Listen + Send` rights, and the function app's
|
|
28
|
+
* `EVENT_INGEST_SERVICE_BUS` connection string is sourced from that rule. This avoids granting the
|
|
29
|
+
* function app access to sibling queues when the namespace is shared.
|
|
30
|
+
*
|
|
31
|
+
* When the queue is external (`queue.useExisting=true`) the construct does not own auth rules on it
|
|
32
|
+
* and falls back to reading the namespace-level `RootManageSharedAccessKey` for the connection string.
|
|
33
|
+
*
|
|
7
34
|
* @example
|
|
35
|
+
* // Minimal subclass (defaults — both namespace and queue created by the construct):
|
|
8
36
|
* import { AzureEventHandler, AzureEventHandlerProps } from '@gradientedge/cdk-utils'
|
|
9
37
|
*
|
|
10
38
|
* class CustomConstruct extends AzureEventHandler {
|
|
@@ -15,6 +43,30 @@ import { AzureEventHandlerProps, EventHandlerEventGridSubscription, EventHandler
|
|
|
15
43
|
* this.initResources()
|
|
16
44
|
* }
|
|
17
45
|
* }
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* // Shared-namespace pattern — reuse a namespace provisioned by another stack, create a new
|
|
49
|
+
* // queue under it. Useful when multiple event handlers should share a single Service Bus namespace.
|
|
50
|
+
* import * as pulumi from '@pulumi/pulumi'
|
|
51
|
+
*
|
|
52
|
+
* const sharedInfraStack = new pulumi.StackReference('shared-infra')
|
|
53
|
+
* const sharedNamespace = sharedInfraStack.getOutput('serviceBusNamespace')
|
|
54
|
+
*
|
|
55
|
+
* new CustomConstruct('my-event-handler', {
|
|
56
|
+
* ...baseProps,
|
|
57
|
+
* serviceBus: {
|
|
58
|
+
* namespace: {
|
|
59
|
+
* useExisting: true,
|
|
60
|
+
* namespaceName: sharedNamespace.apply((ns) => ns.name),
|
|
61
|
+
* resourceGroupName: sharedNamespace.apply((ns) => ns.resourceGroupName),
|
|
62
|
+
* },
|
|
63
|
+
* queue: {
|
|
64
|
+
* useExisting: false,
|
|
65
|
+
* queueName: 'my-event-queue',
|
|
66
|
+
* },
|
|
67
|
+
* },
|
|
68
|
+
* })
|
|
69
|
+
*
|
|
18
70
|
* @category Construct
|
|
19
71
|
*/
|
|
20
72
|
export declare class AzureEventHandler extends AzureFunctionApp {
|
|
@@ -44,6 +96,18 @@ export declare class AzureEventHandler extends AzureFunctionApp {
|
|
|
44
96
|
* @summary Method to create the dead-letter queue storage container for EventGrid subscriptions
|
|
45
97
|
*/
|
|
46
98
|
protected createEventGridSubscriptionDlqStorageContainer(): void;
|
|
99
|
+
/**
|
|
100
|
+
* @summary Resolve effective `useExisting` flags for the Service Bus namespace and queue.
|
|
101
|
+
*
|
|
102
|
+
* Per-resource flags (`namespace.useExisting`, `queue.useExisting`) take precedence over the
|
|
103
|
+
* deprecated top-level `serviceBus.useExisting`, which is treated as an alias that sets both.
|
|
104
|
+
* Throws if the invalid combination (namespace.useExisting=false + queue.useExisting=true) is
|
|
105
|
+
* requested — a queue cannot be looked up under a namespace the construct is about to create.
|
|
106
|
+
*/
|
|
107
|
+
protected resolveServiceBusUseExisting(): {
|
|
108
|
+
namespace: boolean;
|
|
109
|
+
queue: boolean;
|
|
110
|
+
};
|
|
47
111
|
/**
|
|
48
112
|
* @summary Method to create the Service Bus namespace
|
|
49
113
|
*/
|
|
@@ -52,16 +116,37 @@ export declare class AzureEventHandler extends AzureFunctionApp {
|
|
|
52
116
|
* @summary Method to create the Service Bus queue
|
|
53
117
|
*/
|
|
54
118
|
protected createServiceBusQueue(): void;
|
|
119
|
+
/**
|
|
120
|
+
* @summary Provision a per-queue Listen+Send authorization rule.
|
|
121
|
+
*
|
|
122
|
+
* Skipped when the construct does not own the queue (`queue.useExisting=true`) — in that case
|
|
123
|
+
* the producer/owner of the queue is responsible for its auth rules and the function app's
|
|
124
|
+
* connection string falls back to the namespace-level root rule in {@link createFunctionAppSiteConfig}.
|
|
125
|
+
*
|
|
126
|
+
* Replaces the previous reliance on `RootManageSharedAccessKey`, which grants Listen+Send+Manage
|
|
127
|
+
* on every queue in the namespace. The new rule narrows the scope to this one queue while keeping
|
|
128
|
+
* Listen+Send so existing function code can both consume and publish through it (Manage is
|
|
129
|
+
* intentionally dropped — a runtime app should not create or delete queues).
|
|
130
|
+
*/
|
|
131
|
+
protected createServiceBusQueueAuthorizationRule(): void;
|
|
55
132
|
/**
|
|
56
133
|
* @summary Method to create or resolve an existing EventGrid topic
|
|
57
134
|
*/
|
|
58
135
|
protected createEventGrid(): void;
|
|
59
136
|
/**
|
|
60
|
-
* @summary Method to create the EventGrid event subscription with Service Bus queue destination
|
|
137
|
+
* @summary Method to create the EventGrid event subscription with Service Bus queue destination.
|
|
138
|
+
*
|
|
139
|
+
* Skipped when the construct is reusing an existing queue (the producer/owner of that queue owns
|
|
140
|
+
* the subscription). When the construct creates a new queue — including the case where the queue
|
|
141
|
+
* is new but the parent namespace is externally-managed — the subscription is wired here.
|
|
61
142
|
*/
|
|
62
143
|
protected createEventGridEventSubscription(): void;
|
|
63
144
|
/**
|
|
64
|
-
* @summary Method to create diagnostic log settings for the Service Bus namespace
|
|
145
|
+
* @summary Method to create diagnostic log settings for the Service Bus namespace.
|
|
146
|
+
*
|
|
147
|
+
* Diagnostic settings live on the namespace, so the construct only registers them when it owns
|
|
148
|
+
* the namespace. When the namespace is external (e.g. provisioned by a shared infrastructure
|
|
149
|
+
* stack), its owner is responsible for diagnostic settings — registering again here would conflict.
|
|
65
150
|
*/
|
|
66
151
|
protected createServiceBusDiagnosticLog(): void;
|
|
67
152
|
/**
|
|
@@ -72,6 +157,17 @@ export declare class AzureEventHandler extends AzureFunctionApp {
|
|
|
72
157
|
* @summary Override to extend the function app site config with service bus connection strings
|
|
73
158
|
*/
|
|
74
159
|
protected createFunctionAppSiteConfig(): void;
|
|
160
|
+
/**
|
|
161
|
+
* @summary Resolve the connection string injected as `EVENT_INGEST_SERVICE_BUS` on the function app.
|
|
162
|
+
*
|
|
163
|
+
* - When the construct provisioned the queue itself, read from the per-queue Listen-scoped
|
|
164
|
+
* authorization rule created in {@link createServiceBusQueueAuthorizationRule}. Scope is
|
|
165
|
+
* limited to this one queue, which is correct for a shared (per-domain) namespace.
|
|
166
|
+
* - When the queue is external (legacy `WebhookEventHandler` cross-stack pattern), fall back to
|
|
167
|
+
* the namespace-level `RootManageSharedAccessKey` — preserves pre-existing behaviour for that
|
|
168
|
+
* caller shape since the construct does not own the queue and cannot provision a rule on it.
|
|
169
|
+
*/
|
|
170
|
+
protected resolveServiceBusConnectionString(): Output<string>;
|
|
75
171
|
/**
|
|
76
172
|
* @summary Override to extend the dashboard variables with service bus and event grid specifics
|
|
77
173
|
*/
|
|
@@ -1,10 +1,39 @@
|
|
|
1
1
|
import { Provider } from '@pulumi/azure-native';
|
|
2
2
|
import { getTopicOutput } from '@pulumi/azure-native/eventgrid/index.js';
|
|
3
|
-
import { getNamespaceOutput, getQueueOutput, listNamespaceKeysOutput } from '@pulumi/azure-native/servicebus/index.js';
|
|
3
|
+
import { getNamespaceOutput, getQueueOutput, listNamespaceKeysOutput, listQueueKeysOutput, } from '@pulumi/azure-native/servicebus/index.js';
|
|
4
|
+
import { AccessRights } from '@pulumi/azure-native/types/enums/servicebus/index.js';
|
|
4
5
|
import { AzureFunctionApp } from '../function-app/index.js';
|
|
5
6
|
/**
|
|
6
|
-
* Provides a construct to create and deploy an Azure EventGrid Event Handler with Service Bus integration
|
|
7
|
+
* Provides a construct to create and deploy an Azure EventGrid Event Handler with Service Bus integration.
|
|
8
|
+
*
|
|
9
|
+
* ## Service Bus configuration
|
|
10
|
+
*
|
|
11
|
+
* The construct manages a Service Bus namespace and queue. Each can independently be created by the
|
|
12
|
+
* construct or resolved from existing Azure resources via the `namespace.useExisting` and
|
|
13
|
+
* `queue.useExisting` flags on {@link EventHandlerServiceBusProps}:
|
|
14
|
+
*
|
|
15
|
+
* | `namespace.useExisting` | `queue.useExisting` | Behaviour |
|
|
16
|
+
* |---|---|---|
|
|
17
|
+
* | `false` | `false` | Create both — the default. Used by single-purpose stacks that own the whole Service Bus surface. |
|
|
18
|
+
* | `true` | `false` | Look up the namespace, create a new queue under it. Use this when one namespace is provisioned by a shared infrastructure stack and multiple event-handler stacks each provision their own queue under it. |
|
|
19
|
+
* | `true` | `true` | Look up both. Cross-stack pattern where the producer/owner of the queue is a different stack (e.g. `WebhookEventHandler` consuming a queue created by `WebhookGateway`). |
|
|
20
|
+
* | `false` | `true` | **Invalid** — construct-time error. You cannot resolve an existing queue under a namespace the construct is creating. |
|
|
21
|
+
*
|
|
22
|
+
* The top-level `serviceBus.useExisting` flag is retained as a deprecated alias that sets both
|
|
23
|
+
* per-resource flags to the same value, so existing callers continue to work unchanged.
|
|
24
|
+
*
|
|
25
|
+
* ## Authorization and the `EVENT_INGEST_SERVICE_BUS` connection string
|
|
26
|
+
*
|
|
27
|
+
* When the construct owns the queue (`queue.useExisting=false`), it provisions a per-queue
|
|
28
|
+
* authorization rule named `listen-send` (scoped to the queue) with `Listen + Send` rights, and the function app's
|
|
29
|
+
* `EVENT_INGEST_SERVICE_BUS` connection string is sourced from that rule. This avoids granting the
|
|
30
|
+
* function app access to sibling queues when the namespace is shared.
|
|
31
|
+
*
|
|
32
|
+
* When the queue is external (`queue.useExisting=true`) the construct does not own auth rules on it
|
|
33
|
+
* and falls back to reading the namespace-level `RootManageSharedAccessKey` for the connection string.
|
|
34
|
+
*
|
|
7
35
|
* @example
|
|
36
|
+
* // Minimal subclass (defaults — both namespace and queue created by the construct):
|
|
8
37
|
* import { AzureEventHandler, AzureEventHandlerProps } from '@gradientedge/cdk-utils'
|
|
9
38
|
*
|
|
10
39
|
* class CustomConstruct extends AzureEventHandler {
|
|
@@ -15,6 +44,30 @@ import { AzureFunctionApp } from '../function-app/index.js';
|
|
|
15
44
|
* this.initResources()
|
|
16
45
|
* }
|
|
17
46
|
* }
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* // Shared-namespace pattern — reuse a namespace provisioned by another stack, create a new
|
|
50
|
+
* // queue under it. Useful when multiple event handlers should share a single Service Bus namespace.
|
|
51
|
+
* import * as pulumi from '@pulumi/pulumi'
|
|
52
|
+
*
|
|
53
|
+
* const sharedInfraStack = new pulumi.StackReference('shared-infra')
|
|
54
|
+
* const sharedNamespace = sharedInfraStack.getOutput('serviceBusNamespace')
|
|
55
|
+
*
|
|
56
|
+
* new CustomConstruct('my-event-handler', {
|
|
57
|
+
* ...baseProps,
|
|
58
|
+
* serviceBus: {
|
|
59
|
+
* namespace: {
|
|
60
|
+
* useExisting: true,
|
|
61
|
+
* namespaceName: sharedNamespace.apply((ns) => ns.name),
|
|
62
|
+
* resourceGroupName: sharedNamespace.apply((ns) => ns.resourceGroupName),
|
|
63
|
+
* },
|
|
64
|
+
* queue: {
|
|
65
|
+
* useExisting: false,
|
|
66
|
+
* queueName: 'my-event-queue',
|
|
67
|
+
* },
|
|
68
|
+
* },
|
|
69
|
+
* })
|
|
70
|
+
*
|
|
18
71
|
* @category Construct
|
|
19
72
|
*/
|
|
20
73
|
export class AzureEventHandler extends AzureFunctionApp {
|
|
@@ -49,6 +102,7 @@ export class AzureEventHandler extends AzureFunctionApp {
|
|
|
49
102
|
this.createEventGridSubscriptionDlqStorageContainer();
|
|
50
103
|
this.createServiceBusNamespace();
|
|
51
104
|
this.createServiceBusQueue();
|
|
105
|
+
this.createServiceBusQueueAuthorizationRule();
|
|
52
106
|
this.createEventGrid();
|
|
53
107
|
this.createEventGridEventSubscription();
|
|
54
108
|
this.createServiceBusDiagnosticLog();
|
|
@@ -80,11 +134,35 @@ export class AzureEventHandler extends AzureFunctionApp {
|
|
|
80
134
|
resourceGroupName: this.resourceGroup.name,
|
|
81
135
|
});
|
|
82
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* @summary Resolve effective `useExisting` flags for the Service Bus namespace and queue.
|
|
139
|
+
*
|
|
140
|
+
* Per-resource flags (`namespace.useExisting`, `queue.useExisting`) take precedence over the
|
|
141
|
+
* deprecated top-level `serviceBus.useExisting`, which is treated as an alias that sets both.
|
|
142
|
+
* Throws if the invalid combination (namespace.useExisting=false + queue.useExisting=true) is
|
|
143
|
+
* requested — a queue cannot be looked up under a namespace the construct is about to create.
|
|
144
|
+
*/
|
|
145
|
+
resolveServiceBusUseExisting() {
|
|
146
|
+
// TODO: remove `deprecatedServiceBusUseExisting` and the `?? deprecatedServiceBusUseExisting`
|
|
147
|
+
// fallbacks once all callers have migrated to the per-resource flags
|
|
148
|
+
// (see EventHandlerServiceBusProps.useExisting in types.ts).
|
|
149
|
+
const deprecatedServiceBusUseExisting = this.props.serviceBus?.useExisting;
|
|
150
|
+
const namespaceUseExisting = this.props.serviceBus?.namespace?.useExisting;
|
|
151
|
+
const queueUseExisting = this.props.serviceBus?.queue?.useExisting;
|
|
152
|
+
const namespace = namespaceUseExisting ?? deprecatedServiceBusUseExisting ?? false;
|
|
153
|
+
const queue = queueUseExisting ?? deprecatedServiceBusUseExisting ?? false;
|
|
154
|
+
if (!namespace && queue) {
|
|
155
|
+
throw new Error(`[${this.id}] invalid serviceBus configuration: queue.useExisting=true requires namespace.useExisting=true ` +
|
|
156
|
+
`(cannot resolve an existing queue under a namespace the construct is creating).`);
|
|
157
|
+
}
|
|
158
|
+
return { namespace, queue };
|
|
159
|
+
}
|
|
83
160
|
/**
|
|
84
161
|
* @summary Method to create the Service Bus namespace
|
|
85
162
|
*/
|
|
86
163
|
createServiceBusNamespace() {
|
|
87
|
-
|
|
164
|
+
const useExistingFlags = this.resolveServiceBusUseExisting();
|
|
165
|
+
if (useExistingFlags.namespace && this.props.serviceBus?.namespace?.namespaceName) {
|
|
88
166
|
this.serviceBus.namespace = getNamespaceOutput({
|
|
89
167
|
namespaceName: this.props.serviceBus.namespace.namespaceName,
|
|
90
168
|
resourceGroupName: this.props.serviceBus.namespace.resourceGroupName,
|
|
@@ -105,7 +183,8 @@ export class AzureEventHandler extends AzureFunctionApp {
|
|
|
105
183
|
* @summary Method to create the Service Bus queue
|
|
106
184
|
*/
|
|
107
185
|
createServiceBusQueue() {
|
|
108
|
-
|
|
186
|
+
const useExistingFlags = this.resolveServiceBusUseExisting();
|
|
187
|
+
if (useExistingFlags.queue &&
|
|
109
188
|
this.props.serviceBus?.namespace?.namespaceName &&
|
|
110
189
|
this.props.serviceBus?.queue?.queueName) {
|
|
111
190
|
this.serviceBus.queue = getQueueOutput({
|
|
@@ -115,11 +194,17 @@ export class AzureEventHandler extends AzureFunctionApp {
|
|
|
115
194
|
});
|
|
116
195
|
}
|
|
117
196
|
else {
|
|
197
|
+
// Azure requires the queue's resource group to match its parent namespace's resource group.
|
|
198
|
+
// When the namespace is external, use the namespace's resource group from props;
|
|
199
|
+
// otherwise the construct is creating the namespace alongside the queue in the consumer stack's own resource group.
|
|
200
|
+
const namespaceResourceGroupName = useExistingFlags.namespace
|
|
201
|
+
? (this.props.serviceBus?.namespace?.resourceGroupName ?? this.resourceGroup.name)
|
|
202
|
+
: this.resourceGroup.name;
|
|
118
203
|
this.serviceBus.queue = this.serviceBusManager.createServiceBusQueue(this.id, this, {
|
|
119
204
|
...this.props.serviceBus?.queue,
|
|
120
205
|
queueName: this.props.serviceBus?.queue?.queueName ?? this.id,
|
|
121
206
|
namespaceName: this.serviceBus.namespace.name,
|
|
122
|
-
resourceGroupName:
|
|
207
|
+
resourceGroupName: namespaceResourceGroupName,
|
|
123
208
|
});
|
|
124
209
|
}
|
|
125
210
|
this.registerOutputs({
|
|
@@ -127,6 +212,39 @@ export class AzureEventHandler extends AzureFunctionApp {
|
|
|
127
212
|
serviceBusQueueName: this.serviceBus.queue.name,
|
|
128
213
|
});
|
|
129
214
|
}
|
|
215
|
+
/**
|
|
216
|
+
* @summary Provision a per-queue Listen+Send authorization rule.
|
|
217
|
+
*
|
|
218
|
+
* Skipped when the construct does not own the queue (`queue.useExisting=true`) — in that case
|
|
219
|
+
* the producer/owner of the queue is responsible for its auth rules and the function app's
|
|
220
|
+
* connection string falls back to the namespace-level root rule in {@link createFunctionAppSiteConfig}.
|
|
221
|
+
*
|
|
222
|
+
* Replaces the previous reliance on `RootManageSharedAccessKey`, which grants Listen+Send+Manage
|
|
223
|
+
* on every queue in the namespace. The new rule narrows the scope to this one queue while keeping
|
|
224
|
+
* Listen+Send so existing function code can both consume and publish through it (Manage is
|
|
225
|
+
* intentionally dropped — a runtime app should not create or delete queues).
|
|
226
|
+
*/
|
|
227
|
+
createServiceBusQueueAuthorizationRule() {
|
|
228
|
+
const useExistingFlags = this.resolveServiceBusUseExisting();
|
|
229
|
+
if (useExistingFlags.queue)
|
|
230
|
+
return;
|
|
231
|
+
const namespaceResourceGroupName = useExistingFlags.namespace
|
|
232
|
+
? (this.props.serviceBus?.namespace?.resourceGroupName ?? this.resourceGroup.name)
|
|
233
|
+
: this.resourceGroup.name;
|
|
234
|
+
// Azure caps `authorizationRuleName` at 50 chars. The rule's scope is the queue itself
|
|
235
|
+
// (`…/namespaces/<ns>/queues/<queue>/authorizationRules/<rule>`), so a literal name is
|
|
236
|
+
// unambiguous and avoids hitting the cap on long stack ids.
|
|
237
|
+
this.serviceBus.queueAuthorizationRule = this.serviceBusManager.createServiceBusQueueAuthorizationRule(this.id, this, {
|
|
238
|
+
authorizationRuleName: 'listen-send',
|
|
239
|
+
namespaceName: this.serviceBus.namespace.name,
|
|
240
|
+
queueName: this.serviceBus.queue.name,
|
|
241
|
+
resourceGroupName: namespaceResourceGroupName,
|
|
242
|
+
rights: [AccessRights.Listen, AccessRights.Send],
|
|
243
|
+
});
|
|
244
|
+
this.registerOutputs({
|
|
245
|
+
serviceBusQueueAuthorizationRuleId: this.serviceBus.queueAuthorizationRule.id,
|
|
246
|
+
});
|
|
247
|
+
}
|
|
130
248
|
/**
|
|
131
249
|
* @summary Method to create or resolve an existing EventGrid topic
|
|
132
250
|
*/
|
|
@@ -157,10 +275,15 @@ export class AzureEventHandler extends AzureFunctionApp {
|
|
|
157
275
|
}
|
|
158
276
|
}
|
|
159
277
|
/**
|
|
160
|
-
* @summary Method to create the EventGrid event subscription with Service Bus queue destination
|
|
278
|
+
* @summary Method to create the EventGrid event subscription with Service Bus queue destination.
|
|
279
|
+
*
|
|
280
|
+
* Skipped when the construct is reusing an existing queue (the producer/owner of that queue owns
|
|
281
|
+
* the subscription). When the construct creates a new queue — including the case where the queue
|
|
282
|
+
* is new but the parent namespace is externally-managed — the subscription is wired here.
|
|
161
283
|
*/
|
|
162
284
|
createEventGridEventSubscription() {
|
|
163
|
-
|
|
285
|
+
const useExistingFlags = this.resolveServiceBusUseExisting();
|
|
286
|
+
if (useExistingFlags.queue || !this.eventGridEventSubscription.dlqStorageAccount)
|
|
164
287
|
return;
|
|
165
288
|
this.eventGridEventSubscription.eventSubscription = this.eventgridManager.createEventgridSubscription(this.id, this, {
|
|
166
289
|
...this.props.eventGridEventSubscription,
|
|
@@ -178,10 +301,15 @@ export class AzureEventHandler extends AzureFunctionApp {
|
|
|
178
301
|
});
|
|
179
302
|
}
|
|
180
303
|
/**
|
|
181
|
-
* @summary Method to create diagnostic log settings for the Service Bus namespace
|
|
304
|
+
* @summary Method to create diagnostic log settings for the Service Bus namespace.
|
|
305
|
+
*
|
|
306
|
+
* Diagnostic settings live on the namespace, so the construct only registers them when it owns
|
|
307
|
+
* the namespace. When the namespace is external (e.g. provisioned by a shared infrastructure
|
|
308
|
+
* stack), its owner is responsible for diagnostic settings — registering again here would conflict.
|
|
182
309
|
*/
|
|
183
310
|
createServiceBusDiagnosticLog() {
|
|
184
|
-
|
|
311
|
+
const useExistingFlags = this.resolveServiceBusUseExisting();
|
|
312
|
+
if (useExistingFlags.namespace)
|
|
185
313
|
return;
|
|
186
314
|
this.monitorManager.createMonitorDiagnosticSettings(this.id, this, {
|
|
187
315
|
name: `${this.id}-servicebus`,
|
|
@@ -230,15 +358,40 @@ export class AzureEventHandler extends AzureFunctionApp {
|
|
|
230
358
|
this.appConnectionStrings = [
|
|
231
359
|
{
|
|
232
360
|
name: 'EVENT_INGEST_SERVICE_BUS',
|
|
233
|
-
value:
|
|
234
|
-
resourceGroupName: this.props.serviceBus?.namespace?.resourceGroupName ?? this.resourceGroup.name,
|
|
235
|
-
namespaceName: this.serviceBus.namespace.name,
|
|
236
|
-
authorizationRuleName: 'RootManageSharedAccessKey',
|
|
237
|
-
}).primaryConnectionString,
|
|
361
|
+
value: this.resolveServiceBusConnectionString(),
|
|
238
362
|
type: 'ServiceBus',
|
|
239
363
|
},
|
|
240
364
|
];
|
|
241
365
|
}
|
|
366
|
+
/**
|
|
367
|
+
* @summary Resolve the connection string injected as `EVENT_INGEST_SERVICE_BUS` on the function app.
|
|
368
|
+
*
|
|
369
|
+
* - When the construct provisioned the queue itself, read from the per-queue Listen-scoped
|
|
370
|
+
* authorization rule created in {@link createServiceBusQueueAuthorizationRule}. Scope is
|
|
371
|
+
* limited to this one queue, which is correct for a shared (per-domain) namespace.
|
|
372
|
+
* - When the queue is external (legacy `WebhookEventHandler` cross-stack pattern), fall back to
|
|
373
|
+
* the namespace-level `RootManageSharedAccessKey` — preserves pre-existing behaviour for that
|
|
374
|
+
* caller shape since the construct does not own the queue and cannot provision a rule on it.
|
|
375
|
+
*/
|
|
376
|
+
resolveServiceBusConnectionString() {
|
|
377
|
+
if (this.serviceBus.queueAuthorizationRule) {
|
|
378
|
+
const useExistingFlags = this.resolveServiceBusUseExisting();
|
|
379
|
+
const namespaceResourceGroupName = useExistingFlags.namespace
|
|
380
|
+
? (this.props.serviceBus?.namespace?.resourceGroupName ?? this.resourceGroup.name)
|
|
381
|
+
: this.resourceGroup.name;
|
|
382
|
+
return listQueueKeysOutput({
|
|
383
|
+
resourceGroupName: namespaceResourceGroupName,
|
|
384
|
+
namespaceName: this.serviceBus.namespace.name,
|
|
385
|
+
queueName: this.serviceBus.queue.name,
|
|
386
|
+
authorizationRuleName: this.serviceBus.queueAuthorizationRule.name,
|
|
387
|
+
}).primaryConnectionString;
|
|
388
|
+
}
|
|
389
|
+
return listNamespaceKeysOutput({
|
|
390
|
+
resourceGroupName: this.props.serviceBus?.namespace?.resourceGroupName ?? this.resourceGroup.name,
|
|
391
|
+
namespaceName: this.serviceBus.namespace.name,
|
|
392
|
+
authorizationRuleName: 'RootManageSharedAccessKey',
|
|
393
|
+
}).primaryConnectionString;
|
|
394
|
+
}
|
|
242
395
|
/**
|
|
243
396
|
* @summary Override to extend the dashboard variables with service bus and event grid specifics
|
|
244
397
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EventSubscription } from '@pulumi/azure-native/eventgrid/index.js';
|
|
2
|
-
import { GetNamespaceResult, GetQueueResult, Namespace, Queue } from '@pulumi/azure-native/servicebus/index.js';
|
|
2
|
+
import { GetNamespaceResult, GetQueueResult, Namespace, Queue, QueueAuthorizationRule } from '@pulumi/azure-native/servicebus/index.js';
|
|
3
3
|
import { BlobContainer, StorageAccount } from '@pulumi/azure-native/storage/index.js';
|
|
4
4
|
import { Input, Output } from '@pulumi/pulumi';
|
|
5
5
|
import { DefenderForStorageProps, EventgridEventSubscriptionProps, EventgridTopicProps, ServiceBusNamespaceProps, ServiceBusQueueProps, StorageAccountProps, StorageContainerProps } from '../../services/index.js';
|
|
@@ -27,15 +27,47 @@ export interface EventHandlerEventGridSubscription {
|
|
|
27
27
|
eventSubscription?: EventSubscription;
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
|
-
* Properties for configuring the Service Bus
|
|
30
|
+
* Properties for configuring the Service Bus namespace inside the event handler.
|
|
31
|
+
* Wraps {@link ServiceBusNamespaceProps} with a `useExisting` flag controlling
|
|
32
|
+
* whether the construct creates the namespace or resolves an existing one.
|
|
33
|
+
* @category Interface
|
|
34
|
+
*/
|
|
35
|
+
export interface EventHandlerServiceBusNamespaceProps extends ServiceBusNamespaceProps {
|
|
36
|
+
/** When true, resolves an existing namespace via getNamespaceOutput instead of creating one */
|
|
37
|
+
useExisting?: boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Properties for configuring the Service Bus queue inside the event handler.
|
|
41
|
+
* Wraps {@link ServiceBusQueueProps} with a `useExisting` flag controlling
|
|
42
|
+
* whether the construct creates the queue or resolves an existing one.
|
|
43
|
+
* @category Interface
|
|
44
|
+
*/
|
|
45
|
+
export interface EventHandlerServiceBusQueueProps extends ServiceBusQueueProps {
|
|
46
|
+
/** When true, resolves an existing queue via getQueueOutput instead of creating one */
|
|
47
|
+
useExisting?: boolean;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Properties for configuring the Service Bus integration in the event handler.
|
|
51
|
+
*
|
|
52
|
+
* `namespace.useExisting` and `queue.useExisting` are independent. The supported combinations are:
|
|
53
|
+
* - `namespace.useExisting=false, queue.useExisting=false` — create both (default)
|
|
54
|
+
* - `namespace.useExisting=true, queue.useExisting=false` — reuse an existing (e.g. shared) namespace, create a new queue under it
|
|
55
|
+
* - `namespace.useExisting=true, queue.useExisting=true` — reuse both (cross-stack reference to a queue someone else owns)
|
|
56
|
+
* - `namespace.useExisting=false, queue.useExisting=true` — invalid; construct throws at construct-time
|
|
31
57
|
* @category Interface
|
|
32
58
|
*/
|
|
33
59
|
export interface EventHandlerServiceBusProps {
|
|
34
|
-
/** Service Bus namespace properties */
|
|
35
|
-
namespace?:
|
|
36
|
-
/** Service Bus queue properties */
|
|
37
|
-
queue?:
|
|
38
|
-
/**
|
|
60
|
+
/** Service Bus namespace properties (extends {@link ServiceBusNamespaceProps} with `useExisting`) */
|
|
61
|
+
namespace?: EventHandlerServiceBusNamespaceProps;
|
|
62
|
+
/** Service Bus queue properties (extends {@link ServiceBusQueueProps} with `useExisting`) */
|
|
63
|
+
queue?: EventHandlerServiceBusQueueProps;
|
|
64
|
+
/**
|
|
65
|
+
* Convenience alias that sets both `namespace.useExisting` and `queue.useExisting` to the same value.
|
|
66
|
+
* @deprecated Prefer `namespace.useExisting` and `queue.useExisting` individually. Retained as an alias
|
|
67
|
+
* so existing callers (e.g. WebhookEventHandler) continue to compile unchanged.
|
|
68
|
+
* TODO: remove once all callers have migrated to the per-resource flags. Also remove the
|
|
69
|
+
* resolution fallback in `resolveServiceBusUseExisting()` in main.ts.
|
|
70
|
+
*/
|
|
39
71
|
useExisting?: boolean;
|
|
40
72
|
}
|
|
41
73
|
/**
|
|
@@ -47,6 +79,13 @@ export interface EventHandlerServiceBus {
|
|
|
47
79
|
namespace: Namespace | Output<GetNamespaceResult>;
|
|
48
80
|
/** The provisioned or resolved Service Bus queue */
|
|
49
81
|
queue: Queue | Output<GetQueueResult>;
|
|
82
|
+
/**
|
|
83
|
+
* Per-queue authorization rule (Listen+Send) used to build the function app's
|
|
84
|
+
* `EVENT_INGEST_SERVICE_BUS` connection string. Provisioned only when the
|
|
85
|
+
* construct owns the queue (`queue.useExisting=false`); undefined when the
|
|
86
|
+
* queue is external and the connection string falls back to the namespace-level rule.
|
|
87
|
+
*/
|
|
88
|
+
queueAuthorizationRule?: QueueAuthorizationRule;
|
|
50
89
|
}
|
|
51
90
|
/**
|
|
52
91
|
* Properties for configuring the EventGrid topic in the event handler
|
|
@@ -17,5 +17,7 @@ export declare enum RoleDefinitionId {
|
|
|
17
17
|
/** Read, write, and delete Azure Storage blob data */
|
|
18
18
|
STORAGE_BLOB_DATA_CONTRIBUTOR = "/providers/Microsoft.Authorization/roleDefinitions/ba92f5b4-2d11-453d-a403-e96b0029c9fe",
|
|
19
19
|
/** Read, write, and delete Azure Storage table data */
|
|
20
|
-
STORAGE_TABLE_DATA_CONTRIBUTOR = "/providers/Microsoft.Authorization/roleDefinitions/0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3"
|
|
20
|
+
STORAGE_TABLE_DATA_CONTRIBUTOR = "/providers/Microsoft.Authorization/roleDefinitions/0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3",
|
|
21
|
+
/** Full data-plane + management access on Service Bus namespaces (create queues/topics, listKeys on auth rules, send/receive) */
|
|
22
|
+
AZURE_SERVICE_BUS_DATA_OWNER = "/providers/Microsoft.Authorization/roleDefinitions/090c5cfd-751d-490a-894a-3ce6f1109419"
|
|
21
23
|
}
|
|
@@ -19,4 +19,6 @@ export var RoleDefinitionId;
|
|
|
19
19
|
RoleDefinitionId["STORAGE_BLOB_DATA_CONTRIBUTOR"] = "/providers/Microsoft.Authorization/roleDefinitions/ba92f5b4-2d11-453d-a403-e96b0029c9fe";
|
|
20
20
|
/** Read, write, and delete Azure Storage table data */
|
|
21
21
|
RoleDefinitionId["STORAGE_TABLE_DATA_CONTRIBUTOR"] = "/providers/Microsoft.Authorization/roleDefinitions/0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3";
|
|
22
|
+
/** Full data-plane + management access on Service Bus namespaces (create queues/topics, listKeys on auth rules, send/receive) */
|
|
23
|
+
RoleDefinitionId["AZURE_SERVICE_BUS_DATA_OWNER"] = "/providers/Microsoft.Authorization/roleDefinitions/090c5cfd-751d-490a-894a-3ce6f1109419";
|
|
22
24
|
})(RoleDefinitionId || (RoleDefinitionId = {}));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ResourceOptions } from '@pulumi/pulumi';
|
|
2
2
|
import { CommonAzureConstruct } from '../../common/index.js';
|
|
3
|
-
import { ResolveServicebusQueueProps, ServiceBusNamespaceProps, ServiceBusQueueProps, ServiceBusSubscriptionProps, ServiceBusTopicProps } from './types.js';
|
|
3
|
+
import { ResolveServicebusQueueProps, ServiceBusNamespaceProps, ServiceBusQueueAuthorizationRuleProps, ServiceBusQueueProps, ServiceBusSubscriptionProps, ServiceBusTopicProps } from './types.js';
|
|
4
4
|
/**
|
|
5
5
|
* Provides operations on Azure Servicebus using Pulumi
|
|
6
6
|
* - A new instance of this class is injected into {@link CommonAzureConstruct} constructor.
|
|
@@ -47,6 +47,15 @@ export declare class AzureServiceBusManager {
|
|
|
47
47
|
* @see [Pulumi Azure Native Service Bus Queue]{@link https://www.pulumi.com/registry/packages/azure-native/api-docs/service bus/queue/}
|
|
48
48
|
*/
|
|
49
49
|
createServiceBusQueue(id: string, scope: CommonAzureConstruct, props: ServiceBusQueueProps, resourceOptions?: ResourceOptions): import("@pulumi/azure-native/servicebus/queue.js").Queue;
|
|
50
|
+
/**
|
|
51
|
+
* @summary Method to create a new service bus queue authorization rule
|
|
52
|
+
* @param id scoped id of the resource
|
|
53
|
+
* @param scope scope in which this resource is defined
|
|
54
|
+
* @param props service bus queue authorization rule properties
|
|
55
|
+
* @param resourceOptions Optional settings to control resource behaviour
|
|
56
|
+
* @see [Pulumi Azure Native Service Bus Queue Authorization Rule]{@link https://www.pulumi.com/registry/packages/azure-native/api-docs/servicebus/queueauthorizationrule/}
|
|
57
|
+
*/
|
|
58
|
+
createServiceBusQueueAuthorizationRule(id: string, scope: CommonAzureConstruct, props: ServiceBusQueueAuthorizationRuleProps, resourceOptions?: ResourceOptions): import("@pulumi/azure-native/servicebus/queueAuthorizationRule.js").QueueAuthorizationRule;
|
|
50
59
|
/**
|
|
51
60
|
* @summary Method to create a new service bus subscription
|
|
52
61
|
* @param id scoped id of the resource
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getQueueOutput, ManagedServiceIdentityType, Namespace, Queue, SkuName, Subscription, Topic, } from '@pulumi/azure-native/servicebus/index.js';
|
|
1
|
+
import { getQueueOutput, ManagedServiceIdentityType, Namespace, Queue, QueueAuthorizationRule, SkuName, Subscription, Topic, } from '@pulumi/azure-native/servicebus/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* Provides operations on Azure Servicebus using Pulumi
|
|
4
4
|
* - A new instance of this class is injected into {@link CommonAzureConstruct} constructor.
|
|
@@ -87,6 +87,19 @@ export class AzureServiceBusManager {
|
|
|
87
87
|
enablePartitioning: props.enablePartitioning ?? false,
|
|
88
88
|
}, { parent: scope, ...resourceOptions });
|
|
89
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* @summary Method to create a new service bus queue authorization rule
|
|
92
|
+
* @param id scoped id of the resource
|
|
93
|
+
* @param scope scope in which this resource is defined
|
|
94
|
+
* @param props service bus queue authorization rule properties
|
|
95
|
+
* @param resourceOptions Optional settings to control resource behaviour
|
|
96
|
+
* @see [Pulumi Azure Native Service Bus Queue Authorization Rule]{@link https://www.pulumi.com/registry/packages/azure-native/api-docs/servicebus/queueauthorizationrule/}
|
|
97
|
+
*/
|
|
98
|
+
createServiceBusQueueAuthorizationRule(id, scope, props, resourceOptions) {
|
|
99
|
+
if (!props)
|
|
100
|
+
throw new Error(`Props undefined for ${id}`);
|
|
101
|
+
return new QueueAuthorizationRule(`${id}-sqar`, { ...props }, { parent: scope, ...resourceOptions });
|
|
102
|
+
}
|
|
90
103
|
/**
|
|
91
104
|
* @summary Method to create a new service bus subscription
|
|
92
105
|
* @param id scoped id of the resource
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GetQueueOutputArgs, NamespaceArgs, QueueArgs, SubscriptionArgs, TopicArgs } from '@pulumi/azure-native/servicebus/index.js';
|
|
1
|
+
import { GetQueueOutputArgs, NamespaceArgs, QueueArgs, QueueAuthorizationRuleArgs, SubscriptionArgs, TopicArgs } from '@pulumi/azure-native/servicebus/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* Properties for creating a Service Bus namespace
|
|
4
4
|
* @see [Pulumi Azure Native Service Bus Namespace]{@link https://www.pulumi.com/registry/packages/azure-native/api-docs/servicebus/namespace/}
|
|
@@ -20,6 +20,13 @@ export interface ServiceBusTopicProps extends TopicArgs {
|
|
|
20
20
|
*/
|
|
21
21
|
export interface ServiceBusQueueProps extends QueueArgs {
|
|
22
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Properties for creating a Service Bus queue authorization rule
|
|
25
|
+
* @see [Pulumi Azure Native Service Bus Queue Authorization Rule]{@link https://www.pulumi.com/registry/packages/azure-native/api-docs/servicebus/queueauthorizationrule/}
|
|
26
|
+
* @category Interface
|
|
27
|
+
*/
|
|
28
|
+
export interface ServiceBusQueueAuthorizationRuleProps extends QueueAuthorizationRuleArgs {
|
|
29
|
+
}
|
|
23
30
|
/**
|
|
24
31
|
* Properties for creating a Service Bus subscription
|
|
25
32
|
* @see [Pulumi Azure Native Service Bus Subscription]{@link https://www.pulumi.com/registry/packages/azure-native/api-docs/servicebus/subscription/}
|