@pagopa/opex-dashboard 0.0.2 → 0.2.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/README.md CHANGED
@@ -60,12 +60,76 @@ npx @pagopa/opex-dashboard generate -t azure-dashboard -c config.yaml --package
60
60
 
61
61
  ### 3. Deploy with Terraform
62
62
 
63
+ The deployment process depends on the configuration mode you chose:
64
+
65
+ #### Multi-Environment Mode
66
+
67
+ When using the multi-environment configuration (with `environments` section),
68
+ the generated package includes separate subdirectories for each environment:
69
+
63
70
  ```bash
64
71
  cd output/azure-dashboard
72
+ # Deploy to dev
65
73
  terraform init -backend-config=env/dev/backend.tfvars
66
74
  terraform apply -var-file=env/dev/terraform.tfvars
75
+
76
+ # Deploy to prod
77
+ terraform init -backend-config=env/prod/backend.tfvars
78
+ terraform apply -var-file=env/prod/terraform.tfvars
67
79
  ```
68
80
 
81
+ **Generated structure:**
82
+
83
+ ```
84
+ output/azure-dashboard/
85
+ ├── main.tf
86
+ ├── variables.tf
87
+ ├── dashboard.tf
88
+ └── env/
89
+ ├── dev/
90
+ │ ├── backend.tfvars
91
+ │ └── terraform.tfvars
92
+ ├── uat/
93
+ │ ├── backend.tfvars
94
+ │ └── terraform.tfvars
95
+ └── prod/
96
+ ├── backend.tfvars
97
+ └── terraform.tfvars
98
+ ```
99
+
100
+ #### Flat Mode
101
+
102
+ When using flat configuration (with `prefix` and `env_short` directly under
103
+ `terraform`), all files are generated in the root directory:
104
+
105
+ ```bash
106
+ cd output/azure-dashboard
107
+ terraform init -backend-config=backend.tfvars
108
+ terraform apply -var-file=terraform.tfvars
109
+ ```
110
+
111
+ **Generated structure:**
112
+
113
+ ```
114
+ output/azure-dashboard/
115
+ ├── main.tf
116
+ ├── variables.tf
117
+ ├── dashboard.tf
118
+ ├── backend.tfvars
119
+ └── terraform.tfvars
120
+ ```
121
+
122
+ **Use flat mode when:**
123
+
124
+ - Deploying to a single environment
125
+ - Managing infrastructure for a specific environment in a separate repository
126
+ - You don't need environment-specific subdirectories
127
+
128
+ **Use multi-environment mode when:**
129
+
130
+ - Managing multiple environments (dev/uat/prod) in the same repository
131
+ - You want organized environment-specific configurations in subdirectories
132
+
69
133
  ## Dashboard Components
70
134
 
71
135
  For each endpoint in the OpenAPI spec, the dashboard includes:
@@ -129,6 +193,7 @@ action_groups: string[] # Array of Azure Action Group IDs
129
193
 
130
194
  # Optional fields (with defaults)
131
195
  resource_type: app-gateway | api-management # Default: app-gateway
196
+ resource_group: string # Default: dashboards (Azure resource group for dashboard and alerts)
132
197
  timespan: string # Default: 5m
133
198
  evaluation_frequency: integer # Default: 10 (minutes)
134
199
  evaluation_time_window: integer # Default: 20 (minutes)
@@ -137,7 +202,10 @@ availability_threshold`: float # Default: 0.99 (99%)
137
202
  response_time_threshold: float # Default: 1.0 second
138
203
 
139
204
  # When generating Terraform packages (using `--package` option),
140
- # you can optionally configure environment-specific settings
205
+ # you can optionally configure environment-specific settings.
206
+ # Two configuration modes are supported:
207
+
208
+ # 1. Multi-environment mode (with subdirectories):
141
209
  terraform:
142
210
  environments:
143
211
  dev:
@@ -150,6 +218,16 @@ terraform:
150
218
  key: string
151
219
  uat: # Similar to dev
152
220
  prod: # Similar to dev
221
+
222
+ # 2. Flat mode (single environment, no subdirectories):
223
+ terraform:
224
+ prefix: string # Max 6 chars (required)
225
+ env_short: string # Max 1 char: 'd', 'u', 'p' (required)
226
+ backend: # Optional backend state configuration
227
+ resource_group_name: string
228
+ storage_account_name: string
229
+ container_name: string
230
+ key: string
153
231
  ```
