Skip to content

Commit ef41af5

Browse files
authored
Propagate agent host tags for mysql (#18400)
1 parent 9eb8f2d commit ef41af5

File tree

10 files changed

+139
-8
lines changed

10 files changed

+139
-8
lines changed

mysql/assets/configuration/spec.yaml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ files:
44
options:
55
- template: init_config
66
options:
7+
- name: propagate_agent_tags
8+
description: |
9+
Set to `true` to propagate the tags from `datadog.yaml` to the check.
10+
When set to `true`, the tags from `datadog.yaml` are added to the check's tags for all instances.
11+
value:
12+
example: false
13+
type: boolean
714
- template: init_config/db
815
overrides:
916
global_custom_queries.value.example:
@@ -49,6 +56,14 @@ files:
4956
type: number
5057
example: 3306
5158

59+
- name: propagate_agent_tags
60+
description: |
61+
Set to `true` to propagate the tags from `datadog.yaml` to the check.
62+
When set to `true`, the tags from `datadog.yaml` are added to the check's tags for all instances.
63+
value:
64+
example: false
65+
type: boolean
66+
5267
- name: reported_hostname
5368
description: |
5469
Set the reported hostname for this instance. This value overrides the hostname detected by the Agent
@@ -390,7 +405,7 @@ files:
390405
Capped by `schemas_collection.collection_interval`
391406
value:
392407
type: number
393-
example: 60
408+
example: 60
394409
- name: query_metrics
395410
description: Configure collection of query metrics
396411
options:

mysql/changelog.d/18400.added

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Update the propagate_agent_tags setting. When set to `true`, the tags from the agent host are now added to the check's tags for all instances.

mysql/datadog_checks/mysql/config.py

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@
44
from datadog_checks.base import ConfigurationError, is_affirmative
55
from datadog_checks.base.log import get_check_logger
66
from datadog_checks.base.utils.aws import rds_parse_tags_from_endpoint
7+
from datadog_checks.base.utils.db.utils import get_agent_host_tags
78

89
DEFAULT_MAX_CUSTOM_QUERIES = 20
910

1011

1112
class MySQLConfig(object):
12-
def __init__(self, instance):
13+
def __init__(self, instance, init_config):
1314
self.log = get_check_logger()
1415
self.host = instance.get('host', instance.get('server', ''))
1516
self.port = int(instance.get('port', 0))
@@ -18,7 +19,10 @@ def __init__(self, instance):
1819
self.defaults_file = instance.get('defaults_file', '')
1920
self.user = instance.get('username', instance.get('user', ''))
2021
self.password = str(instance.get('password', instance.get('pass', '')))
21-
self.tags = self._build_tags(instance.get('tags', []))
22+
self.tags = self._build_tags(
23+
custom_tags=instance.get('tags', []),
24+
propagate_agent_tags=self._should_propagate_agent_tags(instance, init_config),
25+
)
2226
self.options = instance.get('options', {}) or {} # options could be None if empty in the YAML
2327
replication_channel = self.options.get('replication_channel')
2428
if replication_channel:
@@ -94,12 +98,26 @@ def __init__(self, instance):
9498
self.database_instance_collection_interval = instance.get('database_instance_collection_interval', 300)
9599
self.configuration_checks()
96100

97-
def _build_tags(self, custom_tags):
98-
tags = list(set(custom_tags)) or []
101+
def _build_tags(self, custom_tags, propagate_agent_tags):
102+
# Clean up tags in case there was a None entry in the instance
103+
# e.g. if the yaml contains tags: but no actual tags
104+
if custom_tags is None:
105+
tags = []
106+
else:
107+
tags = list(set(custom_tags))
99108

100109
rds_tags = rds_parse_tags_from_endpoint(self.host)
101110
if rds_tags:
102111
tags.extend(rds_tags)
112+
113+
if propagate_agent_tags:
114+
try:
115+
agent_tags = get_agent_host_tags()
116+
tags.extend(agent_tags)
117+
except Exception as e:
118+
raise ConfigurationError(
119+
'propagate_agent_tags enabled but there was an error fetching agent tags {}'.format(e)
120+
)
103121
return tags
104122

105123
def configuration_checks(self):
@@ -119,3 +137,20 @@ def configuration_checks(self):
119137

120138
if self.mysql_sock and self.host:
121139
self.log.warning("Both socket and host have been specified, socket will be used")
140+
141+
@staticmethod
142+
def _should_propagate_agent_tags(instance, init_config) -> bool:
143+
'''
144+
return True if the agent tags should be propagated to the check
145+
'''
146+
instance_propagate_agent_tags = instance.get('propagate_agent_tags')
147+
init_config_propagate_agent_tags = init_config.get('propagate_agent_tags')
148+
149+
if instance_propagate_agent_tags is not None:
150+
# if the instance has explicitly set the value, return the boolean
151+
return instance_propagate_agent_tags
152+
if init_config_propagate_agent_tags is not None:
153+
# if the init_config has explicitly set the value, return the boolean
154+
return init_config_propagate_agent_tags
155+
# if neither the instance nor the init_config has set the value, return False
156+
return False

mysql/datadog_checks/mysql/config_models/defaults.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
# ddev -x validate models -s <INTEGRATION_NAME>
99

1010

11+
def shared_propagate_agent_tags():
12+
return False
13+
14+
1115
def instance_connect_timeout():
1216
return 10
1317

@@ -52,5 +56,9 @@ def instance_port():
5256
return 3306
5357

5458

59+
def instance_propagate_agent_tags():
60+
return False
61+
62+
5563
def instance_use_global_custom_queries():
5664
return 'true'

mysql/datadog_checks/mysql/config_models/instance.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ class InstanceConfig(BaseModel):
205205
options: Optional[Options] = None
206206
password: Optional[str] = None
207207
port: Optional[float] = None
208+
propagate_agent_tags: Optional[bool] = None
208209
queries: Optional[tuple[MappingProxyType[str, Any], ...]] = None
209210
query_activity: Optional[QueryActivity] = None
210211
query_metrics: Optional[QueryMetrics] = None

mysql/datadog_checks/mysql/config_models/shared.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from datadog_checks.base.utils.functions import identity
1818
from datadog_checks.base.utils.models import validation
1919

20-
from . import validators
20+
from . import defaults, validators
2121

2222

2323
class SharedConfig(BaseModel):
@@ -27,6 +27,7 @@ class SharedConfig(BaseModel):
2727
frozen=True,
2828
)
2929
global_custom_queries: Optional[tuple[MappingProxyType[str, Any], ...]] = None
30+
propagate_agent_tags: Optional[bool] = None
3031
service: Optional[str] = None
3132

