Skip to content

Commit d98faec

Browse files
authored
Merge branch 'master' into sy/ddev-bump-dcd
2 parents c2d6133 + 98a519e commit d98faec

File tree

20 files changed

+169
-69
lines changed

20 files changed

+169
-69
lines changed

.in-toto/tag.ec45eb9d.link

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

datadog_checks_dev/CHANGELOG.md

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

33
<!-- towncrier release notes start -->
44

5+
## 32.1.1 / 2024-05-09
6+
7+
***Fixed***:
8+
9+
* Fix trailing `,` in manifest.json generation template ([#17538](https://github.com/DataDog/integrations-core/pull/17538))
10+
511
## 32.1.0 / 2024-05-03
612

713
***Added***:

datadog_checks_dev/changelog.d/17538.fixed

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# (C) Datadog, Inc. 2018-present
22
# All rights reserved
33
# Licensed under a 3-clause BSD style license (see LICENSE)
4-
__version__ = '32.1.0'
4+
__version__ = '32.1.1'

ddev/changelog.d/17521.added

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add sample_tags to metadata validation

ddev/src/ddev/cli/validate/metadata.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,12 +130,17 @@ def metadata(app: Application, integrations: tuple[str, ...], check_duplicates:
130130

131131
error_message += f"{current_check.name}:{line} Invalid column {invalid_headers}.\n"
132132

133-
missing_headers = metadata_utils.ALL_HEADERS.difference(all_keys)
133+
missing_headers = metadata_utils.HEADERS_TO_CHECK.difference(all_keys)
134134
if missing_headers:
135135
errors = True
136136

137137
error_message += f"{current_check.name}:{line} Missing columns {missing_headers}.\n"
138-
continue
138+
139+
if errors:
140+
# There's now an optional sample_tag column that isn't added yet to the existing metadata.csv
141+
# all_keys will not be same as ALL_HEADERS. But since that sample_tag column is optional and not
142+
# inside HEADERS_TO_CHECK, we should only continue if there's an invalid header or missing_header.
143+
continue
139144

140145
# check duplicate metric name
141146
duplicate_metric_name = check_duplicate_values(

ddev/src/ddev/cli/validate/metadata_utils.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,18 @@
55

66
REQUIRED_HEADERS = {'metric_name', 'metric_type', 'orientation', 'integration'}
77

8-
OPTIONAL_HEADERS = {'description', 'interval', 'unit_name', 'per_unit_name', 'short_name', 'curated_metric'}
8+
OPTIONAL_HEADERS = {
9+
'description',
10+
'interval',
11+
'unit_name',
12+
'per_unit_name',
13+
'short_name',
14+
'curated_metric',
15+
}
916

10-
ALL_HEADERS = REQUIRED_HEADERS | OPTIONAL_HEADERS
17+
EXPERIMENTAL_HEADER = {"sample_tags"}
18+
ALL_HEADERS = REQUIRED_HEADERS | OPTIONAL_HEADERS | EXPERIMENTAL_HEADER
19+
HEADERS_TO_CHECK = REQUIRED_HEADERS | OPTIONAL_HEADERS
1120

1221
ORDERED_HEADERS = [
1322
"metric_name",
@@ -20,6 +29,7 @@
2029
"integration",
2130
"short_name",
2231
"curated_metric",
32+
"sample_tags",
2333
]
2434

2535
VALID_METRIC_TYPE = {'count', 'gauge', 'rate'}

ddev/tests/cli/validate/test_metrics.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,58 @@ def test_metrics_ordered(fake_repo, ddev, helpers):
715715
)
716716

717717

718+
def test_passing_with_experimental_column(fake_repo, ddev, helpers):
719+
# Testing to ensure that experimental header sample_tags is allowed
720+
write_file(
721+
fake_repo.path / "metadata_integration",
722+
'metadata.csv',
723+
"""metric_name,metric_type,interval,unit_name,per_unit_name,description,orientation,integration,short_name,curated_metric,sample_tags
724+
metadata_integration.metric_a,gauge,,,,My metric A,0,metadata_integration,,,
725+
metadata_integration.metric_b,gauge,,,,My metric B,0,metadata_integration,,,
726+
""",
727+
)
728+
729+
result = ddev('validate', 'metadata', 'metadata_integration')
730+
731+
assert result.exit_code == 0, result.output
732+
assert helpers.remove_trailing_spaces(result.output) == helpers.dedent(
733+
"""
734+
Metrics validation
735+
736+
Passed: 1
737+
"""
738+
)
739+
740+
741+
def test_passing_invalid_experimental_column(fake_repo, ddev, helpers):
742+
# Testing to ensure that experimental header sample_tags is allowed. But if other tags are added,
743+
# it will be flagged as an error
744+
write_file(
745+
fake_repo.path / "metadata_integration",
746+
'metadata.csv',
747+
"""metric_name,metric_type,interval,unit_name,per_unit_name,description,orientation,integration,short_name,curated_metric,sample_tags,foo
748+
metadata_integration.metric_a,gauge,,,,My metric A,0,metadata_integration,,,,
749+
metadata_integration.metric_b,gauge,,,,My metric B,0,metadata_integration,,,,
750+
""",
751+
)
752+
outfile = os.path.join('metadata_integration', 'metadata.csv')
753+
result = ddev('validate', 'metadata', 'metadata_integration')
754+
755+
assert result.exit_code == 1, result.output
756+
assert helpers.remove_trailing_spaces(result.output) == helpers.dedent(
757+
f"""
758+
Metrics validation
759+
└── metadata_integration
760+
└── {outfile}
761+
762+
metadata_integration:2 Invalid column {{'foo'}}.
763+
metadata_integration:3 Invalid column {{'foo'}}.
764+
765+
Errors: 1
766+
"""
767+
)
768+
769+
718770
def test_metrics_not_ordered(fake_repo, ddev, helpers):
719771
outfile = os.path.join('metadata_integration', 'metadata.csv')
720772
result = ddev('validate', 'metadata', 'metadata_integration')

esxi/assets/configuration/spec.yaml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ files:
4242
value:
4343
type: boolean
4444
example: false
45+
- name: use_configured_hostname
46+
description: |
47+
If true, the check will use the configured `host` parameter for ESXi hostnames instead of the Host name.
48+
You may need to use this if you install both the vSphere check and ESXi check to avoid duplicate entries
49+
for hosts in the web application UI.
50+
value:
51+
type: boolean
52+
example: true
4553
- name: collect_per_instance_filters
4654
description: |
4755
Use this option to collect metrics tagged with instance values.
@@ -139,8 +147,8 @@ files:
139147
description: |
140148
Use this option to send a subset of host tags as metric tags.
141149
The ESXi integration collects tags for every ESXi host or VM in your environment.
142-
Those tags can be `esxi_url`, esxi_type`, `esxi_host`, `esxi_folder`, `esxi_cluster`
143-
`esxi_compute`, `esxi_datacenter`, `esxi_datastore` and are attached to the ESXi metrics by default.
150+
Those tags can be `esxi_url`, esxi_type`, `esxi_host`, and `esxi_datastore`
151+
and are attached to the ESXi metrics by default.
144152
By default these tags are submitted as host tags, but you can submit them as metric tags instead by using
145153
this configuration option, see: https://docs.datadoghq.com/tagging/using_tags/
146154
You will lose the ability to filter your hosts on the tags you specify but they will appear faster

esxi/changelog.d/17544.added

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add option to use configured host as hostname.

esxi/changelog.d/17549.fixed

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Remove invalid host tags

esxi/datadog_checks/esxi/check.py

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ def __init__(self, name, init_config, instances):
4444
self.host = self.instance.get("host")
4545
self.username = self.instance.get("username")
4646
self.password = self.instance.get("password")
47-
self.use_guest_hostname = self.instance.get("use_guest_hostname", False)
47+
self.use_guest_hostname = is_affirmative(self.instance.get("use_guest_hostname", False))
48+
self.use_configured_hostname = is_affirmative(self.instance.get("use_configured_hostname", False))
4849
self.excluded_host_tags = self._validate_excluded_host_tags(self.instance.get("excluded_host_tags", []))
4950
self.collect_per_instance_filters = self._parse_metric_regex_filters(
5051
self.instance.get("collect_per_instance_filters", {})
@@ -62,8 +63,7 @@ def _validate_excluded_host_tags(self, excluded_host_tags):
6263
if excluded_host_tag not in AVAILABLE_HOST_TAGS:
6364
self.log.warning(
6465
"Unknown host tag `%s` cannot be excluded. Available host tags are: "
65-
"`esxi_url`, `esxi_type`, `esxi_host`, `esxi_folder`, `esxi_cluster` "
66-
"`esxi_compute`, `esxi_datacenter`, and `esxi_datastore`",
66+
"`esxi_url`, `esxi_type`, `esxi_host`, `esxi_compute`, and `esxi_datastore`",
6767
excluded_host_tag,
6868
)
6969
else:
@@ -238,7 +238,7 @@ def get_available_metric_ids_for_entity(self, entity):
238238
metric_ids = [vim.PerformanceManager.MetricId(counterId=counter, instance="") for counter in counter_ids]
239239
return counter_keys_and_names, metric_ids
240240

241-
def collect_metrics_for_entity(self, metric_ids, counter_keys_and_names, entity, entity_name, metric_tags):
241+
def collect_metrics_for_entity(self, metric_ids, counter_keys_and_names, entity, hostname, metric_tags):
242242
resource_type = type(entity)
243243
resource_name = RESOURCE_TYPE_TO_NAME[resource_type]
244244
for metric_id in metric_ids:
@@ -297,7 +297,7 @@ def collect_metrics_for_entity(self, metric_ids, counter_keys_and_names, entity,
297297
self.log.debug(
298298
"Skipping metric %s for %s because no value was returned by the %s",
299299
metric_name,
300-
entity_name,
300+
hostname,
301301
resource_name,
302302
)
303303
continue
@@ -308,7 +308,7 @@ def collect_metrics_for_entity(self, metric_ids, counter_keys_and_names, entity,
308308
"Skipping metric %s for %s, because the value returned by the %s"
309309
" is negative (i.e. the metric is not yet available). values: %s",
310310
metric_name,
311-
entity_name,
311+
hostname,
312312
resource_name,
313313
list(metric_result.value),
314314
)
@@ -321,10 +321,10 @@ def collect_metrics_for_entity(self, metric_ids, counter_keys_and_names, entity,
321321
"Submit metric: name=`%s`, value=`%s`, hostname=`%s`, tags=`%s`",
322322
metric_name,
323323
most_recent_val,
324-
entity_name,
324+
hostname,
325325
all_tags,
326326
)
327-
self.gauge(metric_name, most_recent_val, hostname=entity_name, tags=all_tags)
327+
self.gauge(metric_name, most_recent_val, hostname=hostname, tags=all_tags)
328328

329329
def set_version_metadata(self):
330330
esxi_version = self.content.about.version
@@ -388,6 +388,8 @@ def check(self, _):
388388
}
389389

390390
for resource_obj, resource_props in all_resources_with_metrics.items():
391+
resource_type = type(resource_obj)
392+
resource_type_name = RESOURCE_TYPE_TO_NAME[resource_type]
391393

392394
if not is_resource_collected_by_filters(resource_obj, all_resources_with_metrics, self.resource_filters):
393395
self.log.debug(
@@ -397,16 +399,18 @@ def check(self, _):
397399

398400
hostname = resource_props.get("name")
399401

400-
resource_type = RESOURCE_TYPE_TO_NAME[type(resource_obj)]
401-
if resource_type == "vm" and self.use_guest_hostname:
402+
if resource_type == VM_RESOURCE and self.use_guest_hostname:
402403
hostname = resource_props.get("guest.hostName", hostname)
403404

405+
if resource_type == HOST_RESOURCE and self.use_configured_hostname:
406+
hostname = self.host
407+
404408
self.log.debug("Collect metrics and host tags for hostname: %s, object: %s", hostname, resource_obj)
405409

406410
tags = []
407411
parent = resource_props.get('parent')
408412

409-
if resource_type == "vm":
413+
if resource_type == VM_RESOURCE:
410414
runtime_host = resource_props.get('runtime.host')
411415
runtime_host_props = {}
412416
if runtime_host:
@@ -418,19 +422,14 @@ def check(self, _):
418422
runtime_hostname = to_string(runtime_host_props.get("name", "unknown"))
419423
tags.append('esxi_host:{}'.format(runtime_hostname))
420424

421-
if runtime_host is not None:
422-
tags.extend(
423-
get_tags_recursively(
424-
runtime_host,
425-
resource_map,
426-
include_only=['esxi_cluster'],
427-
)
428-
)
429-
430425
if parent is not None:
431-
tags.extend(get_tags_recursively(parent, resource_map))
426+
tags.extend(
427+
get_tags_recursively(
428+
parent, resource_map, include_only=["esxi_compute", "esxi_host", "esxi_datastore"]
429+
)
430+
)
432431

433-
tags.append('esxi_type:{}'.format(resource_type))
432+
tags.append('esxi_type:{}'.format(resource_type_name))
434433

435434
metric_tags = self.tags
436435
if self.excluded_host_tags:
@@ -444,7 +443,7 @@ def check(self, _):
444443
else:
445444
self.log.debug("No host name found for %s; skipping external tag submission", resource_obj)
446445

447-
self.count(f"{resource_type}.count", 1, tags=tags, hostname=None)
446+
self.count(f"{resource_type_name}.count", 1, tags=tags, hostname=None)
448447

449448
counter_keys_and_names, metric_ids = self.get_available_metric_ids_for_entity(resource_obj)
450449
self.collect_metrics_for_entity(metric_ids, counter_keys_and_names, resource_obj, hostname, metric_tags)

esxi/datadog_checks/esxi/config_models/defaults.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,9 @@ def instance_ssl_verify():
2828
return True
2929

3030

31+
def instance_use_configured_hostname():
32+
return True
33+
34+
3135
def instance_use_guest_hostname():
3236
return False

esxi/datadog_checks/esxi/config_models/instance.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ class InstanceConfig(BaseModel):
7878
ssl_capath: Optional[str] = None
7979
ssl_verify: Optional[bool] = None
8080
tags: Optional[tuple[str, ...]] = None
81+
use_configured_hostname: Optional[bool] = None
8182
use_guest_hostname: Optional[bool] = None
8283
username: str
8384

esxi/datadog_checks/esxi/constants.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,7 @@
6161
"esxi_url",
6262
"esxi_type",
6363
"esxi_host",
64-
"esxi_folder",
65-
"esxi_cluster",
6664
"esxi_compute",
67-
"esxi_datacenter",
6865
"esxi_datastore",
6966
]
7067

esxi/datadog_checks/esxi/data/conf.yaml.example

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ instances:
3939
#
4040
# use_guest_hostname: false
4141

42+
## @param use_configured_hostname - boolean - optional - default: true
43+
## If true, the check will use the configured `host` parameter for ESXi hostnames instead of the Host name.
44+
## You may need to use this if you install both the vSphere check and ESXi check to avoid duplicate entries
45+
## for hosts in the web application UI.
46+
#
47+
# use_configured_hostname: true
48+
4249
## @param collect_per_instance_filters - mapping - optional
4350
## Use this option to collect metrics tagged with instance values.
4451
## Some ESXi metrics can be tagged with instance values.
@@ -101,8 +108,8 @@ instances:
101108
## @param excluded_host_tags - list of strings - optional - default: []
102109
## Use this option to send a subset of host tags as metric tags.
103110
## The ESXi integration collects tags for every ESXi host or VM in your environment.
104-
## Those tags can be `esxi_url`, esxi_type`, `esxi_host`, `esxi_folder`, `esxi_cluster`
105-
## `esxi_compute`, `esxi_datacenter`, `esxi_datastore` and are attached to the ESXi metrics by default.
111+
## Those tags can be `esxi_url`, esxi_type`, `esxi_host`, and `esxi_datastore`
112+
## and are attached to the ESXi metrics by default.
106113
## By default these tags are submitted as host tags, but you can submit them as metric tags instead by using
107114
## this configuration option, see: https://docs.datadoghq.com/tagging/using_tags/
108115
## You will lose the ability to filter your hosts on the tags you specify but they will appear faster

esxi/tests/test_integration.py

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,6 @@ def test_vcsim_external_host_tags(vcsim_instance, datadog_agent, dd_run_check):
8585
{
8686
'esxi': [
8787
'esxi_compute:localhost.localdomain',
88-
'esxi_datacenter:ha-datacenter',
89-
'esxi_folder:ha-folder-root',
90-
'esxi_folder:host',
9188
'esxi_type:host',
9289
'esxi_url:127.0.0.1:8989',
9390
]
@@ -97,9 +94,6 @@ def test_vcsim_external_host_tags(vcsim_instance, datadog_agent, dd_run_check):
9794
'ha-host_VM0',
9895
{
9996
'esxi': [
100-
'esxi_datacenter:ha-datacenter',
101-
'esxi_folder:ha-folder-root',
102-
'esxi_folder:vm',
10397
'esxi_type:vm',
10498
'esxi_host:localhost.localdomain',
10599
'esxi_url:127.0.0.1:8989',
@@ -110,9 +104,6 @@ def test_vcsim_external_host_tags(vcsim_instance, datadog_agent, dd_run_check):
110104
'ha-host_VM1',
111105
{
112106
'esxi': [
113-
'esxi_datacenter:ha-datacenter',
114-
'esxi_folder:ha-folder-root',
115-
'esxi_folder:vm',
116107
'esxi_type:vm',
117108
'esxi_host:localhost.localdomain',
118109
'esxi_url:127.0.0.1:8989',
@@ -129,16 +120,10 @@ def test_esxi_resource_count_metrics(vcsim_instance, dd_run_check, aggregator):
129120

130121
host_tags = [
131122
'esxi_compute:localhost.localdomain',
132-
'esxi_datacenter:ha-datacenter',
133-
'esxi_folder:ha-folder-root',
134-
'esxi_folder:host',
135123
'esxi_type:host',
136124
'esxi_url:127.0.0.1:8989',
137125
]
138126
vm_tags = [
139-
'esxi_datacenter:ha-datacenter',
140-
'esxi_folder:ha-folder-root',
141-
'esxi_folder:vm',
142127
'esxi_type:vm',
143128
'esxi_host:localhost.localdomain',
144129
'esxi_url:127.0.0.1:8989',

0 commit comments

Comments
 (0)