Skip to content
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
7db1b0c
Detect non-existent fields when running ddev validate config
ddog-nasirthomas Oct 16, 2025
906e138
Fixing error messaging to include what option name has the incorrect …
ddog-nasirthomas Oct 20, 2025
d4ae0d6
Editing the error message
ddog-nasirthomas Oct 22, 2025
32ccc7f
Fix spec.yaml fields with incorrect option or value level fields
ddog-nasirthomas Oct 24, 2025
62f4a94
Fix typo in test case
ddog-nasirthomas Oct 24, 2025
f27a8a8
Fix linting issue
ddog-nasirthomas Oct 24, 2025
03f326b
Add field validation for DDEV validate config
ddog-nasirthomas Oct 24, 2025
f955f3d
Fix value level fields to correct field name.
ddog-nasirthomas Oct 27, 2025
2841b4a
Fix: include 'default' field when generating spec.yaml
ddog-nasirthomas Nov 6, 2025
ca44bf1
Update spec.yaml to use default value from default model
ddog-nasirthomas Nov 6, 2025
69f8773
Update conf.yaml files to display 'default' values defined in spec.yaml
ddog-nasirthomas Nov 6, 2025
0bec013
Update documentation to clarify display_default behaivor
ddog-nasirthomas Nov 6, 2025
45e7aa4
Update conf.yaml to display 'default' field defined in spec.yaml
ddog-nasirthomas Nov 6, 2025
245b6d8
Fix linting issues
ddog-nasirthomas Nov 6, 2025
43244a7
Update changelog from 'changed' to 'fixed'
ddog-nasirthomas Nov 6, 2025
19347f4
Annotate arguments for validate_fields
ddog-nasirthomas Nov 12, 2025
9ce6d33
Remove changelog
ddog-nasirthomas Nov 12, 2025
9fb226b
Update docs to include value precedence
ddog-nasirthomas Nov 12, 2025
5e154ec
Fix lint issue
ddog-nasirthomas Nov 12, 2025
d3ed422
Merge branch 'master' into nasir.thomas/AI-5146/ddev-validate-config-…
AAraKKe Nov 19, 2025
9f33042
Remove unnecessary 'default' from spec.yaml
ddog-nasirthomas Nov 19, 2025
e8c064d
Remove unnecessary 'default' from spec.yaml
ddog-nasirthomas Nov 19, 2025
2cfe2e9
Change display_default field to default
ddog-nasirthomas Nov 19, 2025
b673e62
Restoring changelog
ddog-nasirthomas Nov 19, 2025
a99dcd6
Merge branch 'master' into nasir.thomas/AI-5146/ddev-validate-config-…
ddog-nasirthomas Nov 26, 2025
0e6f7a5
Cleaning up error message when an integration has multiple errors
ddog-nasirthomas Nov 26, 2025
db5dfd5
Fixing display_default field
ddog-nasirthomas Nov 26, 2025
79872b1
Fixing defaults displayed
ddog-nasirthomas Nov 26, 2025
290f6da
Adding changelog for ibm_lsf
ddog-nasirthomas Nov 26, 2025
0df6e91
Fixing lint issues
ddog-nasirthomas Nov 26, 2025
9f5ef95
Merge remote-tracking branch 'origin/master' into nasir.thomas/AI-514…
ddog-nasirthomas Dec 8, 2025
2b531f9
Merge branch 'master' into nasir.thomas/AI-5146/ddev-validate-config-…
AAraKKe Dec 9, 2025
0b52586
Merge branch 'master' into nasir.thomas/AI-5146/ddev-validate-config-…
ddog-nasirthomas Jan 23, 2026
a31c6c0
Add 'fleet_configurable' as a valid option level field
ddog-nasirthomas Jan 23, 2026
b28ae19
Merge branch 'master' into nasir.thomas/AI-5146/ddev-validate-config-…
AAraKKe Jan 29, 2026
79dc34d
Merge branch 'master' into nasir.thomas/AI-5146/ddev-validate-config-…
ddog-nasirthomas Jan 30, 2026
29f391e
Updating postgres conf.yaml
ddog-nasirthomas Jan 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions avi_vantage/changelog.d/21744.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Update conf.yaml to display 'default' field defined in spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ instances:
#
- avi_controller_url: https://<AVI_CONTROLLER_HOSTNAME>/