3233
@model_validator(mode='before')
@@ -39,6 +40,8 @@ def _validate(cls, value, info):
3940
field_name = field.alias or info.field_name
4041
if field_name in info.context['configured_fields']:
4142
value = getattr(validators, f'shared_{info.field_name}', identity)(value, field=field)
43+
else:
44+
value = getattr(defaults, f'shared_{info.field_name}', lambda: value)()
4245

4346
return validation.utils.make_immutable(value)
4447

mysql/datadog_checks/mysql/data/conf.yaml.example

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
#
33
init_config:
44

5+
## @param propagate_agent_tags - boolean - optional - default: false
6+
## Set to `true` to propagate the tags from `datadog.yaml` to the check.
7+
## When set to `true`, the tags from `datadog.yaml` are added to the check's tags for all instances.
8+
#
9+
# propagate_agent_tags: false
10+
511
## @param global_custom_queries - list of mappings - optional
612
## See `custom_queries` defined below.
713
##
@@ -46,6 +52,12 @@ instances:
4652
#
4753
port: 3306
4854

55+
## @param propagate_agent_tags - boolean - optional - default: false
56+
## Set to `true` to propagate the tags from `datadog.yaml` to the check.
57+
## When set to `true`, the tags from `datadog.yaml` are added to the check's tags for all instances.
58+
#
59+
# propagate_agent_tags: false
60+
4961
## @param reported_hostname - string - optional
5062
## Set the reported hostname for this instance. This value overrides the hostname detected by the Agent
5163
## and can be useful to set a custom hostname when connecting to a remote database through a proxy.

