Skip to content

Commit d162b4d

Browse files
vitkyrkaclaudedkirov-dd
authored
milvus: add container-based config discovery support (DataDog#24319)
* milvus: add container-based config discovery support Add an openmetrics_from_ports discovery strategy (port hint 9091) and an auto_conf.yaml Autodiscovery template so the Agent can discover Milvus containers automatically, plus e2e coverage for the generated candidates. Environment: Datadog workspace Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * milvus: add changelog entry for discovery support Environment: Datadog workspace Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix * Update milvus/changelog.d/24319.added Co-authored-by: dkirov-dd <166512750+dkirov-dd@users.noreply.github.com> --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com> Co-authored-by: dkirov-dd <166512750+dkirov-dd@users.noreply.github.com>
1 parent 89fc290 commit d162b4d

8 files changed

Lines changed: 143 additions & 12 deletions

File tree

milvus/assets/configuration/spec.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@ name: Milvus
22
fleet_configurable: true
33
files:
44
- name: milvus.yaml
5+
discovery:
6+
strategies:
7+
- template: discovery/openmetrics_from_ports
8+
overrides:
9+
port_hints:
10+
- 9091
511
options:
612
- template: init_config
713
options:
@@ -19,3 +25,10 @@ files:
1925
- type: docker
2026
source: milvus
2127
service: <SERVICE>
28+
- name: auto_conf.yaml
29+
options:
30+
- template: ad_identifiers
31+
overrides:
32+
value.example:
33+
- milvus
34+
- template: auto_conf/discovery

milvus/changelog.d/24319.added

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add container-based config discovery support.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# (C) Datadog, Inc. 2026-present
2+
# All rights reserved
3+
# Licensed under a 3-clause BSD style license (see LICENSE)
4+
5+
# This file is autogenerated.
6+
# To change this file you should edit assets/configuration/spec.yaml and then run the following commands:
7+
# ddev -x validate config -s <INTEGRATION_NAME>
8+
# ddev -x validate models -s <INTEGRATION_NAME>
9+
10+
from __future__ import annotations
11+
12+
from collections.abc import Iterator
13+
from typing import Any
14+
15+
from datadog_checks.base.utils.discovery import Service, candidate_ports
16+
from datadog_checks.milvus.config_models import discovery_overrides
17+
from datadog_checks.milvus.config_models.instance import InstanceConfig
18+
from datadog_checks.milvus.config_models.shared import SharedConfig
19+
20+
21+
def _generated_candidates(service: Service) -> Iterator[dict[str, Any]]:
22+
shared = SharedConfig.model_validate({}, context={'configured_fields': frozenset()}).model_dump(
23+
by_alias=True, mode='json', exclude_none=True
24+
)
25+
# discovery[0]: from_ports
26+
for port in candidate_ports(service, [9091]):
27+
ctx = {'port': port}
28+
instance_data = {
29+
'openmetrics_endpoint': 'http://{service.host}:{port.number}/metrics'.format(service=service, **ctx),
30+
}
31+
instance = InstanceConfig.model_validate(
32+
instance_data, context={'configured_fields': frozenset(instance_data)}
33+
).model_dump(by_alias=True, mode='json', exclude_none=True)
34+
yield {'init_config': shared, 'instances': [instance]}
35+
36+
37+
def candidates(service: Service) -> Iterator[dict[str, Any]]:
38+
override = getattr(discovery_overrides, 'candidates', None)
39+
if override is None:
40+
yield from _generated_candidates(service)
41+
else:
42+
yield from override(service, default=_generated_candidates)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# (C) Datadog, Inc. 2026-present
2+
# All rights reserved
3+
# Licensed under a 3-clause BSD style license (see LICENSE)
4+
# Override the generated discovery candidates() for this integration.
5+
#
6+
# Define a candidates(service, default) function to wrap or replace the generated
7+
# candidate generation. `default` is the generated generator; call it to reuse
8+
# the spec-driven candidates, or ignore it to replace them entirely.
9+
#
10+
# def candidates(service, default):
11+
# yield from default(service)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# (C) Datadog, Inc. 2026-present
2+
# All rights reserved
3+
# Licensed under a 3-clause BSD style license (see LICENSE)
4+
# Here you can define custom (local:) discovery strategies for this integration.
5+
#
6+
# Decorate a generator with @discovery_strategy (imported from
7+
# datadog_checks.base.utils.discovery) and reference it from the spec discovery
8+
# stanza as `strategy: local:<function_name>`. The function receives the
9+
# discovered Service plus the inputs declared in the spec and yields one context
10+
# (ctx) mapping per candidate, exposing the keys listed in `provides`.
11+
#
12+
# from datadog_checks.base.utils.discovery import discovery_strategy
13+
#
14+
# @discovery_strategy(provides=('svc',))
15+
# def from_some_config(service, config_path):
16+
# ...
17+
# yield {'svc': ...}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
## @param ad_identifiers - list of strings - required
2+
## A list of container identifiers that are used by Autodiscovery to identify
3+
## which container the check should be run against. For more information, see:
4+
## https://docs.datadoghq.com/agent/guide/ad_identifiers/
5+
#
6+
ad_identifiers:
7+
- milvus
8+
9+
## Enables configuration discovery
10+
#
11+
discovery: {}
12+
13+
## Unused init configuration
14+
#
15+
init_config:
16+
17+
## Unused instance configuration
18+
#
19+
instances: []

milvus/tests/conftest.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import pytest
88

9-
from datadog_checks.dev import docker_run
9+
from datadog_checks.dev import docker_run, get_e2e_discovery_metadata
1010
from datadog_checks.dev.conditions import CheckDockerLogs, CheckEndpoints
1111

1212
from . import common
@@ -23,9 +23,12 @@ def dd_environment():
2323
]
2424
logging.info(conditions)
2525
with docker_run(compose_file, conditions=conditions):
26-
yield {
27-
'instances': [common.MOCKED_INSTANCE],
28-
}
26+
yield (
27+
{
28+
'instances': [common.MOCKED_INSTANCE],
29+
},
30+
get_e2e_discovery_metadata(),
31+
)
2932

