@gradientedge/cdk-utils-azure 2.19.0 → 2.21.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.
@@ -14,6 +14,9 @@ export function isTaggableResource(resourceType) {
14
14
  return false;
15
15
  if (resourceType.startsWith('pulumi:'))
16
16
  return false;
17
+ if (resourceType.startsWith('azure-native:apimanagement:') &&
18
+ resourceType !== 'azure-native:apimanagement:ApiManagementService')
19
+ return false;
17
20
  // Extract the resource name from the type (e.g., 'ResourceGroup' from 'azure-native:resources:ResourceGroup')
18
21
  const resourceName = resourceType.split(':').pop() || '';
19
22
  // Check if this resource is in the exclusion list
@@ -3,6 +3,7 @@ import * as path from 'path';
3
3
  import * as archive from '@pulumi/archive';
4
4
  import { getConfigurationStoreOutput, } from '@pulumi/azure-native/appconfiguration/index.js';
5
5
  import { getComponentOutput } from '@pulumi/azure-native/applicationinsights/index.js';
6
+ import { PrincipalType } from '@pulumi/azure-native/authorization/index.js';
6
7
  import { SkuFamily, SkuName } from '@pulumi/azure-native/keyvault/index.js';
7
8
  import { listStorageAccountKeysOutput } from '@pulumi/azure-native/storage/index.js';
8
9
  import { AuthenticationType, FunctionsDeploymentStorageType, } from '@pulumi/azure-native/web/index.js';
@@ -93,6 +94,7 @@ export class AzureFunctionApp extends CommonAzureConstruct {
93
94
  this.appServicePlan = this.appServiceManager.createAppServicePlan(`${this.id}-app-service-plan`, this, {
94
95
  ...this.props.functionApp.servicePlan,
95
96
  name: this.id,
97
+ kind: this.props.functionApp.servicePlan?.kind ?? 'functionapp',
96
98
  resourceGroupName: this.resourceGroup.name,
97
99
  location: this.resourceGroup.location,
98
100
  });
@@ -240,7 +242,7 @@ export class AzureFunctionApp extends CommonAzureConstruct {
240
242
  * @summary Method to create and configure the function host.json
241
243
  */
242
244
  createFunctionHosts() {
243
- const currentDirectory = path.resolve();
245
+ const currentDirectory = path.resolve(process.cwd(), '..');
244
246
  const hostsJsonFile = `${currentDirectory}/${this.props.functionApp.deploySource}/host.json`;
245
247
  if (!fs.existsSync(hostsJsonFile))
246
248
  return;
@@ -252,7 +254,7 @@ export class AzureFunctionApp extends CommonAzureConstruct {
252
254
  * @summary Method to create the code package archive for deployment
253
255
  */
254
256
  createCodePackage() {
255
- const currentDirectory = path.resolve();
257
+ const currentDirectory = path.resolve(process.cwd(), '..');
256
258
  this.appCodeArchiveFile = archive.getFileOutput({
257
259
  type: 'zip',
258
260
  sourceDir: `${currentDirectory}/${this.props.functionApp.deploySource}`,
@@ -272,6 +274,7 @@ export class AzureFunctionApp extends CommonAzureConstruct {
272
274
  this.app = this.functionManager.createFunctionAppFlexConsumption(`${this.id}-function-app-flex`, this, {
273
275
  ...this.props.functionApp,
274
276
  name: this.props.functionApp.app?.name ?? this.id,
277
+ scaleAndConcurrency: this.props.functionApp.app?.scaleAndConcurrency,
275
278
  serverFarmId: this.appServicePlan.id,
276
279
  resourceGroupName: this.resourceGroup.name,
277
280
  functionAppConfig: {
@@ -281,7 +284,7 @@ export class AzureFunctionApp extends CommonAzureConstruct {
281
284
  value: pulumi.interpolate `${this.appStorageAccount.primaryEndpoints.apply(e => e?.blob)}${this.appDeploymentStorageContainer.name}`,
282
285
  authentication: {
283
286
  type: AuthenticationType.StorageAccountConnectionString,
284
- storageAccountConnectionStringName: 'AzureWebJobsStorage',
287
+ storageAccountConnectionStringName: 'DEPLOYMENT_STORAGE_CONNECTION_STRING',
285
288
  },
286
289
  },
287
290
  },
@@ -298,7 +301,7 @@ export class AzureFunctionApp extends CommonAzureConstruct {
298
301
  value: this.applicationInsights.instrumentationKey,
299
302
  },
300
303
  {
301
- name: 'AzureWebJobsStorage',
304
+ name: 'DEPLOYMENT_STORAGE_CONNECTION_STRING',
302
305
  value: pulumi.interpolate `DefaultEndpointsProtocol=https;AccountName=${this.appStorageAccount.name};AccountKey=${listStorageAccountKeysOutput({
303
306
  resourceGroupName: this.resourceGroup.name,
304
307
  accountName: this.appStorageAccount.name,
@@ -321,11 +324,11 @@ export class AzureFunctionApp extends CommonAzureConstruct {
321
324
  */
322
325
  createRoleAssignments() {
323
326
  if (this.props.dataStorageAccount) {
324
- this.authorisationManager.grantRoleAssignmentToStorageAccount(`${this.id}-data`, this, this.dataStorageAccount.id, this.getFunctionAppPrincipalId(), RoleDefinitionId.STORAGE_BLOB_DATA_CONTRIBUTOR);
327
+ this.authorisationManager.grantRoleAssignmentToStorageAccount(`${this.id}-data`, this, this.dataStorageAccount.id, this.getFunctionAppPrincipalId(), PrincipalType.ServicePrincipal, this.authorisationManager.resolveRoleDefinitionId(this, RoleDefinitionId.STORAGE_BLOB_DATA_CONTRIBUTOR));
325
328
  }
326
- this.authorisationManager.grantRoleAssignmentToStorageAccount(this.id, this, this.appStorageAccount.id, this.getFunctionAppPrincipalId(), RoleDefinitionId.STORAGE_BLOB_DATA_CONTRIBUTOR);
329
+ this.authorisationManager.grantRoleAssignmentToStorageAccount(this.id, this, this.appStorageAccount.id, this.getFunctionAppPrincipalId(), PrincipalType.ServicePrincipal, this.authorisationManager.resolveRoleDefinitionId(this, RoleDefinitionId.STORAGE_BLOB_DATA_CONTRIBUTOR));
327
330
  if (!this.props.useConfigOverride) {
328
- this.authorisationManager.grantRoleAssignmentToApplicationConfiguration(this.id, this, this.appConfig.id, this.getFunctionAppPrincipalId(), RoleDefinitionId.APP_CONFIGURATION_DATA_READER);
331
+ this.authorisationManager.grantRoleAssignmentToApplicationConfiguration(this.id, this, this.appConfig.id, this.getFunctionAppPrincipalId(), PrincipalType.ServicePrincipal, this.authorisationManager.resolveRoleDefinitionId(this, RoleDefinitionId.APP_CONFIGURATION_DATA_READER));
329
332
  }
330
333
  if (this.appConfigurationsParsedConfig &&
331
334
  AzureAppConfigurationManager.hasCosmosDependencies(this.appConfigurationsParsedConfig)) {
@@ -334,12 +337,12 @@ export class AzureFunctionApp extends CommonAzureConstruct {
334
337
  if (this.appKeyVaultsByResourceGroup && this.appKeyVaultsByResourceGroup.size > 0) {
335
338
  this.appKeyVaultsByResourceGroup.forEach((keyVaultNames, resourceGroup) => {
336
339
  keyVaultNames.forEach(keyVaultName => {
337
- this.authorisationManager.grantRoleAssignmentToKeyVault(this.id, this, keyVaultName, resourceGroup, this.getFunctionAppPrincipalId(), RoleDefinitionId.KEY_VAULT_SECRETS_USER);
340
+ this.authorisationManager.grantRoleAssignmentToKeyVault(this.id, this, keyVaultName, resourceGroup, this.getFunctionAppPrincipalId(), PrincipalType.ServicePrincipal, this.authorisationManager.resolveRoleDefinitionId(this, RoleDefinitionId.KEY_VAULT_SECRETS_USER));
338
341
  });
339
342
  });
340
343
  }
341
344
  if (AzureAppConfigurationManager.hasEventGridTargets(this.appConfigurationsParsedConfig)) {
342
- this.authorisationManager.grantRoleAssignmentToEventgridTopic(this.id, this, this.props.existingTopicName, this.props.existingTopicResourceGroupName, this.getFunctionAppPrincipalId(), RoleDefinitionId.EVENTGRID_DATA_SENDER);
345
+ this.authorisationManager.grantRoleAssignmentToEventgridTopic(this.id, this, this.props.existingTopicName, this.props.existingTopicResourceGroupName, this.getFunctionAppPrincipalId(), PrincipalType.ServicePrincipal, this.authorisationManager.resolveRoleDefinitionId(this, RoleDefinitionId.EVENTGRID_DATA_SENDER));
343
346
  }
344
347
  }
345
348
  /**
@@ -1,5 +1,6 @@
1
- import { HostnameType, LoggerType } from '@pulumi/azure-native/apimanagement/index.js';
1
+ import { getApiManagementServiceOutput, HostnameType, LoggerType } from '@pulumi/azure-native/apimanagement/index.js';
2
2
  import { getComponentOutput } from '@pulumi/azure-native/applicationinsights/index.js';
3
+ import { PrincipalType } from '@pulumi/azure-native/authorization/index.js';
3
4
  import { getVaultOutput } from '@pulumi/azure-native/keyvault/index.js';
4
5
  import * as pulumi from '@pulumi/pulumi';
5
6
  import { CommonAzureConstruct } from '../../common/index.js';
@@ -83,7 +84,7 @@ export class AzureRestApi extends CommonAzureConstruct {
83
84
  {
84
85
  hostName: `api-${this.props.locationConfig?.[this.props.location].name}.${this.props.domainName}`,
85
86
  keyVaultId: this.props.apiManagement.certificateKeyVaultId,
86
- type: HostnameType.Management,
87
+ type: HostnameType.Proxy,
87
88
  },
88
89
  ];
89
90
  }
@@ -97,10 +98,15 @@ export class AzureRestApi extends CommonAzureConstruct {
97
98
  this.api.id = this.api.apim.id;
98
99
  this.api.name = this.api.apim.name;
99
100
  this.api.resourceGroupName = this.resourceGroup.name;
100
- if (this.props.apiManagement.certificateKeyVaultId) {
101
+ const apimIdentity = getApiManagementServiceOutput({
102
+ serviceName: this.api.apim.name,
103
+ resourceGroupName: this.resourceGroup.name,
104
+ }).identity;
105
+ if (this.props.apiManagement.certificateKeyVaultId && apimIdentity) {
101
106
  this.authorisationManager.createRoleAssignment(`${this.id}-kv-role`, this, {
102
- principalId: this.api.apim.identity.apply(identity => identity?.principalId ?? ''),
103
- roleDefinitionId: RoleDefinitionId.KEY_VAULT_CERTIFICATE_USER,
107
+ principalId: apimIdentity.apply(id => id?.principalId ?? ''),
108
+ roleDefinitionId: this.authorisationManager.resolveRoleDefinitionId(this, RoleDefinitionId.KEY_VAULT_CERTIFICATE_USER),
109
+ principalType: PrincipalType.ServicePrincipal,
104
110
  scope: this.props.apiManagement.certificateKeyVaultId,
105
111
  });
106
112
  }
@@ -117,11 +123,18 @@ export class AzureRestApi extends CommonAzureConstruct {
117
123
  createNamespaceSecretRole() {
118
124
  if (this.props.apiManagement.useExistingApiManagement)
119
125
  return;
120
- this.api.namedValueRoleAssignment = this.authorisationManager.createRoleAssignment(`${this.id}-key-vault-role-api-namespace`, this, {
121
- principalId: this.api.apim.identity.apply(identity => identity?.principalId ?? ''),
122
- roleDefinitionId: `/subscriptions/${this.props.subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/4633458b-17de-408a-b874-0445c86b69e6`,
123
- scope: this.api.authKeyVault.id,
124
- });
126
+ const apimIdentity = getApiManagementServiceOutput({
127
+ serviceName: this.api.apim.name,
128
+ resourceGroupName: this.resourceGroup.name,
129
+ }).identity;
130
+ if (apimIdentity) {
131
+ this.api.namedValueRoleAssignment = this.authorisationManager.createRoleAssignment(`${this.id}-key-vault-role-api-namespace`, this, {
132
+ principalId: apimIdentity.apply(id => id?.principalId ?? ''),
133
+ principalType: PrincipalType.ServicePrincipal,
134
+ roleDefinitionId: this.authorisationManager.resolveRoleDefinitionId(this, RoleDefinitionId.KEY_VAULT_SECRETS_USER),
135
+ scope: this.api.authKeyVault.id,
136
+ });
137
+ }
125
138
  }
126
139
  /**
127
140
  * @summary Method to create the namespace secret in Key Vault for Application Insights
@@ -131,8 +144,8 @@ export class AzureRestApi extends CommonAzureConstruct {
131
144
  return;
132
145
  this.api.namedValueSecret = this.keyVaultManager.createKeyVaultSecret(`${this.id}-key-vault-api-namespace-secret`, this, {
133
146
  vaultName: this.api.authKeyVault.name,
134
- secretName: `${this.applicationInsights.name}-${this.id}-key`,
135
- resourceGroupName: this.resourceGroup.name,
147
+ secretName: pulumi.interpolate `${this.applicationInsights.name}-${this.id}-key`,
148
+ resourceGroupName: this.props.apiAuthKeyVault.resourceGroupName,
136
149
  properties: {
137
150
  value: this.applicationInsights.instrumentationKey,
138
151
  },
@@ -150,12 +163,12 @@ export class AzureRestApi extends CommonAzureConstruct {
150
163
  displayName: 'all-apis',
151
164
  state: 'active',
152
165
  allowTracing: false,
153
- scope: '', // todo
166
+ scope: '/apis',
154
167
  });
155
168
  this.keyVaultManager.createKeyVaultSecret(`${this.id}-key-vault-api-subscription-key-secret`, this, {
156
169
  vaultName: this.api.authKeyVault.name,
157
170
  secretName: `${this.id}-subscription-key`,
158
- resourceGroupName: this.resourceGroup.name,
171
+ resourceGroupName: this.props.apiAuthKeyVault.resourceGroupName,
159
172
  properties: {
160
173
  value: apiManagementSubscription.primaryKey.apply(key => key ?? ''),
161
174
  },
@@ -171,21 +184,22 @@ export class AzureRestApi extends CommonAzureConstruct {
171
184
  displayName: this.applicationInsights.name,
172
185
  resourceGroupName: this.resourceGroup.name,
173
186
  serviceName: this.api.apim.name,
174
- namedValueId: `${this.applicationInsights.name}-key`,
187
+ namedValueId: pulumi.interpolate `${this.applicationInsights.name}-key`,
175
188
  secret: true,
176
189
  keyVault: {
177
- secretIdentifier: this.api.namedValueSecret.id,
190
+ secretIdentifier: this.api.namedValueSecret.properties.apply(p => p.secretUri),
178
191
  },
179
192
  });
180
193
  this.api.logger = this.apiManagementManager.createLogger(`${this.id}-am-logger`, this, {
194
+ loggerId: this.applicationInsights.name,
181
195
  resourceGroupName: this.resourceGroup.name,
182
196
  serviceName: this.api.apim.name,
183
197
  resourceId: this.applicationInsights.id,
184
198
  loggerType: LoggerType.ApplicationInsights,
185
199
  credentials: {
186
- instrumentationKey: `{{${apiAppNamedValue.displayName}}}`,
200
+ instrumentationKey: pulumi.interpolate `{{${apiAppNamedValue.displayName}}}`,
187
201
  },
188
- });
202
+ }, { dependsOn: [apiAppNamedValue] });
189
203
  }
190
204
  /**
191
205
  * @summary Method to create the API diagnostic settings for API Management
@@ -1,4 +1,4 @@
1
- import { HostnameType, NamedValue } from '@pulumi/azure-native/apimanagement/index.js';
1
+ import { HostnameType, NamedValue, PolicyContentFormat } from '@pulumi/azure-native/apimanagement/index.js';
2
2
  import { getVaultOutput } from '@pulumi/azure-native/keyvault/index.js';
3
3
  import { listWebAppHostKeysOutput } from '@pulumi/azure-native/web/index.js';
4
4
  import * as pulumi from '@pulumi/pulumi';
@@ -81,7 +81,7 @@ export class AzureRestApiFunction extends AzureFunctionApp {
81
81
  this.api.namedValueSecret = this.keyVaultManager.createKeyVaultSecret(`${this.id}-key-vault-api-namespace-secret`, this, {
82
82
  vaultName: this.api.authKeyVault.name,
83
83
  secretName: pulumi.interpolate `${this.app.name}key`,
84
- resourceGroupName: this.resourceGroup.name,
84
+ resourceGroupName: this.props.apiAuthKeyVault.resourceGroupName,
85
85
  properties: {
86
86
  value: functionDefaultKey.functionKeys?.apply(keys => keys?.['default'] ?? ''),
87
87
  },
@@ -94,9 +94,10 @@ export class AzureRestApiFunction extends AzureFunctionApp {
94
94
  if (this.props.apiManagement.useExistingApiManagement) {
95
95
  if (this.props.apiManagement.apiStackName) {
96
96
  const apiStack = new pulumi.StackReference(this.props.apiManagement.apiStackName);
97
- this.api.id = apiStack.getOutput('apiId');
98
- this.api.name = apiStack.getOutput('apiName');
99
- this.api.resourceGroupName = apiStack.getOutput('apiResourceGroupName');
97
+ const stackOutputs = apiStack.getOutput('stackOutputs');
98
+ this.api.id = stackOutputs.apply(o => o.apiId);
99
+ this.api.name = stackOutputs.apply(o => o.apiName);
100
+ this.api.resourceGroupName = stackOutputs.apply(o => o.resourceGroupName);
100
101
  }
101
102
  }
102
103
  else {
@@ -123,7 +124,7 @@ export class AzureRestApiFunction extends AzureFunctionApp {
123
124
  if (this.props.apiManagement.certificateKeyVaultId) {
124
125
  this.authorisationManager.createRoleAssignment(`${this.id}-kv-role`, this, {
125
126
  principalId: this.api.apim.identity.apply(identity => identity?.principalId ?? ''),
126
- roleDefinitionId: RoleDefinitionId.KEY_VAULT_CERTIFICATE_USER,
127
+ roleDefinitionId: this.authorisationManager.resolveRoleDefinitionId(this, RoleDefinitionId.KEY_VAULT_CERTIFICATE_USER),
127
128
  scope: this.props.apiManagement.certificateKeyVaultId,
128
129
  });
129
130
  }
@@ -136,14 +137,15 @@ export class AzureRestApiFunction extends AzureFunctionApp {
136
137
  this.api.namedValue = new NamedValue(`${this.id}-am-nv`, {
137
138
  displayName: this.app.name,
138
139
  keyVault: {
139
- secretIdentifier: this.api.namedValueSecret.id,
140
+ secretIdentifier: this.api.namedValueSecret.properties.apply(p => p.secretUri),
140
141
  },
141
142
  resourceGroupName: this.api.resourceGroupName,
142
143
  secret: true,
143
144
  serviceName: this.api.name,
144
- });
145
+ }, { parent: this });
145
146
  this.api.backend = this.apiManagementManager.createBackend(this.id, this, {
146
147
  ...this.props.apiManagementBackend,
148
+ backendId: this.id,
147
149
  title: this.id,
148
150
  resourceGroupName: this.api.resourceGroupName,
149
151
  serviceName: this.api.name,
@@ -151,7 +153,7 @@ export class AzureRestApiFunction extends AzureFunctionApp {
151
153
  resourceId: pulumi.interpolate `https://management.azure.com/subscriptions/${this.props.subscriptionId}/resourceGroups/${this.resourceGroup.name}/providers/Microsoft.Web/sites/${this.app.name}`,
152
154
  credentials: {
153
155
  header: {
154
- 'x-functions-key': [`{{${this.api.namedValue.name}}}`],
156
+ 'x-functions-key': [pulumi.interpolate `{{${this.api.namedValue.name}}}`],
155
157
  },
156
158
  },
157
159
  });
@@ -162,6 +164,7 @@ export class AzureRestApiFunction extends AzureFunctionApp {
162
164
  createApiManagementRoutes() {
163
165
  this.api.managementApi = this.apiManagementManager.createApi(`${this.id}-apim-api`, this, {
164
166
  ...this.props.apiManagementApi,
167
+ apiId: this.id,
165
168
  displayName: this.props.apiManagementApi.displayName ?? this.id,
166
169
  serviceName: this.api.name,
167
170
  resourceGroupName: this.api.resourceGroupName,
@@ -182,7 +185,7 @@ export class AzureRestApiFunction extends AzureFunctionApp {
182
185
  method: operation.method.toString().toUpperCase(),
183
186
  serviceName: this.api.name,
184
187
  resourceGroupName: this.api.resourceGroupName,
185
- apiId: this.api.id,
188
+ apiId: this.resourceNameFormatter.format(this.id, this.props.resourceNameOptions?.apiManagementApi),
186
189
  displayName: operation.displayName,
187
190
  urlTemplate: operation.urlTemplate,
188
191
  templateParameters: operation.templateParameters,
@@ -195,28 +198,28 @@ export class AzureRestApiFunction extends AzureFunctionApp {
195
198
  if (!operation.caching || !operation.caching.enableCacheSet)
196
199
  return;
197
200
  this.apiManagementManager.createOperationPolicy(`${this.id}-apim-api-operation-policy-${operation.displayName}-${operation.method}`, this, {
198
- apiId: this.api.id,
201
+ apiId: this.resourceNameFormatter.format(this.id, this.props.resourceNameOptions?.apiManagementApi),
199
202
  resourceGroupName: this.api.resourceGroupName,
200
203
  serviceName: this.api.name,
201
204
  operationId: `${operation.displayName}-${operation.method}`,
205
+ format: PolicyContentFormat.Rawxml,
202
206
  value: `
203
207
  <policies>
204
- <policies>
205
- <inbound>
206
- <base />
207
- ${this.props.apiManagementApi.cacheSetInboundPolicy}
208
- </inbound>
209
- <backend>
210
- <base />
211
- </backend>
212
- <outbound>
213
- <base />
214
- ${this.props.apiManagementApi.cacheSetOutboundPolicy}
215
- </outbound>
216
- <on-error>
217
- <base />
218
- </on-error>
219
- </policies>`.replace(/\n[ \t]*\n/g, '\n'), // move to utils
208
+ <inbound>
209
+ <base />
210
+ ${this.props.apiManagementApi.cacheSetInboundPolicy ?? ''}
211
+ </inbound>
212
+ <backend>
213
+ <base />
214
+ </backend>
215
+ <outbound>
216
+ <base />
217
+ ${this.props.apiManagementApi.cacheSetOutboundPolicy ?? ''}
218
+ </outbound>
219
+ <on-error>
220
+ <base />
221
+ </on-error>
222
+ </policies>`.replace(/\n[ \t]*\n/g, '\n'),
220
223
  });
221
224
  }
222
225
  /**
@@ -287,8 +290,9 @@ export class AzureRestApiFunction extends AzureFunctionApp {
287
290
  </policies>`;
288
291
  this.apiManagementManager.createPolicy(`${this.id}-apim-api-policy`, this, {
289
292
  serviceName: this.api.name,
290
- apiId: this.api.id,
293
+ apiId: this.resourceNameFormatter.format(this.id, this.props.resourceNameOptions?.apiManagementApi),
291
294
  resourceGroupName: this.api.resourceGroupName,
295
+ format: PolicyContentFormat.Rawxml,
292
296
  value: policyXmlContent.apply(xml => xml.replace(/\n[ \t]*\n/g, '\n')),
293
297
  });
294
298
  }
@@ -64,8 +64,8 @@ export class AzureRestApiWithCache extends AzureRestApi {
64
64
  }).apply(keys => `${hostName}:10000,password=${keys.primaryKey},ssl=True,abortConnect=False`));
65
65
  this.api.redisNamedValueSecret = this.keyVaultManager.createKeyVaultSecret(`${this.id}-key-vault-redis-namespace-secret`, this, {
66
66
  vaultName: this.api.authKeyVault.name,
67
- secretName: `${this.api.redisCluster.name}key`,
68
- resourceGroupName: this.resourceGroup.name,
67
+ secretName: pulumi.interpolate `${this.api.redisCluster.name}key`,
68
+ resourceGroupName: this.props.apiAuthKeyVault.resourceGroupName,
69
69
  properties: {
70
70
  value: connectionString,
71
71
  },
@@ -76,13 +76,13 @@ export class AzureRestApiWithCache extends AzureRestApi {
76
76
  */
77
77
  createRedisCacheNamespace() {
78
78
  this.api.redisNamedValue = this.apiManagementManager.createNamedValue(`${this.id}-redis-nv`, this, {
79
- displayName: `${this.api.redisCluster.name}key`,
79
+ displayName: pulumi.interpolate `${this.api.redisCluster.name}key`,
80
80
  resourceGroupName: this.resourceGroup.name,
81
81
  serviceName: this.api.apim.name,
82
- namedValueId: `${this.api.redisCluster.name}key`,
82
+ namedValueId: pulumi.interpolate `${this.api.redisCluster.name}key`,
83
83
  secret: true,
84
84
  keyVault: {
85
- secretIdentifier: this.api.redisNamedValueSecret.id,
85
+ secretIdentifier: this.api.redisNamedValueSecret.properties.apply(p => p.secretUri),
86
86
  },
87
87
  });
88
88
  }
@@ -92,11 +92,11 @@ export class AzureRestApiWithCache extends AzureRestApi {
92
92
  createRedisCacheApiManagement() {
93
93
  this.apiManagementManager.createCache(`${this.id}-am-redis-cache`, this, {
94
94
  serviceName: this.api.apim.name,
95
- connectionString: `{{${this.api.redisNamedValue.name}}}`,
96
- cacheId: this.api.redisCluster.id,
95
+ connectionString: pulumi.interpolate `{{${this.api.redisNamedValue.name}}}`,
96
+ cacheId: this.api.redisCluster.name,
97
97
  resourceGroupName: this.resourceGroup.name,
98
98
  useFromLocation: this.api.redisCluster.location,
99
- description: `Redis cache for ${this.api.apim.name}`,
99
+ description: pulumi.interpolate `Redis cache for ${this.api.apim.name}`,
100
100
  });
101
101
  }
102
102
  }
@@ -60,6 +60,8 @@ export class SiteWithWebApp extends CommonAzureConstruct {
60
60
  createSiteAppServicePlan() {
61
61
  this.site.appServicePlan = this.appServiceManager.createAppServicePlan(`${this.id}-app-service-plan`, this, {
62
62
  ...this.props.site.appServicePlan,
63
+ name: this.id,
64
+ kind: this.props.site.appServicePlan?.kind ?? 'linux',
63
65
  location: this.resourceGroup.location,
64
66
  resourceGroupName: this.resourceGroup.name,
65
67
  });
@@ -131,6 +133,7 @@ export class SiteWithWebApp extends CommonAzureConstruct {
131
133
  createWebApp(resourceOptions) {
132
134
  this.site.webApp = this.appServiceManager.createLinuxWebApp(`${this.id}-web-app`, this, {
133
135
  ...this.props.site.webApp,
136
+ kind: this.props.site.webApp.kind ?? 'app,linux',
134
137
  location: this.resourceGroup.location,
135
138
  resourceGroupName: this.resourceGroup.name,
136
139
  serverFarmId: this.site.appServicePlan.id,
@@ -71,7 +71,7 @@ export declare class AzureApiManagementManager {
71
71
  * @param resourceOptions Optional settings to control resource behaviour
72
72
  * @see [Pulumi Azure Native API Management Diagnostic]{@link https://www.pulumi.com/registry/packages/azure-native/api-docs/apimanagement/apidiagnostic/}
73
73
  */
74
- createApiDiagnostic(id: string, scope: CommonAzureConstruct, props: ApiDiagnosticProps, resourceOptions?: ResourceOptions): import("@pulumi/azure-native/apimanagement/apiDiagnostic.js").ApiDiagnostic;
74
+ createApiDiagnostic(id: string, scope: CommonAzureConstruct, props: ApiDiagnosticProps, resourceOptions?: ResourceOptions): import("@pulumi/azure-native/apimanagement/diagnostic.js").Diagnostic;
75
75
  /**
76
76
  * @summary Method to create a new API Logger
77
77
  * @param id scoped id of the resource
@@ -1,4 +1,4 @@
1
- import { Api, ApiDiagnostic, ApiManagementService, ApiOperation, ApiOperationPolicy, ApiPolicy, Backend, BackendProtocol, Cache, getApiManagementServiceOutput, Logger, LoggerType, NamedValue, Protocol, Subscription, } from '@pulumi/azure-native/apimanagement/index.js';
1
+ import { Api, ApiManagementService, ApiOperation, ApiOperationPolicy, ApiPolicy, Backend, BackendProtocol, Cache, Diagnostic, getApiManagementServiceOutput, Logger, LoggerType, NamedValue, Protocol, Subscription, } from '@pulumi/azure-native/apimanagement/index.js';
2
2
  import { listDatabaseKeysOutput } from '@pulumi/azure-native/redisenterprise/index.js';
3
3
  import * as pulumi from '@pulumi/pulumi';
4
4
  /**
@@ -148,7 +148,7 @@ export class AzureApiManagementManager {
148
148
  createApiDiagnostic(id, scope, props, resourceOptions) {
149
149
  if (!props)
150
150
  throw new Error(`Props undefined for ${id}`);
151
- return new ApiDiagnostic(`${id}`, props, { parent: scope, ...resourceOptions });
151
+ return new Diagnostic(`${id}`, props, { parent: scope, ...resourceOptions });
152
152
  }
153
153
  /**
154
154
  * @summary Method to create a new API Logger
@@ -222,7 +222,7 @@ export class AzureApiManagementManager {
222
222
  * @see [Pulumi Azure Native API Management Operation Policy]{@link https://www.pulumi.com/registry/packages/azure-native/api-docs/apimanagement/apioperationpolicy/}
223
223
  */
224
224
  createOperationPolicy(id, scope, props, resourceOptions) {
225
- return new ApiOperationPolicy(`${id}`, props, { parent: scope, ...resourceOptions });
225
+ return new ApiOperationPolicy(`${id}`, { ...props, policyId: 'policy' }, { parent: scope, ...resourceOptions });
226
226
  }
227
227
  /**
228
228
  * @summary Method to create a new API policy
@@ -233,7 +233,7 @@ export class AzureApiManagementManager {
233
233
  * @see [Pulumi Azure Native API Management Policy]{@link https://www.pulumi.com/registry/packages/azure-native/api-docs/apimanagement/apipolicy/}
234
234
  */
235
235
  createPolicy(id, scope, props, resourceOptions) {
236
- return new ApiPolicy(`${id}`, props, { parent: scope, ...resourceOptions });
236
+ return new ApiPolicy(`${id}`, { ...props, policyId: 'policy' }, { parent: scope, ...resourceOptions });
237
237
  }
238
238
  /**
239
239
  * @summary Method to create a new API Management custom domain
@@ -36,6 +36,7 @@ export class AzureAppServiceManager {
36
36
  name: scope.resourceNameFormatter.format(props.name?.toString(), scope.props.resourceNameOptions?.appServicePlan),
37
37
  resourceGroupName,
38
38
  location: props.location ?? scope.props.location,
39
+ kind: props.kind ?? 'functionapp',
39
40
  sku: props.sku ?? {
40
41
  name: 'FC1',
41
42
  tier: 'FlexConsumption',
@@ -30,14 +30,13 @@ export class AzureApplicationInsightsManager {
30
30
  if (!props)
31
31
  throw new Error(`Props undefined for ${id}`);
32
32
  // Get resource group name
33
- const resourceGroupName = (props.resourceGroupName ?? scope.props.resourceGroupName)
34
- ? `${scope.props.resourceGroupName}-${scope.props.stage}`
35
- : props.resourceGroupName;
33
+ const resourceGroupName = props.resourceGroupName ?? scope.resourceNameFormatter.format(scope.props.resourceGroupName);
36
34
  if (!resourceGroupName)
37
35
  throw new Error(`Resource group name undefined for ${id}`);
38
- const component = new Component(`${id}-ai`, {
36
+ const resourceName = scope.resourceNameFormatter.format(props.resourceName?.toString(), scope.props.resourceNameOptions?.applicationInsights);
37
+ const component = new Component(`${id}`, {
39
38
  ...props,
40
- resourceName: scope.resourceNameFormatter.format(props.resourceName?.toString(), scope.props.resourceNameOptions?.applicationInsights),
39
+ resourceName,
41
40
  resourceGroupName,
42
41
  applicationType: props.applicationType ?? ApplicationType.Web,
43
42
  kind: props.kind ?? 'web',
@@ -48,7 +47,12 @@ export class AzureApplicationInsightsManager {
48
47
  },
49
48
  }, { parent: scope, ...resourceOptions });
50
49
  if (props.billingFeatures) {
51
- this.createComponentCurrentBillingFeature(`${id}-billing`, scope, props.billingFeatures, {
50
+ this.createComponentCurrentBillingFeature(`${id}-billing`, scope, {
51
+ ...props.billingFeatures,
52
+ currentBillingFeatures: props.billingFeatures?.currentBillingFeatures ?? ['Basic'],
53
+ resourceName,
54
+ resourceGroupName,
55
+ }, {
52
56
  parent: scope,
53
57
  ...resourceOptions,
54
58
  });
@@ -1,3 +1,4 @@
1
+ import { PrincipalType } from '@pulumi/azure-native/authorization/index.js';
1
2
  import { Input, ResourceOptions } from '@pulumi/pulumi';
2
3
  import { CommonAzureConstruct } from '../../common/index.js';
3
4
  import { RoleDefinitionId } from './constants.js';
@@ -40,7 +41,7 @@ export declare class AzureAuthorisationManager {
40
41
  * @param roleDefinitionId the role definition id
41
42
  * @param resourceOptions Optional settings to control resource behaviour
42
43
  */
43
- grantRoleAssignmentToKeyVault(id: string, scope: CommonAzureConstruct, vaultName: string, resourceGroupName: Input<string>, principalId: Input<string>, roleDefinitionId: RoleDefinitionId, resourceOptions?: ResourceOptions): import("@pulumi/azure-native/authorization/roleAssignment.js").RoleAssignment;
44
+ grantRoleAssignmentToKeyVault(id: string, scope: CommonAzureConstruct, vaultName: string, resourceGroupName: Input<string>, principalId: Input<string>, principalType: Input<PrincipalType>, roleDefinitionId: string, resourceOptions?: ResourceOptions): import("@pulumi/azure-native/authorization/roleAssignment.js").RoleAssignment;
44
45
  /**
45
46
  * @summary Method to grant a role assignment to event grid topic
46
47
  * @param id scoped id of the resource
@@ -51,7 +52,7 @@ export declare class AzureAuthorisationManager {
51
52
  * @param roleDefinitionId the role definition id
52
53
  * @param resourceOptions Optional settings to control resource behaviour
53
54
  */
54
- grantRoleAssignmentToEventgridTopic(id: string, scope: CommonAzureConstruct, topicName: Input<string>, resourceGroupName: Input<string>, principalId: Input<string>, roleDefinitionId: RoleDefinitionId, resourceOptions?: ResourceOptions): import("@pulumi/azure-native/authorization/roleAssignment.js").RoleAssignment;
55
+ grantRoleAssignmentToEventgridTopic(id: string, scope: CommonAzureConstruct, topicName: Input<string>, resourceGroupName: Input<string>, principalId: Input<string>, principalType: Input<PrincipalType>, roleDefinitionId: string, resourceOptions?: ResourceOptions): import("@pulumi/azure-native/authorization/roleAssignment.js").RoleAssignment;
55
56
  /**
56
57
  * @summary Method to grant a role assignment to application configuration
57
58
  * @param id scoped id of the resource
@@ -61,7 +62,7 @@ export declare class AzureAuthorisationManager {
61
62
  * @param roleDefinitionId the role definition id
62
63
  * @param resourceOptions Optional settings to control resource behaviour
63
64
  */
64
- grantRoleAssignmentToApplicationConfiguration(id: string, scope: CommonAzureConstruct, appConfigId: Input<string>, principalId: Input<string>, roleDefinitionId: RoleDefinitionId, resourceOptions?: ResourceOptions): import("@pulumi/azure-native/authorization/roleAssignment.js").RoleAssignment;
65
+ grantRoleAssignmentToApplicationConfiguration(id: string, scope: CommonAzureConstruct, appConfigId: Input<string>, principalId: Input<string>, principalType: Input<PrincipalType>, roleDefinitionId: string, resourceOptions?: ResourceOptions): import("@pulumi/azure-native/authorization/roleAssignment.js").RoleAssignment;
65
66
  /**
66
67
  * @summary Method to grant a role assignment to storage account
67
68
  * @param id scoped id of the resource
@@ -71,7 +72,7 @@ export declare class AzureAuthorisationManager {
71
72
  * @param roleDefinitionId the role definition id
72
73
  * @param resourceOptions Optional settings to control resource behaviour
73
74
  */
74
- grantRoleAssignmentToStorageAccount(id: string, scope: CommonAzureConstruct, accountId: Input<string>, principalId: Input<string>, roleDefinitionId: RoleDefinitionId, resourceOptions?: ResourceOptions): import("@pulumi/azure-native/authorization/roleAssignment.js").RoleAssignment;
75
+ grantRoleAssignmentToStorageAccount(id: string, scope: CommonAzureConstruct, accountId: Input<string>, principalId: Input<string>, principalType: Input<PrincipalType>, roleDefinitionId: string, resourceOptions?: ResourceOptions): import("@pulumi/azure-native/authorization/roleAssignment.js").RoleAssignment;
75
76
  /**
76
77
  * @summary Method to grant a role assignment to storage table
77
78
  * @param id scoped id of the resource
@@ -81,5 +82,6 @@ export declare class AzureAuthorisationManager {
81
82
  * @param roleDefinitionId the role definition id
82
83
  * @param resourceOptions Optional settings to control resource behaviour
83
84
  */
84
- grantRoleAssignmentToStorageTable(id: string, scope: CommonAzureConstruct, tableId: Input<string>, principalId: Input<string>, roleDefinitionId: RoleDefinitionId, resourceOptions?: ResourceOptions): import("@pulumi/azure-native/authorization/roleAssignment.js").RoleAssignment;
85
+ grantRoleAssignmentToStorageTable(id: string, scope: CommonAzureConstruct, tableId: Input<string>, principalId: Input<string>, principalType: Input<PrincipalType>, roleDefinitionId: string, resourceOptions?: ResourceOptions): import("@pulumi/azure-native/authorization/roleAssignment.js").RoleAssignment;
86
+ resolveRoleDefinitionId(scope: CommonAzureConstruct, roleDefinitionId: RoleDefinitionId): string;
85
87
  }
@@ -29,7 +29,7 @@ export class AzureAuthorisationManager {
29
29
  createRoleAssignment(id, scope, props, resourceOptions) {
30
30
  if (!props)
31
31
  throw new Error(`Props undefined for ${id}`);
32
- return new RoleAssignment(`${id}`, props, { parent: scope, ...resourceOptions });
32
+ return new RoleAssignment(`${id}`, props, { parent: scope, ignoreChanges: ['scope'], ...resourceOptions });
33
33
  }
34
34
  /**
35
35
  * @summary Method to grant a role assignment to key vault
@@ -41,10 +41,11 @@ export class AzureAuthorisationManager {
41
41
  * @param roleDefinitionId the role definition id
42
42
  * @param resourceOptions Optional settings to control resource behaviour
43
43
  */
44
- grantRoleAssignmentToKeyVault(id, scope, vaultName, resourceGroupName, principalId, roleDefinitionId, resourceOptions) {
44
+ grantRoleAssignmentToKeyVault(id, scope, vaultName, resourceGroupName, principalId, principalType, roleDefinitionId, resourceOptions) {
45
45
  const keyVault = scope.keyVaultManager.resolveKeyVault(scope, vaultName, resourceGroupName, resourceOptions);
46
46
  return this.createRoleAssignment(`${id}-kv-role-${vaultName}`, scope, {
47
47
  principalId,
48
+ principalType,
48
49
  roleDefinitionId,
49
50
  scope: keyVault.id,
50
51
  }, resourceOptions);
@@ -59,13 +60,14 @@ export class AzureAuthorisationManager {
59
60
  * @param roleDefinitionId the role definition id
60
61
  * @param resourceOptions Optional settings to control resource behaviour
61
62
  */
62
- grantRoleAssignmentToEventgridTopic(id, scope, topicName, resourceGroupName, principalId, roleDefinitionId, resourceOptions) {
63
+ grantRoleAssignmentToEventgridTopic(id, scope, topicName, resourceGroupName, principalId, principalType, roleDefinitionId, resourceOptions) {
63
64
  const topic = scope.eventgridManager.resolveEventgridTopic(`${id}-egt-role-${topicName}`, scope, {
64
65
  topicName,
65
66
  resourceGroupName,
66
67
  }, resourceOptions);
67
68
  return this.createRoleAssignment(`${id}-egt-role-${topicName}`, scope, {
68
69
  principalId,
70
+ principalType,
69
71
  roleDefinitionId,
70
72
  scope: topic.id,
71
73
  }, resourceOptions);
@@ -79,9 +81,10 @@ export class AzureAuthorisationManager {
79
81
  * @param roleDefinitionId the role definition id
80
82
  * @param resourceOptions Optional settings to control resource behaviour
81
83
  */
82
- grantRoleAssignmentToApplicationConfiguration(id, scope, appConfigId, principalId, roleDefinitionId, resourceOptions) {
84
+ grantRoleAssignmentToApplicationConfiguration(id, scope, appConfigId, principalId, principalType, roleDefinitionId, resourceOptions) {
83
85
  return this.createRoleAssignment(`${id}-ac-role`, scope, {
84
86
  principalId,
87
+ principalType,
85
88
  roleDefinitionId,
86
89
  scope: appConfigId,
87
90
  }, resourceOptions);
@@ -95,9 +98,10 @@ export class AzureAuthorisationManager {
95
98
  * @param roleDefinitionId the role definition id
96
99
  * @param resourceOptions Optional settings to control resource behaviour
97
100
  */
98
- grantRoleAssignmentToStorageAccount(id, scope, accountId, principalId, roleDefinitionId, resourceOptions) {
101
+ grantRoleAssignmentToStorageAccount(id, scope, accountId, principalId, principalType, roleDefinitionId, resourceOptions) {
99
102
  return this.createRoleAssignment(`${id}-sa-role`, scope, {
100
103
  principalId,
104
+ principalType,
101
105
  roleDefinitionId,
102
106
  scope: accountId,
103
107
  }, resourceOptions);
@@ -111,11 +115,17 @@ export class AzureAuthorisationManager {
111
115
  * @param roleDefinitionId the role definition id
112
116
  * @param resourceOptions Optional settings to control resource behaviour
113
117
  */
114
- grantRoleAssignmentToStorageTable(id, scope, tableId, principalId, roleDefinitionId, resourceOptions) {
118
+ grantRoleAssignmentToStorageTable(id, scope, tableId, principalId, principalType, roleDefinitionId, resourceOptions) {
115
119
  return this.createRoleAssignment(`${id}-st-role`, scope, {
116
120
  principalId,
121
+ principalType,
117
122
  roleDefinitionId,
118
123
  scope: tableId,
119
124
  }, resourceOptions);
120
125
  }
126
+ resolveRoleDefinitionId(scope, roleDefinitionId) {
127
+ if (!scope.props.subscriptionId)
128
+ throw Error('Subscription id undefined');
129
+ return `/subscriptions/${scope.props.subscriptionId}${roleDefinitionId}`;
130
+ }
121
131
  }
@@ -1,4 +1,5 @@
1
1
  import { DatabaseAccount, getDatabaseAccountOutput, getSqlResourceSqlRoleDefinitionOutput, ResourceIdentityType, SqlResourceSqlContainer, SqlResourceSqlDatabase, SqlResourceSqlRoleAssignment, } from '@pulumi/azure-native/cosmosdb/index.js';
2
+ import { v5 as uuidv5 } from 'uuid';
2
3
  import { CosmosRoleDefinition, CosmosRoleDefinitionId } from './constants.js';
3
4
  /**
4
5
  * Provides operations on Azure CosmosDB using Pulumi
@@ -78,14 +79,14 @@ export class AzureCosmosDbManager {
78
79
  if (!props)
79
80
  throw new Error(`Props undefined for ${id}`);
80
81
  // Get resource group name
81
- const resourceGroupName = (props.resourceGroupName ?? scope.props.resourceGroupName)
82
- ? `${scope.props.resourceGroupName}-${scope.props.stage}`
83
- : props.resourceGroupName;
82
+ const resourceGroupName = props.resourceGroupName ?? scope.resourceNameFormatter.format(scope.props.resourceGroupName);
84
83
  if (!resourceGroupName)
85
84
  throw new Error(`Resource group name undefined for ${id}`);
86
85
  return new SqlResourceSqlContainer(`${id}-cc`, {
87
86
  ...props,
88
- containerName: scope.resourceNameFormatter.format(props.containerName?.toString(), scope.props.resourceNameOptions?.cosmosDbSqlContainer),
87
+ ...(props.containerName && {
88
+ containerName: scope.resourceNameFormatter.format(props.containerName.toString(), scope.props.resourceNameOptions?.cosmosDbSqlContainer),
89
+ }),
89
90
  resourceGroupName,
90
91
  }, { parent: scope, ...resourceOptions });
91
92
  }
@@ -98,7 +99,11 @@ export class AzureCosmosDbManager {
98
99
  * @see [Pulumi Azure Native CosmosDB SQL Role Assignment]{@link https://www.pulumi.com/registry/packages/azure-native/api-docs/documentdb/sqlresourcesqlroleassignment/}
99
100
  */
100
101
  createSqlResourceSqlRoleAssignment(id, scope, props, resourceOptions) {
101
- return new SqlResourceSqlRoleAssignment(`${id}`, props, { parent: scope, ...resourceOptions });
102
+ const namespace = uuidv5(`${scope.id}-${id}`, uuidv5.URL);
103
+ return new SqlResourceSqlRoleAssignment(`${id}`, {
104
+ ...props,
105
+ roleAssignmentId: props.roleAssignmentId ?? uuidv5(id, namespace),
106
+ }, { parent: scope, ...resourceOptions });
102
107
  }
103
108
  /**
104
109
  * @summary Method to resolve an existing cosmosdb account
@@ -1,4 +1,4 @@
1
- import { EventDeliverySchema, EventSubscription, getTopicOutput, SystemTopic, SystemTopicEventSubscription, Topic, } from '@pulumi/azure-native/eventgrid/index.js';
1
+ import { DataResidencyBoundary, EventDeliverySchema, EventSubscription, getTopicOutput, SystemTopic, SystemTopicEventSubscription, TlsVersion, Topic, } from '@pulumi/azure-native/eventgrid/index.js';
2
2
  /**
3
3
  * Provides operations on Azure Event Grid using Pulumi
4
4
  * - A new instance of this class is injected into {@link CommonAzureConstruct} constructor.
@@ -36,6 +36,8 @@ export class AzureEventgridManager {
36
36
  topicName: scope.resourceNameFormatter.format(props.topicName?.toString(), scope.props.resourceNameOptions?.eventGridTopic),
37
37
  location: props.location ?? scope.props.location,
38
38
  resourceGroupName,
39
+ dataResidencyBoundary: props.dataResidencyBoundary ?? DataResidencyBoundary.WithinGeopair,
40
+ minimumTlsVersionAllowed: props.minimumTlsVersionAllowed ?? TlsVersion.TlsVersion_1_2,
39
41
  tags: {
40
42
  environment: scope.props.stage,
41
43
  ...scope.props.defaultTags,
@@ -1,5 +1,5 @@
1
1
  import { Deployment, DeploymentMode, Resource } from '@pulumi/azure-native/resources/index.js';
2
- import { ManagedServiceIdentityType, WebApp, WebAppFunction } from '@pulumi/azure-native/web/index.js';
2
+ import { ClientCertMode, ManagedServiceIdentityType, WebApp, WebAppFunction } from '@pulumi/azure-native/web/index.js';
3
3
  import { CommonAzureStack } from '../../common/index.js';
4
4
  /**
5
5
  * Provides operations on Azure Functions using Pulumi
@@ -92,11 +92,17 @@ export class AzureFunctionManager {
92
92
  location: props.location ?? scope.props.location,
93
93
  resourceGroupName,
94
94
  kind: props.kind ?? 'functionapp,linux',
95
+ reserved: props.reserved ?? true,
95
96
  httpsOnly: props.httpsOnly ?? true,
96
97
  identity: props.identity ?? {
97
98
  type: ManagedServiceIdentityType.SystemAssigned,
98
99
  },
99
- functionAppConfig: props.functionAppConfig ?? {
100
+ clientAffinityEnabled: props.clientAffinityEnabled ?? false,
101
+ clientAffinityProxyEnabled: props.clientAffinityProxyEnabled ?? false,
102
+ clientCertMode: props.clientCertMode ?? ClientCertMode.Optional,
103
+ clientCertEnabled: props.clientCertEnabled ?? false,
104
+ functionAppConfig: {
105
+ ...props.functionAppConfig,
100
106
  runtime: {
101
107
  ...props.runtime,
102
108
  name: props.runtime?.name ?? 'node',
@@ -119,7 +125,7 @@ export class AzureFunctionManager {
119
125
  },
120
126
  }, { parent: scope, ...resourceOptions });
121
127
  const functionAppConfig = props.functionAppConfig;
122
- new Deployment(`${id}-deployment`, {
128
+ new Deployment(`${id}-depl`, {
123
129
  resourceGroupName,
124
130
  properties: {
125
131
  mode: DeploymentMode.Incremental,
@@ -144,12 +150,8 @@ export class AzureFunctionManager {
144
150
  },
145
151
  scaleAndConcurrency: {
146
152
  ...props.scaleAndConcurrency,
147
- instanceMemoryMB: props.scaleAndConcurrency?.instanceMemoryMB ??
148
- functionAppConfig?.scaleAndConcurrency?.instanceMemoryMB ??
149
- 4096,
150
- maximumInstanceCount: props.scaleAndConcurrency?.maximumInstanceCount ??
151
- functionAppConfig?.scaleAndConcurrency?.maximumInstanceCount ??
152
- 40,
153
+ instanceMemoryMB: props.scaleAndConcurrency?.instanceMemoryMB ?? 4096,
154
+ maximumInstanceCount: props.scaleAndConcurrency?.maximumInstanceCount ?? 40,
153
155
  },
154
156
  siteUpdateStrategy: {
155
157
  type: 'RollingUpdate',
@@ -160,7 +162,7 @@ export class AzureFunctionManager {
160
162
  ],
161
163
  },
162
164
  },
163
- }, { parent: scope, ...resourceOptions });
165
+ }, { parent: functionApp, ...resourceOptions });
164
166
  return functionApp;
165
167
  }
166
168
  /**
@@ -32,6 +32,6 @@ export class AzureMonitorManager {
32
32
  return new DiagnosticSetting(`${id}-ds`, {
33
33
  ...props,
34
34
  name: scope.resourceNameFormatter.format(props.name?.toString(), scope.props.resourceNameOptions?.monitorDiagnosticSetting),
35
- }, { parent: scope, ...resourceOptions });
35
+ }, { parent: scope, ignoreChanges: ['resourceUri'], ...resourceOptions });
36
36
  }
37
37
  }
@@ -1,4 +1,4 @@
1
- import { Table, Workspace, WorkspaceSkuNameEnum } from '@pulumi/azure-native/operationalinsights/index.js';
1
+ import { Table, TablePlanEnum, Workspace, WorkspaceSkuNameEnum, } from '@pulumi/azure-native/operationalinsights/index.js';
2
2
  /**
3
3
  * Provides operations on Azure Log Analytics Workspace using Pulumi
4
4
  * - A new instance of this class is injected into {@link CommonAzureConstruct} constructor.
@@ -58,6 +58,11 @@ export class AzureOperationalInsightsManager {
58
58
  createTable(id, scope, props, resourceOptions) {
59
59
  if (!props)
60
60
  throw new Error(`Props undefined for ${id}`);
61
- return new Table(`${id}`, props, { parent: scope, ...resourceOptions });
61
+ return new Table(`${id}`, {
62
+ ...props,
63
+ plan: props.plan ?? TablePlanEnum.Analytics,
64
+ retentionInDays: props.retentionInDays ?? 30,
65
+ totalRetentionInDays: props.totalRetentionInDays ?? 30,
66
+ }, { parent: scope, ...resourceOptions });
62
67
  }
63
68
  }
@@ -1,5 +1,6 @@
1
1
  import fs from 'fs';
2
2
  import { Dashboard } from '@pulumi/azure-native/portal/index.js';
3
+ import * as pulumi from '@pulumi/pulumi';
3
4
  import { AzureDashboardRenderer } from './renderer.js';
4
5
  /**
5
6
  * Provides operations on Azure Portal Dashboards using Pulumi
@@ -32,21 +33,27 @@ export class AzurePortalManager {
32
33
  createDashBoard(id, scope, props, renderer, resourceOptions) {
33
34
  if (!props)
34
35
  throw new Error(`Props undefined for ${id}`);
35
- const resourceGroup = scope.resourceGroupManager.resolveResourceGroup(scope, props.resourceGroupName.toString() ?? scope.props.resourceGroupName, resourceOptions);
36
+ const resourceGroup = scope.resourceGroup ??
37
+ scope.resourceGroupManager.resolveResourceGroup(scope, props.resourceGroupName.toString() ?? scope.props.resourceGroupName, resourceOptions);
36
38
  const dashboardName = scope.resourceNameFormatter.format(props.dashboardName?.toString(), scope.props.resourceNameOptions?.portalDashboard);
37
39
  const dashboardRenderer = renderer ?? new AzureDashboardRenderer();
38
40
  const templateFile = dashboardRenderer.renderToFile(dashboardName, props);
39
41
  const template = fs.readFileSync(templateFile, 'utf-8');
40
- const content = Object.entries(props.variables).reduce((result, [key, value]) => result.replaceAll(`\${${key}}`, JSON.stringify(String(value)).slice(1, -1)), template);
42
+ const keys = Object.keys(props.variables);
43
+ const values = Object.values(props.variables);
44
+ const properties = pulumi.all(values).apply(resolved => {
45
+ const content = keys.reduce((result, key, i) => result.replaceAll(`\${${key}}`, JSON.stringify(String(resolved[i])).slice(1, -1)), template);
46
+ return JSON.parse(content);
47
+ });
41
48
  return new Dashboard(`${id}-dashboard`, {
42
49
  ...props,
43
50
  dashboardName: scope.resourceNameFormatter.format(props.dashboardName?.toString(), scope.props.resourceNameOptions?.portalDashboard),
44
51
  resourceGroupName: resourceGroup.name,
45
52
  location: props.location ?? resourceGroup.location,
46
- properties: JSON.parse(content),
53
+ properties,
47
54
  tags: {
48
55
  'hidden-title': `${props.location} - ${props.displayName}`,
49
56
  },
50
- }, { ...resourceOptions, ignoreChanges: ['location'] });
57
+ }, { parent: scope, ...resourceOptions, ignoreChanges: ['location'] });
51
58
  }
52
59
  }
@@ -35,9 +35,8 @@ export class AzureDashboardRenderer {
35
35
  render(params) {
36
36
  _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
37
37
  // if client is used instead of hosts
38
- let partsIndex = 0;
39
38
  let yIndex = 0;
40
- const parts = {};
39
+ const parts = [];
41
40
  for (const pane of params.panes) {
42
41
  try {
43
42
  const paneTemplate = this.getPaneId(pane.id);
@@ -91,8 +90,7 @@ export class AzureDashboardRenderer {
91
90
  const paneJSON = JSON.parse(paneContent);
92
91
  const templateParts = paneJSON.parts;
93
92
  for (const part of templateParts) {
94
- parts[`${partsIndex}`] = part;
95
- partsIndex++;
93
+ parts.push(part);
96
94
  }
97
95
  yIndex += paneTemplate.dimensions.height;
98
96
  }
@@ -104,12 +102,12 @@ export class AzureDashboardRenderer {
104
102
  }
105
103
  }
106
104
  const dashboard = {
107
- lenses: {
108
- '0': {
105
+ lenses: [
106
+ {
109
107
  order: 0,
110
108
  parts,
111
109
  },
112
- },
110
+ ],
113
111
  metadata: {
114
112
  model: {
115
113
  timeRange: {
@@ -1,4 +1,4 @@
1
- import { Database, RedisEnterprise, SkuName } from '@pulumi/azure-native/redisenterprise/index.js';
1
+ import { AccessKeysAuthentication, ClusteringPolicy, Database, DeferUpgradeSetting, EvictionPolicy, Protocol, RedisEnterprise, SkuName, } from '@pulumi/azure-native/redisenterprise/index.js';
2
2
  /**
3
3
  * Provides operations on Azure Managed Redis (Enterprise) using Pulumi
4
4
  * - A new instance of this class is injected into {@link CommonAzureConstruct} constructor.
@@ -49,6 +49,13 @@ export class AzureRedisManager {
49
49
  clusterName: cluster.name,
50
50
  resourceGroupName,
51
51
  databaseName: databaseProps?.databaseName ?? 'default',
52
+ accessKeysAuthentication: databaseProps?.accessKeysAuthentication ?? AccessKeysAuthentication.Enabled,
53
+ clientProtocol: databaseProps?.clientProtocol ?? Protocol.Encrypted,
54
+ clusteringPolicy: databaseProps?.clusteringPolicy ?? ClusteringPolicy.OSSCluster,
55
+ evictionPolicy: databaseProps?.evictionPolicy ?? EvictionPolicy.VolatileLRU,
56
+ port: databaseProps?.port ?? 10000,
57
+ persistence: databaseProps?.persistence ?? { aofEnabled: false, rdbEnabled: false },
58
+ deferUpgrade: databaseProps?.deferUpgrade ?? DeferUpgradeSetting.NotDeferred,
52
59
  }, { parent: scope, dependsOn: [cluster], ...resourceOptions });
53
60
  return { cluster, database };
54
61
  }
@@ -38,6 +38,7 @@ export class AzureStorageManager {
38
38
  .replace(/\W/g, '')
39
39
  .toLowerCase(),
40
40
  allowBlobPublicAccess: props.allowBlobPublicAccess ?? false,
41
+ isHnsEnabled: props.isHnsEnabled ?? false,
41
42
  resourceGroupName,
42
43
  sku: props.sku ?? {
43
44
  name: SkuName.Standard_LRS,
@@ -61,7 +62,7 @@ export class AzureStorageManager {
61
62
  enabled: true,
62
63
  days: 7,
63
64
  },
64
- });
65
+ }, { parent: scope, ...resourceOptions });
65
66
  return storageAccount;
66
67
  }
67
68
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gradientedge/cdk-utils-azure",
3
- "version": "2.19.0",
3
+ "version": "2.21.0",
4
4
  "description": "Azure Pulumi utilities for @gradientedge/cdk-utils",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",
@@ -17,10 +17,11 @@
17
17
  "@pulumi/archive": "0.3.7",
18
18
  "@pulumi/azure-native": "3.16.0",
19
19
  "@pulumi/azuread": "6.9.0",
20
- "@pulumi/pulumi": "3.230.0",
20
+ "@pulumi/pulumi": "3.231.0",
21
21
  "@types/lodash": "4.17.24",
22
22
  "app-root-path": "3.1.0",
23
23
  "lodash": "4.18.1",
24
+ "uuid": "13.0.0",
24
25
  "yaml": "2.8.3",
25
26
  "@gradientedge/cdk-utils-common": "2.1.0"
26
27
  },