Merge "Fixes Hyper-V 2008 R2 agent VLAN Settings issue" into stable/juno
This commit is contained in:
commit
de3f6bbf3a
@ -246,7 +246,10 @@ class HyperVNeutronAgent(n_rpc.RpcCallback):
|
||||
|
||||
vswitch_name = self._get_vswitch_name(network_type, physical_network)
|
||||
|
||||
if network_type in [p_const.TYPE_VLAN, p_const.TYPE_FLAT]:
|
||||
if network_type == p_const.TYPE_VLAN:
|
||||
self._utils.set_switch_external_port_trunk_vlan(vswitch_name,
|
||||
segmentation_id, constants.TRUNK_ENDPOINT_MODE)
|
||||
elif network_type == p_const.TYPE_FLAT:
|
||||
#Nothing to do
|
||||
pass
|
||||
elif network_type == p_const.TYPE_LOCAL:
|
||||
|
@ -41,6 +41,10 @@ WMI_JOB_STATE_COMPLETED = 7
|
||||
class HyperVUtils(object):
|
||||
|
||||
_ETHERNET_SWITCH_PORT = 'Msvm_SwitchPort'
|
||||
_SWITCH_LAN_ENDPOINT = 'Msvm_SwitchLanEndpoint'
|
||||
_VIRTUAL_SWITCH = 'Msvm_VirtualSwitch'
|
||||
_BINDS_TO = 'Msvm_BindsTo'
|
||||
_VLAN_ENDPOINT_SET_DATA = 'Msvm_VLANEndpointSettingData'
|
||||
|
||||
_wmi_namespace = '//./root/virtualization'
|
||||
|
||||
@ -207,17 +211,21 @@ class HyperVUtils(object):
|
||||
vswitch_name)
|
||||
return vswitch[0]
|
||||
|
||||
def _get_vswitch_external_port(self, vswitch):
|
||||
vswitch_ports = vswitch.associators(
|
||||
wmi_result_class=self._ETHERNET_SWITCH_PORT)
|
||||
for vswitch_port in vswitch_ports:
|
||||
lan_endpoints = vswitch_port.associators(
|
||||
def _get_vswitch_external_port(self, vswitch_name):
|
||||
ext_ports = self._conn.Msvm_ExternalEthernetPort()
|
||||
for ext_port in ext_ports:
|
||||
lan_endpoint_list = ext_port.associators(
|
||||
wmi_result_class='Msvm_SwitchLanEndpoint')
|
||||
if lan_endpoints:
|
||||
ext_port = lan_endpoints[0].associators(
|
||||
wmi_result_class='Msvm_ExternalEthernetPort')
|
||||
if ext_port:
|
||||
return vswitch_port
|
||||
if lan_endpoint_list:
|
||||
vswitch_port_list = lan_endpoint_list[0].associators(
|
||||
wmi_result_class=self._ETHERNET_SWITCH_PORT)
|
||||
if vswitch_port_list:
|
||||
vswitch_port = vswitch_port_list[0]
|
||||
vswitch_list = vswitch_port.associators(
|
||||
wmi_result_class='Msvm_VirtualSwitch')
|
||||
if (vswitch_list and
|
||||
vswitch_list[0].ElementName == vswitch_name):
|
||||
return vswitch_port
|
||||
|
||||
def set_vswitch_port_vlan_id(self, vlan_id, switch_port_name):
|
||||
vlan_endpoint_settings = self._conn.Msvm_VLANEndpointSettingData(
|
||||
@ -226,6 +234,21 @@ class HyperVUtils(object):
|
||||
vlan_endpoint_settings.AccessVLAN = vlan_id
|
||||
vlan_endpoint_settings.put()
|
||||
|
||||
def set_switch_external_port_trunk_vlan(self, vswitch_name, vlan_id,
|
||||
desired_endpoint_mode):
|
||||
vswitch_external_port = self._get_vswitch_external_port(vswitch_name)
|
||||
if vswitch_external_port:
|
||||
vlan_endpoint = vswitch_external_port.associators(
|
||||
wmi_association_class=self._BINDS_TO)[0]
|
||||
if vlan_endpoint.DesiredEndpointMode != desired_endpoint_mode:
|
||||
vlan_endpoint.DesiredEndpointMode = desired_endpoint_mode
|
||||
vlan_endpoint.put()
|
||||
vlan_endpoint_settings = vlan_endpoint.associators(
|
||||
wmi_result_class=self._VLAN_ENDPOINT_SET_DATA)[0]
|
||||
if vlan_id not in vlan_endpoint_settings.TrunkedVLANList:
|
||||
vlan_endpoint_settings.TrunkedVLANList += (vlan_id,)
|
||||
vlan_endpoint_settings.put()
|
||||
|
||||
def _get_switch_port_path_by_name(self, switch_port_name):
|
||||
vswitch = self._conn.Msvm_SwitchPort(ElementName=switch_port_name)
|
||||
if vswitch:
|
||||
|
@ -134,21 +134,6 @@ class HyperVUtilsV2(utils.HyperVUtils):
|
||||
vswitch_name)
|
||||
return vswitch[0]
|
||||
|
||||
def _get_vswitch_external_port(self, vswitch):
|
||||
vswitch_ports = vswitch.associators(
|
||||
wmi_result_class=self._ETHERNET_SWITCH_PORT)
|
||||
for vswitch_port in vswitch_ports:
|
||||
lan_endpoints = vswitch_port.associators(
|
||||
wmi_result_class=self._LAN_ENDPOINT)
|
||||
if len(lan_endpoints):
|
||||
lan_endpoints = lan_endpoints[0].associators(
|
||||
wmi_result_class=self._LAN_ENDPOINT)
|
||||
if len(lan_endpoints):
|
||||
ext_port = lan_endpoints[0].associators(
|
||||
wmi_result_class=self._EXTERNAL_PORT)
|
||||
if ext_port:
|
||||
return vswitch_port
|
||||
|
||||
def set_vswitch_port_vlan_id(self, vlan_id, switch_port_name):
|
||||
port_alloc, found = self._get_switch_port_allocation(switch_port_name)
|
||||
if not found:
|
||||
@ -171,6 +156,10 @@ class HyperVUtilsV2(utils.HyperVUtils):
|
||||
port_alloc.path_(), [vlan_settings.GetText_(1)])
|
||||
self._check_job_status(ret_val, job_path)
|
||||
|
||||
def set_switch_external_port_trunk_vlan(self, vswitch_name, vlan_id,
|
||||
desired_endpoint_mode):
|
||||
pass
|
||||
|
||||
def _get_vlan_setting_data_from_port_alloc(self, port_alloc):
|
||||
return self._get_first_item(port_alloc.associators(
|
||||
wmi_result_class=self._PORT_VLAN_SET_DATA))
|
||||
|
@ -18,3 +18,4 @@ TUNNEL = 'tunnel'
|
||||
|
||||
# Special vlan_id value in ovs_vlan_allocations table indicating flat network
|
||||
FLAT_VLAN_ID = -1
|
||||
TRUNK_ENDPOINT_MODE = 5
|
||||
|
@ -21,8 +21,11 @@ Unit tests for Windows Hyper-V virtual switch neutron driver
|
||||
import mock
|
||||
from oslo.config import cfg
|
||||
|
||||
from neutron.plugins.common import constants as p_const
|
||||
from neutron.plugins.hyperv.agent import hyperv_neutron_agent
|
||||
from neutron.plugins.hyperv.agent import utils
|
||||
from neutron.plugins.hyperv.agent import utilsfactory
|
||||
from neutron.plugins.hyperv.common import constants
|
||||
from neutron.tests import base
|
||||
|
||||
cfg.CONF.import_opt('enable_metrics_collection',
|
||||
@ -54,6 +57,7 @@ class TestHyperVNeutronAgent(base.BaseTestCase):
|
||||
'neutron.agent.firewall.NoopFirewallDriver',
|
||||
group='SECURITYGROUP')
|
||||
self.agent = hyperv_neutron_agent.HyperVNeutronAgent()
|
||||
self.agent._utils = mock.MagicMock()
|
||||
self.agent.plugin_rpc = mock.Mock()
|
||||
self.agent.sec_groups_agent = mock.MagicMock()
|
||||
self.agent.sg_plugin_rpc = mock.Mock()
|
||||
@ -220,3 +224,54 @@ class TestHyperVNeutronAgent(base.BaseTestCase):
|
||||
self.assertTrue(common_config.init.called)
|
||||
self.assertTrue(common_config.setup_logging.called)
|
||||
plugin.assert_has_calls([mock.call().daemon_loop()])
|
||||
|
||||
@mock.patch.object(hyperv_neutron_agent.HyperVNeutronAgent,
|
||||
"_get_vswitch_name")
|
||||
def test_provision_network_exception(self, mock_get_vswitch_name):
|
||||
self.assertRaises(utils.HyperVException, self.agent._provision_network,
|
||||
mock.sentinel.FAKE_PORT_ID,
|
||||
mock.sentinel.FAKE_NET_UUID,
|
||||
mock.sentinel.FAKE_NETWORK_TYPE,
|
||||
mock.sentinel.FAKE_PHYSICAL_NETWORK,
|
||||
mock.sentinel.FAKE_SEGMENTATION_ID)
|
||||
mock_get_vswitch_name.assert_called_once_with(
|
||||
mock.sentinel.FAKE_NETWORK_TYPE,
|
||||
mock.sentinel.FAKE_PHYSICAL_NETWORK)
|
||||
|
||||
@mock.patch.object(hyperv_neutron_agent.HyperVNeutronAgent,
|
||||
"_get_vswitch_name")
|
||||
def test_provision_network_vlan(self, mock_get_vswitch_name):
|
||||
vswitch_name = mock_get_vswitch_name.return_value
|
||||
self.agent._provision_network(mock.sentinel.FAKE_PORT_ID,
|
||||
mock.sentinel.FAKE_NET_UUID,
|
||||
p_const.TYPE_VLAN,
|
||||
mock.sentinel.FAKE_PHYSICAL_NETWORK,
|
||||
mock.sentinel.FAKE_SEGMENTATION_ID)
|
||||
mock_get_vswitch_name.assert_called_once_with(p_const.TYPE_VLAN,
|
||||
mock.sentinel.FAKE_PHYSICAL_NETWORK)
|
||||
set_switch = self.agent._utils.set_switch_external_port_trunk_vlan
|
||||
set_switch.assert_called_once_with(vswitch_name,
|
||||
mock.sentinel.FAKE_SEGMENTATION_ID,
|
||||
constants.TRUNK_ENDPOINT_MODE)
|
||||
|
||||
@mock.patch.object(hyperv_neutron_agent.HyperVNeutronAgent,
|
||||
"_get_vswitch_name")
|
||||
def test_provision_network_flat(self, mock_get_vswitch_name):
|
||||
self.agent._provision_network(mock.sentinel.FAKE_PORT_ID,
|
||||
mock.sentinel.FAKE_NET_UUID,
|
||||
p_const.TYPE_FLAT,
|
||||
mock.sentinel.FAKE_PHYSICAL_NETWORK,
|
||||
mock.sentinel.FAKE_SEGMENTATION_ID)
|
||||
mock_get_vswitch_name.assert_called_once_with(p_const.TYPE_FLAT,
|
||||
mock.sentinel.FAKE_PHYSICAL_NETWORK)
|
||||
|
||||
@mock.patch.object(hyperv_neutron_agent.HyperVNeutronAgent,
|
||||
"_get_vswitch_name")
|
||||
def test_provision_network_local(self, mock_get_vswitch_name):
|
||||
self.agent._provision_network(mock.sentinel.FAKE_PORT_ID,
|
||||
mock.sentinel.FAKE_NET_UUID,
|
||||
p_const.TYPE_LOCAL,
|
||||
mock.sentinel.FAKE_PHYSICAL_NETWORK,
|
||||
mock.sentinel.FAKE_SEGMENTATION_ID)
|
||||
mock_get_vswitch_name.assert_called_once_with(p_const.TYPE_LOCAL,
|
||||
mock.sentinel.FAKE_PHYSICAL_NETWORK)
|
||||
|
107
neutron/tests/unit/hyperv/test_hyperv_utils.py
Normal file
107
neutron/tests/unit/hyperv/test_hyperv_utils.py
Normal file
@ -0,0 +1,107 @@
|
||||
# Copyright 2014 Cloudbase Solutions SRL
|
||||
#
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""
|
||||
Unit tests for the Hyper-V Utils class.
|
||||
"""
|
||||
|
||||
import mock
|
||||
|
||||
from neutron.plugins.hyperv.agent import utils
|
||||
from neutron.plugins.hyperv.common import constants
|
||||
from neutron.tests import base
|
||||
|
||||
|
||||
class HyperVUtilsTestCase(base.BaseTestCase):
|
||||
|
||||
FAKE_VLAN_ID = 500
|
||||
|
||||
def setUp(self):
|
||||
super(HyperVUtilsTestCase, self).setUp()
|
||||
self.utils = utils.HyperVUtils()
|
||||
self.utils._wmi_conn = mock.MagicMock()
|
||||
|
||||
def test_get_vswitch_external_port(self):
|
||||
ext_port = mock.MagicMock()
|
||||
self.utils._conn.Msvm_ExternalEthernetPort.return_value = [ext_port]
|
||||
lan_endpoint = mock.MagicMock()
|
||||
ext_port.associators.return_value = [lan_endpoint]
|
||||
vswitch_port = mock.MagicMock()
|
||||
lan_endpoint.associators.return_value = [vswitch_port]
|
||||
vswitch = mock.MagicMock()
|
||||
vswitch.ElementName = mock.sentinel.FAKE_VSWITCH_NAME
|
||||
vswitch_port.associators.return_value = [vswitch]
|
||||
|
||||
result = self.utils._get_vswitch_external_port(
|
||||
mock.sentinel.FAKE_VSWITCH_NAME)
|
||||
|
||||
self.assertEqual(vswitch_port, result)
|
||||
|
||||
ext_port.associators.assert_called_once_with(
|
||||
wmi_result_class=self.utils._SWITCH_LAN_ENDPOINT)
|
||||
lan_endpoint.associators.assert_called_once_with(
|
||||
wmi_result_class=self.utils._ETHERNET_SWITCH_PORT)
|
||||
vswitch_port.associators.assert_called_once_with(
|
||||
wmi_result_class=self.utils._VIRTUAL_SWITCH)
|
||||
|
||||
@mock.patch.object(utils.HyperVUtils, "_get_vswitch_external_port")
|
||||
def _check_set_switch_ext_port_trunk_vlan(self,
|
||||
mock_get_vswitch_external_port, desired_endpoint_mode,
|
||||
trunked_list):
|
||||
vswitch_external_port = mock_get_vswitch_external_port.return_value
|
||||
vlan_endpoint = mock.MagicMock()
|
||||
vswitch_external_port.associators.return_value = [vlan_endpoint]
|
||||
vlan_endpoint_settings = mock.MagicMock()
|
||||
vlan_endpoint_settings.TrunkedVLANList = trunked_list
|
||||
vlan_endpoint.associators.return_value = [vlan_endpoint_settings]
|
||||
|
||||
self.utils.set_switch_external_port_trunk_vlan(
|
||||
mock.sentinel.FAKE_VSWITCH_NAME, self.FAKE_VLAN_ID,
|
||||
desired_endpoint_mode)
|
||||
|
||||
mock_get_vswitch_external_port.assert_called_once_with(
|
||||
mock.sentinel.FAKE_VSWITCH_NAME)
|
||||
vswitch_external_port.associators.assert_called_once_with(
|
||||
wmi_association_class=self.utils._BINDS_TO)
|
||||
vlan_endpoint.associators.assert_called_once_with(
|
||||
wmi_result_class=self.utils._VLAN_ENDPOINT_SET_DATA)
|
||||
|
||||
self.assertEqual(desired_endpoint_mode,
|
||||
vlan_endpoint.DesiredEndpointMode)
|
||||
self.assertIn(self.FAKE_VLAN_ID,
|
||||
vlan_endpoint_settings.TrunkedVLANList)
|
||||
|
||||
@mock.patch.object(utils.HyperVUtils, "_get_vswitch_external_port")
|
||||
def test_set_switch_ext_port_trunk_vlan_internal(self,
|
||||
mock_get_vswitch_external_port):
|
||||
mock_get_vswitch_external_port.return_value = None
|
||||
|
||||
self.utils.set_switch_external_port_trunk_vlan(
|
||||
mock.sentinel.FAKE_VSWITCH_NAME, self.FAKE_VLAN_ID,
|
||||
constants.TRUNK_ENDPOINT_MODE)
|
||||
|
||||
mock_get_vswitch_external_port.assert_called_once_with(
|
||||
mock.sentinel.FAKE_VSWITCH_NAME)
|
||||
|
||||
def test_set_switch_ext_port_trunk_vlan_trunked_missing(self):
|
||||
self._check_set_switch_ext_port_trunk_vlan(
|
||||
desired_endpoint_mode=constants.TRUNK_ENDPOINT_MODE,
|
||||
trunked_list=[])
|
||||
|
||||
def test_set_switch_ext_port_trunk_vlan_trunked_added(self):
|
||||
self._check_set_switch_ext_port_trunk_vlan(
|
||||
desired_endpoint_mode=constants.TRUNK_ENDPOINT_MODE,
|
||||
trunked_list=[self.FAKE_VLAN_ID])
|
@ -180,19 +180,6 @@ class TestHyperVUtilsV2(base.BaseTestCase):
|
||||
self.assertRaises(utils.HyperVException, self._utils._get_vswitch,
|
||||
self._FAKE_VSWITCH_NAME)
|
||||
|
||||
def test_get_vswitch_external_port(self):
|
||||
mock_vswitch = mock.MagicMock()
|
||||
mock_sw_port = mock.MagicMock()
|
||||
mock_vswitch.associators.return_value = [mock_sw_port]
|
||||
mock_le = mock_sw_port.associators.return_value
|
||||
mock_le.__len__.return_value = 1
|
||||
mock_le1 = mock_le[0].associators.return_value
|
||||
mock_le1.__len__.return_value = 1
|
||||
|
||||
vswitch_port = self._utils._get_vswitch_external_port(mock_vswitch)
|
||||
|
||||
self.assertEqual(mock_sw_port, vswitch_port)
|
||||
|
||||
def test_set_vswitch_port_vlan_id(self):
|
||||
mock_port_alloc = mock.MagicMock()
|
||||
self._utils._get_switch_port_allocation = mock.MagicMock(return_value=(
|
||||
|
Loading…
Reference in New Issue
Block a user