154
232
 
155
233
  See [`examples/`](./examples) directory for complete configuration samples.
package/bin/index.js CHANGED
@@ -759,6 +759,7 @@ var AzDashboardRawBuilder = class extends Builder {
759
759
  location: options.location,
760
760
  name: options.name,
761
761
  queries: options.queries,
762
+ resource_group: options.resourceGroup,
762
763
  resource_type: options.resourceType,
763
764
  response_time_threshold: options.responseTimeThreshold,
764
765
  time_window: options.evaluationTimeWindow,
@@ -792,6 +793,19 @@ var AzDashboardRawBuilder = class extends Builder {
792
793
  import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
793
794
  import * as path3 from "path";
794
795
 
796
+ // src/core/config/defaults.ts
797
+ var DEFAULT_TIMESPAN = "5m";
798
+ var DEFAULT_RESOURCE_GROUP = "dashboards";
799
+ var DEFAULTS = {
800
+ availability_threshold: DEFAULT_AVAILABILITY_THRESHOLD,
801
+ evaluation_frequency: EVALUATION_FREQUENCY_MINUTES,
802
+ evaluation_time_window: TIME_WINDOW_MINUTES,
803
+ event_occurrences: EVENT_OCCURRENCES,
804
+ resource_group: DEFAULT_RESOURCE_GROUP,
805
+ response_time_threshold: DEFAULT_RESPONSE_TIME_THRESHOLD,
806
+ timespan: DEFAULT_TIMESPAN
807
+ };
808
+
795
809
  // src/builders/azure-dashboard/packager.ts
796
810
  import { mkdir, writeFile } from "fs/promises";
797
811
  import * as path2 from "path";
@@ -874,7 +888,28 @@ async function generateTerraformAssets(outputPath, terraformConfig) {
874
888
  "utf-8"
875
889
  )
876
890
  ]);
