Skip to content

Commit

Permalink
Add support for VM property metrics (#14787)
Browse files Browse the repository at this point in the history
* Add base VM property metrics

* Add network ip

* Add new properties

* Report only VM values and use host tags

* Clean up code

* Add more tests and add to cache

* Add more tests

* use vm hostname

* Clean up code and add tests for all property metrics

* Add submit_property_metric function

* Add type hints and add helper methods

* Add new metrics and update metadata.csv

* Only log if in debug mode

* Add unneeded types and log

* Remove duplicated code, fix metadata.csv

* Move mocks to common file

* Sync models

* update metadata and docs to reflect interval

* Further refactor, standardize metric types, and add another test

* Add tests for logging

* Add cache time test

* Add tools version status metric

* Address review comments

* use new version of models
  • Loading branch information
sarah-witt authored Jul 21, 2023
1 parent d723344 commit 8d8cc63
Show file tree
Hide file tree
Showing 16 changed files with 1,191 additions and 9 deletions.
12 changes: 12 additions & 0 deletions vsphere/assets/configuration/spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,18 @@ files:
value:
type: boolean
example: false
- name: collect_property_metrics
description: |
If true, the vSphere integration will collect additional metrics about the resource types
you have configured to monitor. These are configuration properties such as disk information
in a VM and DRS config status in clusters.
Note: These metrics are collected at a frequency of `refresh_infrastructure_cache_interval`.
Warning: Depending on the size of the vSphere environment, property metric collection can be slow,
very CPU intensive and put pressure on the vCenter Server.
value:
type: boolean
example: false
- name: attributes_prefix
description: |
Custom attributes attached to vSphere resources will be prefixed with this prefix when collected.
Expand Down
21 changes: 19 additions & 2 deletions vsphere/datadog_checks/vsphere/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@

from datadog_checks.base.log import CheckLoggingAdapter # noqa: F401
from datadog_checks.vsphere.config import VSphereConfig # noqa: F401
from datadog_checks.vsphere.constants import ALL_RESOURCES, MAX_QUERY_METRICS_OPTION, UNLIMITED_HIST_METRICS_PER_QUERY
from datadog_checks.vsphere.constants import (
ALL_RESOURCES,
MAX_QUERY_METRICS_OPTION,
UNLIMITED_HIST_METRICS_PER_QUERY,
VM_PROPERTIES,
)
from datadog_checks.vsphere.event import ALLOWED_EVENTS
from datadog_checks.vsphere.types import InfrastructureData

Expand Down Expand Up @@ -184,6 +189,10 @@ def _get_raw_infrastructure(self):
property_spec.pathSet.append("runtime.powerState")
property_spec.pathSet.append("runtime.host")
property_spec.pathSet.append("guest.hostName")
if self.config.collect_property_metrics:
for vm_property in VM_PROPERTIES:
property_spec.pathSet.append(vm_property)

property_specs.append(property_spec)

# Specify the attribute of the root object to traverse to obtain all the attributes
Expand Down Expand Up @@ -267,13 +276,21 @@ def get_infrastructure(self):
root_folder = self._conn.content.rootFolder
infrastructure_data[root_folder] = {"name": root_folder.name, "parent": None}

if self.config.should_collect_attributes:
if self.config.should_collect_attributes or self.config.collect_property_metrics:
# Clean up attributes in infrastructure_data,
# at this point they are custom pyvmomi objects and the attribute keys are not resolved.

attribute_keys = {x.key: x.name for x in self._fetch_all_attributes()}
for props in itervalues(infrastructure_data):
mor_attributes = []
if self.config.collect_property_metrics:
all_properties = {}
for attribute_name in VM_PROPERTIES:
attribute_val = props.pop(attribute_name, None)
if attribute_val is not None:
all_properties[attribute_name] = attribute_val
props['properties'] = all_properties

if 'customValue' not in props:
continue
for attribute in props.pop('customValue'):
Expand Down
6 changes: 6 additions & 0 deletions vsphere/datadog_checks/vsphere/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,9 @@ def set_mor_props(self, mor, mor_data):
if mor_type not in self._mors:
self._mors[mor_type] = {}
self._mors[mor_type][mor] = mor_data

def clear_properties(self):
# type: () -> None
for _, mors in self._mors.items():
for _, mor_props in mors.items():
mor_props.pop('properties', None)
1 change: 1 addition & 0 deletions vsphere/datadog_checks/vsphere/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ def __init__(self, instance, init_config, log):
self.should_collect_tags = is_affirmative(instance.get("collect_tags", False))
self.tags_prefix = instance.get("tags_prefix", DEFAULT_VSPHERE_TAG_PREFIX)
self.should_collect_attributes = is_affirmative(instance.get("collect_attributes", False))
self.collect_property_metrics = is_affirmative(instance.get("collect_property_metrics", False))
self.attr_prefix = instance.get("attributes_prefix", DEFAULT_VSPHERE_ATTR_PREFIX)
self.excluded_host_tags = instance.get("excluded_host_tags", [])
self.base_tags = instance.get("tags", []) + ["vcenter_server:{}".format(self.hostname)]
Expand Down
4 changes: 4 additions & 0 deletions vsphere/datadog_checks/vsphere/config_models/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ def instance_collect_events_only():
return False


def instance_collect_property_metrics():
return False


def instance_collect_tags():
return False

Expand Down
1 change: 1 addition & 0 deletions vsphere/datadog_checks/vsphere/config_models/instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ class InstanceConfig(BaseModel):
collect_events: Optional[bool] = None
collect_events_only: Optional[bool] = None
collect_per_instance_filters: Optional[CollectPerInstanceFilters] = None
collect_property_metrics: Optional[bool] = None
collect_tags: Optional[bool] = None
collection_level: Optional[int] = None
collection_type: Optional[str] = None
Expand Down
30 changes: 30 additions & 0 deletions vsphere/datadog_checks/vsphere/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,33 @@

DEFAULT_VSPHERE_TAG_PREFIX = ""
DEFAULT_VSPHERE_ATTR_PREFIX = ""

PROPERTY_COUNT_METRICS = [
"guest.net",
"guest.ipStack.ipRoute",
"guest.net.ipConfig.address",
"guest.toolsRunningStatus",
"guest.toolsVersionStatus2",
"guest.toolsVersion",
"guest.guestFullName",
]
VM_OBJECT_PROPERTIES = ["guest.disk", "guest.net", "guest.ipStack"]

VM_SIMPLE_PROPERTIES = [
"guest.toolsRunningStatus",
"guest.toolsVersionStatus2",
"guest.toolsVersion",
"config.hardware.numCoresPerSocket",
"config.cpuAllocation.limit",
"config.cpuAllocation.overheadLimit",
"config.memoryAllocation.limit",
"config.memoryAllocation.overheadLimit",
"summary.config.numCpu",
"summary.config.memorySizeMB",
"summary.config.numEthernetCards",
"summary.config.numVirtualDisks",
"summary.quickStats.uptimeSeconds",
"guest.guestFullName",
]

VM_PROPERTIES = VM_OBJECT_PROPERTIES + VM_SIMPLE_PROPERTIES
11 changes: 11 additions & 0 deletions vsphere/datadog_checks/vsphere/data/conf.yaml.example
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,17 @@ instances:
#
# collect_attributes: false

## @param collect_property_metrics - boolean - optional - default: false
## If true, the vSphere integration will collect additional metrics about the resource types
## you have configured to monitor. These are configuration properties such as disk information
## in a VM and DRS config status in clusters.
##
## Note: These metrics are collected at a frequency of `refresh_infrastructure_cache_interval`.
## Warning: Depending on the size of the vSphere environment, property metric collection can be slow,
## very CPU intensive and put pressure on the vCenter Server.
#
# collect_property_metrics: false

## @param attributes_prefix - string - optional
## Custom attributes attached to vSphere resources will be prefixed with this prefix when collected.
## Example use cases:
Expand Down
17 changes: 16 additions & 1 deletion vsphere/datadog_checks/vsphere/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from typing import Any, Dict, List, Optional, Pattern, Type, TypedDict

# CONFIG ALIASES
from pyVmomi import vim
from pyVmomi import VmomiSupport, vim

ResourceFilterConfig = TypedDict(
'ResourceFilterConfig', {'resource': str, 'property': str, 'type': str, 'patterns': List[str]}
Expand Down Expand Up @@ -52,13 +52,28 @@
MetricName = str
CounterId = int

VmomiObject = VmomiSupport.Object

InfrastructureDataItem = TypedDict(
'InfrastructureDataItem',
{
'name': str,
'runtime.host': vim.ManagedEntity,
'guest.hostName': str,
'runtime.powerState': str,
'summary.config.numCpu': int,
'summary.config.memorySizeMB': int,
'summary.config.numEthernetCards': int,
'summary.config.numVirtualDisks': int,
'summary.quickStats.uptimeSeconds': int,
'guest.guestFullName': str,
'guest.disk': List[VmomiObject],
'guest.net': List[VmomiObject],
'guest.ipStack': List[VmomiObject],
'guest.toolsRunningStatus': str,
'guest.toolsVersionStatus2': str,
'guest.toolsVersion': str,
'config.hardware.numCoresPerSocket': str,
'parent': Optional[vim.ManagedEntity],
'attributes': List[str],
},
Expand Down
9 changes: 8 additions & 1 deletion vsphere/datadog_checks/vsphere/utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# (C) Datadog, Inc. 2019-present
# All rights reserved
# Licensed under Simplified BSD License (see LICENSE)
from typing import List, Optional, Type # noqa: F401
from typing import Any, Dict, List, Optional, Type # noqa: F401

from pyVmomi import vim
from six import iteritems
Expand Down Expand Up @@ -153,3 +153,10 @@ def get_mapped_instance_tag(metric_name):
if metric_name.startswith(prefix):
return tag_key
return 'instance'


def add_additional_tags(tags, additional_tags):
# type: (List[str], Dict[str, Optional[Any]]) -> List[str]
for tag_name, tag_value in additional_tags.items():
if tag_value is not None:
tags.append("{}:{}".format(tag_name, tag_value))
Loading

0 comments on commit 8d8cc63

Please sign in to comment.