]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Adds metrics collection support in Hyper-V
authorAlessandro Pilotti <apilotti@cloudbasesolutions.com>
Thu, 22 Aug 2013 00:14:00 +0000 (03:14 +0300)
committerAlessandro Pilotti <apilotti@cloudbasesolutions.com>
Wed, 28 Aug 2013 15:12:35 +0000 (18:12 +0300)
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

etc/neutron/plugins/hyperv/hyperv_neutron_plugin.ini
neutron/plugins/hyperv/agent/hyperv_neutron_agent.py
neutron/plugins/hyperv/agent/utils.py
neutron/plugins/hyperv/agent/utilsv2.py
neutron/tests/unit/hyperv/test_hyperv_utilsv2.py

index b3b52180628ebc1a405ae53447d70861b45fe877..236bc7e0f0aab8edabab3ab5196808d1f5b42ee9 100644 (file)
 # 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.
 #-----------------------------------------------------------------------------
index 6082086365cdbd70d1afd06fa63fc1b4bc0c000e..d5befb11c70cdf862d66fa411373fdc039f58fa7 100644 (file)
@@ -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:
index 11bdf7c240d695f4a6b578d6c4ca045dcda78162..2b6d56f66fe36906ffdb51ac38ce00c02fcc1dfe 100644 (file)
@@ -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"))
index c0fbb5559c08155f230e15d526291b53a04833e5..73eed9824f4881921ec49d5946a500acbc4573c2 100644 (file)
@@ -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)
index 5a40fdd6cfe95c1b307b6d170cb24dae79714a8b..76f88ead2b0c7436c94037107d49f10841229928 100644 (file)
@@ -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)