/api/v1/config tree improvements and swagger documentation (#16764)
Costa Tsaousis committed
Jan 12, 2024 at 03:09 UTC
7fce3dcd9cb9eb87509a9cec80e51fefd0a971ff
4 files changed
+591
-12
daemon/config/dyncfg-tree.c
+16
-4
@@ -21,6 +21,10 @@ static void dyncfg_to_json(DYNCFG *df, const char *id, BUFFER *wb) {
21
buffer_json_member_add_object(wb, id);
22
{
23
buffer_json_member_add_string(wb, "type", dyncfg_id2type(df->type));
24
+
25
+ if(df->type == DYNCFG_TYPE_JOB)
26
+ buffer_json_member_add_string(wb, "template", string2str(df->template));
27
+
28
buffer_json_member_add_string(wb, "status", dyncfg_id2status(df->status));
29
dyncfg_cmds2json_array(df->cmds, "cmds", wb);
30
buffer_json_member_add_string(wb, "source_type", dyncfg_id2source_type(df->source_type));
@@ -46,13 +50,17 @@ static void dyncfg_to_json(DYNCFG *df, const char *id, BUFFER *wb) {
50
buffer_json_object_close(wb);
51
}
52
49
-static void dyncfg_tree_for_host(RRDHOST *host, BUFFER *wb, const char *parent, const char *id __maybe_unused) {
53
+static void dyncfg_tree_for_host(RRDHOST *host, BUFFER *wb, const char *path, const char *id) {
54
size_t entries = dictionary_entries(dyncfg_globals.nodes);
55
size_t used = 0;
56
const DICTIONARY_ITEM *items[entries];
57
size_t restart_required = 0, plugin_rejected = 0, status_incomplete = 0, status_failed = 0;
58
55
- size_t parent_len = strlen(parent);
59
+ STRING *template = NULL;
60
+ if(id && *id)
61
+ template = string_strdupz(id);
62
+
63
+ size_t path_len = strlen(path);
64
DYNCFG *df;
65
dfe_start_read(dyncfg_globals.nodes, df) {
66
if(!df->host) {
@@ -60,17 +68,21 @@ static void dyncfg_tree_for_host(RRDHOST *host, BUFFER *wb, const char *parent,
68
df->host = host;
69
}
70
63
- if(df->host != host || strncmp(string2str(df->path), parent, parent_len) != 0)
71
+ if(df->host != host || strncmp(string2str(df->path), path, path_len) != 0)
72
continue;
73
74
if(!rrd_function_available(host, string2str(df->function)))
75
df->status = DYNCFG_STATUS_ORPHAN;
76
77
+ if((id && strcmp(id, df_dfe.name) != 0) || (template && df->template != template))
78
+ continue;
79
+
80
items[used++] = dictionary_acquired_item_dup(dyncfg_globals.nodes, df_dfe.item);
81
}
82
dfe_done(df);
83
73
- qsort(items, used, sizeof(const DICTIONARY_ITEM *), dyncfg_tree_compar);
84
+ if(used > 1)
85
+ qsort(items, used, sizeof(const DICTIONARY_ITEM *), dyncfg_tree_compar);
86
87
buffer_flush(wb);
88
buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_MINIFY);
web/api/netdata-swagger.json
+349
-6
@@ -373,6 +373,201 @@
373
}
374
}
375
},
376
+ "/api/v1/config": {
377
+ "get": {
378
+ "operationId": "getConfig",
379
+ "tags": [
380
+ "dyncfg"
381
+ ],
382
+ "description": "Get dynamic configuration information.\n",
383
+ "parameters": [
384
+ {
385
+ "name": "action",
386
+ "in": "query",
387
+ "description": "The type of information required",
388
+ "schema": {
389
+ "type": "string",
390
+ "enum": [
391
+ "tree",
392
+ "schema",
393
+ "get",
394
+ "enable",
395
+ "disable",
396
+ "restart"
397
+ ],
398
+ "default": "tree"
399
+ }
400
+ },
401
+ {
402
+ "name": "id",
403
+ "in": "query",
404
+ "description": "The ID of the dynamic configuration entity",
405
+ "schema": {
406
+ "type": "string"
407
+ }
408
+ },
409
+ {
410
+ "name": "path",
411
+ "in": "query",
412
+ "description": "Top level path of the configuration entities, used with action 'tree'",
413
+ "schema": {
414
+ "type": "string",
415
+ "default": "/"
416
+ }
417
+ },
418
+ {
419
+ "name": "timeout",
420
+ "in": "query",
421
+ "description": "The timeout in seconds",
422
+ "schema": {
423
+ "type": "number",
424
+ "default": 120
425
+ }
426
+ }
427
+ ],
428
+ "responses": {
429
+ "200": {
430
+ "description": "The call was successful.",
431
+ "content": {
432
+ "application/json": {
433
+ "schema": {
434
+ "oneOf": [
435
+ {
436
+ "$ref": "#/components/schemas/config_default_response"
437
+ },
438
+ {
439
+ "$ref": "#/components/schemas/config_tree"
440
+ },
441
+ {
442
+ "$ref": "#/components/schemas/config_schema"
443
+ }
444
+ ]
445
+ }
446
+ }
447
+ }
448
+ },
449
+ "400": {
450
+ "description": "Something is wrong with the request.",
451
+ "content": {
452
+ "application/json": {
453
+ "schema": {
454
+ "$ref": "#/components/schemas/config_default_response"
455
+ }
456
+ }
457
+ }
458
+ },
459
+ "404": {
460
+ "description": "The configurable entity requests is not found.",
461
+ "content": {
462
+ "application/json": {
463
+ "schema": {
464
+ "$ref": "#/components/schemas/config_default_response"
465
+ }
466
+ }
467
+ }
468
+ }
469
+ }
470
+ },
471
+ "post": {
472
+ "operationId": "postConfig",
473
+ "tags": [
474
+ "dyncfg"
475
+ ],
476
+ "description": "Post dynamic configuration to Netdata.\n",
477
+ "parameters": [
478
+ {
479
+ "name": "action",
480
+ "in": "query",
481
+ "description": "The type of action required.",
482
+ "schema": {
483
+ "type": "string",
484
+ "enum": [
485
+ "add",
486
+ "test",
487
+ "update"
488
+ ]
489
+ }
490
+ },
491
+ {
492
+ "name": "id",
493
+ "in": "query",
494
+ "description": "The ID of the dynamic configuration entity to configure.",
495
+ "schema": {
496
+ "type": "string"
497
+ }
498
+ },
499
+ {
500
+ "name": "name",
501
+ "in": "query",
502
+ "description": "Name of the dynamic configuration entity, used with action 'add'",
503
+ "schema": {
504
+ "type": "string"
505
+ }
506
+ },
507
+ {
508
+ "name": "timeout",
509
+ "in": "query",
510
+ "description": "The timeout in seconds",
511
+ "schema": {
512
+ "type": "number",
513
+ "default": 120
514
+ }
515
+ }
516
+ ],
517
+ "responses": {
518
+ "200": {
519
+ "description": "The call was successful. This also means the configuration is currently running.",
520
+ "content": {
521
+ "application/json": {
522
+ "schema": {
523
+ "$ref": "#/components/schemas/config_default_response"
524
+ }
525
+ }
526
+ }
527
+ },
528
+ "202": {
529
+ "description": "The call was successful. The configuration has been accepted, but its status is not yet known.",
530
+ "content": {
531
+ "application/json": {
532
+ "schema": {
533
+ "$ref": "#/components/schemas/config_default_response"
534
+ }
535
+ }
536
+ }
537
+ },
538
+ "299": {
539
+ "description": "The call was successful. The configuration has been accepted, but a restart is required to apply it.",
540
+ "content": {
541
+ "application/json": {
542
+ "schema": {
543
+ "$ref": "#/components/schemas/config_default_response"
544
+ }
545
+ }
546
+ }
547
+ },
548
+ "400": {
549
+ "description": "Something is wrong with the request.",
550
+ "content": {
551
+ "application/json": {
552
+ "schema": {
553
+ "$ref": "#/components/schemas/config_default_response"
554
+ }
555
+ }
556
+ }
557
+ },
558
+ "404": {
559
+ "description": "The configurable entity requests is not found.",
560
+ "content": {
561
+ "application/json": {
562
+ "schema": {
563
+ "$ref": "#/components/schemas/config_default_response"
564
+ }
565
+ }
566
+ }
567
+ }
568
+ }
569
+ }
570
+ },
571
"/api/v2/data": {
572
"get": {
573
"operationId": "dataQuery2",
@@ -385,7 +580,7 @@
580
{
581
"name": "group_by",
582
"in": "query",
388
- "description": "A comma separated list of the groupings required.\nAll possible values can be combined together, except `selected`. If `selected` is given in the list, all others are ignored.\nThe order they are placed in the list is currently ignored.\n",
583
+ "description": "A comma separated list of the groupings required.\nAll possible values can be combined together, except `selected`. If `selected` is given in the list, all others are ignored.\nThe order they are placed in the list is currently ignored.\nThis parameter is also accepted as `group_by[0]` and `group_by[1]` when multiple grouping passes are required.\n",
584
"required": false,
585
"schema": {
586
"type": "array",
@@ -410,7 +605,7 @@
605
{
606
"name": "group_by_label",
607
"in": "query",
413
- "description": "A comma separated list of the label keys to group by their values. The order of the labels in the list is respected.\n",
608
+ "description": "A comma separated list of the label keys to group by their values. The order of the labels in the list is respected.\nThis parameter is also accepted as `group_by_label[0]` and `group_by_label[1]` when multiple grouping passes are required.\n",
609
"required": false,
610
"schema": {
611
"type": "string",
@@ -421,7 +616,7 @@
616
{
617
"name": "aggregation",
618
"in": "query",
424
- "description": "The aggregation function to apply when grouping metrics together.\nWhen option `raw` is given, `average` and `avg` behave like `sum` and the caller is expected to calculate the average.\n",
619
+ "description": "The aggregation function to apply when grouping metrics together.\nWhen option `raw` is given, `average` and `avg` behave like `sum` and the caller is expected to calculate the average.\nThis parameter is also accepted as `aggregation[0]` and `aggregation[1]` when multiple grouping passes are required.\n",
620
"required": false,
621
"schema": {
622
"type": "string",
@@ -430,7 +625,8 @@
625
"max",
626
"avg",
627
"average",
433
- "sum"
628
+ "sum",
629
+ "percentage"
630
],
631
"default": "average"
632
}
@@ -3689,8 +3885,11 @@
3885
"type": "integer"
3886
},
3887
"count": {
3692
- "description": "The number of metrics aggregated into this point. This exists only when the option `raw` is given to the query.\n",
3888
+ "description": "The number of metrics aggregated into this point.\nThis exists only when the option `raw` is given to the query and the final aggregation point is NOT `percentage`.\n",
3889
"type": "integer"
3890
+ },
3891
+ "hidden": {
3892
+ "description": "The sum of the non-selected dimensions aggregated for this group item point.\nThis exists only when the option `raw` is given to the query and the final aggregation method is `percentage`.\n"
3893
}
3894
}
3895
},
@@ -4415,7 +4614,151 @@
4614
},
4615
"weighted_dimension": {
4616
"type": "number"
4617
+ },
4618
+ "config_schema": {
4619
+ "type": "object",
4620
+ "properties": {
4621
+ "jsonSchema": {
4622
+ "type": "object",
4623
+ "description": "Standard JSON Schema object describing the schema of each configurable entity."
4624
+ },
4625
+ "uiSchema": {
4626
+ "type": "object",
4627
+ "description": "Schema for react-json-schema-form to drive the UI. Provides additional UI-specific configuration."
4628
+ }
4629
+ }
4630
+ },
4631
+ "config_tree": {
4632
+ "type": "object",
4633
+ "properties": {
4634
+ "version": {
4635
+ "type": "integer",
4636
+ "description": "The version of dynamic configuration supported by the Netdata agent."
4637
+ },
4638
+ "tree": {
4639
+ "type": "object",
4640
+ "description": "A map of configuration entity paths, each containing one or more configurable entities.",
4641
+ "additionalProperties": {
4642
+ "type": "object",
4643
+ "additionalProperties": {
4644
+ "$ref": "#/components/schemas/config_entity"
4645
+ }
4646
+ }
4647
+ },
4648
+ "attention": {
4649
+ "$ref": "#/components/schemas/config_attention"
4650
+ }
4651
+ }
4652
+ },
4653
+ "config_entity": {
4654
+ "type": "object",
4655
+ "properties": {
4656
+ "type": {
4657
+ "type": "string",
4658
+ "description": "Can be 'single' for entities appearing once, 'template' for entities supporting multiple instances, or 'job' for jobs belonging to a template."
4659
+ },
4660
+ "status": {
4661
+ "type": "string",
4662
+ "description": "The current status of the entity. Values include 'accepted', 'running', 'failed', 'disabled', 'incomplete', or 'orphan'."
4663
+ },
4664
+ "cmds": {
4665
+ "type": "array",
4666
+ "items": {
4667
+ "type": "string"
4668
+ },
4669
+ "description": "An array of the possible actions supported by this entity."
4670
+ },
4671
+ "source_type": {
4672
+ "type": "string",
4673
+ "description": "The source type of the configuration (e.g., 'internal', 'stock', 'user', 'discovered', 'dyncfg')."
4674
+ },
4675
+ "source": {
4676
+ "type": "string",
4677
+ "description": "Additional information about the source, formatted as comma-separated name-value pairs."
4678
+ },
4679
+ "sync": {
4680
+ "type": "boolean",
4681
+ "description": "Indicates if this is an internal module (true) or an external plugin (false)."
4682
+ },
4683
+ "user_disabled": {
4684
+ "type": "boolean",
4685
+ "description": "True if the entity is disabled by the user."
4686
+ },
4687
+ "restart_required": {
4688
+ "type": "boolean",
4689
+ "description": "True if the entity requires a restart after addition or update."
4690
+ },
4691
+ "plugin_rejected": {
4692
+ "type": "boolean",
4693
+ "description": "True if a previously saved configuration failed to apply after a restart."
4694
+ },
4695
+ "payload": {
4696
+ "type": "object",
4697
+ "description": "Object containing at least an 'available' boolean indicating if there's a saved configuration for this entity.",
4698
+ "properties": {
4699
+ "available": {
4700
+ "type": "boolean"
4701
+ }
4702
+ }
4703
+ },
4704
+ "saves": {
4705
+ "type": "integer",
4706
+ "description": "The number of times this configuration has been saved to disk by the dynamic configuration manager."
4707
+ },
4708
+ "created_ut": {
4709
+ "type": "integer",
4710
+ "format": "int64",
4711
+ "description": "The timestamp in microseconds when this dynamic configuration was first created."
4712
+ },
4713
+ "modified_ut": {
4714
+ "type": "integer",
4715
+ "format": "int64",
4716
+ "description": "The timestamp in microseconds when this dynamic configuration was last modified."
4717
+ },
4718
+ "template": {
4719
+ "type": "string",
4720
+ "description": "Shows the template the job belongs to, applicable when type is 'job'."
4721
+ }
4722
+ }
4723
+ },
4724
+ "config_attention": {
4725
+ "type": "object",
4726
+ "properties": {
4727
+ "degraded": {
4728
+ "type": "boolean"
4729
+ },
4730
+ "restart_required": {
4731
+ "type": "integer"
4732
+ },
4733
+ "plugin_rejected": {
4734
+ "type": "integer"
4735
+ },
4736
+ "status_failed": {
4737
+ "type": "integer"
4738
+ },
4739
+ "status_incomplete": {
4740
+ "type": "integer"
4741
+ }
4742
+ }
4743
+ },
4744
+ "config_default_response": {
4745
+ "type": "object",
4746
+ "properties": {
4747
+ "status": {
4748
+ "type": "integer",
4749
+ "description": "The HTTP status code of the response."
4750
+ },
4751
+ "message": {
4752
+ "type": "string",
4753
+ "description": "A descriptive message about the response or the action taken."
4754
+ },
4755
+ "data": {
4756
+ "type": "object",
4757
+ "description": "The data payload of the response, contents vary depending on the specific request and action.",
4758
+ "additionalProperties": true
4759
+ }
4760
+ }
4761
}
4762
}
4763
}
4421
-}
4764
+}
\ No newline at end of file
web/api/netdata-swagger.yaml
+225
@@ -226,6 +226,129 @@ paths:
226
description: No context id was supplied in the request.
227
"404":
228
description: No context with the given id is found.
229
+ /api/v1/config:
230
+ get:
231
+ operationId: getConfig
232
+ tags:
233
+ - dyncfg
234
+ description: |
235
+ Get dynamic configuration information.
236
+ parameters:
237
+ - name: action
238
+ in: query
239
+ description: The type of information required
240
+ schema:
241
+ type: string
242
+ enum:
243
+ - tree
244
+ - schema
245
+ - get
246
+ - enable
247
+ - disable
248
+ - restart
249
+ default: tree
250
+ - name: id
251
+ in: query
252
+ description: The ID of the dynamic configuration entity
253
+ schema:
254
+ type: string
255
+ - name: path
256
+ in: query
257
+ description: Top level path of the configuration entities, used with action 'tree'
258
+ schema:
259
+ type: string
260
+ default: '/'
261
+ - name: timeout
262
+ in: query
263
+ description: The timeout in seconds
264
+ schema:
265
+ type: number
266
+ default: 120
267
+ responses:
268
+ "200":
269
+ description: The call was successful.
270
+ content:
271
+ application/json:
272
+ schema:
273
+ oneOf:
274
+ - $ref: '#/components/schemas/config_default_response'
275
+ - $ref: '#/components/schemas/config_tree'
276
+ - $ref: "#/components/schemas/config_schema"
277
+ "400":
278
+ description: Something is wrong with the request.
279
+ content:
280
+ application/json:
281
+ schema:
282
+ $ref: '#/components/schemas/config_default_response'
283
+ "404":
284
+ description: The configurable entity requests is not found.
285
+ content:
286
+ application/json:
287
+ schema:
288
+ $ref: '#/components/schemas/config_default_response'
289
+ post:
290
+ operationId: postConfig
291
+ tags:
292
+ - dyncfg
293
+ description: |
294
+ Post dynamic configuration to Netdata.
295
+ parameters:
296
+ - name: action
297
+ in: query
298
+ description: The type of action required.
299
+ schema:
300
+ type: string
301
+ enum:
302
+ - add
303
+ - test
304
+ - update
305
+ - name: id
306
+ in: query
307
+ description: The ID of the dynamic configuration entity to configure.
308
+ schema:
309
+ type: string
310
+ - name: name
311
+ in: query
312
+ description: Name of the dynamic configuration entity, used with action 'add'
313
+ schema:
314
+ type: string
315
+ - name: timeout
316
+ in: query
317
+ description: The timeout in seconds
318
+ schema:
319
+ type: number
320
+ default: 120
321
+ responses:
322
+ "200":
323
+ description: The call was successful. This also means the configuration is currently running.
324
+ content:
325
+ application/json:
326
+ schema:
327
+ $ref: '#/components/schemas/config_default_response'
328
+ "202":
329
+ description: The call was successful. The configuration has been accepted, but its status is not yet known.
330
+ content:
331
+ application/json:
332
+ schema:
333
+ $ref: '#/components/schemas/config_default_response'
334
+ "299":
335
+ description: The call was successful. The configuration has been accepted, but a restart is required to apply it.
336
+ content:
337
+ application/json:
338
+ schema:
339
+ $ref: '#/components/schemas/config_default_response'
340
+ "400":
341
+ description: Something is wrong with the request.
342
+ content:
343
+ application/json:
344
+ schema:
345
+ $ref: '#/components/schemas/config_default_response'
346
+ "404":
347
+ description: The configurable entity requests is not found.
348
+ content:
349
+ application/json:
350
+ schema:
351
+ $ref: '#/components/schemas/config_default_response'
352
/api/v2/data:
353
get:
354
operationId: dataQuery2
@@ -3259,3 +3382,105 @@ components:
3382
$ref: '#/components/schemas/weighted_dimension'
3383
weighted_dimension:
3384
type: number
3385
+ config_schema:
3386
+ type: object
3387
+ properties:
3388
+ jsonSchema:
3389
+ type: object
3390
+ description: Standard JSON Schema object describing the schema of each configurable entity.
3391
+ uiSchema:
3392
+ type: object
3393
+ description: Schema for react-json-schema-form to drive the UI. Provides additional UI-specific configuration.
3394
+ config_tree:
3395
+ type: object
3396
+ properties:
3397
+ version:
3398
+ type: integer
3399
+ description: The version of dynamic configuration supported by the Netdata agent.
3400
+ tree:
3401
+ type: object
3402
+ description: A map of configuration entity paths, each containing one or more configurable entities.
3403
+ additionalProperties:
3404
+ type: object
3405
+ additionalProperties:
3406
+ $ref: '#/components/schemas/config_entity'
3407
+ attention:
3408
+ $ref: '#/components/schemas/config_attention'
3409
+ config_entity:
3410
+ type: object
3411
+ properties:
3412
+ type:
3413
+ type: string
3414
+ description: Can be 'single' for entities appearing once, 'template' for entities supporting multiple instances, or 'job' for jobs belonging to a template.
3415
+ status:
3416
+ type: string
3417
+ description: The current status of the entity. Values include 'accepted', 'running', 'failed', 'disabled', 'incomplete', or 'orphan'.
3418
+ cmds:
3419
+ type: array
3420
+ items:
3421
+ type: string
3422
+ description: An array of the possible actions supported by this entity.
3423
+ source_type:
3424
+ type: string
3425
+ description: The source type of the configuration (e.g., 'internal', 'stock', 'user', 'discovered', 'dyncfg').
3426
+ source:
3427
+ type: string
3428
+ description: Additional information about the source, formatted as comma-separated name-value pairs.
3429
+ sync:
3430
+ type: boolean
3431
+ description: Indicates if this is an internal module (true) or an external plugin (false).
3432
+ user_disabled:
3433
+ type: boolean
3434
+ description: True if the entity is disabled by the user.
3435
+ restart_required:
3436
+ type: boolean
3437
+ description: True if the entity requires a restart after addition or update.
3438
+ plugin_rejected:
3439
+ type: boolean
3440
+ description: True if a previously saved configuration failed to apply after a restart.
3441
+ payload:
3442
+ type: object
3443
+ description: Object containing at least an 'available' boolean indicating if there's a saved configuration for this entity.
3444
+ properties:
3445
+ available:
3446
+ type: boolean
3447
+ saves:
3448
+ type: integer
3449
+ description: The number of times this configuration has been saved to disk by the dynamic configuration manager.
3450
+ created_ut:
3451
+ type: integer
3452
+ format: int64
3453
+ description: The timestamp in microseconds when this dynamic configuration was first created.
3454
+ modified_ut:
3455
+ type: integer
3456
+ format: int64
3457
+ description: The timestamp in microseconds when this dynamic configuration was last modified.
3458
+ template:
3459
+ type: string
3460
+ description: Shows the template the job belongs to, applicable when type is 'job'.
3461
+ config_attention:
3462
+ type: object
3463
+ properties:
3464
+ degraded:
3465
+ type: boolean
3466
+ restart_required:
3467
+ type: integer
3468
+ plugin_rejected:
3469
+ type: integer
3470
+ status_failed:
3471
+ type: integer
3472
+ status_incomplete:
3473
+ type: integer
3474
+ config_default_response:
3475
+ type: object
3476
+ properties:
3477
+ status:
3478
+ type: integer
3479
+ description: The HTTP status code of the response.
3480
+ message:
3481
+ type: string
3482
+ description: A descriptive message about the response or the action taken.
3483
+ data:
3484
+ type: object
3485
+ description: The data payload of the response, contents vary depending on the specific request and action.
3486
+ additionalProperties: true
web/api/web_api_v1.c
+1
-2
@@ -1548,8 +1548,7 @@ static int web_client_api_request_v1_config(RRDHOST *host, struct web_client *w,
1548
NULL, NULL,
1549
web_client_progress_functions_update, w,
1550
web_client_interrupt_callback, w,
1551
- w->payload,
1552
- buffer_tostring(source));
1551
+ w->payload, buffer_tostring(source));
1552
1553
return code;
1554
}