Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

mcache check supports IPv6 address #19359

Merged
merged 2 commits into from
Jan 10, 2025
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
2 changes: 1 addition & 1 deletion agent_requirements.in
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pysmi==1.2.1
pysnmp-mibs==0.1.6
pysnmp==5.1.0
pysocks==1.7.1
python-binary-memcached==0.31.2; sys_platform != 'win32'
python-binary-memcached==0.31.4; sys_platform != 'win32'
python-dateutil==2.9.0.post0
python3-gearman==0.1.0; sys_platform != 'win32'
pyvmomi==8.0.3.0.1
Expand Down
1 change: 1 addition & 0 deletions mcache/changelog.d/19359.added
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Support IPv6.
15 changes: 15 additions & 0 deletions mcache/datadog_checks/mcache/mcache.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
# Licensed under Simplified BSD License (see LICENSE)
from __future__ import division

from ipaddress import IPv6Address

import bmemcached

from datadog_checks.base import AgentCheck, ConfigurationError
Expand Down Expand Up @@ -175,6 +177,13 @@ def _get_metrics(self, client, tags, service_check_tags=None):
except BadResponseError:
raise

def _is_ipv6(self, address):
try:
IPv6Address(address)
return True
except ValueError:
return False

def _get_optional_metrics(self, client, tags, options=None):
for arg, metrics_args in self.OPTIONAL_STATS.items():
if not options or options.get(arg, False):
Expand Down Expand Up @@ -257,6 +266,12 @@ def check(self, instance):
if not server and not socket:
raise InvalidConfigError('Either "url" or "socket" must be configured')

if self._is_ipv6(server):
# When it is already enclosed, this code path is not executed.
# bmemcached requires IPv6 addresses to be enclosed in brackets,
# because we set port with IP address at the client initialization.
server = "[{}]".format(server)

if socket:
server = 'unix'
port = socket
Expand Down
2 changes: 1 addition & 1 deletion mcache/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ dynamic = [

[project.optional-dependencies]
deps = [
"python-binary-memcached==0.31.2; sys_platform != 'win32'",
"python-binary-memcached==0.31.4; sys_platform != 'win32'",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This patch version includes jaysonsantos/python-binary-memcached#258

]

[project.urls]
Expand Down
17 changes: 17 additions & 0 deletions mcache/tests/compose/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,20 @@ services:
volumes:
- ${HOST_SOCKET_DIR}:${DOCKER_SOCKET_DIR}
command: memcached -S -s ${DOCKER_SOCKET_PATH} -a 777

memcached_ipv6:
image: datadog/docker-library:memcached_SASL
environment:
USERNAME: testuser
PASSWORD: testpass
networks:
ip6net:
ipv6_address: 2001:db8::2
command: "memcached -S -l::"

networks:
ip6net:
enable_ipv6: true
ipam:
config:
- subnet: 2001:db8::/64
17 changes: 17 additions & 0 deletions mcache/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,17 @@ def dd_environment(e2e_instance):
yield e2e_instance


@pytest.fixture(scope='session')
def dd_environment_ipv6(instance_ipv6):
with docker_run(
os.path.join(HERE, 'compose', 'docker-compose.yaml'),
service_name='memcached_ipv6',
env_vars={'PWD': HERE},
conditions=[WaitFor(connect_to_mcache, args=(['{}:{}'.format('[2001:db8::2]', PORT)], USERNAME, PASSWORD))],
):
yield instance_ipv6


@pytest.fixture
def client():
return bmemcached.Client(["{}:{}".format(HOST, PORT)], USERNAME, PASSWORD)
Expand Down Expand Up @@ -93,3 +104,9 @@ def e2e_instance():
@pytest.fixture
def instance_socket():
return {'socket': get_host_socket_path(), 'tags': ['foo:bar'], 'username': USERNAME, 'password': PASSWORD}


@pytest.fixture(scope='session')
def instance_ipv6():
# This IPv6 address is defined in the docker-compose file.
return {'url': '2001:db8::2', 'port': PORT, 'tags': ['foo:bar'], 'username': USERNAME, 'password': PASSWORD}
15 changes: 15 additions & 0 deletions mcache/tests/test_integration_e2e.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,18 @@ def test_connections_leaks(check, instance):
check.check(instance)
# Verify that the count is still 0
assert count_connections(PORT) == 0


@pytest.mark.integration
@pytest.mark.usefixtures('dd_environment_ipv6')
def test_service_ok_ipv6(instance_ipv6, aggregator, dd_run_check):
"""
Service is up
"""
tags = ["host:[2001:db8::2]", "port:{}".format(PORT), "foo:bar"]
check = Memcache('mcache', {}, [instance_ipv6])
dd_run_check(check)
assert len(aggregator.service_checks(SERVICE_CHECK)) == 1
sc = aggregator.service_checks(SERVICE_CHECK)[0]
assert sc.status == check.OK
assert sc.tags == tags
Loading