mysql/datadog_checks/mysql/mysql.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ def __init__(self, name, init_config, instances):
115115
self._resolved_hostname = None
116116
self._agent_hostname = None
117117
self._is_aurora = None
118-
self._config = MySQLConfig(self.instance)
118+
self._config = MySQLConfig(self.instance, init_config)
119119
self.tags = self._config.tags
120120
self.cloud_metadata = self._config.cloud_metadata
121121

mysql/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ classifiers = [
2828
"Private :: Do Not Upload",
2929
]
3030
dependencies = [
31-
"datadog-checks-base>=36.5.0",
31+
"datadog-checks-base>=36.14.0",
3232
]
3333
dynamic = [
3434
"version",

mysql/tests/test_mysql.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,3 +759,59 @@ def test_database_instance_metadata(aggregator, dd_run_check, instance_complex,
759759
dbm_metadata = aggregator.get_event_platform_events("dbm-metadata")
760760
event = next((e for e in dbm_metadata if e['kind'] == 'database_instance'), None)
761761
assert event is None
762+
763+
764+
@pytest.mark.parametrize(
765+
'instance_propagate_agent_tags,init_config_propagate_agent_tags,should_propagate_agent_tags',
766+
[
767+
pytest.param(True, True, True, id="both true"),
768+
pytest.param(True, False, True, id="instance config true prevails"),
769+
pytest.param(False, True, False, id="instance config false prevails"),
770+
pytest.param(False, False, False, id="both false"),
771+
pytest.param(None, True, True, id="init_config true applies to all instances"),
772+
pytest.param(None, False, False, id="init_config false applies to all instances"),
773+
pytest.param(None, None, False, id="default to false"),
774+
pytest.param(True, None, True, id="instance config true prevails, init_config is None"),
775+
pytest.param(False, None, False, id="instance config false prevails, init_config is None"),
776+
],
777+
)
778+
@pytest.mark.integration
779+
def test_propagate_agent_tags(
780+
aggregator,
781+
dd_run_check,
782+
instance_basic,
783+
instance_propagate_agent_tags,
784+
init_config_propagate_agent_tags,
785+
should_propagate_agent_tags,
786+
):
787+
instance_basic['propagate_agent_tags'] = instance_propagate_agent_tags
788+
init_config = {}
789+
if init_config_propagate_agent_tags is not None:
790+
init_config['propagate_agent_tags'] = init_config_propagate_agent_tags
791+
792+
agent_tags = ['my-env:test-env', 'random:tag', 'bar:foo']
793+
expected_tags = (
794+
instance_basic.get('tags', [])
795+
+ [
796+
'server:{}'.format(HOST),
797+
'port:{}'.format(PORT),
798+
'dd.internal.resource:database_instance:forced_hostname',
799+
"dd.internal.resource:aws_rds_instance:foo.aws.com",
800+
"dd.internal.resource:azure_mysql_server:my-instance",
801+
'dd.internal.resource:gcp_sql_database_instance:foo-project:bar',
802+
]
803+
+ agent_tags
804+
)
805+
806+
with mock.patch('datadog_checks.mysql.config.get_agent_host_tags', return_value=agent_tags):
807+
check = MySql(common.CHECK_NAME, init_config, [instance_basic])
808+
assert check._config._should_propagate_agent_tags(instance_basic, init_config) == should_propagate_agent_tags
809+
if should_propagate_agent_tags:
810+
assert all(tag in check.tags for tag in agent_tags)
811+
dd_run_check(check)
812+
aggregator.assert_service_check(
813+
'mysql.can_connect',
814+
count=1,
815+
status=MySql.OK,
816+
tags=expected_tags,
817+
)

0 commit comments

Comments
 (0)