@webda/azure 0.0.0-stage → 4.0.0-beta.14

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.
Files changed (68) hide show
  1. package/LICENSE +166 -0
  2. package/README.md +248 -2
  3. package/lib/auth.d.ts +36 -0
  4. package/lib/auth.d.ts.map +1 -0
  5. package/lib/auth.js +70 -0
  6. package/lib/auth.js.map +1 -0
  7. package/lib/deployers/arm.service.d.ts +177 -0
  8. package/lib/deployers/arm.service.d.ts.map +1 -0
  9. package/lib/deployers/arm.service.js +307 -0
  10. package/lib/deployers/arm.service.js.map +1 -0
  11. package/lib/deployers/containerapps.service.d.ts +186 -0
  12. package/lib/deployers/containerapps.service.d.ts.map +1 -0
  13. package/lib/deployers/containerapps.service.js +482 -0
  14. package/lib/deployers/containerapps.service.js.map +1 -0
  15. package/lib/deployers/functions-entrypoint.d.ts +60 -0
  16. package/lib/deployers/functions-entrypoint.d.ts.map +1 -0
  17. package/lib/deployers/functions-entrypoint.js +78 -0
  18. package/lib/deployers/functions-entrypoint.js.map +1 -0
  19. package/lib/deployers/functions.service.d.ts +96 -0
  20. package/lib/deployers/functions.service.d.ts.map +1 -0
  21. package/lib/deployers/functions.service.js +340 -0
  22. package/lib/deployers/functions.service.js.map +1 -0
  23. package/lib/deployers/functionspackager.service.d.ts +82 -0
  24. package/lib/deployers/functionspackager.service.d.ts.map +1 -0
  25. package/lib/deployers/functionspackager.service.js +157 -0
  26. package/lib/deployers/functionspackager.service.js.map +1 -0
  27. package/lib/index.d.ts +15 -0
  28. package/lib/index.d.ts.map +1 -0
  29. package/lib/index.js +18 -0
  30. package/lib/index.js.map +1 -0
  31. package/lib/services/azure-parameters.d.ts +56 -0
  32. package/lib/services/azure-parameters.d.ts.map +1 -0
  33. package/lib/services/azure-parameters.js +43 -0
  34. package/lib/services/azure-parameters.js.map +1 -0
  35. package/lib/services/blob.service.d.ts +196 -0
  36. package/lib/services/blob.service.d.ts.map +1 -0
  37. package/lib/services/blob.service.js +450 -0
  38. package/lib/services/blob.service.js.map +1 -0
  39. package/lib/services/contributors.d.ts +50 -0
  40. package/lib/services/contributors.d.ts.map +1 -0
  41. package/lib/services/contributors.js +2 -0
  42. package/lib/services/contributors.js.map +1 -0
  43. package/lib/services/cosmos.service.d.ts +253 -0
  44. package/lib/services/cosmos.service.d.ts.map +1 -0
  45. package/lib/services/cosmos.service.js +566 -0
  46. package/lib/services/cosmos.service.js.map +1 -0
  47. package/lib/services/functionserver.service.d.ts +51 -0
  48. package/lib/services/functionserver.service.d.ts.map +1 -0
  49. package/lib/services/functionserver.service.js +232 -0
  50. package/lib/services/functionserver.service.js.map +1 -0
  51. package/lib/services/keyvault.service.d.ts +106 -0
  52. package/lib/services/keyvault.service.d.ts.map +1 -0
  53. package/lib/services/keyvault.service.js +228 -0
  54. package/lib/services/keyvault.service.js.map +1 -0
  55. package/lib/services/monitorlogger.service.d.ts +117 -0
  56. package/lib/services/monitorlogger.service.d.ts.map +1 -0
  57. package/lib/services/monitorlogger.service.js +149 -0
  58. package/lib/services/monitorlogger.service.js.map +1 -0
  59. package/lib/services/servicebus.service.d.ts +224 -0
  60. package/lib/services/servicebus.service.d.ts.map +1 -0
  61. package/lib/services/servicebus.service.js +351 -0
  62. package/lib/services/servicebus.service.js.map +1 -0
  63. package/lib/template.d.ts +68 -0
  64. package/lib/template.d.ts.map +1 -0
  65. package/lib/template.js +74 -0
  66. package/lib/template.js.map +1 -0
  67. package/package.json +77 -3
  68. package/webda.module.json +1891 -0