877
- if (terraformConfig?.environments) {
891
+ if (terraformConfig && "prefix" in terraformConfig) {
892
+ const backendTfvarsContent = generateBackendTfvars(
893
+ terraformConfig.backend
894
+ );
895
+ const terraformTfvarsContent = generateTerraformTfvars({
896
+ backend: terraformConfig.backend,
897
+ env_short: terraformConfig.env_short,
898
+ prefix: terraformConfig.prefix
899
+ });
900
+ await Promise.all([
901
+ writeFile(
902
+ path2.join(outputPath, "backend.tfvars"),
903
+ backendTfvarsContent,
904
+ "utf-8"
905
+ ),
906
+ writeFile(
907
+ path2.join(outputPath, "terraform.tfvars"),
908
+ terraformTfvarsContent,
909
+ "utf-8"
910
+ )
911
+ ]);
912
+ } else if (terraformConfig && "environments" in terraformConfig) {
878
913
  const envPromises = [];
879
914
  for (const [env, envConfig] of Object.entries(
880
915
  terraformConfig.environments
@@ -930,7 +965,7 @@ locals {
930
965
  }
931
966
 
932
967
  data "azurerm_resource_group" "this" {
933
- name = "dashboards"
968
+ name = "${context.resource_group}"
934
969
  }
935
970
 
936
971
  resource "azurerm_portal_dashboard" "this" {
@@ -1045,6 +1080,7 @@ var AzDashboardBuilder = class extends Builder {
1045
1080
  location: options.location,
1046
1081
  name: options.name.replace(/ /g, "_"),
1047
1082
  // Replace spaces with underscores for Terraform compatibility
1083
+ resource_group: options.resourceGroup ?? DEFAULTS.resource_group,
1048
1084
  resource_type: options.resourceType,
1049
1085
  time_window: options.evaluationTimeWindow,
1050
1086
  timespan: options.timespan
@@ -1100,6 +1136,7 @@ async function createAzureRawBuilder(params) {
1100
1136
  name: params.name,
1101
1137
  oa3Spec,
1102
1138
  queries: params.queries,
1139
+ resourceGroup: params.resource_group,
1103
1140
  resources: params.resources,
1104
1141
  resourceType: params.resource_type,
1105
1142
  responseTimeThreshold: params.response_time_threshold,
@@ -1117,6 +1154,7 @@ async function createAzureTerraformBuilder(params) {
1117
1154
  eventOccurrences: params.event_occurrences,
1118
1155
  location: params.location,
1119
1156
  name: params.name,
1157
+ resourceGroup: params.resource_group,
1120
1158
  resourceType: params.resource_type,
1121
1159
  terraformConfig: params.terraform,
1122
1160
  timespan: params.timespan
@@ -1152,17 +1190,6 @@ var QueryConfigSchema = z3.object({
1152
1190
  status_code_categories: z3.array(z3.string()).default(["1XX", "2XX", "3XX", "4XX", "5XX"]).describe("HTTP status code categories for response codes queries")
1153
1191
  });
1154
1192
 
1155
- // src/core/config/defaults.ts
1156
- var DEFAULT_TIMESPAN = "5m";
1157
- var DEFAULTS = {
1158
- availability_threshold: DEFAULT_AVAILABILITY_THRESHOLD,
1159
- evaluation_frequency: EVALUATION_FREQUENCY_MINUTES,
1160
- evaluation_time_window: TIME_WINDOW_MINUTES,
1161
- event_occurrences: EVENT_OCCURRENCES,
1162
- response_time_threshold: DEFAULT_RESPONSE_TIME_THRESHOLD,
1163
- timespan: DEFAULT_TIMESPAN
1164
- };
1165
-
1166
1193
  // src/core/config/config.schema.ts
1167
1194
  var EndpointOverrideSchema = EndpointOverridePropertiesSchema.extend({
1168
1195
  availability_evaluation_frequency: z4.number().optional().describe(
@@ -1210,13 +1237,17 @@ var EnvironmentConfigSchema = z4.object({
1210
1237
  env_short: z4.string().max(1).describe("Environment short name (1 char: 'd'=dev, 'u'=uat, 'p'=prod)"),
1211
1238
  prefix: z4.string().max(6).describe("Project prefix (max 6 chars, e.g., 'io', 'pagopa')")
1212
1239
  });
1213
- var TerraformConfigSchema = z4.object({
1240
+ var TerraformEnvironmentsConfigSchema = z4.object({
1214
1241
  environments: z4.object({
1215
1242
  dev: EnvironmentConfigSchema.optional(),
1216
1243
  prod: EnvironmentConfigSchema.optional(),
1217
1244
  uat: EnvironmentConfigSchema.optional()
1218
- }).optional().describe("Environment-specific configurations for dev/uat/prod")
1219
- });
1245
+ }).describe("Environment-specific configurations for dev/uat/prod")
1246
+ }).strict();
1247
+ var TerraformConfigSchema = z4.union([
1248
+ EnvironmentConfigSchema.strict(),
1249
+ TerraformEnvironmentsConfigSchema
1250
+ ]);
1220
1251
  var ConfigSchema = z4.object({
1221
1252
  action_groups: z4.array(z4.string()).describe(
1222
1253
  "Array of Azure Action Group resource IDs for alarm notifications"
@@ -1245,6 +1276,9 @@ var ConfigSchema = z4.object({
1245
1276
  queries: QueryConfigSchema.optional().describe(
1246
1277
  "Optional global query configuration overrides"
1247
1278
  ),
1279
+ resource_group: z4.string().optional().default(DEFAULTS.resource_group).describe(
1280
+ "Azure resource group name where dashboard and alerts will be created. Default: dashboards"
1281
+ ),
1248
1282
  resource_type: z4.enum(["app-gateway", "api-management"]).optional().default("app-gateway").describe(
1249
1283
  "Type of Azure resource to monitor: app-gateway (Application Gateway) or api-management (API Management). Default: app-gateway"
1250
1284
  ),
@@ -1416,6 +1450,7 @@ async function generateHandler(options) {
1416
1450
  name: config.name,
1417
1451
  queries: config.queries || config.overrides?.queries,
1418
1452
  resolver,
1453
+ resource_group: config.resource_group,
1419
1454
  resource_type: config.resource_type,
1420
1455
  resources: [config.data_source],
1421
1456
  response_time_threshold: config.response_time_threshold,
@@ -1447,5 +1482,5 @@ async function generateHandler(options) {
1447
1482
  // src/cli/index.ts
1448
1483
  var program = new Command2();
1449
1484
  program.name("opex_dashboard").description("Generate operational dashboards from OpenAPI 3 specifications");
1450
- program.addCommand(createGenerateCommand()).version("0.0.2");
1485
+ program.addCommand(createGenerateCommand()).version("0.2.0");
1451
1486
  program.parse(process.argv);
@@ -3,7 +3,7 @@
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "description": "Configuration schema for generating operational dashboards from OpenAPI specifications",
5
5
  "title": "OpEx Dashboard Configuration",
6
- "version": "0.0.2",
6
+ "version": "0.2.0",
7
7
  "type": "object",
8
8
  "properties": {
9
9
  "action_groups": {
@@ -168,6 +168,11 @@
168
168
  ],
169
169
  "additionalProperties": false
170
170
  },
171
+ "resource_group": {
172
+ "description": "Azure resource group name where dashboard and alerts will be created. Default: dashboards",
173
+ "default": "dashboards",
174
+ "type": "string"
175
+ },
171
176
  "resource_type": {
172
177
  "description": "Type of Azure resource to monitor: app-gateway (Application Gateway) or api-management (API Management). Default: app-gateway",
173
178
  "default": "app-gateway",
@@ -184,164 +189,220 @@
184
189
  },
185
190
  "terraform": {
186
191
  "description": "Optional Terraform and environment-specific configuration",
187
- "type": "object",
188
- "properties": {
189
- "environments": {
190
- "description": "Environment-specific configurations for dev/uat/prod",
192
+ "anyOf": [
193
+ {
191
194
  "type": "object",
192
195
  "properties": {
193
- "dev": {
196
+ "backend": {
197
+ "description": "Azure backend configuration for Terraform state",
194
198
  "type": "object",
195
199
  "properties": {
196
- "backend": {
197
- "description": "Azure backend configuration for Terraform state",
198
- "type": "object",
199
- "properties": {
200
- "container_name": {
201
- "description": "Blob container name for Terraform state",
202
- "type": "string"
203
- },
204
- "key": {
205
- "description": "State file key/path",
206
- "type": "string"
207
- },
208
- "resource_group_name": {
209
- "description": "Azure resource group for backend state",
210
- "type": "string"
211
- },
212
- "storage_account_name": {
213
- "description": "Storage account for Terraform state",
214
- "type": "string"
215
- }
216
- },
217
- "required": [
218
- "container_name",
219
- "key",
220
- "resource_group_name",
221
- "storage_account_name"
222
- ],
223
- "additionalProperties": false
200
+ "container_name": {
201
+ "description": "Blob container name for Terraform state",
202
+ "type": "string"
203
+ },
204
+ "key": {
205
+ "description": "State file key/path",
206
+ "type": "string"
224
207
  },
225
- "env_short": {
226
- "description": "Environment short name (1 char: 'd'=dev, 'u'=uat, 'p'=prod)",
227
- "type": "string",
228
- "maxLength": 1
208
+ "resource_group_name": {
209
+ "description": "Azure resource group for backend state",
210
+ "type": "string"
229
211
  },
230
- "prefix": {
231
- "description": "Project prefix (max 6 chars, e.g., 'io', 'pagopa')",
232
- "type": "string",
233
- "maxLength": 6
212
+ "storage_account_name": {
213
+ "description": "Storage account for Terraform state",
214
+ "type": "string"
234
215
  }
235
216
  },
236
217
  "required": [
237
- "env_short",
238
- "prefix"
218
+ "container_name",
219
+ "key",
220
+ "resource_group_name",
221
+ "storage_account_name"
239
222
  ],
240
223
  "additionalProperties": false
241
224
  },
242
- "prod": {
225
+ "env_short": {
226
+ "description": "Environment short name (1 char: 'd'=dev, 'u'=uat, 'p'=prod)",
227
+ "type": "string",
228
+ "maxLength": 1
229
+ },
230
+ "prefix": {
231
+ "description": "Project prefix (max 6 chars, e.g., 'io', 'pagopa')",
232
+ "type": "string",
233
+ "maxLength": 6
234
+ }
235
+ },
236
+ "required": [
237
+ "env_short",
238
+ "prefix"
239
+ ],
240
+ "additionalProperties": false
241
+ },
242
+ {
243
+ "type": "object",
244
+ "properties": {
245
+ "environments": {
246
+ "description": "Environment-specific configurations for dev/uat/prod",
243
247
  "type": "object",
244
248
  "properties": {
245
- "backend": {
246
- "description": "Azure backend configuration for Terraform state",
249
+ "dev": {
247
250
  "type": "object",
248
251
  "properties": {
249
- "container_name": {
250
- "description": "Blob container name for Terraform state",
251
- "type": "string"
252
- },
253
- "key": {
254
- "description": "State file key/path",
255
- "type": "string"
252
+ "backend": {
253
+ "description": "Azure backend configuration for Terraform state",
254
+ "type": "object",
255
+ "properties": {
256
+ "container_name": {
257
+ "description": "Blob container name for Terraform state",
258
+ "type": "string"
259
+ },
260
+ "key": {
261
+ "description": "State file key/path",
262
+ "type": "string"
263
+ },
264
+ "resource_group_name": {
265
+ "description": "Azure resource group for backend state",
266
+ "type": "string"
267
+ },
268
+ "storage_account_name": {
269
+ "description": "Storage account for Terraform state",
270
+ "type": "string"
271
+ }
272
+ },
273
+ "required": [
274
+ "container_name",
275
+ "key",
276
+ "resource_group_name",
277
+ "storage_account_name"
278
+ ],
279
+ "additionalProperties": false
256
280
  },
257
- "resource_group_name": {
258
- "description": "Azure resource group for backend state",
259
- "type": "string"
281
+ "env_short": {
282
+ "description": "Environment short name (1 char: 'd'=dev, 'u'=uat, 'p'=prod)",
283
+ "type": "string",
284
+ "maxLength": 1
260
285
  },
261
- "storage_account_name": {
262
- "description": "Storage account for Terraform state",
263
- "type": "string"
286
+ "prefix": {
287
+ "description": "Project prefix (max 6 chars, e.g., 'io', 'pagopa')",
288
+ "type": "string",
289
+ "maxLength": 6
264
290
  }
265
291
  },
266
292
  "required": [
267
- "container_name",
268
- "key",
269
- "resource_group_name",
270
- "storage_account_name"
293
+ "env_short",
294
+ "prefix"
271
295
  ],
272
296
  "additionalProperties": false
273
297
  },
274
- "env_short": {
275
- "description": "Environment short name (1 char: 'd'=dev, 'u'=uat, 'p'=prod)",
276
- "type": "string",
277
- "maxLength": 1
278
- },
279
- "prefix": {
280
- "description": "Project prefix (max 6 chars, e.g., 'io', 'pagopa')",
281
- "type": "string",
282
- "maxLength": 6
283
- }
284
- },
285
- "required": [
286
- "env_short",
287
- "prefix"
288
- ],
289
- "additionalProperties": false
290
- },
291
- "uat": {
292
- "type": "object",
293
- "properties": {
294
- "backend": {
295
- "description": "Azure backend configuration for Terraform state",
298
+ "prod": {
296
299
  "type": "object",
297
300
  "properties": {
298
- "container_name": {
299
- "description": "Blob container name for Terraform state",
300
- "type": "string"
301
- },
302
- "key": {
303
- "description": "State file key/path",
304
- "type": "string"
301
+ "backend": {
302
+ "description": "Azure backend configuration for Terraform state",
303
+ "type": "object",
304
+ "properties": {
305
+ "container_name": {
306
+ "description": "Blob container name for Terraform state",
307
+ "type": "string"
308
+ },
309
+ "key": {
310
+ "description": "State file key/path",
311
+ "type": "string"
312
+ },
313
+ "resource_group_name": {
314
+ "description": "Azure resource group for backend state",
315
+ "type": "string"
316
+ },
317
+ "storage_account_name": {
318
+ "description": "Storage account for Terraform state",
319
+ "type": "string"
320
+ }
321
+ },
322
+ "required": [
323
+ "container_name",
324
+ "key",
325
+ "resource_group_name",
326
+ "storage_account_name"
327
+ ],
328
+ "additionalProperties": false
305
329
  },
306
- "resource_group_name": {
307
- "description": "Azure resource group for backend state",
308
- "type": "string"
330
+ "env_short": {
331
+ "description": "Environment short name (1 char: 'd'=dev, 'u'=uat, 'p'=prod)",
332
+ "type": "string",
333
+ "maxLength": 1
309
334
  },
310
- "storage_account_name": {
311
- "description": "Storage account for Terraform state",
312
- "type": "string"
335
+ "prefix": {
336
+ "description": "Project prefix (max 6 chars, e.g., 'io', 'pagopa')",
337
+ "type": "string",
338
+ "maxLength": 6
313
339
  }
314
340
  },
315
341
  "required": [
316
- "container_name",
317
- "key",
318
- "resource_group_name",
319
- "storage_account_name"
342
+ "env_short",
343
+ "prefix"
320
344
  ],
321
345
  "additionalProperties": false
322
346
  },
323
- "env_short": {
324
- "description": "Environment short name (1 char: 'd'=dev, 'u'=uat, 'p'=prod)",
325
- "type": "string",
326
- "maxLength": 1
327
- },
328
- "prefix": {
329
- "description": "Project prefix (max 6 chars, e.g., 'io', 'pagopa')",
330
- "type": "string",
331
- "maxLength": 6
347
+ "uat": {
348
+ "type": "object",
349
+ "properties": {
350
+ "backend": {
351
+ "description": "Azure backend configuration for Terraform state",
352
+ "type": "object",
353
+ "properties": {
354
+ "container_name": {
355
+ "description": "Blob container name for Terraform state",
356
+ "type": "string"
357
+ },
358
+ "key": {
359
+ "description": "State file key/path",
360
+ "type": "string"
361
+ },
362
+ "resource_group_name": {
363
+ "description": "Azure resource group for backend state",
364
+ "type": "string"
365
+ },
366
+ "storage_account_name": {
367
+ "description": "Storage account for Terraform state",
368
+ "type": "string"
369
+ }
370
+ },
371
+ "required": [
372
+ "container_name",
373
+ "key",
374
+ "resource_group_name",
375
+ "storage_account_name"
376
+ ],
377
+ "additionalProperties": false
378
+ },
379
+ "env_short": {
380
+ "description": "Environment short name (1 char: 'd'=dev, 'u'=uat, 'p'=prod)",
381
+ "type": "string",
382
+ "maxLength": 1
383
+ },
384
+ "prefix": {
385
+ "description": "Project prefix (max 6 chars, e.g., 'io', 'pagopa')",
386
+ "type": "string",
387
+ "maxLength": 6
388
+ }
389
+ },
390
+ "required": [
391
+ "env_short",
392
+ "prefix"
393
+ ],
394
+ "additionalProperties": false
332
395
  }
333
396
  },
334
- "required": [
335
- "env_short",
336
- "prefix"
337
- ],
338
397
  "additionalProperties": false
339
398
  }
340
399
  },
400
+ "required": [
401
+ "environments"
402
+ ],
341
403
  "additionalProperties": false
342
404
  }
343
- },
344
- "additionalProperties": false
405
+ ]
345
406
  },
346
407
  "timespan": {
347
408
  "description": "Time range for dashboard queries (e.g., 5m, 1h, 24h). Default: 5m",
@@ -354,7 +415,8 @@
354
415
  "data_source",
355
416
  "location",
356
417
  "name",
357
- "oa3_spec"
418
+ "oa3_spec",
419
+ "resource_group"
358
420
  ],
359
421
  "additionalProperties": false
360
422
  }
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "url": "git+https://github.com/pagopa/dx.git",
6
6
  "directory": "apps/opex-dashboard"
7
7
  },
8
- "version": "0.0.2",
8
+ "version": "0.2.0",
9
9
  "description": "Generate operational dashboards from OpenAPI specifications",
10
10
  "main": "dist/index.js",
11
11
  "bin": {