Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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
238 changes: 226 additions & 12 deletions snmp/tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,189 @@

EXCLUDED_E2E_TAG_KEYS = ['agent_version']

# Tag keys the SNMP corecheck used to attach to every per-device metric but, since
# DataDog/datadog-agent#49822, ships only on the `network-devices-metadata`
# event-platform payload when `collect_device_metadata` is enabled (the default).
# The backend re-joins these onto metrics at ingest from the metadata, so E2E
# tests that ran against the raw `agent check --json` aggregator state must
# assert them against the metadata payload (see test_e2e_core_metadata.py)
# rather than against per-metric tags.
DEVICE_METADATA_TAG_KEYS = (
# Device identity (always emitted from the instance config)
'agent_host',
'device_id',
'device_ip',
'device_namespace',
'snmp_device',
# Profile-level globals derived from sysObjectID / sysName / sysDescr
'device_hostname',
'device_vendor',
'snmp_host',
'snmp_profile',
# Common profile metadata.device.fields
'firmware_version',
'model',
'os_name',
'os_version',
'product_name',
'serial_num',
'ups_name',
'version',
# Profile-specific metadata.device.fields. Each entry below is a tag key
# that one or more profiles declare as a global metric_tag whose value
# comes from a metadata.device.fields lookup. They're stripped by the
# agent the same way as the common identity fields above.
'agent_inventory_machine_model',
'agent_inventory_software_version',
'avaya_cmg_active_controller_address',
'avaya_cmg_hw_type',
'avaya_cmg_model_number',
'avaya_cmg_serial_number',
'avaya_cmg_voip_admin_state',
'avaya_cmg_voip_current_ip_address',
'avaya_gen_cpu_utilization_enable_monitoring',
'avaya_s5_chas_ser_num',
'avaya_s5_chas_ver',
'ax_sys_a_fle_x_engine_version',
'ax_sys_firmware_version',
'ax_sys_serial_number',
'bcn_sys_id_os_release',
'bcn_sys_id_platform',
'bcn_sys_id_product',
'br_info_serial_number',
'cppm_cluster_node_type',
'cppm_num_cluster_nodes',
'cppm_nw_data_port_ip_address',
'cppm_nw_data_port_mac_address',
'cppm_nw_mgmt_port_ip_address',
'cppm_nw_mgmt_port_mac_address',
'cppm_system_num_cp_us',
'cppm_system_version',
'cppm_zone_name',
'e_pdu_ident_model_number',
'e_pdu_ident_name',
'e_pdu_ident_serial_number',
'envir_ident_location',
'envir_ident_name',
'fe_hardware_model',
'fe_serial_number',
'filer_bios_version',
'filer_cpu_arch',
'filer_cpu_model',
'filer_identifier',
'filer_package_format',
'filer_platform_name',
'filer_platform_type',
'filer_serial_number',
'filer_version',
'fs_sys_serial',
'fs_sys_version',
'hawk_i2_inv_fw_revision',
'hawk_i2_inv_hw_revision',
'hawk_i2_inv_serial_num',
'hawk_i2_ip_temp_scale_flag',
'hpe_fibrechannel_cpq_si_product_name',
'hpe_fibrechannel_cpq_si_sys_product_id',
'hpe_fibrechannel_cpq_si_sys_serial_num',
'huawei_hw_entity_system_model',
'ib_hardware_type',
'ib_nios_version',
'ib_serial_number',
'ibm_imm_machine_level_product_name',
'ibm_imm_machine_level_serial_number',
'ironport_cache_admin',
'ironport_cache_software',
'ironport_cache_version',
'ironport_http_ports',
'ironport_license_expiration',
'juniper_ive_esap_version',
'juniper_ive_ive_max_concurrent_users_license_capacity',
'juniper_ive_product_name',
'juniper_ive_product_version',
'kcprt_general_model_name',
'kcprt_serial_number',
'legacy_pdu_macaddress',
'legacy_pdu_model',
'legacy_pdu_name',
'legacy_pdu_version',
'lgp_agent_ident_model',
'lgp_agent_ident_serial_number',
'mcafee_mwg_k_build_number',
'mcafee_mwg_k_company_name',
'mcafee_mwg_k_custom_version',
'mcafee_mwg_k_hotfix_version',
'mcafee_mwg_k_major_version',
'mcafee_mwg_k_micro_version',
'mcafee_mwg_k_minor_version',
'mcafee_mwg_k_product_name',
'mcafee_mwg_k_product_version',
'mcafee_mwg_k_revision',
'mcafee_mwg_p_am_engine_version',
'mcafee_mwg_p_am_proactive_version',
'mcafee_mwg_p_mfe_engine_version',
'mcafee_mwg_p_mfedat_version',
'mcafee_mwg_p_tsdb_version',
'netscaler_sdx_system_bios_version',
'netscaler_sdx_system_gateway',
'netscaler_sdx_system_gateway_type',
'netscaler_sdx_system_netmask',
'netscaler_sdx_system_netmask_type',
'netscaler_sdx_system_network_interface',
'netscaler_sdx_system_product',
'netscaler_sdx_system_svm_ip_address',
'netscaler_sdx_system_svm_ip_address_type',
'netscaler_sdx_system_xen_ip_address',
'netscaler_sdx_system_xen_ip_address_type',
'peplink_bal_firmware',
'peplink_bal_serial_number',
'peplink_device_firmware_version',
'peplink_device_model',
'peplink_device_serial_number',
'powernet_r_pdu_ident_firmware_rev',
'powernet_r_pdu_ident_hardware_rev',
'powernet_r_pdu_ident_model_number',
'powernet_r_pdu_ident_name',
'powernet_r_pdu_ident_serial_number',
'riverbed_interceptor_model',
'riverbed_interceptor_serial_number',
'ruckus_unleashed_system_licensed_aps',
'ruckus_unleashed_system_model',
'ruckus_unleashed_system_serial_number',
'servertech_sentry3_system_nic_serial_number',
'servertech_sentry3_system_version',
'sfos_device_fw_version',
'sfos_device_type',
'sfos_ips_version',
'synology_model_name',
'synology_serial_number',
'synology_version',
'tl_ups_ident_id',
'tl_ups_ident_serial_num',
'tl_ups_location',
'tl_ups_snmp_card_serial_num',
'ups_ident_manufacturer',
'ups_ident_model',
'ups_ident_name',
'vertiv_product_friendly_name',
'vertiv_product_mac_address',
'vertiv_product_title',
'vertiv_product_version',
'wdmycloudex2_agent_ver',
'wdmycloudex2_ftp_server',
'wdmycloudex2_host_name',
'wdmycloudex2_net_type',
'wdmycloudex2_software_version',
'wlsx_model_name',
'wlsx_switch_license_serial_number',
'wlsx_switch_role',
'wlsx_sys_ext_hw_version',
'wlsx_sys_ext_sw_version',
'zyxel_sys_product_model',
'zyxel_sys_product_serial_number',
'zyxel_sys_sw_platform',
'zyxel_sys_sw_version_string',
)

