Skip to content

Commit a51c86a

Browse files
vitkyrkaclaude
andauthored
Add container-based config discovery support to weaviate
Adds a `from_ports`-based discovery strategy scoped to weaviate's OpenMetrics port (2112) and wires the kind-based E2E harness to exercise it against a real Kubernetes cluster via the new kube_discovery helpers. Environment: Datadog workspace Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1 parent 2c0dc75 commit a51c86a

7 files changed

Lines changed: 144 additions & 2 deletions

File tree

weaviate/assets/configuration/spec.yaml

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@ name: Weaviate
22
fleet_configurable: true
33
files:
44
- name: weaviate.yaml
5+
discovery:
6+
strategies:
7+
- template: discovery/openmetrics_from_ports
8+
overrides:
9+
port_hints:
10+
- 2112
511
options:
612
- template: init_config
713
options:
@@ -25,4 +31,12 @@ files:
2531
value:
2632
display_default: null
2733
example: http://localhost:8080
28-
type: string
34+
type: string
35+
36+
- name: auto_conf.yaml
37+
options:
38+
- template: ad_identifiers
39+
overrides:
40+
value.example:
41+
- weaviate
42+
- template: auto_conf/discovery
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.weaviate.config_models import discovery_overrides
17+
from datadog_checks.weaviate.config_models.instance import InstanceConfig
18+
from datadog_checks.weaviate.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, [2112]):
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: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# (C) Datadog, Inc. 2026-present
2+
# All rights reserved
3+
# Licensed under a 3-clause BSD style license (see LICENSE)
4+
5+
# Override the generated discovery candidates() for this integration.
6+
#
7+
# Define a candidates(service, default) function to wrap or replace the generated
8+
# candidate generation. `default` is the generated generator; call it to reuse
9+
# the spec-driven candidates, or ignore it to replace them entirely.
10+
#
11+
# def candidates(service, default):
12+
# yield from default(service)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# (C) Datadog, Inc. 2026-present
2+
# All rights reserved
3+
# Licensed under a 3-clause BSD style license (see LICENSE)
4+
5+
# Here you can define custom (local:) discovery strategies for this integration.
6+
#
7+
# Decorate a generator with @discovery_strategy (imported from
8+
# datadog_checks.base.utils.discovery) and reference it from the spec discovery
9+
# stanza as `strategy: local:<function_name>`. The function receives the
10+
# discovered Service plus the inputs declared in the spec and yields one context
11+
# (ctx) mapping per candidate, exposing the keys listed in `provides`.
12+
#
13+
# from datadog_checks.base.utils.discovery import discovery_strategy
14+
#
15+
# @discovery_strategy(provides=('svc',))
16+
# def from_some_config(service, config_path):
17+
# ...
18+
# 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+
- weaviate
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: []

weaviate/tests/conftest.py

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

1212
from datadog_checks.dev import get_here
1313
from datadog_checks.dev.kind import kind_run
14+
from datadog_checks.dev.kube_discovery import save_kube_discovery_state, setup_discovery_agent
1415
from datadog_checks.dev.kube_port_forward import port_forward
1516
from datadog_checks.dev.subprocess import run_command
1617
from datadog_checks.weaviate.check import DEFAULT_LIVENESS_ENDPOINT
@@ -37,6 +38,9 @@ def setup_weaviate():
3738
@pytest.fixture(scope='session')
3839
def dd_environment():
3940
with kind_run(conditions=[setup_weaviate]) as kubeconfig, ExitStack() as stack:
41+
setup_discovery_agent(kubeconfig)
42+
save_kube_discovery_state(kubeconfig)
43+
4044
weaviate_host, weaviate_port = stack.enter_context(
4145
port_forward(kubeconfig, 'weaviate', 2112, 'statefulset', 'weaviate')
4246
)

weaviate/tests/test_e2e.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,14 @@
44
import pytest
55

66
from datadog_checks.base.constants import ServiceCheck
7+
from datadog_checks.dev.kube_discovery import (
8+
assert_all_discovery_candidates_stable_kubernetes,
9+
run_discovery_check_kubernetes,
10+
)
711
from datadog_checks.dev.utils import get_metadata_metrics
12+
from datadog_checks.weaviate import WeaviateCheck
813

9-
from .common import E2E_METRICS, FLAKY_E2E_METRICS
14+
from .common import E2E_METRICS, FLAKY_E2E_METRICS, OM_METRICS
1015

1116

1217
@pytest.mark.e2e
@@ -22,3 +27,31 @@ def test_e2e_openmetrics_v2(dd_agent_check):
2227

2328
aggregator.assert_all_metrics_covered()
2429
aggregator.assert_metrics_using_metadata(get_metadata_metrics())
30+
31+
32+
@pytest.mark.e2e
33+
def test_e2e_discovery(aggregator, datadog_agent):
34+
# Discovery only knows about the metrics port (2112), not the Restful API port (8080), so it
35+
# can't populate `weaviate_api_endpoint` — only the OpenMetrics metrics are collected here.
36+
run_discovery_check_kubernetes(aggregator, datadog_agent, check_rate=True)
37+
38+
aggregator.assert_service_check('weaviate.openmetrics.health', ServiceCheck.OK, count=2)
39+
for metric in OM_METRICS:
40+
if metric in FLAKY_E2E_METRICS:
41+
aggregator.assert_metric(metric, at_least=0)
42+
else:
43+
aggregator.assert_metric(metric)
44+
45+
aggregator.assert_all_metrics_covered()
46+
aggregator.assert_metrics_using_metadata(get_metadata_metrics())
47+
48+
49+
@pytest.mark.e2e
50+
def test_e2e_discovery_all_candidates(aggregator, datadog_agent):
51+
assert_all_discovery_candidates_stable_kubernetes(
52+
WeaviateCheck,
53+
aggregator,
54+
datadog_agent,
55+
namespace='weaviate',
56+
pod_selector='app=weaviate',
57+
)

0 commit comments

Comments
 (0)