## @param entities - list of strings - optional
## @param entities - list of strings - optional - default: ['controller', 'pool', 'serviceengine', 'virtualservice']
## List of entity types to collect metrics from. Valid options are
## `controller`, `pool`, `serviceengine` and `virtualservice`. By default all types
## are monitored.
Expand Down
1 change: 1 addition & 0 deletions datadog_checks_dev/changelog.d/21744.added
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added validation for option and value level fields in the ddev validate command.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,28 @@

import yaml

from datadog_checks.dev.tooling.configuration.constants import OPENAPI_SCHEMA_PROPERTIES

ALLOWED_OPTION_FIELDS = {
Copy link
Contributor Author

@ddog-nasirthomas ddog-nasirthomas Oct 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't sure if the ALLOWED_OPTION_FIELDS would be better suited in datadog_checks.dev.tooling.configuration.constants since the file seemed specific to Open API constants. Please let me know if I should move it. Thanks

'name',
'description',
'required',
'hidden',
'display_priority',
'deprecation',
'multiple',
'multiple_instances_defined',
'metadata_tags',
'options',
'value',
'secret',
'enabled',
'example',
'template',
'overrides',
'fleet_configurable',
}
ALLOWED_VALUE_FIELDS = OPENAPI_SCHEMA_PROPERTIES | {'example', 'display_default', 'compact_example'}
DESCRIPTION_LINE_LENGTH_LIMIT = 120


Expand Down Expand Up @@ -66,6 +88,18 @@ def option_enabled(option):
return option['required']


def validate_fields(
fields_dict: dict[str, any], option_name: str, allowed_fields: set[str], field_level: str, writer: OptionWriter
):
invalid_fields = [field for field in fields_dict if field not in allowed_fields]

if invalid_fields:
invalid_fields_str = '\n'.join(f" - {field!r}" for field in invalid_fields)
writer.new_error(
f"Option name {option_name!r} contains the following invalid {field_level} fields:\n{invalid_fields_str}"
)


def write_description(option, writer, indent, option_type):
description = option['description']
deprecation = option['deprecation']
Expand Down Expand Up @@ -103,6 +137,9 @@ def write_description(option, writer, indent, option_type):

def write_option(option, writer, indent='', start_list=False):
option_name = option['name']

validate_fields(option, option_name, ALLOWED_OPTION_FIELDS, 'option-level', writer)

if 'value' in option:
value = option['value']
required = option['required']
Expand All @@ -116,11 +153,13 @@ def write_option(option, writer, indent='', start_list=False):
'required' if required else 'optional',
)

validate_fields(value, option_name, ALLOWED_VALUE_FIELDS, 'value-level', writer)

example = value.get('example')
example_type = type(example)
if not required:
if 'display_default' in value:
default = value['display_default']
default = value.get('display_default', value.get('default'))
if default is not None:
default_type = type(default)
if default is not None and str(default).lower() != 'none':
if default_type is str:
Expand All @@ -129,7 +168,7 @@ def write_option(option, writer, indent='', start_list=False):
writer.write(' - default: ', 'true' if default else 'false')
else:
writer.write(' - default: ', repr(default))
else:
elif 'display_default' not in value or 'default' in value:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: I am not sure I understand this statement in the elif block. If we make it here it means that neither display_default nor default is in value as we have defined default before as value.get('display_default', value.get('default')). If display_default is not in value, we take the value of default. If default is not there either then it will return None.

Since the previous block only executes when default is not None, it means that one of the 2 previous options is defined. This conditional here says: if display_default is not in value or default is in value then do this. But since display_default will never be en value, or it would have gone to the previous block, this is always true right?

Shouldn't this be just an else as it was before?

Copy link
Contributor Author

@ddog-nasirthomas ddog-nasirthomas Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was a weird issue I encountered when I left it as else and display_default was null, it wouldn't detect it and would result in files being formatted improperly by either trying to set the default or the example in the header.

I believe this is because of the line default = value.get('display_default', value.get('default')) .

If the key exists and the value is set to null, .get() returns None and this would cause the errors.

if example_type is bool:
writer.write(' - default: ', 'true' if example else 'false')
elif example_type in (int, float):
Expand Down Expand Up @@ -261,6 +300,24 @@ def render(self):
if i != num_options:
writer.write('\n')