snmp_listener_only = pytest.mark.skipif(SNMP_LISTENER_ENV != 'true', reason='Agent snmp lister tests only')
snmp_integration_only = pytest.mark.skipif(SNMP_LISTENER_ENV != 'false', reason='Normal tests')
py3_plus_only = pytest.mark.skipif(sys.version_info[0] < 3, reason='Run test with Python 3+ only')
Expand Down Expand Up @@ -279,43 +462,74 @@ def create_check(instance):
return SnmpCheck('snmp', {}, [instance])


def filter_metric_tags(tags: list[str] | None) -> list[str] | None:
"""Drop device-level tags now joined from the NDM metadata payload at ingest.

Tests pass the device-level `common_tags` list to both metric and metadata
assertions for historical reasons. With the new agent tagging model the
per-metric assertions must only check tags the agent still attaches to
metrics; use this helper to project a `common_tags` list into the subset
that is valid for `aggregator.assert_metric(tags=...)` calls.
"""
if tags is None:
return None
return remove_tags(tags, DEVICE_METADATA_TAG_KEYS)


def assert_common_metrics(aggregator, tags=None, is_e2e=False, loader=None):
assert_common_check_run_metrics(aggregator, tags, is_e2e, loader=loader)
assert_common_device_metrics(aggregator, tags, is_e2e, loader=loader)