3033

3134
@pytest.fixture

milvus/tests/test_e2e.py

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,45 @@
44
import pytest
55

66
from datadog_checks.base.constants import ServiceCheck
7+
from datadog_checks.dev.docker import CONTAINER_STABILITY_LOG_PATTERNS, assert_all_discovery_candidates_stable
8+
from datadog_checks.milvus import MilvusCheck
79

810
from . import common
911

12+
SKIPPED_METRICS = [
13+
'milvus.datacoord.import_tasks',
14+
'milvus.datacoord.index.task',
15+
] # these metrics need a more complex setup to appear
16+
17+
# Milvus standalone logs benign "error"-keyed WARN messages while its internal coordinators
18+
# come up asynchronously (e.g. etcd leader elections, gRPC clients retrying until ready), so the
19+
# generic "error" pattern is dropped in favor of the more specific crash indicators.
20+
DISCOVERY_STABILITY_LOG_PATTERNS = tuple(pattern for pattern in CONTAINER_STABILITY_LOG_PATTERNS if pattern != 'error')
1021

11-
@pytest.mark.e2e
12-
def test_check_milvus_e2e(dd_agent_check, instance):
13-
aggregator = dd_agent_check(instance, rate=True)
1422

15-
for metric, _ in common.STANDALONE_TEST_METRICS.items():
16-
if metric in [
17-
'milvus.datacoord.import_tasks',
18-
'milvus.datacoord.index.task',
19-
]: # these metrics need a more complex setup to appear
23+
def assert_standalone_metrics(aggregator):
24+
for metric in common.STANDALONE_TEST_METRICS:
25+
if metric in SKIPPED_METRICS:
2026
continue
2127
aggregator.assert_metric(name=metric)
2228

2329
aggregator.assert_service_check('milvus.openmetrics.health', ServiceCheck.OK)
30+
31+
32+
@pytest.mark.e2e
33+
def test_check_milvus_e2e(dd_agent_check, instance):
34+
aggregator = dd_agent_check(instance, rate=True)
35+
assert_standalone_metrics(aggregator)
36+
37+
38+
@pytest.mark.e2e
39+
def test_e2e_discovery(dd_agent_check_discovery):
40+
aggregator = dd_agent_check_discovery(rate=True)
41+
assert_standalone_metrics(aggregator)
42+
43+
44+
@pytest.mark.e2e
45+
def test_e2e_discovery_all_candidates(dd_agent_check):
46+
assert_all_discovery_candidates_stable(
47+
dd_agent_check, MilvusCheck, compose_service='milvus', log_patterns=DISCOVERY_STABILITY_LOG_PATTERNS
48+
)

0 commit comments

Comments
 (0)