Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 datadog_checks_base/changelog.d/24555.added
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add a discovery helper for selecting service ports by name.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# (C) Datadog, Inc. 2025-present
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)
from .discovery import Discovery, Port, Service, candidate_ports
from .discovery import Discovery, Port, Service, candidate_ports, candidate_ports_by_name
from .strategies import discovery_strategy

__all__ = ['Discovery', 'Port', 'Service', 'candidate_ports', 'discovery_strategy']
__all__ = ['Discovery', 'Port', 'Service', 'candidate_ports', 'candidate_ports_by_name', 'discovery_strategy']
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,16 @@ def candidate_ports(service: Service, hints: Iterable[int]) -> Iterator[Port]:
if port.number not in seen:
seen.add(port.number)
yield port


def candidate_ports_by_name(service: Service, names: Iterable[str]) -> Iterator[Port]:
"""Yield ports matching each name in order, with no fallback to unmatched ports."""
seen: set[int] = set()

for name in dict.fromkeys(names):
if not name:
continue
for port in service.ports:
if port.name == name and port.number not in seen:
seen.add(port.number)
yield port
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import mock
import pytest

from datadog_checks.base.utils.discovery import Discovery, Port, Service, candidate_ports
from datadog_checks.base.utils.discovery import Discovery, Port, Service, candidate_ports, candidate_ports_by_name


def test_include_empty():
Expand Down Expand Up @@ -209,6 +209,70 @@ def test_candidate_ports_prefers_hints_and_deduplicates():
]


@pytest.mark.parametrize(
"ports, names, expected",
[
pytest.param(
(
Port(number=8080, name='http'),
Port(number=9090, name='metrics'),
Port(number=8081, name='admin'),
),
['metrics', 'http-prom'],
[Port(number=9090, name='metrics')],
id="only_yields_matching_ports",
),
pytest.param(
(
Port(number=8080, name='bar'),
Port(number=9090, name='foo'),
Port(number=8081, name='bar'),
Port(number=9091, name='foo'),
),
['foo', 'bar'],
[
Port(number=9090, name='foo'),
Port(number=9091, name='foo'),
Port(number=8080, name='bar'),
Port(number=8081, name='bar'),
],
id="respects_name_priority",
),
pytest.param(
(
Port(number=8080, name='http'),
Port(number=8081, name='admin'),
),
['metrics'],
[],
id="does_not_fallback_to_other_ports",
),
pytest.param(
(
Port(number=8443, name='metrics'),
Port(number=8443, name='http-metrics'),
Port(number=9443, name='metrics'),
),
['http-metrics', 'metrics'],
[
Port(number=8443, name='http-metrics'),
Port(number=9443, name='metrics'),
],
id="deduplicates_matching_port_numbers",
),
pytest.param(
(Port(number=8080, name=''),),
[''],
[],
id="ignores_empty_names",
),
],
)
def test_candidate_ports_by_name(ports, names, expected):
service = Service(id='svc', host='127.0.0.1', ports=ports)
assert list(candidate_ports_by_name(service, names)) == expected


def test_dev_placeholder_field_constants_match_models():
"""Guard the one fact datadog_checks_dev must hand-copy from base.

Expand Down
Loading