def assert_common_check_run_metrics(aggregator, tags=None, is_e2e=False, loader=None):
# When running against the core loader, the agent strips device-level tags
# from per-device metrics; assert only what the agent still emits.
if is_e2e and loader == 'core':
aggregator.assert_metric('snmp.device.reachable', metric_type=aggregator.GAUGE, tags=tags, at_least=1, value=1)
metric_tags = filter_metric_tags(tags)
aggregator.assert_metric(
'snmp.device.unreachable', metric_type=aggregator.GAUGE, tags=tags, at_least=1, value=0
'snmp.device.reachable', metric_type=aggregator.GAUGE, tags=metric_tags, at_least=1, value=1
)
aggregator.assert_metric(
'snmp.device.unreachable', metric_type=aggregator.GAUGE, tags=metric_tags, at_least=1, value=0
)
aggregator.assert_metric(
'snmp.interface.status', metric_type=aggregator.GAUGE, tags=metric_tags, at_least=0, value=1
)
aggregator.assert_metric('snmp.interface.status', metric_type=aggregator.GAUGE, tags=tags, at_least=0, value=1)

monotonic_type = aggregator.MONOTONIC_COUNT
if is_e2e:
monotonic_type = aggregator.COUNT
loader = loader or 'python'
if tags is not None:
tags = tags + ['loader:' + loader]
aggregator.assert_metric('datadog.snmp.check_duration', metric_type=aggregator.GAUGE, tags=tags)
aggregator.assert_metric('datadog.snmp.check_interval', metric_type=monotonic_type, tags=tags)
aggregator.assert_metric('datadog.snmp.submitted_metrics', metric_type=aggregator.GAUGE, tags=tags)
telemetry_tags = tags
if loader == 'core':
telemetry_tags = filter_metric_tags(tags)
if telemetry_tags is not None:
telemetry_tags = telemetry_tags + ['loader:' + loader]
aggregator.assert_metric('datadog.snmp.check_duration', metric_type=aggregator.GAUGE, tags=telemetry_tags)
aggregator.assert_metric('datadog.snmp.check_interval', metric_type=monotonic_type, tags=telemetry_tags)
aggregator.assert_metric('datadog.snmp.submitted_metrics', metric_type=aggregator.GAUGE, tags=telemetry_tags)
if loader == 'core':
# request_type tag can be get, getbulk, or getnext
aggregator.assert_metric_has_tag_prefix('datadog.snmp.requests', tag_prefix='request_type:get')
for tag in tags:
for tag in telemetry_tags:
aggregator.assert_metric_has_tag('datadog.snmp.requests', tag)


def assert_common_device_metrics(
aggregator, tags=None, is_e2e=False, count=None, devices_monitored_value=None, loader=None
):
loader = loader or 'python'
if tags is not None:
tags = tags + ['loader:' + loader]
metric_tags = tags
if loader == 'core':
metric_tags = filter_metric_tags(tags)
if metric_tags is not None:
metric_tags = metric_tags + ['loader:' + loader]
aggregator.assert_metric(
'snmp.devices_monitored', metric_type=aggregator.GAUGE, tags=tags, count=count, value=devices_monitored_value
'snmp.devices_monitored',
metric_type=aggregator.GAUGE,
tags=metric_tags,
count=count,
value=devices_monitored_value,
)


Expand Down
Loading
Loading