@@ -0,0 +1,186 @@
1
+ import { Deployer, SecretString } from "@webda/core";
2
+ import { AzureTemplate } from "../template.js";
3
+ import { AzureArmDeployer, AzureArmDeployerParameters, AzureDeployResult } from "./arm.service.js";
4
+ export declare const AZURE_SECTIONS: readonly ["LogAnalytics", "ManagedEnvironment", "ContainerApp", "Jobs", "Resources"];
5
+ /** Azure Container Apps unit parameters. Image tags and Azure resource tags are separate. */
6
+ export declare class AzureContainerAppsDeployerParameters extends AzureArmDeployerParameters {
7
+ /**
8
+ * Registry
9
+ */
10
+ registry?: string;
11
+ /**
12
+ * Registry auth
13
+ */
14
+ registryAuth: "aad" | "identity" | "none";
15
+ /**
16
+ * Container app
17
+ */
18
+ containerApp: {
19
+ name?: string;
20
+ cpu?: number;
21
+ memory?: string;
22
+ minReplicas?: number;
23
+ maxReplicas?: number;
24
+ ingress?: false | {
25
+ external?: boolean;
26
+ targetPort?: number;
27
+ transport?: string;
28
+ };
29
+ env?: Record<string, string | {
30
+ secretRef: string;
31
+ }>;
32
+ probes?: Record<string, any>[];
33
+ scaleRules?: Record<string, any>[];
34
+ };
35
+ /**
36
+ * Environment
37
+ */
38
+ environment: {
39
+ name?: string;
40
+ id?: string;
41
+ };
42
+ /**
43
+ * Log analytics
44
+ */
45
+ logAnalytics: false | {
46
+ name?: string;
47
+ retentionInDays?: number;
48
+ };
49
+ /**
50
+ * Secrets
51
+ */
52
+ secrets: Record<string, string | SecretString | {
53
+ keyVaultUrl: string;
54
+ identity: string;
55
+ }>;
56
+ /**
57
+ * Custom domains
58
+ */
59
+ customDomains: {
60
+ name: string;
61
+ certificateId?: string;
62
+ bindingType?: string;
63
+ validationMethod?: "CNAME" | "HTTP";
64
+ }[];
65
+ /**
66
+ * Crons
67
+ */
68
+ crons: boolean;
69
+ }
70
+ /** Build an OCI image and deploy its immutable digest to Azure Container Apps.
71
+ * @WebdaModda
72
+ */
73
+ export declare class AzureContainerAppsDeployer extends AzureArmDeployer<AzureContainerAppsDeployerParameters> implements Deployer {
74
+ /**
75
+ * Parameters
76
+ */
77
+ static Parameters: typeof AzureContainerAppsDeployerParameters;
78
+ /**
79
+ * Image
80
+ */
81
+ protected image: string;
82
+ /**
83
+ * Write the generated ARM template for review.
84
+ * @param output - Optional template output path
85
+ * @returns Generated ARM template
86
+ */
87
+ generate(output?: string): Promise<AzureTemplate>;
88
+ /**
89
+ * Perform get resolved parameters.
90
+ * @override
91
+ */
92
+ getResolvedParameters(): AzureContainerAppsDeployerParameters;
93
+ /**
94
+ * Return the application resource identifier.
95
+ * @returns The app resource id result
96
+ */
97
+ getAppResourceId(): string;
98
+ /**
99
+ * Return the managed identity resource identifier.
100
+ * @returns The identity resource id result
101
+ */
102
+ protected getIdentityResourceId(): string;
103
+ /**
104
+ * Return the ARM expression for the application principal.
105
+ * @returns The app principal id result
106
+ */
107
+ getAppPrincipalId(): string;
108
+ /**
109
+ * Return the managed environment resource identifier.
110
+ * @returns The environment id result
111
+ */
112
+ protected environmentId(): string;
113
+ /**
114
+ * Describe the application managed identity.
115
+ * @returns The identity result
116
+ */
117
+ protected identity(): {
118
+ type: string;
119
+ userAssignedIdentities: {
120
+ [x: string]: {};
121
+ };
122
+ };
123
+ /**
124
+ * Build the runtime environment from contributors and explicit overrides.
125
+ * @returns The env result
126
+ */
127
+ protected env(): {
128
+ name: string;
129
+ value: string;
130
+ }[];
131
+ /**
132
+ * Convert configured secrets to secure parameters or Key Vault references.
133
+ * @returns The secrets result
134
+ */
135
+ protected secrets(): ({
136
+ keyVaultUrl: string;
137
+ identity: string;
138
+ name: string;
139
+ } | {
140
+ name: string;
141
+ value: string;
142
+ })[];
143
+ /**
144
+ * Configure managed identity image pulls.
145
+ * @returns The registries result
146
+ */
147
+ protected registries(): {
148
+ server: string;
149
+ identity: string;
150
+ }[];
151
+ /**
152
+ * Generate the deployment template without contacting Azure.
153
+ * @param image - Immutable container image reference
154
+ * @returns ARM template without secret values
155
+ */
156
+ generateTemplate(image?: string): AzureTemplate;
157
+ /**
158
+ * Add the optional Log Analytics workspace.
159
+ */
160
+ LogAnalytics(): void;
161
+ /**
162
+ * Add the Container Apps managed environment.
163
+ */
164
+ ManagedEnvironment(): void;
165
+ /**
166
+ * Add the application and its scaling and ingress settings.
167
+ */
168
+ ContainerApp(): void;
169
+ /** Issue managed certificates after hostname registration, then bind them in a nested deployment. */
170
+ ManagedCertificates(): void;
171
+ /**
172
+ * Export declared crons as scheduled jobs, each running `cron run --id` on its operation.
173
+ */
174
+ Jobs(): void;
175
+ /**
176
+ * Publish the OCI image using the selected registry authentication.
177
+ * @returns The push result
178
+ */
179
+ push(): Promise<string>;
180
+ /**
181
+ * Publish and deploy the application, returning its endpoints.
182
+ * @returns The deploy result
183
+ */
184
+ deploy(): Promise<AzureDeployResult>;
185
+ }
186
+ //# sourceMappingURL=containerapps.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"containerapps.service.d.ts","sources":["../../src/deployers/containerapps.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,482 @@
1
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
2
+ var useValue = arguments.length > 2;
3
+ for (var i = 0; i < initializers.length; i++) {
4
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
5
+ }
6
+ return useValue ? value : void 0;
7
+ };
8
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
9
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
10
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
11
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
12
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
13
+ var _, done = false;
14
+ for (var i = decorators.length - 1; i >= 0; i--) {
15
+ var context = {};
16
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
17
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
18
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
19
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
20
+ if (kind === "accessor") {
21
+ if (result === void 0) continue;
22
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
23
+ if (_ = accept(result.get)) descriptor.get = _;
24
+ if (_ = accept(result.set)) descriptor.set = _;
25
+ if (_ = accept(result.init)) initializers.unshift(_);
26
+ }
27
+ else if (_ = accept(result)) {
28
+ if (kind === "field") initializers.unshift(_);
29
+ else descriptor[key] = _;
30
+ }
31
+ }
32
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
33
+ done = true;
34
+ };
35
+ import { Command, CronService, getDeploymentVariables, SecretString, WebdaError } from "@webda/core";
36
+ import { formatImageReference, parseImageReference } from "@webda/oci";
37
+ import { AzureAuth } from "../auth.js";
38
+ import { armValue, containerAppsSchedule, resourceId, roleAssignmentId, createAzureTemplate } from "../template.js";
39
+ import { createHash } from "node:crypto";
40
+ import { AzureArmDeployer, AzureArmDeployerParameters } from "./arm.service.js";
41
+ export const AZURE_SECTIONS = ["LogAnalytics", "ManagedEnvironment", "ContainerApp", "Jobs", "Resources"];
42
+ /** Azure Container Apps unit parameters. Image tags and Azure resource tags are separate. */
43
+ export class AzureContainerAppsDeployerParameters extends AzureArmDeployerParameters {
44
+ constructor() {
45
+ super(...arguments);
46
+ /**
47
+ * Registry auth
48
+ */
49
+ this.registryAuth = "aad";
50
+ /**
51
+ * Container app
52
+ */
53
+ this.containerApp = {};
54
+ /**
55
+ * Environment
56
+ */
57
+ this.environment = {};
58
+ /**
59
+ * Log analytics
60
+ */
61
+ this.logAnalytics = {};
62
+ /**
63
+ * Secrets
64
+ */
65
+ this.secrets = {};
66
+ /**
67
+ * Custom domains
68
+ */
69
+ this.customDomains = [];
70
+ /**
71
+ * Crons
72
+ */
73
+ this.crons = true;
74
+ }
75
+ }
76
+ /** Build an OCI image and deploy its immutable digest to Azure Container Apps.
77
+ * @WebdaModda
78
+ */
79
+ let AzureContainerAppsDeployer = (() => {
80
+ var _a;
81
+ let _classSuper = AzureArmDeployer;
82
+ let _instanceExtraInitializers = [];
83
+ let _generate_decorators;
84
+ let _push_decorators;
85
+ let _deploy_decorators;
86
+ return _a = class AzureContainerAppsDeployer extends _classSuper {
87
+ constructor() {
88
+ super(...arguments);
89
+ /**
90
+ * Image
91
+ */
92
+ this.image = (__runInitializers(this, _instanceExtraInitializers), "");
93
+ }
94
+ /**
95
+ * Write the generated ARM template for review.
96
+ * @param output - Optional template output path
97
+ * @returns Generated ARM template
98
+ */
99
+ async generate(output) {
100
+ return super.generate(output);
101
+ }
102
+ /**
103
+ * Perform get resolved parameters.
104
+ * @override
105
+ */
106
+ getResolvedParameters() {
107
+ var _b, _c;
108
+ const p = super.getResolvedParameters();
109
+ const name = this.getName()
110
+ .toLowerCase()
111
+ .replace(/[^a-z0-9-]/g, "-")
112
+ .replace(/^-+|-+$/g, "")
113
+ .slice(0, 32);
114
+ (_b = p.containerApp).name ?? (_b.name = name);
115
+ (_c = p.environment).name ?? (_c.name = p.environment.id && !p.environment.id.startsWith("[")
116
+ ? p.environment.id.split("/").slice(-1)[0]
117
+ : `${p.resourceGroup}-env`);
118
+ if (!p.image && p.registry) {
119
+ const packageName = getDeploymentVariables(this).package.name?.replace(/^@[^/]+\//, "") ?? name;
120
+ p.image = `${p.registry}.azurecr.io/${packageName.toLowerCase()}`;
121
+ }
122
+ if (!p.image)
123
+ throw new WebdaError.BadRequest("Container Apps requires image or registry");
124
+ if (!/^[a-z][a-z0-9-]{0,30}[a-z0-9]$/.test(p.containerApp.name))
125
+ throw new WebdaError.BadRequest("Invalid Container App name (2-32 lowercase letters, numbers and hyphens)");
126
+ return p;
127
+ }
128
+ /**
129
+ * Return the application resource identifier.
130
+ * @returns The app resource id result
131
+ */
132
+ getAppResourceId() {
133
+ return resourceId("Microsoft.App/containerApps", this.resources.containerApp.name);
134
+ }
135
+ /**
136
+ * Return the managed identity resource identifier.
137
+ * @returns The identity resource id result
138
+ */
139
+ getIdentityResourceId() {
140
+ return resourceId("Microsoft.ManagedIdentity/userAssignedIdentities", `${this.resources.containerApp.name}-identity`);
141
+ }
142
+ /**
143
+ * Return the ARM expression for the application principal.
144
+ * @returns The app principal id result
145
+ */
146
+ getAppPrincipalId() {
147
+ return `[reference(${armValue(this.getIdentityResourceId())}, '2023-01-31').principalId]`;
148
+ }
149
+ /**
150
+ * Return the managed environment resource identifier.
151
+ * @returns The environment id result
152
+ */
153
+ environmentId() {
154
+ return (this.resources.environment.id ?? resourceId("Microsoft.App/managedEnvironments", this.resources.environment.name));
155
+ }
156
+ /**
157
+ * Describe the application managed identity.
158
+ * @returns The identity result
159
+ */
160
+ identity() {
161
+ return { type: "SystemAssigned, UserAssigned", userAssignedIdentities: { [this.getIdentityResourceId()]: {} } };
162
+ }
163
+ /**
164
+ * Build the runtime environment from contributors and explicit overrides.
165
+ * @returns The env result
166
+ */
167
+ env() {
168
+ return Object.entries({
169
+ ...this.contributedEnv,
170
+ AZURE_CLIENT_ID: `[reference(${armValue(this.getIdentityResourceId())}, '2023-01-31').clientId]`,
171
+ ...this.resources.containerApp.env
172
+ }).map(([name, value]) => ({ name, ...(typeof value === "string" ? { value } : value) }));
173
+ }
174
+ /**
175
+ * Convert configured secrets to secure parameters or Key Vault references.
176
+ * @returns The secrets result
177
+ */
178
+ secrets() {
179
+ return Object.entries(this.resources.secrets).map(([name, value]) => ({
180
+ name,
181
+ ...(typeof value === "object" && !(value instanceof SecretString)
182
+ ? value
183
+ : { value: this.secureParameter(value) })
184
+ }));
185
+ }
186
+ /**
187
+ * Configure managed identity image pulls.
188
+ * @returns The registries result
189
+ */
190
+ registries() {
191
+ if (this.resources.registryAuth === "none")
192
+ return [];
193
+ const target = parseImageReference(this.resources.image);
194
+ return [{ server: target.registry, identity: this.getIdentityResourceId() }];
195
+ }
196
+ /**
197
+ * Generate the deployment template without contacting Azure.
198
+ * @param image - Immutable container image reference
199
+ * @returns ARM template without secret values
200
+ */
201
+ generateTemplate(image) {
202
+ this.prepare();
203
+ const target = parseImageReference(this.resources.image);
204
+ this.image = image ?? formatImageReference({ ...target, tag: target.digest ? undefined : target.tag });
205
+ this.addResource({
206
+ type: "Microsoft.ManagedIdentity/userAssignedIdentities",
207
+ apiVersion: "2023-01-31",
208
+ name: `${this.resources.containerApp.name}-identity`,
209
+ location: this.resources.location,
210
+ tags: this.getDefaultTags()
211
+ });
212
+ this.Resources();
213
+ if (!this.resources.environment.id) {
214
+ if (this.resources.logAnalytics !== false)
215
+ this.LogAnalytics();
216
+ this.ManagedEnvironment();
217
+ }
218
+ if (this.resources.registryAuth !== "none") {
219
+ const registry = this.resources.registry ?? target.registry.split(".")[0];
220
+ this.roles.push({
221
+ scope: resourceId("Microsoft.ContainerRegistry/registries", registry),
222
+ roleDefinitionId: `/subscriptions/${this.resources.subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/7f951dda-4ed3-4680-a7ca-43fe172d538d`
223
+ });
224
+ }
225
+ this.grantRoles();
226
+ this.ContainerApp();
227
+ this.ManagedCertificates();
228
+ if (this.resources.crons)
229
+ this.Jobs();
230
+ this.template.outputs.fqdn = {
231
+ type: "string",
232
+ value: `[reference(${armValue(this.getAppResourceId())}, '2024-03-01').configuration.ingress.fqdn]`
233
+ };
234
+ this.template.outputs.latestRevisionName = {
235
+ type: "string",
236
+ value: `[reference(${armValue(this.getAppResourceId())}, '2024-03-01').latestRevisionName]`
237
+ };
238
+ return this.template;
239
+ }
240
+ /**
241
+ * Add the optional Log Analytics workspace.
242
+ */
243
+ LogAnalytics() {
244
+ const p = this.resources, log = p.logAnalytics;
245
+ if (log === false)
246
+ return;
247
+ this.addResource({
248
+ type: "Microsoft.OperationalInsights/workspaces",
249
+ apiVersion: "2023-09-01",
250
+ name: log.name ?? `${p.environment.name}-logs`,
251
+ location: p.location,
252
+ tags: this.getDefaultTags(),
253
+ properties: { sku: { name: "PerGB2018" }, retentionInDays: log.retentionInDays ?? 30 }
254
+ });
255
+ }
256
+ /**
257
+ * Add the Container Apps managed environment.
258
+ */
259
+ ManagedEnvironment() {
260
+ const p = this.resources, log = p.logAnalytics;
261
+ const workspace = log === false
262
+ ? undefined
263
+ : resourceId("Microsoft.OperationalInsights/workspaces", log.name ?? `${p.environment.name}-logs`);
264
+ this.addResource({
265
+ type: "Microsoft.App/managedEnvironments",
266
+ apiVersion: "2024-03-01",
267
+ name: p.environment.name,
268
+ location: p.location,
269
+ tags: this.getDefaultTags(),
270
+ dependsOn: workspace ? [workspace] : [],
271
+ properties: workspace
272
+ ? {
273
+ appLogsConfiguration: {
274
+ destination: "log-analytics",
275
+ logAnalyticsConfiguration: {
276
+ customerId: `[reference(${armValue(workspace)}, '2023-09-01').customerId]`,
277
+ sharedKey: `[listKeys(${armValue(workspace)}, '2023-09-01').primarySharedKey]`
278
+ }
279
+ }
280
+ }
281
+ : {}
282
+ });
283
+ }
284
+ /**
285
+ * Add the application and its scaling and ingress settings.
286
+ */
287
+ ContainerApp() {
288
+ const p = this.resources, app = p.containerApp;
289
+ const roleIds = this.template.resources
290
+ .filter(resource => resource.type === "Microsoft.Authorization/roleAssignments")
291
+ .map(roleAssignmentId);
292
+ this.addResource({
293
+ type: "Microsoft.App/containerApps",
294
+ apiVersion: "2024-03-01",
295
+ name: app.name,
296
+ location: p.location,
297
+ tags: this.getDefaultTags(),
298
+ identity: this.identity(),
299
+ dependsOn: [this.getIdentityResourceId(), ...(!p.environment.id ? [this.environmentId()] : []), ...roleIds],
300
+ properties: {
301
+ managedEnvironmentId: this.environmentId(),
302
+ configuration: {
303
+ activeRevisionsMode: "Single",
304
+ ingress: app.ingress === false
305
+ ? undefined
306
+ : {
307
+ external: true,
308
+ targetPort: 18080,
309
+ transport: "auto",
310
+ ...app.ingress,
311
+ customDomains: p.customDomains.map(domain => ({
312
+ name: domain.name,
313
+ certificateId: domain.certificateId,
314
+ bindingType: domain.certificateId ? (domain.bindingType ?? "SniEnabled") : "Disabled"
315
+ }))
316
+ },
317
+ secrets: this.secrets(),
318
+ registries: this.registries()
319
+ },
320
+ template: {
321
+ containers: [
322
+ {
323
+ name: "webda",
324
+ image: this.image,
325
+ resources: { cpu: app.cpu ?? 0.5, memory: app.memory ?? "1Gi" },
326
+ env: this.env(),
327
+ probes: app.probes
328
+ }
329
+ ],
330
+ scale: {
331
+ minReplicas: p.customDomains.some(domain => !domain.certificateId)
332
+ ? Math.max(1, app.minReplicas ?? 0)
333
+ : (app.minReplicas ?? 0),
334
+ maxReplicas: app.maxReplicas ?? 10,
335
+ rules: app.scaleRules
336
+ }
337
+ }
338
+ }
339
+ });
340
+ }
341
+ /** Issue managed certificates after hostname registration, then bind them in a nested deployment. */
342
+ ManagedCertificates() {
343
+ const managed = this.resources.customDomains.filter(domain => !domain.certificateId);
344
+ if (!managed.length)
345
+ return;
346
+ if (this.resources.containerApp.ingress === false || this.resources.containerApp.ingress?.external === false)
347
+ throw new WebdaError.BadRequest("Managed certificates require public HTTP ingress");
348
+ const app = this.template.resources.find(resource => resource.type === "Microsoft.App/containerApps");
349
+ const certificates = new Map();
350
+ for (const domain of managed) {
351
+ if (!/^[a-zA-Z0-9.-]+$/.test(domain.name))
352
+ throw new WebdaError.BadRequest("Invalid custom domain name");
353
+ const name = `${this.resources.containerApp.name}-${createHash("sha256").update(domain.name).digest("hex").slice(0, 8)}`;
354
+ const id = resourceId("Microsoft.App/managedEnvironments/managedCertificates", this.resources.environment.name, name);
355
+ certificates.set(domain.name, id);
356
+ this.addResource({
357
+ type: "Microsoft.App/managedEnvironments/managedCertificates",
358
+ apiVersion: "2024-03-01",
359
+ name: `${this.resources.environment.name}/${name}`,
360
+ location: this.resources.location,
361
+ dependsOn: [this.getAppResourceId()],
362
+ properties: { subjectName: domain.name, domainControlValidation: domain.validationMethod ?? "CNAME" }
363
+ });
364
+ }
365
+ const boundApp = structuredClone(app);
366
+ delete boundApp.dependsOn;
367
+ boundApp.properties.configuration.ingress.customDomains = this.resources.customDomains.map(domain => ({
368
+ name: domain.name,
369
+ certificateId: domain.certificateId ?? certificates.get(domain.name),
370
+ bindingType: domain.bindingType ?? "SniEnabled"
371
+ }));
372
+ const nested = createAzureTemplate();
373
+ nested.parameters = structuredClone(this.template.parameters);
374
+ nested.resources = [boundApp];
375
+ this.addResource({
376
+ type: "Microsoft.Resources/deployments",
377
+ apiVersion: "2022-09-01",
378
+ name: `${this.resources.containerApp.name}-domains`,
379
+ dependsOn: [...certificates.values()],
380
+ properties: {
381
+ mode: "Incremental",
382
+ expressionEvaluationOptions: { scope: "inner" },
383
+ template: nested,
384
+ parameters: Object.fromEntries(Object.keys(nested.parameters).map(name => [name, { value: `[parameters('${name}')]` }]))
385
+ }
386
+ });
387
+ }
388
+ /**
389
+ * Export declared crons as scheduled jobs, each running `cron run --id` on its operation.
390
+ */
391
+ Jobs() {
392
+ for (const cron of CronService.resolveCrons()) {
393
+ const id = CronService.getExportId(cron), p = this.resources, app = p.containerApp;
394
+ const name = `${app.name.slice(0, 15)}-${id.slice(0, 16)}`.toLowerCase();
395
+ this.addResource({
396
+ type: "Microsoft.App/jobs",
397
+ apiVersion: "2024-03-01",
398
+ name,
399
+ location: p.location,
400
+ tags: this.getDefaultTags(),
401
+ identity: this.identity(),
402
+ dependsOn: [this.getAppResourceId()],
403
+ properties: {
404
+ environmentId: this.environmentId(),
405
+ configuration: {
406
+ triggerType: "Schedule",
407
+ replicaTimeout: 1800,
408
+ replicaRetryLimit: 3,
409
+ scheduleTriggerConfig: {
410
+ cronExpression: containerAppsSchedule(cron.cron),
411
+ parallelism: 1,
412
+ replicaCompletionCount: 1
413
+ },
414
+ secrets: this.secrets(),
415
+ registries: this.registries()
416
+ },
417
+ template: {
418
+ containers: [
419
+ {
420
+ name: "webda",
421
+ image: this.image,
422
+ args: ["cron", "run", "--id", id],
423
+ env: this.env(),
424
+ resources: { cpu: app.cpu ?? 0.5, memory: app.memory ?? "1Gi" }
425
+ }
426
+ ]
427
+ }
428
+ }
429
+ });
430
+ }
431
+ }
432
+ /**
433
+ * Publish the OCI image using the selected registry authentication.
434
+ * @returns The push result
435
+ */
436
+ async push() {
437
+ const p = this.getResolvedParameters();
438
+ if (p.registryAuth === "aad") {
439
+ const server = parseImageReference(p.image).registry;
440
+ const token = await new AzureAuth(p).getAcrRefreshToken(server);
441
+ this.parameters.credentials[server] = { identityToken: new SecretString(token, "azure") };
442
+ }
443
+ return super.push();
444
+ }
445
+ /**
446
+ * Publish and deploy the application, returning its endpoints.
447
+ * @returns The deploy result
448
+ */
449
+ async deploy() {
450
+ const digest = await this.push();
451
+ const p = this.getResolvedParameters(), target = parseImageReference(p.image);
452
+ const image = formatImageReference({ ...target, tag: undefined, digest });
453
+ this.generateTemplate(image);
454
+ this.writeTemplate();
455
+ const outputs = await this.sendTemplate();
456
+ return (this.result = {
457
+ image,
458
+ digest,
459
+ fqdn: outputs.fqdn?.value,
460
+ revision: outputs.latestRevisionName?.value,
461
+ outputs
462
+ });
463
+ }
464
+ },
465
+ (() => {
466
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
467
+ _generate_decorators = [Command("azure template", { description: "Generate the Container Apps ARM template" })];
468
+ _push_decorators = [Command("container push", { description: "Build and push the image using Azure registry authentication" })];
469
+ _deploy_decorators = [Command("deploy", { description: "Build, publish and deploy the application to Azure Container Apps" })];
470
+ __esDecorate(_a, null, _generate_decorators, { kind: "method", name: "generate", static: false, private: false, access: { has: obj => "generate" in obj, get: obj => obj.generate }, metadata: _metadata }, null, _instanceExtraInitializers);
471
+ __esDecorate(_a, null, _push_decorators, { kind: "method", name: "push", static: false, private: false, access: { has: obj => "push" in obj, get: obj => obj.push }, metadata: _metadata }, null, _instanceExtraInitializers);
472
+ __esDecorate(_a, null, _deploy_decorators, { kind: "method", name: "deploy", static: false, private: false, access: { has: obj => "deploy" in obj, get: obj => obj.deploy }, metadata: _metadata }, null, _instanceExtraInitializers);
473
+ if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
474
+ })(),
475
+ /**
476
+ * Parameters
477
+ */
478
+ _a.Parameters = AzureContainerAppsDeployerParameters,
479
+ _a;
480
+ })();
481
+ export { AzureContainerAppsDeployer };
482
+ //# sourceMappingURL=containerapps.service.js.map