if writer.errors:
has_option_level_errors = any('option-level' in error for error in writer.errors)
has_value_level_errors = any('value-level' in error for error in writer.errors)

if has_option_level_errors or has_value_level_errors:
valid_fields = []

if has_option_level_errors:
fields_list = '\n'.join(f" - {field!r}" for field in sorted(ALLOWED_OPTION_FIELDS))
valid_fields.append(f"Option-level fields must be one of the following:\n{fields_list}")

if has_value_level_errors:
fields_list = '\n'.join(f" - {field!r}" for field in sorted(ALLOWED_VALUE_FIELDS))
valid_fields.append(f"Value-level fields must be one of the following:\n{fields_list}")

if valid_fields:
writer.errors.append('\n'.join(valid_fields))

files[file['example_name']] = (writer.contents, writer.errors)

return files
Original file line number Diff line number Diff line change
Expand Up @@ -1771,3 +1771,141 @@ def test_multi_instances_w_nested_options():
# option_3: true
"""
)


def test_invalid_option_level_fields():
consumer = get_example_consumer(
"""
name: foo
version: 0.0.0
files:
- name: test.yaml
example_name: test.yaml.example
options:
- name: test_option
description: test description
invalid_option_field: this_should_fail
another_bad_option_field: also_bad
value:
type: string
example: test
"""
)

files = consumer.render()
_, errors = files['test.yaml.example']

assert "invalid_option_field" in errors[0]
assert "another_bad_option_field" in errors[0]
assert "option-level" in errors[0].lower()


def test_valid_option_level_fields():
consumer = get_example_consumer(
"""
name: foo
version: 0.0.0
files:
- name: test.yaml
example_name: test.yaml.example
options:
- name: test_option
description: test description
required: true
hidden: false
display_priority: 10
enabled: true
secret: false
deprecation:
Agent version: 8.0.0
metadata_tags:
- tag1
template: instances
value:
type: string
example: test
"""
)

files = consumer.render()
_, errors = files['test.yaml.example']

assert not errors


def test_invalid_value_level_fields():
consumer = get_example_consumer(
"""
name: foo
version: 0.0.0
files:
- name: test.yaml
example_name: test.yaml.example
options:
- name: test_option
description: test description
value:
type: string
example: something
invalid_value_field: this_should_fail
another_bad_value_field: also_bad
"""
)

files = consumer.render()
_, errors = files['test.yaml.example']

assert "invalid_value_field" in errors[0]
assert "another_bad_value_field" in errors[0]
assert "value-level" in errors[0].lower()


def test_valid_value_level_fields():
consumer = get_example_consumer(
"""
name: foo
version: 0.0.0
files:
- name: test.yaml
example_name: test.yaml.example
options:
- name: test_option
description: test description
value:
type: string
example: something
display_default: default_value
compact_example: true
pattern: ^[a-z]+$
minLength: 1
maxLength: 100
"""
)

files = consumer.render()
_, errors = files['test.yaml.example']

assert not errors


def test_option_level_example_field():
consumer = get_example_consumer(
"""
name: foo
version: 0.0.0
files:
- name: test.yaml
example_name: test.yaml.example
options:
- name: logs
description: Log configuration
example:
- type: file
path: /var/log/test.log
"""
)

files = consumer.render()
_, errors = files['test.yaml.example']

assert not errors
10 changes: 8 additions & 2 deletions docs/developer/meta/config-specs.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,14 @@ It respects a few extra [option](#options)-level attributes:

It also respects a few extra fields under the `value` attribute of each option:

- `display_default` - This is the default value that will be shown in the header of each option, useful if it differs from the `example`.
You may set it to `null` explicitly to disable showing this part of the header.
- `display_default` - Overrides the default value shown in the commented-out header of the example file. This is useful if the value you want to *display* differs from the `example` value or the functional `default` value.

* **Value Precedence:** When generating the header, the consumer displays the *first* value it finds from this priority list:
1. `display_default`
2. `default` (from the [Data model consumer](#data-model-consumer))
3. `example` (from the [Values](#values) section)

* **Suppressing the Default:** To explicitly *prevent* any default value from being shown in the header, set this field to `null`. This will suppress the output even if `default` or `example` are set.
- `compact_example` - Whether or not to display complex types like arrays in their most compact representation. It defaults to `false`.

### Usage
Expand Down
4 changes: 2 additions & 2 deletions ecs_fargate/assets/configuration/spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ files:
- template: instances/http
- template: instances/default
overrides:
min_collection_interval.display_default: 20
min_collection_interval.value.display_default: 20
min_collection_interval.value.example: 20
min_collection_interval.enabled: true
- name: default.yaml
Expand All @@ -34,6 +34,6 @@ files:
- template: instances/http
- template: instances/default
overrides:
min_collection_interval.display_default: 20
min_collection_interval.value.display_default: 20
min_collection_interval.value.example: 20
min_collection_interval.enabled: true
2 changes: 1 addition & 1 deletion http_check/assets/configuration/spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ files:
If any one of the POST, PUT, DELETE, or PATCH method is specified, you can choose to send data in the body of the
request with the data parameter.
SOAP requests are supported if you use the POST method and supply an XML string as the data parameter.
enabled: false
value:
anyOf:
- type: object
- type: string
enabled: false
example:
<KEY>: <VALUE>
- name: content_match
Expand Down
1 change: 0 additions & 1 deletion ibm_ace/assets/configuration/spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ files:
example: false
type: boolean
- name: tls_cipher_spec
type: string
description: |
The TLS cipher to use. It should match the value of the channel's SSLCIPH attribute.
value:
Expand Down
1 change: 1 addition & 0 deletions ibm_i/changelog.d/21744.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Update conf.yaml to display 'default' field defined in spec.yaml
2 changes: 1 addition & 1 deletion ibm_i/datadog_checks/ibm_i/data/conf.yaml.example
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ instances:
#
# query_timeout: 30

## @param queries - list of mappings - optional
## @param queries - list of mappings - optional - default: [{'name': 'disk_usage'}, {'name': 'cpu_usage'}, {'name': 'jobq_job_status'}, {'name': 'active_job_status'}, {'name': 'job_memory_usage'}, {'name': 'memory_info'}, {'name': 'subsystem'}, {'name': 'job_queue'}, {'name': 'message_queue_info'}]
## List of queries to be run against the IBM i system. By default, all queries are run.
#
# queries:
Expand Down
1 change: 1 addition & 0 deletions ibm_spectrum_lsf/changelog.d/21744.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Update conf.yaml to display 'default' field defined in spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ instances:
#
- cluster_name: <CLUSTER_NAME>

## @param metric_sources - list of strings - optional
## @param metric_sources - list of strings - optional - default: ['lsclusters', 'lshosts', 'bhosts', 'lsload', 'bqueues', 'bslots', 'bjobs']
## Enable metrics from different IBM Spectrum LSF commands.
## By default, all commands except GPU commands are enabled.
##
Expand Down
10 changes: 5 additions & 5 deletions kafka_consumer/assets/configuration/spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ files:
value:
type: integer
example: 5
display_default: 5
display_default: 5
- template: init_config/default
- template: instances
options:
Expand Down Expand Up @@ -147,10 +147,10 @@ files:
Protocol used to communicate with brokers.
Valid values are: PLAINTEXT, SSL, SASL_PLAINTEXT, SASL_SSL.
Default: PLAINTEXT.
display_default: PLAINTEXT
value:
type: string
example: PLAINTEXT
display_default: PLAINTEXT
- name: sasl_mechanism
description: |
String picking sasl mechanism when security_protocol is SASL_PLAINTEXT or SASL_SSL.
Expand Down Expand Up @@ -238,7 +238,7 @@ files:
value:
type: boolean
example: false
display_default: false
display_default: false
- name: enable_cluster_monitoring
description: |
(PREVIEW) Enable cluster monitoring to collect broker, topic, partition, consumer group,
Expand All @@ -252,7 +252,7 @@ files:
value:
type: boolean
example: false
display_default: false
display_default: false
- name: schema_registry_url
description: |
Schema Registry URL. When set with enable_cluster_monitoring, collects schema information.
Expand Down Expand Up @@ -281,7 +281,7 @@ files:
value:
type: boolean
example: true
display_default: true
display_default: true
- name: schema_registry_tls_ca_cert
description: |
Path to a custom CA certificate file for Schema Registry TLS verification.
Expand Down
1 change: 0 additions & 1 deletion kube_apiserver_metrics/assets/configuration/spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ files:
enabled: true
value:
example: tls_only
default: false
anyOf:
- type: boolean
- type: string
Expand Down
Loading
Loading