From a9230a38977d6acb804ee8bb6f58c19957dce013 Mon Sep 17 00:00:00 2001 From: Alessandro Pilotti Date: Thu, 22 Aug 2013 03:14:00 +0300 Subject: [PATCH] Adds metrics collection support in Hyper-V Blueprint: hyper-v-metrics Hyper-V Server 2012 supports a new set of metrics API that can be used to provide switch port metrics data to external applications, e.g. Ceilometer. Metrics collection is disabled by default and can be enabled with a config option. Metrics are configured via ACLs applied by the Hyper-V plugin agent. Change-Id: Ife2a53db84936bae7c73b8c027022bbc5e89d48a --- .../plugins/hyperv/hyperv_neutron_plugin.ini | 6 ++++ .../hyperv/agent/hyperv_neutron_agent.py | 10 ++++++ neutron/plugins/hyperv/agent/utils.py | 4 +++ neutron/plugins/hyperv/agent/utilsv2.py | 31 +++++++++++++++++++ .../tests/unit/hyperv/test_hyperv_utilsv2.py | 15 +++++++++ 5 files changed, 66 insertions(+) diff --git a/etc/neutron/plugins/hyperv/hyperv_neutron_plugin.ini b/etc/neutron/plugins/hyperv/hyperv_neutron_plugin.ini index b3b521806..236bc7e0f 100644 --- a/etc/neutron/plugins/hyperv/hyperv_neutron_plugin.ini +++ b/etc/neutron/plugins/hyperv/hyperv_neutron_plugin.ini @@ -39,6 +39,12 @@ # local_network_vswitch = private # Example: local_network_vswitch = custom_vswitch +# (BoolOpt) Enables metrics collections for switch ports by using Hyper-V's +# metric APIs. Collected data can by retrieved by other apps and services, +# e.g.: Ceilometer. Requires Hyper-V / Windows Server 2012 and above. +# +# enable_metrics_collection = False + #----------------------------------------------------------------------------- # Sample Configurations. #----------------------------------------------------------------------------- diff --git a/neutron/plugins/hyperv/agent/hyperv_neutron_agent.py b/neutron/plugins/hyperv/agent/hyperv_neutron_agent.py index 608208636..d5befb11c 100644 --- a/neutron/plugins/hyperv/agent/hyperv_neutron_agent.py +++ b/neutron/plugins/hyperv/agent/hyperv_neutron_agent.py @@ -52,6 +52,13 @@ agent_opts = [ cfg.IntOpt('polling_interval', default=2, help=_("The number of seconds the agent will wait between " "polling for local device changes.")), + cfg.BoolOpt('enable_metrics_collection', + default=False, + help=_('Enables metrics collections for switch ports by using ' + 'Hyper-V\'s metric APIs. Collected data can by ' + 'retrieved by other apps and services, e.g.: ' + 'Ceilometer. Requires Hyper-V / Windows Server 2012 ' + 'and above')) ] @@ -210,6 +217,9 @@ class HyperVNeutronAgent(object): else: LOG.error(_('Unsupported network type %s'), network_type) + if CONF.AGENT.enable_metrics_collection: + self._utils.enable_port_metrics_collection(port_id) + def _port_unbound(self, port_id): (net_uuid, map) = self._get_network_vswitch_map_by_port_id(port_id) if net_uuid not in self._network_vswitch_map: diff --git a/neutron/plugins/hyperv/agent/utils.py b/neutron/plugins/hyperv/agent/utils.py index 11bdf7c24..2b6d56f66 100644 --- a/neutron/plugins/hyperv/agent/utils.py +++ b/neutron/plugins/hyperv/agent/utils.py @@ -243,3 +243,7 @@ class HyperVUtils(object): for switch_port in switch_ports: if (switch_port.ElementName == port_id): return switch_port + + def enable_port_metrics_collection(self, switch_port_name): + raise NotImplementedError(_("Metrics collection is not supported on " + "this version of Hyper-V")) diff --git a/neutron/plugins/hyperv/agent/utilsv2.py b/neutron/plugins/hyperv/agent/utilsv2.py index c0fbb5559..73eed9824 100644 --- a/neutron/plugins/hyperv/agent/utilsv2.py +++ b/neutron/plugins/hyperv/agent/utilsv2.py @@ -26,10 +26,18 @@ class HyperVUtilsV2(utils.HyperVUtils): _ETHERNET_SWITCH_PORT = 'Msvm_EthernetSwitchPort' _PORT_ALLOC_SET_DATA = 'Msvm_EthernetPortAllocationSettingData' _PORT_VLAN_SET_DATA = 'Msvm_EthernetSwitchPortVlanSettingData' + _PORT_ALLOC_ACL_SET_DATA = 'Msvm_EthernetSwitchPortAclSettingData' _LAN_ENDPOINT = 'Msvm_LANEndpoint' _STATE_DISABLED = 3 _OPERATION_MODE_ACCESS = 1 + _ACL_DIR_IN = 1 + _ACL_DIR_OUT = 2 + _ACL_TYPE_IPV4 = 2 + _ACL_TYPE_IPV6 = 3 + _ACL_ACTION_METER = 3 + _ACL_APPLICABILITY_LOCAL = 1 + _wmi_namespace = '//./root/virtualization/v2' def __init__(self): @@ -159,3 +167,26 @@ class HyperVUtilsV2(utils.HyperVUtils): def _get_first_item(self, obj): if obj: return obj[0] + + def enable_port_metrics_collection(self, switch_port_name): + port, found = self._get_switch_port_allocation(switch_port_name, False) + if not found: + return + + # Add the ACLs only if they don't already exist + acls = port.associators(wmi_result_class=self._PORT_ALLOC_ACL_SET_DATA) + for acl_type in [self._ACL_TYPE_IPV4, self._ACL_TYPE_IPV6]: + for acl_dir in [self._ACL_DIR_IN, self._ACL_DIR_OUT]: + acls = [v for v in acls + if v.Action == self._ACL_ACTION_METER and + v.Applicability == self._ACL_APPLICABILITY_LOCAL and + v.Direction == acl_dir and + v.AclType == acl_type] + if not acls: + acl = self._get_default_setting_data( + self._PORT_ALLOC_ACL_SET_DATA) + acl.AclType = acl_type + acl.Direction = acl_dir + acl.Action = self._ACL_ACTION_METER + acl.Applicability = self._ACL_APPLICABILITY_LOCAL + self._add_virt_feature(port, acl) diff --git a/neutron/tests/unit/hyperv/test_hyperv_utilsv2.py b/neutron/tests/unit/hyperv/test_hyperv_utilsv2.py index 5a40fdd6c..76f88ead2 100644 --- a/neutron/tests/unit/hyperv/test_hyperv_utilsv2.py +++ b/neutron/tests/unit/hyperv/test_hyperv_utilsv2.py @@ -213,3 +213,18 @@ class TestHyperVUtilsV2(base.BaseTestCase): True) self.assertEqual(ret_val, (mock_data, False)) + + def test_enable_port_metrics_collection(self): + mock_port = mock.MagicMock() + self._utils._get_switch_port_allocation = mock.MagicMock(return_value=( + mock_port, True)) + + mock_acl = mock.MagicMock() + self._utils._get_default_setting_data = mock.MagicMock( + return_value=mock_acl) + self._utils._add_virt_feature = mock.MagicMock() + + self._utils.enable_port_metrics_collection(self._FAKE_PORT_NAME) + + self.assertEqual(4, len(self._utils._add_virt_feature.mock_calls)) + self._utils._add_virt_feature.assert_called_with(mock_port, mock_acl) -- 2.45.2