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
This commit is contained in:
Alessandro Pilotti 2013-08-22 03:14:00 +03:00
parent c137823c54
commit 21140e341a
5 changed files with 66 additions and 0 deletions

View File

@ -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.
#-----------------------------------------------------------------------------

View 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:

View 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"))

View 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)

View 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)