All integrations use pydantic models as the primary way to validate and interface with configuration.
As config spec data types are based on OpenAPI 3, we automatically generate the necessary code.
The models reside in a package named
config_models located at the root of a check's namespaced package. For example, a new integration named
foo │ ... ├── datadog_checks │ └── foo │ └── config_models │ ├── __init__.py │ ├── defaults.py │ ├── instance.py │ ├── shared.py │ └── validators.py │ └── __init__.py │ ... ...
There are 2 possible models:
shared) that corresponds to the
instance) that corresponds to a check's entry in the
All models are defined in
<ID>.py and are available for import directly under
The default values for optional settings are populated in
defaults.py and are derived from the value property of config spec options.
The precedence is:
examplekey, if it appears to represent a real value rather than an illustrative example and the
typeis a primitive
- the default value of the
The validation of fields for every model occurs in 6 stages.
def initialize_<ID>(values: dict[str, Any], **kwargs) -> dict[str, Any]: ...
If such a validator exists in
validators.py, then it is called once with the raw config that was supplied by the user. The returned mapping is used as the input config for the subsequent stages.
Default value population¶
If a field was not supplied by the user nor during the initialization stage, then its default value is taken from
defaults.py. This stage is skipped for required fields.
Default field validators¶
At this point
pydantic will parse the values and perform validation of types, etc.
Custom field validators¶
The contents of
validators.py are entirely custom and contain functions to perform extra validation if necessary.
def <ID>_<OPTION_NAME>(value: Any, *, field: pydantic.fields.ModelField, **kwargs) -> Any: ...
Such validators are called for the appropriate field of the proper model if the option was supplied by the user.
The returned value is used as the new value of the option for the subsequent stages.
Pre-defined field validators¶
validators key under the value property of config spec options is considered. Every entry will refer to a relative import path to a field validator under
datadog_checks.base.utils.models.validation and is executed in the defined order.
The last returned value is used as the new value of the option for the final stage.
def finalize_<ID>(values: dict[str, Any], **kwargs) -> dict[str, Any]: ...
If such a validator exists in
validators.py, then it is called with the cumulative result of all fields.
The returned mapping is used to instantiate the model.
A check initialization occurs before a check's first run that loads the config models. Validation errors will thus prevent check execution.
The config models package contains a class
ConfigMixin from which checks inherit:
from datadog_checks.base import AgentCheck from .config_models import ConfigMixin class Check(AgentCheck, ConfigMixin): ...
It exposes the instantiated
InstanceConfig model at
SharedConfig model at
Every option marked as deprecated in the config spec will log a warning with information about when it will be removed and what to do.
A validation command
ddev validate models runs in our CI. To locally generate the proper files, run
ddev validate models [CHECK] --sync.