diff -Nru networking-hyperv-5.0.0/AUTHORS networking-hyperv-6.0.0/AUTHORS --- networking-hyperv-5.0.0/AUTHORS 2017-08-09 10:07:13.000000000 +0000 +++ networking-hyperv-6.0.0/AUTHORS 2018-01-26 01:01:19.000000000 +0000 @@ -2,10 +2,13 @@ Alessandro Pilotti Alexandru Coman Alexandru Dan +Alexandru Muresan Alin Balutoiu +Andreas Jaeger Andrei Paul Ghitea Andrei Tira Boden R +Brian Haley Cao Xuan Hoang Chris Valean Claudiu B @@ -23,11 +26,13 @@ Ngo Quoc Cuong Nguyen Van Trung Octavian Ciuhandu +OpenStack Release Bot Remus Buzatu Shivakumar M Tony Breeds Vinod Kumar Zsolt Dudás +Zuul gengchc2 howardlee janonymous @@ -36,4 +41,5 @@ melissaml sonu sonu sudhakaran +wangqiangbj wujun diff -Nru networking-hyperv-5.0.0/ChangeLog networking-hyperv-6.0.0/ChangeLog --- networking-hyperv-5.0.0/ChangeLog 2017-08-09 10:07:13.000000000 +0000 +++ networking-hyperv-6.0.0/ChangeLog 2018-01-26 01:01:19.000000000 +0000 @@ -1,6 +1,45 @@ CHANGES ======= +6.0.0 +----- + +* Fixes VLAN trunk setting issue +* tests: Use mock autospec in unit tests +* Cleans up logic +* Avoids unnecessary lock logging every loop +* Updated from global requirements +* Sets MAC spoof if neutron port security groups enabled / disabled +* Updated from global requirements +* Updated from global requirements +* fix misspelling of 'configruation' +* Updated from global requirements +* Fixes deprecated neutron config option usage +* Start using nova\_metadata\_host +* use EGRESS\_DIRECTION and INGRESS\_DIRECTION from neutron-lib +* Adds SR-IOV support +* Fix vSwitch extension check +* Validate configured vSwitches +* Updated from global requirements +* Updated from global requirements +* Align tox\_install.sh with other projects +* doc: Switch to openstackdocstheme +* Cleanup test-requirements +* Remove setting of version/release from releasenotes +* Updated from global requirements +* cleanup: Remove useless test and fixes another +* Add config sample to networking-hyperv docs +* Add oslo.config entry point +* Avoid using implicit vSwitch names +* Drop MANIFEST.in - it's not needed by pbr +* use qos constants from neutron-lib +* Stop reprocessing a neutron port if the vNIC doesn't exist +* Updated from global requirements +* Updated from global requirements +* Updated from global requirements +* Adds devstack networking-hyperv plugin +* Update reno for stable/pike + 5.0.0 ----- diff -Nru networking-hyperv-5.0.0/debian/changelog networking-hyperv-6.0.0/debian/changelog --- networking-hyperv-5.0.0/debian/changelog 2017-08-18 15:31:25.000000000 +0000 +++ networking-hyperv-6.0.0/debian/changelog 2018-01-26 21:55:04.000000000 +0000 @@ -1,8 +1,18 @@ -networking-hyperv (5.0.0-0ubuntu1~cloud0) xenial-pike; urgency=medium +networking-hyperv (6.0.0-0ubuntu1~cloud0) xenial-queens; urgency=medium * New upstream release for the Ubuntu Cloud Archive. - -- Openstack Ubuntu Testing Bot Fri, 18 Aug 2017 15:31:25 +0000 + -- Openstack Ubuntu Testing Bot Fri, 26 Jan 2018 21:55:04 +0000 + +networking-hyperv (6.0.0-0ubuntu1) bionic; urgency=medium + + * New upstream release for OpenStack Queens. + * d/*: wrap-and-sort -bast. + * d/control: Update Standards-Version to 4.1.2. + * d/control: Bump debhelper compat to 10. + * d/control: Align (Build-)Depends with upstream. + + -- Corey Bryant Fri, 26 Jan 2018 15:14:38 -0500 networking-hyperv (5.0.0-0ubuntu1) artful; urgency=medium diff -Nru networking-hyperv-5.0.0/debian/compat networking-hyperv-6.0.0/debian/compat --- networking-hyperv-5.0.0/debian/compat 2017-08-18 13:38:17.000000000 +0000 +++ networking-hyperv-6.0.0/debian/compat 2018-01-26 20:14:38.000000000 +0000 @@ -1 +1 @@ -9 +10 diff -Nru networking-hyperv-5.0.0/debian/control networking-hyperv-6.0.0/debian/control --- networking-hyperv-5.0.0/debian/control 2017-08-18 13:38:17.000000000 +0000 +++ networking-hyperv-6.0.0/debian/control 2018-01-26 20:14:38.000000000 +0000 @@ -2,56 +2,59 @@ Section: python Priority: optional Maintainer: Ubuntu Developers -Build-Depends: debhelper (>= 9), - dh-python, - openstack-pkg-tools (>= 34~), - python-all, - python-pbr (>= 2.0.0), - python-setuptools, - python-sphinx, -Build-Depends-Indep: python-babel (>= 2.3.4), - python-coverage (>= 4.0), - python-ddt (>= 1.0.1), - python-docutils (>= 0.11), - python-eventlet (>= 0.18.2), - python-fixtures (>= 3.0.0), - python-hacking (>= 0.12.0), - python-mock (>= 2.0), - python-neutron (>= 2:8.0.0), - python-neutron-lib (>= 1.9.0), - python-neutronclient (>= 1:6.3.0), - python-openstackdocstheme (>= 1.16.0), - python-os-win (>= 2.0.0), - python-oslo.config (>= 1:4.0.0), - python-oslo.i18n (>= 2.1.0), - python-oslo.log (>= 3.22.0), - python-oslo.serialization (>= 1.10.0), - python-oslo.utils (>= 3.20.0), - python-oslosphinx (>= 4.7.0), - python-oslotest (>= 1.10.0), - python-sphinx (>= 1.2.1), - python-testrepository (>= 0.0.18), - python-testscenarios (>= 0.4), - python-testtools (>= 1.4.0), -Standards-Version: 3.9.6 +Build-Depends: + debhelper (>= 10~), + dh-python, + openstack-pkg-tools (>= 34~), + python-all, + python-pbr (>= 2.0.0), + python-setuptools, + python-sphinx (>= 1.6.2), +Build-Depends-Indep: + python-babel (>= 2.3.4), + python-coverage (>= 4.0), + python-ddt (>= 1.0.1), + python-docutils (>= 0.11), + python-eventlet (>= 0.18.2), + python-fixtures (>= 3.0.0), + python-hacking (>= 0.12.0), + python-mock (>= 2.0.0), + python-neutron (>= 2:8.0.0), + python-neutron-lib (>= 1.12.0), + python-neutronclient (>= 1:6.3.0), + python-openstackdocstheme (>= 1.18.1), + python-os-win (>= 2.0.0), + python-oslo.config (>= 1:5.1.0), + python-oslo.i18n (>= 3.15.3), + python-oslo.log (>= 3.36.0), + python-oslo.serialization (>= 2.18.0), + python-oslo.utils (>= 3.33.0), + python-oslosphinx (>= 4.7.0), + python-oslotest (>= 1:3.2.0), + python-sphinx (>= 1.6.2), + python-testrepository (>= 0.0.18), + python-testscenarios (>= 0.4), + python-testtools (>= 2.2.0), +Standards-Version: 4.1.2 Homepage: https://github.com/openstack/networking-hyperv Package: python-networking-hyperv Architecture: all -Depends: python-babel (>= 2.3.4), - python-eventlet (>= 0.18.2), - python-neutron (>= 2:8.0.0), - python-neutron-lib (>= 1.9.0), - python-neutronclient (>= 1:6.3.0), - python-os-win (>= 2.0.0), - python-oslo.config (>= 1:4.0.0), - python-oslo.i18n (>= 2.1.0), - python-oslo.log (>= 3.22.0), - python-oslo.serialization (>= 1.10.0), - python-oslo.utils (>= 3.20.0), - python-pbr (>= 2.0.0), - ${misc:Depends}, - ${python:Depends} +Depends: + python-babel (>= 2.3.4), + python-eventlet (>= 0.18.2), + python-neutron (>= 2:8.0.0), + python-neutron-lib (>= 1.12.0), + python-neutronclient (>= 1:6.3.0), + python-os-win (>= 2.0.0), + python-oslo.config (>= 1:5.1.0), + python-oslo.i18n (>= 3.15.3), + python-oslo.log (>= 3.36.0), + python-oslo.serialization (>= 2.18.0), + python-oslo.utils (>= 3.33.0), + python-pbr (>= 2.0.0), + ${misc:Depends}, + ${python:Depends}, Description: OpenStack Networking Hyper-V ML2 mechanism driver Neutron is a virtual network service for Openstack, and a part of Netstack. Just like OpenStack Nova provides an API to dynamically diff -Nru networking-hyperv-5.0.0/devstack/plugin.sh networking-hyperv-6.0.0/devstack/plugin.sh --- networking-hyperv-5.0.0/devstack/plugin.sh 1970-01-01 00:00:00.000000000 +0000 +++ networking-hyperv-6.0.0/devstack/plugin.sh 2018-01-26 00:51:46.000000000 +0000 @@ -0,0 +1,11 @@ +#!/bin/bash + +NETWORKING_HYPERV_DIR=$DEST/networking-hyperv + +if [[ "$1" == "stack" && "$2" == "install" ]]; then + cd $NETWORKING_HYPERV_DIR + echo "Installing networking-hyperv." + setup_develop $NETWORKING_HYPERV_DIR + + echo "Successfully installed networking-hyperv." +fi diff -Nru networking-hyperv-5.0.0/doc/source/conf.py networking-hyperv-6.0.0/doc/source/conf.py --- networking-hyperv-5.0.0/doc/source/conf.py 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/doc/source/conf.py 2018-01-26 00:51:46.000000000 +0000 @@ -21,8 +21,9 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ 'sphinx.ext.autodoc', + 'oslo_config.sphinxconfiggen', #'sphinx.ext.intersphinx', - 'oslosphinx' + 'openstackdocstheme' ] # autodoc generation is a bit aggressive and a nuisance when doing heavy @@ -32,6 +33,9 @@ # The suffix of source filenames. source_suffix = '.rst' +config_generator_config_file = '../../etc/networking-hyperv-config-generator.conf' +sample_config_basename = '_static/networking-hyperv' + # The master toctree document. master_doc = 'index' @@ -39,6 +43,11 @@ project = 'networking-hyperv' copyright = '2013, OpenStack Foundation' +# openstackdocstheme options +repository_name = 'openstack/networking-hyperv' +bug_project = 'networking-hyperv' +bug_tag = '' + # If true, '()' will be appended to :func: etc. cross-reference text. add_function_parentheses = True @@ -54,12 +63,14 @@ # The theme to use for HTML and HTML Help pages. Major themes that come with # Sphinx are currently 'default' and 'sphinxdoc'. # html_theme_path = ["."] -# html_theme = '_theme' -# html_static_path = ['static'] +html_theme = 'openstackdocs' +html_static_path = ['_static'] # Output file base name for HTML help builder. htmlhelp_basename = '%sdoc' % project +html_last_updated_fmt = '%Y-%m-%d %H:%M' + # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass # [howto/manual]). diff -Nru networking-hyperv-5.0.0/doc/source/index.rst networking-hyperv-6.0.0/doc/source/index.rst --- networking-hyperv-5.0.0/doc/source/index.rst 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/doc/source/index.rst 2018-01-26 00:51:46.000000000 +0000 @@ -16,10 +16,10 @@ usage contributing -Indices and tables -================== +Sample Configuration File +------------------------- -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` +.. toctree:: + :maxdepth: 1 + sample_config diff -Nru networking-hyperv-5.0.0/doc/source/sample_config.rst networking-hyperv-6.0.0/doc/source/sample_config.rst --- networking-hyperv-5.0.0/doc/source/sample_config.rst 1970-01-01 00:00:00.000000000 +0000 +++ networking-hyperv-6.0.0/doc/source/sample_config.rst 2018-01-26 00:51:46.000000000 +0000 @@ -0,0 +1,17 @@ +======================================= +Networking-hyperv Configuration Options +======================================= + +The following is a sample networking-hyperv configuration for adaptation and +use. + +The sample configuration can also be viewed in :download:`file from +`. + +.. important:: + + The sample configuration file is auto-generated from networking-hyperv when + this documentation is built. You must ensure your version of + networking-hyperv matches the version of this documentation. + +.. literalinclude:: /_static/networking-hyperv.conf.sample diff -Nru networking-hyperv-5.0.0/etc/networking-hyperv-config-generator.conf networking-hyperv-6.0.0/etc/networking-hyperv-config-generator.conf --- networking-hyperv-5.0.0/etc/networking-hyperv-config-generator.conf 1970-01-01 00:00:00.000000000 +0000 +++ networking-hyperv-6.0.0/etc/networking-hyperv-config-generator.conf 2018-01-26 00:51:46.000000000 +0000 @@ -0,0 +1,9 @@ +[DEFAULT] +output_file = etc/networking-hyperv.conf.sample +wrap_width = 80 + +namespace = networking_hyperv +namespace = os_win +namespace = oslo.log +namespace = oslo.messaging +namespace = oslo.concurrency diff -Nru networking-hyperv-5.0.0/MANIFEST.in networking-hyperv-6.0.0/MANIFEST.in --- networking-hyperv-5.0.0/MANIFEST.in 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/MANIFEST.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -include AUTHORS -include ChangeLog -exclude .gitignore -exclude .gitreview - -global-exclude *.pyc diff -Nru networking-hyperv-5.0.0/networking_hyperv/neutron/agent/hnv_metadata_agent.py networking-hyperv-6.0.0/networking_hyperv/neutron/agent/hnv_metadata_agent.py --- networking-hyperv-5.0.0/networking_hyperv/neutron/agent/hnv_metadata_agent.py 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/networking_hyperv/neutron/agent/hnv_metadata_agent.py 2018-01-26 00:52:28.000000000 +0000 @@ -194,7 +194,7 @@ def _get_agent_configurations(self): return { - 'nova_metadata_ip': CONF.nova_metadata_host, + 'nova_metadata_host': CONF.nova_metadata_host, 'nova_metadata_port': CONF.nova_metadata_port, 'log_agent_heartbeats': CONF.AGENT.log_agent_heartbeats, } diff -Nru networking-hyperv-5.0.0/networking_hyperv/neutron/agent/hnv_neutron_agent.py networking-hyperv-6.0.0/networking_hyperv/neutron/agent/hnv_neutron_agent.py --- networking-hyperv-5.0.0/networking_hyperv/neutron/agent/hnv_neutron_agent.py 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/networking_hyperv/neutron/agent/hnv_neutron_agent.py 2018-01-26 00:52:28.000000000 +0000 @@ -23,7 +23,6 @@ from oslo_log import log as logging from networking_hyperv.common.i18n import _LI # noqa -from networking_hyperv.neutron import _common_utils as c_util from networking_hyperv.neutron.agent import layer2 as hyperv_base from networking_hyperv.neutron import config from networking_hyperv.neutron import constants as h_const @@ -32,8 +31,6 @@ LOG = logging.getLogger(__name__) CONF = config.CONF -_port_synchronized = c_util.get_port_synchronized_decorator('n-hv-agent-') - class HNVAgent(hyperv_base.Layer2Agent): @@ -71,10 +68,12 @@ self._network_vswitch_map[net_uuid] = vswitch_map def _port_bound(self, port_id, network_id, network_type, physical_network, - segmentation_id): + segmentation_id, port_security_enabled, set_port_sriov): """Bind the port to the recived network.""" super(HNVAgent, self)._port_bound(port_id, network_id, network_type, - physical_network, segmentation_id) + physical_network, segmentation_id, + port_security_enabled, + set_port_sriov) LOG.debug("Getting the profile id for the current port.") profile_id = self._neutron_client.get_port_profile_id(port_id) @@ -91,16 +90,6 @@ vendor_id=h_const.VENDOR_ID, vendor_name=h_const.VENDOR_NAME) - @_port_synchronized - def _treat_vif_port(self, port_id, network_id, network_type, - physical_network, segmentation_id, - admin_state_up): - if admin_state_up: - self._port_bound(port_id, network_id, network_type, - physical_network, segmentation_id) - else: - self._port_unbound(port_id) - def main(): """The entry point for the HNV Agent.""" diff -Nru networking-hyperv-5.0.0/networking_hyperv/neutron/agent/hyperv_neutron_agent.py networking-hyperv-6.0.0/networking_hyperv/neutron/agent/hyperv_neutron_agent.py --- networking-hyperv-5.0.0/networking_hyperv/neutron/agent/hyperv_neutron_agent.py 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/networking_hyperv/neutron/agent/hyperv_neutron_agent.py 2018-01-26 00:52:28.000000000 +0000 @@ -185,11 +185,11 @@ self._network_vswitch_map[net_uuid] = vswitch_map def _port_bound(self, port_id, network_id, network_type, physical_network, - segmentation_id): + segmentation_id, port_security_enabled, set_port_sriov): """Bind the port to the recived network.""" super(HyperVNeutronAgent, self)._port_bound( port_id, network_id, network_type, physical_network, - segmentation_id + segmentation_id, port_security_enabled, set_port_sriov ) vswitch_map = self._network_vswitch_map[network_id] @@ -209,6 +209,16 @@ self._utils.add_metrics_collection_acls(port_id) self._port_metric_retries[port_id] = self._metrics_max_retries + # check if security groups is enabled. + # if not, teardown the security group rules + if self._enable_security_groups: + self._sec_groups_agent.refresh_firewall([port_id]) + else: + self._utils.remove_all_security_rules(port_id) + + self._utils.set_vswitch_port_mac_spoofing(port_id, + port_security_enabled) + def _port_enable_control_metrics(self): if not self._enable_metrics_collection: return @@ -233,22 +243,9 @@ "metrics.", port_id) del self._port_metric_retries[port_id] - @_port_synchronized - def _treat_vif_port(self, port_id, network_id, network_type, - physical_network, segmentation_id, - admin_state_up): - if admin_state_up: - self._port_bound(port_id, network_id, network_type, - physical_network, segmentation_id) - # check if security groups is enabled. - # if not, teardown the security group rules - if self._enable_security_groups: - self._sec_groups_agent.refresh_firewall([port_id]) - else: - self._utils.remove_all_security_rules(port_id) - else: - self._port_unbound(port_id) - self._sec_groups_agent.remove_devices_filter([port_id]) + def _port_unbound(self, port_id, vnic_deleted=False): + super(HyperVNeutronAgent, self)._port_unbound(port_id, vnic_deleted) + self._sec_groups_agent.remove_devices_filter([port_id]) def _process_added_port(self, device_details): super(HyperVNeutronAgent, self)._process_added_port( diff -Nru networking-hyperv-5.0.0/networking_hyperv/neutron/agent/layer2.py networking-hyperv-6.0.0/networking_hyperv/neutron/agent/layer2.py --- networking-hyperv-5.0.0/networking_hyperv/neutron/agent/layer2.py 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/networking_hyperv/neutron/agent/layer2.py 2018-01-26 00:52:28.000000000 +0000 @@ -25,6 +25,7 @@ from neutron.common import rpc as n_rpc from neutron.common import topics from neutron_lib import constants as n_const +from os_win import constants as os_win_const from os_win import exceptions as os_win_exc from oslo_concurrency import lockutils from oslo_log import log as logging @@ -32,14 +33,17 @@ import six from networking_hyperv.common.i18n import _, _LI, _LE # noqa +from networking_hyperv.neutron import _common_utils as c_util from networking_hyperv.neutron.agent import base as base_agent from networking_hyperv.neutron import config from networking_hyperv.neutron import constants +from networking_hyperv.neutron import exception LOG = logging.getLogger(__name__) CONF = config.CONF _synchronized = lockutils.synchronized_with_prefix('n-hv-agent-') +_port_synchronized = c_util.get_port_synchronized_decorator('n-hv-agent-') class Layer2Agent(base_agent.BaseAgent): @@ -47,6 +51,8 @@ """Contract class for all the layer two agents.""" _AGENT_TOPIC = n_const.L2_AGENT_TOPIC + _OVS_EXT_NAME_RE = re.compile(r'.*((open.?v.?switch)|(ovs)).*', + re.IGNORECASE) def __init__(self): super(Layer2Agent, self).__init__() @@ -76,8 +82,9 @@ self._phys_net_map = agent_config.get( 'physical_network_vswitch_mappings', []) self._local_network_vswitch = agent_config.get( - 'local_network_vswitch', 'private') + 'local_network_vswitch') self._load_physical_network_mappings(self._phys_net_map) + self._validate_vswitches() self._endpoints.append(self) self._event_callback_pairs.extend([ @@ -102,12 +109,12 @@ [topics.PORT, topics.DELETE] ]) - self.connection = agent_rpc.create_consumers( + self._connection = agent_rpc.create_consumers( self._endpoints, self._topic, self._consumers, start_listening=False ) self._setup_qos_extension() - self.connection.consume_in_threads() + self._connection.consume_in_threads() report_interval = CONF.AGENT.report_interval if report_interval: @@ -136,6 +143,49 @@ vswitch = parts[1].strip() self._physical_network_mappings[pattern] = vswitch + def _validate_vswitches(self): + vswitch_names = list(self._physical_network_mappings.values()) + if self._local_network_vswitch: + vswitch_names.append(self._local_network_vswitch) + + vswitches_valid = True + for vswitch_name in vswitch_names: + try: + self._validate_vswitch(vswitch_name) + except exception.ValidationError: + # We're validating all the vSwitches before erroring out. + LOG.error("Validating vSwitch %s failed", vswitch_name) + vswitches_valid = False + + # We're currently stopping the service if any of the configured + # vSwitches are unavailable. + if not vswitches_valid: + err_msg = _("Validating one or more configured vSwitches failed.") + raise exception.ValidationError(err_msg) + elif not vswitch_names: + err_msg = _("No vSwitch configured.") + raise exception.ValidationError(err_msg) + + def _validate_vswitch(self, vswitch_name): + try: + vswitch_extensions = self._utils.get_vswitch_extensions( + vswitch_name) + except os_win_exc.HyperVvSwitchNotFound as exc: + raise exception.ValidationError(exc.message) + + for ext in vswitch_extensions: + if (self._is_ovs_extension(ext) and + ext['enabled_state'] == os_win_const.CIM_STATE_ENABLED): + err_msg = _("The Open vSwitch extension is enabled on the " + "'%s' vSwitch. For this reason, this agent " + "cannot use the specified vSwitch.") + raise exception.ValidationError(err_msg % vswitch_name) + + def _is_ovs_extension(self, vswitch_extension): + # The OVS extension name keeps changing, while some vendors + # redistribute it under a different name. + return bool(self._OVS_EXT_NAME_RE.match(vswitch_extension['name'])) + def _get_vswitch_name(self, network_type, physical_network): """Get the vswitch name for the received network information.""" if network_type != constants.TYPE_LOCAL: @@ -143,7 +193,16 @@ physical_network) else: vswitch_name = self._local_network_vswitch - return vswitch_name + + if vswitch_name: + return vswitch_name + + err_msg = _("No vSwitch configured for physical network " + "'%(physical_network)s'. Neutron network type: " + "'%(network_type)s'.") + raise exception.NetworkingHyperVException( + err_msg % dict(physical_network=physical_network, + network_type=network_type)) def _get_vswitch_for_physical_network(self, phys_network_name): """Get the vswitch name for the received network name.""" @@ -152,8 +211,6 @@ phys_network_name = '' if re.match(pattern, phys_network_name): return self._physical_network_mappings[pattern] - # Not found in the mappings, the vswitch has the same name - return phys_network_name def _get_network_vswitch_map_by_port_id(self, port_id): """Get the vswitch name for the received port id.""" @@ -192,7 +249,7 @@ del self._network_vswitch_map[net_uuid] def _port_bound(self, port_id, network_id, network_type, physical_network, - segmentation_id): + segmentation_id, port_security_enabled, set_port_sriov): """Bind the port to the recived network.""" LOG.debug("Binding port %s", port_id) @@ -210,6 +267,9 @@ vswitch_name=vswitch_map['vswitch_name'], switch_port_name=port_id, ) + if set_port_sriov: + LOG.debug("Enabling SR-IOV for port: %s", port_id) + self._utils.set_vswitch_port_sriov(port_id, True) def _port_unbound(self, port_id, vnic_deleted=False): LOG.debug("Trying to unbind the port %r", port_id) @@ -229,13 +289,17 @@ self._reclaim_local_network(net_uuid) def _process_added_port(self, device_details): + # NOTE(claudiub): A port requiring SR-IOV will specify a PCI slot. + set_port_sriov = 'pci_slot' in device_details.get('profile', {}) self._treat_vif_port( port_id=device_details['port_id'], network_id=device_details['network_id'], network_type=device_details['network_type'], physical_network=device_details['physical_network'], segmentation_id=device_details['segmentation_id'], - admin_state_up=device_details['admin_state_up']) + admin_state_up=device_details['admin_state_up'], + port_security_enabled=device_details['port_security_enabled'], + set_port_sriov=set_port_sriov) def process_added_port(self, device_details): """Process the new ports. @@ -255,9 +319,14 @@ except os_win_exc.HyperVvNicNotFound: LOG.debug('vNIC %s not found. This can happen if the VM was ' 'destroyed.', port_id) + reprocess = False except os_win_exc.HyperVPortNotFoundException: LOG.debug('vSwitch port %s not found. This can happen if the VM ' 'was destroyed.', port_id) + # NOTE(claudiub): just to be on the safe side, in case Hyper-V said + # that the port was added, but it hasn't really, we're leaving + # reprocess = True. If the VM / vNIC was removed, on the next + # reprocess, a HyperVvNicNotFound will be raised. except Exception as ex: # NOTE(claudiub): in case of a non-transient error, the port will # be processed over and over again, and will not be reported as @@ -350,7 +419,8 @@ self._utils.update_cache() self._refresh_cache = False - eventlet.spawn_n(self._notify_plugin_on_port_updates) + if self._bound_ports or self._unbound_ports: + eventlet.spawn_n(self._notify_plugin_on_port_updates) # notify plugin about port deltas if self._added_ports: @@ -373,6 +443,7 @@ physical_network=physical_network, segmentation_id=segmentation_id, admin_state_up=port['admin_state_up'], + port_security_enabled=port['port_security_enabled'], ) else: LOG.debug("No port %s defined on agent.", port['id']) @@ -397,8 +468,14 @@ """Provision the network with the received information.""" pass - @abc.abstractmethod + @_port_synchronized def _treat_vif_port(self, port_id, network_id, network_type, physical_network, segmentation_id, - admin_state_up): - pass + admin_state_up, port_security_enabled, + set_port_sriov=False): + if admin_state_up: + self._port_bound(port_id, network_id, network_type, + physical_network, segmentation_id, + port_security_enabled, set_port_sriov) + else: + self._port_unbound(port_id) diff -Nru networking-hyperv-5.0.0/networking_hyperv/neutron/config.py networking-hyperv-6.0.0/networking_hyperv/neutron/config.py --- networking-hyperv-5.0.0/networking_hyperv/neutron/config.py 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/networking_hyperv/neutron/config.py 2018-01-26 00:51:46.000000000 +0000 @@ -39,7 +39,6 @@ 'wildcards, e.g.: ."*:external"')), cfg.StrOpt( 'local_network_vswitch', - default='private', help=_('Private vswitch name used for local networks')), cfg.IntOpt('polling_interval', default=2, min=1, help=_("The number of seconds the agent will wait between " @@ -145,21 +144,25 @@ "traffic.")), ] +ALL_OPTS = [ + (HYPERV_AGENT_GROUP, HYPERV_AGENT_OPTS), + (NVGRE_GROUP, NVGRE_OPTS), + (NEUTRON_GROUP, NEUTRON_OPTS), + (HNV_GROUP, HNV_OPTS) +] -def register_opts(): - CONF.register_group(HYPERV_AGENT_GROUP) - CONF.register_opts(HYPERV_AGENT_OPTS, group=HYPERV_AGENT_GROUP_NAME) - CONF.register_group(NVGRE_GROUP) - CONF.register_opts(NVGRE_OPTS, group=NVGRE_GROUP_NAME) +def register_opts(): + for group, opts in ALL_OPTS: + CONF.register_group(group) + CONF.register_opts(opts, group=group) - CONF.register_group(NEUTRON_GROUP) - CONF.register_opts(NEUTRON_OPTS, group=NEUTRON_GROUP_NAME) ks_loading.register_session_conf_options(CONF, NEUTRON_GROUP) ks_loading.register_auth_conf_options(CONF, NEUTRON_GROUP) - CONF.register_group(HNV_GROUP) - CONF.register_opts(HNV_OPTS, group=HNV_GROUP_NAME) + +def list_opts(): + return ALL_OPTS register_opts() diff -Nru networking-hyperv-5.0.0/networking_hyperv/neutron/exception.py networking-hyperv-6.0.0/networking_hyperv/neutron/exception.py --- networking-hyperv-5.0.0/networking_hyperv/neutron/exception.py 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/networking_hyperv/neutron/exception.py 2018-01-26 00:51:46.000000000 +0000 @@ -17,3 +17,11 @@ class NetworkingHyperVException(Exception): pass + + +class Invalid(NetworkingHyperVException): + pass + + +class ValidationError(Invalid): + pass diff -Nru networking-hyperv-5.0.0/networking_hyperv/neutron/ml2/README networking-hyperv-6.0.0/networking_hyperv/neutron/ml2/README --- networking-hyperv-5.0.0/networking_hyperv/neutron/ml2/README 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/networking_hyperv/neutron/ml2/README 2018-01-26 00:51:46.000000000 +0000 @@ -3,7 +3,7 @@ This mechanism driver is used by ``neutron-server`` in order to bind neutron ports to Hyper-V hosts. In order to use it, ``neutron-server`` must use the -Ml2Plugin as a ``core_plugin``. The service's configration file +Ml2Plugin as a ``core_plugin``. The service's configuration file (``/etc/neutron/neutron.conf``), must contain this following line: :: diff -Nru networking-hyperv-5.0.0/networking_hyperv/neutron/qos/qos_driver.py networking-hyperv-6.0.0/networking_hyperv/neutron/qos/qos_driver.py --- networking-hyperv-5.0.0/networking_hyperv/neutron/qos/qos_driver.py 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/networking_hyperv/neutron/qos/qos_driver.py 2018-01-26 00:51:46.000000000 +0000 @@ -15,7 +15,7 @@ # under the License. from neutron.agent.l2.extensions import qos -from neutron.services.qos import qos_consts +from neutron_lib.services.qos import constants as qos_consts from os_win.utils.network import networkutils from oslo_log import log as logging diff -Nru networking-hyperv-5.0.0/networking_hyperv/neutron/security_groups_driver.py networking-hyperv-6.0.0/networking_hyperv/neutron/security_groups_driver.py --- networking-hyperv-5.0.0/networking_hyperv/neutron/security_groups_driver.py 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/networking_hyperv/neutron/security_groups_driver.py 2018-01-26 00:52:28.000000000 +0000 @@ -17,6 +17,7 @@ import netaddr from neutron.agent import firewall +from neutron_lib import constants from os_win import exceptions from os_win.utils.network import networkutils from os_win import utilsfactory @@ -28,10 +29,8 @@ LOG = logging.getLogger(__name__) -INGRESS_DIRECTION = 'ingress' -EGRESS_DIRECTION = 'egress' -DIRECTION_IP_PREFIX = {'ingress': 'source_ip_prefix', - 'egress': 'dest_ip_prefix'} +DIRECTION_IP_PREFIX = {constants.INGRESS_DIRECTION: 'source_ip_prefix', + constants.EGRESS_DIRECTION: 'dest_ip_prefix'} ACL_PROP_MAP = { 'direction': {'ingress': networkutils.NetworkUtils._ACL_DIR_IN, @@ -126,10 +125,10 @@ newports = {} for port in ports: _rules = [] - _rules.extend(self._select_sg_rules_for_port(port, - INGRESS_DIRECTION)) - _rules.extend(self._select_sg_rules_for_port(port, - EGRESS_DIRECTION)) + _rules.extend(self._select_sg_rules_for_port( + port, constants.INGRESS_DIRECTION)) + _rules.extend(self._select_sg_rules_for_port( + port, constants.EGRESS_DIRECTION)) newports[port['id']] = _rules return newports diff -Nru networking-hyperv-5.0.0/networking_hyperv/neutron/trunk_driver.py networking-hyperv-6.0.0/networking_hyperv/neutron/trunk_driver.py --- networking-hyperv-5.0.0/networking_hyperv/neutron/trunk_driver.py 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/networking_hyperv/neutron/trunk_driver.py 2018-01-26 00:52:28.000000000 +0000 @@ -143,4 +143,4 @@ vlan_id, port_id, operation_mode=op_mode, - vlan_trunk=vlan_trunk) + trunk_vlans=vlan_trunk) diff -Nru networking-hyperv-5.0.0/networking_hyperv/tests/base.py networking-hyperv-6.0.0/networking_hyperv/tests/base.py --- networking-hyperv-5.0.0/networking_hyperv/tests/base.py 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/networking_hyperv/tests/base.py 2018-01-26 00:52:28.000000000 +0000 @@ -27,6 +27,7 @@ import mock from os_win import utilsfactory from oslo_utils import strutils +from oslotest import mock_fixture import testtools from networking_hyperv.neutron import config @@ -35,6 +36,8 @@ LOG_FORMAT = "%(asctime)s %(levelname)8s [%(name)s] %(message)s" +mock_fixture.patch_mock_module() + def bool_from_env(key, strict=False, default=False): value = os.environ.get(key) @@ -43,8 +46,12 @@ class BaseTestCase(testtools.TestCase): + _autospec_classes = [] + def setUp(self): super(BaseTestCase, self).setUp() + self.useFixture(mock_fixture.MockAutospecFixture()) + self._patch_autospec_classes() self.addCleanup(CONF.reset) self.addCleanup(mock.patch.stopall) @@ -78,6 +85,14 @@ self.addOnException(self.check_for_systemexit) + def _patch_autospec_classes(self): + for class_type in self._autospec_classes: + mocked_class = mock.Mock(autospec=class_type) + patcher = mock.patch( + '.'.join([class_type.__module__, class_type.__name__]), + mocked_class) + patcher.start() + def check_for_systemexit(self, exc_info): if isinstance(exc_info[1], SystemExit): self.fail("A SystemExit was raised during the test. %s" diff -Nru networking-hyperv-5.0.0/networking_hyperv/tests/unit/neutron/agent/test_base.py networking-hyperv-6.0.0/networking_hyperv/tests/unit/neutron/agent/test_base.py --- networking-hyperv-5.0.0/networking_hyperv/tests/unit/neutron/agent/test_base.py 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/networking_hyperv/tests/unit/neutron/agent/test_base.py 2018-01-26 00:52:28.000000000 +0000 @@ -18,6 +18,7 @@ """ import mock +from neutron.agent import rpc as agent_rpc from networking_hyperv.neutron.agent import base as agent_base from networking_hyperv.tests import base as test_base @@ -44,13 +45,8 @@ self._agent._agent_id = mock.sentinel.agent_id self._agent._context = mock.sentinel.admin_context - self._agent._utils = mock.MagicMock() - - self._agent._client = mock.MagicMock() - self._agent._plugin_rpc = mock.Mock() - self._agent._connection = mock.MagicMock() - - self._agent._state_rpc = mock.MagicMock() + self._agent._state_rpc = mock.MagicMock( + autospec=agent_rpc.PluginReportStateAPI) def test_set_agent_state(self): self._agent._agent_state = {} diff -Nru networking-hyperv-5.0.0/networking_hyperv/tests/unit/neutron/agent/test_hnv_metadata_agent.py networking-hyperv-6.0.0/networking_hyperv/tests/unit/neutron/agent/test_hnv_metadata_agent.py --- networking-hyperv-5.0.0/networking_hyperv/tests/unit/neutron/agent/test_hnv_metadata_agent.py 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/networking_hyperv/tests/unit/neutron/agent/test_hnv_metadata_agent.py 2018-01-26 00:52:28.000000000 +0000 @@ -30,15 +30,14 @@ class TestMetadataProxyHandler(test_base.BaseTestCase): - @mock.patch("networking_hyperv.neutron.neutron_client.NeutronAPIClient") - @mock.patch("neutron_lib.context.get_admin_context_without_session") - def _get_proxy(self, mock_get_context, mock_neutron_client): - return hnv_metadata_agent._MetadataProxyHandler() + _autospec_classes = [ + hnv_metadata_agent.neutron_client.NeutronAPIClient, + ] def setUp(self): super(TestMetadataProxyHandler, self).setUp() hnv_metadata_agent.register_config_opts() - self._proxy = self._get_proxy() + self._proxy = hnv_metadata_agent._MetadataProxyHandler() self._neutron_client = self._proxy._neutron_client @mock.patch.object(hnv_metadata_agent._MetadataProxyHandler, @@ -116,7 +115,7 @@ def _test_proxy_request(self, mock_get_headers, mock_http, valid_path=True, valid_profile_id=True, response_code=200, method='GET'): - nova_url = '%s:%s' % (CONF.nova_metadata_ip, + nova_url = '%s:%s' % (CONF.nova_metadata_host, CONF.nova_metadata_port) path = "/9d0bab3e-1abf-11e7-a7ef-5cc5d4a321db" if valid_path else "/" headers = {"X-Not-Empty": True} if valid_profile_id else {} @@ -231,12 +230,12 @@ def test_get_agent_configurations(self): fake_ip = '10.10.10.10' fake_port = 9999 - self.config(nova_metadata_ip=fake_ip, + self.config(nova_metadata_host=fake_ip, nova_metadata_port=fake_port) configuration = self._agent._get_agent_configurations() - self.assertEqual(fake_ip, configuration["nova_metadata_ip"]) + self.assertEqual(fake_ip, configuration["nova_metadata_host"]) self.assertEqual(fake_port, configuration["nova_metadata_port"]) self.assertEqual(CONF.AGENT.log_agent_heartbeats, configuration["log_agent_heartbeats"]) diff -Nru networking-hyperv-5.0.0/networking_hyperv/tests/unit/neutron/agent/test_hnv_neutron_agent.py networking-hyperv-6.0.0/networking_hyperv/tests/unit/neutron/agent/test_hnv_neutron_agent.py --- networking-hyperv-5.0.0/networking_hyperv/tests/unit/neutron/agent/test_hnv_neutron_agent.py 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/networking_hyperv/tests/unit/neutron/agent/test_hnv_neutron_agent.py 2018-01-26 00:52:28.000000000 +0000 @@ -28,6 +28,10 @@ class TestHNVAgent(test_base.HyperVBaseTestCase): + _autospec_classes = [ + hnv_agent.neutron_client.NeutronAPIClient, + ] + @mock.patch.object(hnv_agent.HNVAgent, "_setup") @mock.patch.object(hnv_agent.HNVAgent, "_setup_rpc") @mock.patch.object(hnv_agent.HNVAgent, "_set_agent_state") @@ -38,7 +42,7 @@ super(TestHNVAgent, self).setUp() self.agent = self._get_agent() - self.agent._neutron_client = mock.Mock() + self.agent._utils = mock.Mock(autospec=self.agent._utils) def test_get_agent_configurations(self): self.config(logical_network=mock.sentinel.logical_network, @@ -82,12 +86,14 @@ self.agent._port_bound( mock.sentinel.port_id, mock.sentinel.network_id, mock.sentinel.network_type, mock.sentinel.physical_network, - mock.sentinel.segmentation_id) + mock.sentinel.segmentation_id, mock.sentinel.port_security_enabled, + mock.sentinel.set_port_sriov) mock_super_port_bound.assert_called_once_with( mock.sentinel.port_id, mock.sentinel.network_id, mock.sentinel.network_type, mock.sentinel.physical_network, - mock.sentinel.segmentation_id) + mock.sentinel.segmentation_id, mock.sentinel.port_security_enabled, + mock.sentinel.set_port_sriov) mock_neutron_client = self.agent._neutron_client mock_neutron_client.get_port_profile_id.assert_called_once_with( mock.sentinel.port_id) @@ -102,27 +108,6 @@ vendor_id=constants.VENDOR_ID, vendor_name=constants.VENDOR_NAME) - @mock.patch.object(hnv_agent.HNVAgent, '_port_bound') - def test_treat_vif_port_state_up(self, mock_port_bound): - self.agent._treat_vif_port( - mock.sentinel.port_id, mock.sentinel.network_id, - mock.sentinel.network_type, mock.sentinel.physical_network, - mock.sentinel.segmentation_id, True) - - mock_port_bound.assert_called_once_with( - mock.sentinel.port_id, mock.sentinel.network_id, - mock.sentinel.network_type, mock.sentinel.physical_network, - mock.sentinel.segmentation_id) - - @mock.patch.object(hnv_agent.HNVAgent, '_port_unbound') - def test_treat_vif_port_state_down(self, mock_port_unbound): - self.agent._treat_vif_port( - mock.sentinel.port_id, mock.sentinel.network_id, - mock.sentinel.network_type, mock.sentinel.physical_network, - mock.sentinel.segmentation_id, False) - - mock_port_unbound.assert_called_once_with(mock.sentinel.port_id) - class TestMain(test_base.BaseTestCase): diff -Nru networking-hyperv-5.0.0/networking_hyperv/tests/unit/neutron/agent/test_hyperv_neutron_agent.py networking-hyperv-6.0.0/networking_hyperv/tests/unit/neutron/agent/test_hyperv_neutron_agent.py --- networking-hyperv-5.0.0/networking_hyperv/tests/unit/neutron/agent/test_hyperv_neutron_agent.py 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/networking_hyperv/tests/unit/neutron/agent/test_hyperv_neutron_agent.py 2018-01-26 00:52:28.000000000 +0000 @@ -20,7 +20,10 @@ import sys +import ddt import mock +from neutron.agent import rpc as agent_rpc +from neutron.common import rpc as n_rpc from neutron.common import topics from os_win import exceptions @@ -68,18 +71,22 @@ super(TestHyperVNeutronAgent, self).setUp() self.agent = self._get_agent() - self.agent._qos_ext = mock.MagicMock() - self.agent._plugin_rpc = mock.Mock() - self.agent._metricsutils = mock.MagicMock() - self.agent._utils = mock.MagicMock() - self.agent._sec_groups_agent = mock.MagicMock() - self.agent._context = mock.Mock() - self.agent._client = mock.MagicMock() - self.agent._connection = mock.MagicMock() - self.agent._agent_id = mock.Mock() - self.agent._utils = mock.MagicMock() - self.agent._nvgre_ops = mock.MagicMock() - self.agent._vlan_driver = mock.MagicMock() + self.agent._utils = mock.MagicMock(autospec=self.agent._utils) + self.agent._metricsutils = mock.MagicMock( + autospec=self.agent._metricsutils) + self.agent._nvgre_ops = mock.MagicMock( + autospec=hyperv_agent.nvgre_ops.HyperVNvgreOps) + + self.agent._sec_groups_agent = mock.MagicMock( + autospec=hyperv_agent.HyperVSecurityAgent) + self.agent._vlan_driver = mock.MagicMock( + autospec=hyperv_agent.trunk_driver.HyperVTrunkDriver) + self.agent._qos_ext = mock.MagicMock( + autospec=hyperv_agent.qos_extension.QosAgentExtension) + + self.agent._plugin_rpc = mock.MagicMock(autospec=agent_rpc.PluginApi) + self.agent._client = mock.MagicMock(autospec=n_rpc.BackingOffClient) + self.agent._connection = mock.MagicMock(autospec=n_rpc.Connection) self.agent._refresh_cache = False self.agent._added_ports = set() @@ -232,60 +239,55 @@ constants.TYPE_LOCAL, mock.sentinel.FAKE_PHYSICAL_NETWORK) - def _test_port_bound(self, enable_metrics): - self.agent._enable_metrics_collection = enable_metrics - port = mock.MagicMock() + @ddt.data({'enable_security_groups': True}, + {'network_type': constants.TYPE_LOCAL}, + {'network_type': constants.TYPE_VLAN}, + {'network_type': constants.TYPE_NVGRE}) + @ddt.unpack + @mock.patch.object(layer2.Layer2Agent, '_port_bound') + def test_port_bound(self, mock_super_bound, + network_type=constants.TYPE_FLAT, + enable_security_groups=False): net_uuid = 'my-net-uuid' + self.agent._enable_metrics_collection = True + self.agent._enable_security_groups = enable_security_groups + self.agent._network_vswitch_map[net_uuid] = mock.sentinel.vswitch_name - self.agent._port_bound(port, net_uuid, 'vlan', None, None) - - self.assertEqual(enable_metrics, - self.agent._utils.add_metrics_collection_acls.called) - - def test_port_bound_enable_metrics(self): - self._test_port_bound(True) - - def test_port_bound_no_metrics(self): - self._test_port_bound(False) - - @mock.patch.object(hyperv_agent.HyperVNeutronAgent, - '_provision_network') - def _check_port_bound_net_type(self, mock_provision_network, network_type): - net_uuid = 'my-net-uuid' - fake_map = {'vswitch_name': mock.sentinel.vswitch_name, - 'ports': []} - - def fake_prov_network(*args, **kwargs): - self.agent._network_vswitch_map[net_uuid] = fake_map - - mock_provision_network.side_effect = fake_prov_network - - self.agent._port_bound(mock.sentinel.port_id, net_uuid, network_type, + self.agent._port_bound(mock.sentinel.port_id, net_uuid, + network_type, mock.sentinel.physical_network, - mock.sentinel.segmentation_id) + mock.sentinel.segmentation_id, + mock.sentinel.port_security_enabled, + False) - self.assertIn(mock.sentinel.port_id, fake_map['ports']) - mock_provision_network.assert_called_once_with( + mock_super_bound.assert_called_once_with( mock.sentinel.port_id, net_uuid, network_type, - mock.sentinel.physical_network, mock.sentinel.segmentation_id) - self.agent._utils.connect_vnic_to_vswitch.assert_called_once_with( - vswitch_name=mock.sentinel.vswitch_name, - switch_port_name=mock.sentinel.port_id) - - def test_port_bound_vlan(self): - self._check_port_bound_net_type(network_type=constants.TYPE_VLAN) - - self.agent._vlan_driver.bind_vlan_port.assert_called_once_with( - mock.sentinel.port_id, mock.sentinel.segmentation_id) - - def test_port_bound_nvgre(self): - self.agent._nvgre_enabled = True - self._check_port_bound_net_type(network_type=constants.TYPE_NVGRE) + mock.sentinel.physical_network, + mock.sentinel.segmentation_id, mock.sentinel.port_security_enabled, + False) + + if network_type == constants.TYPE_VLAN: + self.agent._vlan_driver.bind_vlan_port.assert_called_once_with( + mock.sentinel.port_id, mock.sentinel.segmentation_id) + elif network_type == constants.TYPE_NVGRE: + self.agent._nvgre_ops.bind_nvgre_port.assert_called_once_with( + mock.sentinel.segmentation_id, mock.sentinel.vswitch_name, + mock.sentinel.port_id) - self.agent._nvgre_ops.bind_nvgre_port.assert_called_once_with( - mock.sentinel.segmentation_id, mock.sentinel.vswitch_name, + self.agent._utils.add_metrics_collection_acls.assert_called_once_with( mock.sentinel.port_id) + if enable_security_groups: + refresh_firewall = self.agent._sec_groups_agent.refresh_firewall + refresh_firewall.assert_called_once_with([mock.sentinel.port_id]) + else: + remove_sec_rules = self.agent._utils.remove_all_security_rules + remove_sec_rules.assert_called_once_with(mock.sentinel.port_id) + + set_mac_spoofing = self.agent._utils.set_vswitch_port_mac_spoofing + set_mac_spoofing.assert_called_once_with( + mock.sentinel.port_id, mock.sentinel.port_security_enabled) + def test_port_enable_control_metrics_ok(self): self.agent._enable_metrics_collection = True self.agent._port_metric_retries[self._FAKE_PORT_ID] = ( @@ -321,59 +323,15 @@ self.agent._port_enable_control_metrics() self.assertNotIn(self._FAKE_PORT_ID, self.agent._port_metric_retries) - @mock.patch.object(hyperv_agent.HyperVNeutronAgent, - '_port_unbound') - def test_vif_port_state_down(self, mock_port_unbound): - self.agent._treat_vif_port( - mock.sentinel.port_id, mock.sentinel.network_id, - mock.sentinel.network_type, mock.sentinel.physical_network, - mock.sentinel.segmentation_id, False) - - mock_port_unbound.assert_called_once_with(mock.sentinel.port_id) - sg_agent = self.agent._sec_groups_agent - sg_agent.remove_devices_filter.assert_called_once_with( - [mock.sentinel.port_id]) - - @mock.patch.object(hyperv_agent.HyperVNeutronAgent, - '_port_bound') - def _check_treat_vif_port_state_up(self, mock_port_bound): - self.agent._treat_vif_port( - mock.sentinel.port_id, mock.sentinel.network_id, - mock.sentinel.network_type, mock.sentinel.physical_network, - mock.sentinel.segmentation_id, True) - - mock_port_bound.assert_called_once_with( - mock.sentinel.port_id, mock.sentinel.network_id, - mock.sentinel.network_type, mock.sentinel.physical_network, - mock.sentinel.segmentation_id) - - def test_treat_vif_port_sg_enabled(self): - self.agent._enable_security_groups = True - - self._check_treat_vif_port_state_up() - - sg_agent = self.agent._sec_groups_agent - sg_agent.refresh_firewall.assert_called_once_with( - [mock.sentinel.port_id]) - - def test_treat_vif_port_sg_disabled(self): - self.agent._enable_security_groups = False - - self._check_treat_vif_port_state_up() - - self.agent._utils.remove_all_security_rules.assert_called_once_with( - mock.sentinel.port_id) - - def _get_fake_port_details(self): - return { - 'device': mock.sentinel.device, - 'port_id': mock.sentinel.port_id, - 'network_id': mock.sentinel.network_id, - 'network_type': mock.sentinel.network_type, - 'physical_network': mock.sentinel.physical_network, - 'segmentation_id': mock.sentinel.segmentation_id, - 'admin_state_up': mock.sentinel.admin_state_up - } + @mock.patch.object(layer2.Layer2Agent, '_port_unbound') + def test_port_unbound(self, mock_super_unbound): + self.agent._port_unbound(mock.sentinel.port_id, + mock.sentinel.vnic_deleted) + + mock_super_unbound.assert_called_once_with( + mock.sentinel.port_id, mock.sentinel.vnic_deleted) + remove_dev_filter = self.agent._sec_groups_agent.remove_devices_filter + remove_dev_filter.assert_called_once_with([mock.sentinel.port_id]) @mock.patch.object(layer2.Layer2Agent, "_process_added_port") def test_process_added_port(self, mock_process): diff -Nru networking-hyperv-5.0.0/networking_hyperv/tests/unit/neutron/agent/test_layer2.py networking-hyperv-6.0.0/networking_hyperv/tests/unit/neutron/agent/test_layer2.py --- networking-hyperv-5.0.0/networking_hyperv/tests/unit/neutron/agent/test_layer2.py 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/networking_hyperv/tests/unit/neutron/agent/test_layer2.py 2018-01-26 00:52:28.000000000 +0000 @@ -24,6 +24,7 @@ import neutron from neutron.common import topics from neutron.conf.agent import common as neutron_config +from os_win import constants as os_win_const from os_win import exceptions as os_win_exc from networking_hyperv.neutron.agent import layer2 as agent_base @@ -47,11 +48,6 @@ physical_network, segmentation_id): pass - def _treat_vif_port(self, port_id, network_id, network_type, - physical_network, segmentation_id, - admin_state_up): - pass - @ddt.ddt class TestLayer2Agent(test_base.HyperVBaseTestCase): @@ -70,21 +66,16 @@ self._agent = self._get_agent() - self._agent._qos_ext = mock.MagicMock() - self._agent._plugin_rpc = mock.Mock() - self._agent._metricsutils = mock.MagicMock() - self._agent._utils = mock.MagicMock() - self._agent._context = mock.Mock() - self._agent._client = mock.MagicMock() - self._agent._connection = mock.MagicMock() - self._agent._agent_id = mock.Mock() - self._agent._utils = mock.MagicMock() - self._agent._nvgre_ops = mock.MagicMock() - self._agent._vlan_driver = mock.MagicMock() - self._agent._physical_network_mappings = collections.OrderedDict() - self._agent._config = mock.MagicMock() + self._agent._utils = mock.MagicMock( + autospec=self._agent._utils) + self._agent._plugin_rpc = mock.Mock( + autospec=agent_base.agent_rpc.PluginApi) self._agent._endpoints = mock.MagicMock() - self._agent._event_callback_pairs = mock.MagicMock() + self._agent._client = mock.MagicMock( + autospec=agent_base.n_rpc.BackingOffClient) + self._agent._connection = mock.MagicMock( + autospec=agent_base.n_rpc.Connection) + self._agent._physical_network_mappings = collections.OrderedDict() self._agent._network_vswitch_map = {} def _get_fake_port_details(self): @@ -95,18 +86,21 @@ 'network_type': mock.sentinel.network_type, 'physical_network': mock.sentinel.physical_network, 'segmentation_id': mock.sentinel.segmentation_id, - 'admin_state_up': mock.sentinel.admin_state_up + 'admin_state_up': mock.sentinel.admin_state_up, + 'port_security_enabled': mock.sentinel.port_security_enabled, } @mock.patch.object(agent_base.Layer2Agent, '_process_removed_port_event', mock.sentinel._process_removed_port_event) @mock.patch.object(agent_base.Layer2Agent, '_process_added_port_event', mock.sentinel._process_added_port_event) + @mock.patch.object(agent_base.Layer2Agent, '_validate_vswitches') @mock.patch.object(eventlet.tpool, 'set_num_threads') @mock.patch.object(agent_base.Layer2Agent, '_load_physical_network_mappings') def test_setup(self, mock_load_phys_net_mapp, - mock_set_num_threads): + mock_set_num_threads, + mock_validate_vswitches): self.config( group="AGENT", worker_count=12, @@ -117,6 +111,7 @@ self._agent._setup() mock_load_phys_net_mapp.assert_called_once_with(["fake_mappings"]) + mock_validate_vswitches.assert_called_once_with() self._agent._endpoints.append.assert_called_once_with(self._agent) self.assertIn((self._agent._utils.EVENT_TYPE_CREATE, mock.sentinel._process_added_port_event), @@ -188,6 +183,86 @@ sorted(self._agent._physical_network_mappings.items()) ) + @ddt.data(True, False) + @mock.patch.object(agent_base.Layer2Agent, '_validate_vswitch') + def test_validate_vswitches(self, all_valid, mock_validate_vswitch): + phys_mappings = { + 'fakenetwork0': mock.sentinel.vswitch_name_0, + 'fakenetwork1': mock.sentinel.vswitch_name_1 + } + self._agent._physical_network_mappings = phys_mappings + self._agent._local_network_vswitch = mock.sentinel.local_vswitch + + exp_vswitch_names = ( + list(phys_mappings.values()) + [mock.sentinel.local_vswitch]) + + mock_validate_vswitch.side_effect = ( + exception.ValidationError if not all_valid else None, + None, None) + + if all_valid: + self._agent._validate_vswitches() + else: + self.assertRaises(exception.ValidationError, + self._agent._validate_vswitches) + + mock_validate_vswitch.assert_has_calls( + [mock.call(vswitch_name) + for vswitch_name in exp_vswitch_names], + any_order=True) + + def test_validate_vswitches_none_configured(self): + self._agent._physical_network_mappings = {} + self._agent._local_network_vswitch = None + + self.assertRaises(exception.ValidationError, + self._agent._validate_vswitches) + + def test_is_ovs_extension(self): + valid_ovs_ext_names = ['Cloudbase Open vSwitch Extension', + 'Open vSwitch Extension', + 'VendorX ovs', + 'open v-switch', + 'openvswitch'] + for ovs_ext_name in valid_ovs_ext_names: + ext = dict(name=ovs_ext_name) + self.assertTrue( + self._agent._is_ovs_extension(ext)) + + ext = dict(name='fake extension') + self.assertFalse(self._agent._is_ovs_extension(ext)) + + @ddt.data({}, + {'is_valid': False, 'exists': False}, + {'is_valid': False, + 'is_ovs_ext': True, + 'enabled_state': os_win_const.CIM_STATE_ENABLED}, + {'is_ovs_ext': True, + 'enabled_state': os_win_const.CIM_STATE_DISABLED}, + {'enabled_state': os_win_const.CIM_STATE_ENABLED}) + @ddt.unpack + @mock.patch.object(agent_base.Layer2Agent, '_is_ovs_extension') + def test_validate_vswitch(self, mock_is_ovs_ext, + is_valid=True, exists=True, is_ovs_ext=False, + enabled_state=os_win_const.CIM_STATE_ENABLED): + extension = dict(enabled_state=enabled_state) + mock_is_ovs_ext.return_value = is_ovs_ext + + mock_get_ext = self._agent._utils.get_vswitch_extensions + mock_get_ext.side_effect = ( + [[extension]] if exists + else os_win_exc.HyperVvSwitchNotFound(message='fake_msg')) + + if is_valid: + self._agent._validate_vswitch(mock.sentinel.vswitch_name) + mock_is_ovs_ext.assert_called_once_with(extension) + else: + self.assertRaises(exception.ValidationError, + self._agent._validate_vswitch, + mock.sentinel.vswitch_name) + + mock_get_ext.assert_called_once_with(mock.sentinel.vswitch_name) + def test_get_vswitch_for_physical_network_with_default_switch(self): test_mappings = [ 'fakenetwork:fake_vswitch', @@ -202,7 +277,7 @@ self.assertEqual('fake_vswitch_2', get_vswitch('fakenetwork2$')) self.assertEqual('fake_vswitch_3', get_vswitch('fakenetwork3')) self.assertEqual('fake_vswitch_3', get_vswitch('fakenetwork35')) - self.assertEqual('fake_network1', get_vswitch('fake_network1')) + self.assertIsNone(get_vswitch('fake_network1')) def test_get_vswitch_for_physical_network_without_default_switch(self): test_mappings = [ @@ -223,7 +298,7 @@ 'fakenetwork2:fake_vswitch_2' ] self._agent._load_physical_network_mappings(test_mappings) - self.assertEqual('', get_vswitch(None)) + self.assertIsNone(get_vswitch(None)) test_mappings = [ 'fakenetwork:fake_vswitch', @@ -250,6 +325,19 @@ mock_get_vswitch_for_phys_net.assert_called_once_with( mock.sentinel.FAKE_PHYSICAL_NETWORK) + @mock.patch.object(agent_base.Layer2Agent, + "_get_vswitch_for_physical_network") + @ddt.data(constants.TYPE_VLAN, constants.TYPE_LOCAL) + def test_get_vswitch_name_missing(self, network_type, + mock_get_vswitch_for_phys_net): + mock_get_vswitch_for_phys_net.return_value = None + self._agent._local_network_vswitch = '' + + self.assertRaises(exception.NetworkingHyperVException, + self._agent._get_vswitch_name, + network_type, + mock.sentinel.FAKE_PHYSICAL_NETWORK) + def test_get_network_vswitch_map_by_port_id(self): net_uuid = 'net-uuid' self._agent._network_vswitch_map = { @@ -319,21 +407,8 @@ self.assertNotIn(mock.sentinel.net_id, self._agent._network_vswitch_map) - def test_port_bound_no_metrics(self): - self._agent.enable_metrics_collection = False - port = mock.sentinel.port - net_uuid = 'my-net-uuid' - self._agent._network_vswitch_map[net_uuid] = { - 'ports': [], - 'vswitch_name': [] - } - self._agent._port_bound(str(port), net_uuid, 'vlan', None, None) - - self.assertFalse(self._agent._utils.add_metrics_collection_acls.called) - - @mock.patch.object(agent_base.Layer2Agent, - '_provision_network') - def _check_port_bound_net_type(self, mock_provision_network, network_type): + @mock.patch.object(_Layer2Agent, '_provision_network') + def test_port_bound_net_type(self, mock_provision_network): net_uuid = 'my-net-uuid' fake_map = {'vswitch_name': mock.sentinel.vswitch_name, 'ports': []} @@ -344,16 +419,20 @@ mock_provision_network.side_effect = fake_prov_network self._agent._port_bound(mock.sentinel.port_id, - net_uuid, network_type, + net_uuid, mock.sentinel.network_type, mock.sentinel.physical_network, - mock.sentinel.segmentation_id) + mock.sentinel.segmentation_id, + mock.sentinel.port_security_enabled, True) self.assertIn(mock.sentinel.port_id, fake_map['ports']) mock_provision_network.assert_called_once_with( - mock.sentinel.port_id, net_uuid, network_type, + mock.sentinel.port_id, net_uuid, mock.sentinel.network_type, mock.sentinel.physical_network, mock.sentinel.segmentation_id) self._agent._utils.connect_vnic_to_vswitch.assert_called_once_with( - mock.sentinel.vswitch_name, mock.sentinel.port_id) + vswitch_name=mock.sentinel.vswitch_name, + switch_port_name=mock.sentinel.port_id) + self._agent._utils.set_vswitch_port_sriov.assert_called_once_with( + mock.sentinel.port_id, True) @mock.patch.object(agent_base.Layer2Agent, '_get_network_vswitch_map_by_port_id') @@ -389,6 +468,17 @@ def test_port_unbound_port_not_found(self): self._check_port_unbound() + @mock.patch.object(_Layer2Agent, '_treat_vif_port') + def test_process_added_port_sriov(self, mock_treat_vif_port): + details = self._get_fake_port_details() + details.pop('device') + port_details = dict(profile={'pci_slot': mock.sentinel.pci_slot}, + **self._get_fake_port_details()) + + self._agent.process_added_port(port_details) + mock_treat_vif_port.assert_called_once_with(set_port_sriov=True, + **details) + @ddt.data(os_win_exc.HyperVvNicNotFound(vnic_name='fake_vnic'), os_win_exc.HyperVPortNotFoundException(port_name='fake_port'), Exception) @@ -397,9 +487,18 @@ mock_treat_vif_port.side_effect = side_effect self._agent._added_ports = set() details = self._get_fake_port_details() + details.pop('device') + port_details = self._get_fake_port_details() + + self._agent.process_added_port(port_details) - self._agent.process_added_port(details) - self.assertIn(mock.sentinel.device, self._agent._added_ports) + if isinstance(side_effect, os_win_exc.HyperVvNicNotFound): + self.assertNotIn(mock.sentinel.device, self._agent._added_ports) + else: + self.assertIn(mock.sentinel.device, self._agent._added_ports) + + mock_treat_vif_port.assert_called_once_with(set_port_sriov=False, + **details) def test_treat_devices_added_returns_true_for_missing_device(self): self._agent._added_ports = set([mock.sentinel.port_id]) @@ -506,6 +605,7 @@ def test_work(self, mock_spawn, mock_treat_dev_added, mock_treat_dev_removed): self._agent._refresh_cache = True + self._agent._bound_ports = set([mock.sentinel.bound_port]) self._agent._added_ports = set([mock.sentinel.bound_port]) self._agent._removed_ports = set([mock.sentinel.unbound_port]) @@ -518,16 +618,29 @@ mock_treat_dev_added.assert_called_once_with() mock_treat_dev_removed.assert_called_once_with() + @mock.patch.object(agent_base.Layer2Agent, '_treat_devices_removed') + @mock.patch.object(agent_base.Layer2Agent, '_treat_devices_added') + @mock.patch('eventlet.spawn_n') + def test_work_noop(self, mock_spawn, mock_treat_dev_added, + mock_treat_dev_removed): + self._agent._work() + + self.assertFalse(mock_spawn.called) + self.assertFalse(mock_treat_dev_added.called) + self.assertFalse(mock_treat_dev_removed.called) + def test_port_update_not_found(self): self._agent._utils.vnic_port_exists.return_value = False port = {'id': mock.sentinel.port_id} self._agent.port_update(self._agent._context, port) - def test_port_update(self): + @mock.patch.object(agent_base.Layer2Agent, '_treat_vif_port') + def test_port_update(self, mock_treat_vif_port): self._agent._utils.vnic_port_exists.return_value = True port = {'id': mock.sentinel.port_id, 'network_id': mock.sentinel.network_id, - 'admin_state_up': mock.sentinel.admin_state_up} + 'admin_state_up': mock.sentinel.admin_state_up, + 'port_security_enabled': mock.sentinel.port_security_enabled} self._agent.port_update(self._agent._context, port, mock.sentinel.network_type, @@ -550,3 +663,27 @@ def test_network_delete_not_defined(self, mock_reclaim_local_network): self._agent.network_delete(mock.sentinel.context, mock.sentinel.net_id) self.assertFalse(mock_reclaim_local_network.called) + + @mock.patch.object(agent_base.Layer2Agent, '_port_bound') + def test_treat_vif_port_state_up(self, mock_port_bound): + self._agent._treat_vif_port( + mock.sentinel.port_id, mock.sentinel.network_id, + mock.sentinel.network_type, mock.sentinel.physical_network, + mock.sentinel.segmentation_id, True, + mock.sentinel.port_security_enabled) + + mock_port_bound.assert_called_once_with( + mock.sentinel.port_id, mock.sentinel.network_id, + mock.sentinel.network_type, mock.sentinel.physical_network, + mock.sentinel.segmentation_id, mock.sentinel.port_security_enabled, + False) + + @mock.patch.object(agent_base.Layer2Agent, '_port_unbound') + def test_treat_vif_port_state_down(self, mock_port_unbound): + self._agent._treat_vif_port( + mock.sentinel.port_id, mock.sentinel.network_id, + mock.sentinel.network_type, mock.sentinel.physical_network, + mock.sentinel.segmentation_id, False, + mock.sentinel.port_security_enabled) + + mock_port_unbound.assert_called_once_with(mock.sentinel.port_id) diff -Nru networking-hyperv-5.0.0/networking_hyperv/tests/unit/neutron/qos/test_qos_driver.py networking-hyperv-6.0.0/networking_hyperv/tests/unit/neutron/qos/test_qos_driver.py --- networking-hyperv-5.0.0/networking_hyperv/tests/unit/neutron/qos/test_qos_driver.py 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/networking_hyperv/tests/unit/neutron/qos/test_qos_driver.py 2018-01-26 00:52:28.000000000 +0000 @@ -18,7 +18,7 @@ """ import mock -from neutron.services.qos import qos_consts +from neutron_lib.services.qos import constants as qos_consts from networking_hyperv.neutron.qos import qos_driver from networking_hyperv.tests import base @@ -30,7 +30,8 @@ def setUp(self): super(TestQosHyperVAgentDriver, self).setUp() self.driver = qos_driver.QosHyperVAgentDriver() - self.driver._utils = mock.Mock() + self.driver.initialize() + self.driver._utils = mock.Mock(autospec=self.driver._utils) @mock.patch.object(qos_driver, 'networkutils') def test_initialize(self, mock_networkutils): diff -Nru networking-hyperv-5.0.0/networking_hyperv/tests/unit/neutron/test_config.py networking-hyperv-6.0.0/networking_hyperv/tests/unit/neutron/test_config.py --- networking-hyperv-5.0.0/networking_hyperv/tests/unit/neutron/test_config.py 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/networking_hyperv/tests/unit/neutron/test_config.py 2018-01-26 00:51:46.000000000 +0000 @@ -30,18 +30,12 @@ def test_register_opts(self, mock_CONF, mock_ks_loading): config.register_opts() - all_groups = [config.HYPERV_AGENT_GROUP, config.NVGRE_GROUP, - config.NEUTRON_GROUP, config.HNV_GROUP] + all_groups = [pair[0] for pair in config.ALL_OPTS] mock_CONF.register_group.assert_has_calls([ mock.call(group) for group in all_groups]) - all_opts = [ - (config.HYPERV_AGENT_OPTS, config.HYPERV_AGENT_GROUP_NAME), - (config.NVGRE_OPTS, config.NVGRE_GROUP_NAME), - (config.NEUTRON_OPTS, config.NEUTRON_GROUP_NAME), - (config.HNV_OPTS, config.HNV_GROUP_NAME)] mock_CONF.register_opts.assert_has_calls([ - mock.call(opts, group=group) for opts, group in all_opts]) + mock.call(opts, group=group) for group, opts in config.ALL_OPTS]) mock_ks_loading.register_session_conf_options.assert_called_once_with( mock_CONF, config.NEUTRON_GROUP) diff -Nru networking-hyperv-5.0.0/networking_hyperv/tests/unit/neutron/test_neutron_client.py networking-hyperv-6.0.0/networking_hyperv/tests/unit/neutron/test_neutron_client.py --- networking-hyperv-5.0.0/networking_hyperv/tests/unit/neutron/test_neutron_client.py 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/networking_hyperv/tests/unit/neutron/test_neutron_client.py 2018-01-26 00:52:28.000000000 +0000 @@ -29,6 +29,10 @@ class TestNeutronClient(base.BaseTestCase): + _autospec_classes = [ + neutron_client.clientv20.Client, + ] + _FAKE_CIDR = '10.0.0.0/24' _FAKE_GATEWAY = '10.0.0.1' _FAKE_HOST = 'fake_host' @@ -36,7 +40,6 @@ def setUp(self): super(TestNeutronClient, self).setUp() self._neutron = neutron_client.NeutronAPIClient() - self._neutron._client = mock.MagicMock() @mock.patch.object(neutron_client.clientv20, "Client") @mock.patch.object(neutron_client, "ks_loading") diff -Nru networking-hyperv-5.0.0/networking_hyperv/tests/unit/neutron/test_nvgre_ops.py networking-hyperv-6.0.0/networking_hyperv/tests/unit/neutron/test_nvgre_ops.py --- networking-hyperv-5.0.0/networking_hyperv/tests/unit/neutron/test_nvgre_ops.py 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/networking_hyperv/tests/unit/neutron/test_nvgre_ops.py 2018-01-26 00:52:28.000000000 +0000 @@ -29,6 +29,10 @@ class TestHyperVNvgreOps(base.HyperVBaseTestCase): + _autospec_classes = [ + nvgre_ops.neutron_client.NeutronAPIClient, + ] + FAKE_MAC_ADDR = 'fa:ke:ma:ca:dd:re:ss' FAKE_CIDR = '10.0.0.0/24' FAKE_VSWITCH_NAME = 'fake_vswitch' @@ -41,11 +45,11 @@ self.ops._vswitch_ips[mock.sentinel.network_name] = ( mock.sentinel.ip_addr) self.ops.context = self.context - self.ops._notifier = mock.MagicMock() - self.ops._hyperv_utils = mock.MagicMock() - self.ops._nvgre_utils = mock.MagicMock() - self.ops._n_client = mock.MagicMock() - self.ops._db = mock.MagicMock() + self.ops._notifier = mock.MagicMock( + autospec=nvgre_ops.hyperv_agent_notifier.AgentNotifierApi) + self.ops._hyperv_utils = mock.MagicMock( + autospec=self.ops._hyperv_utils) + self.ops._nvgre_utils = mock.MagicMock(autospec=self.ops._nvgre_utils) @mock.patch.object(nvgre_ops.hyperv_agent_notifier, 'AgentNotifierApi') def test_init_notifier(self, mock_notifier): @@ -227,6 +231,7 @@ @mock.patch.object(nvgre_ops.HyperVNvgreOps, '_register_lookup_record') def test_refresh_nvgre_records(self, mock_register_record): + self.ops._n_client.get_tunneling_agents.return_value = {} self.ops._nvgre_ports.append(mock.sentinel.processed_port_id) self.ops._tunneling_agents[mock.sentinel.host_id] = ( mock.sentinel.agent_ip) @@ -262,6 +267,7 @@ @mock.patch.object(nvgre_ops.HyperVNvgreOps, '_register_lookup_record') def test_refresh_nvgre_records_exception(self, mock_register_record): + self.ops._n_client.get_tunneling_agents.return_value = {} self.ops._tunneling_agents[mock.sentinel.host_id] = ( mock.sentinel.agent_ip) self.ops._network_vsids[mock.sentinel.net_id] = (mock.sentinel.vsid) diff -Nru networking-hyperv-5.0.0/networking_hyperv/tests/unit/neutron/test_security_groups_driver.py networking-hyperv-6.0.0/networking_hyperv/tests/unit/neutron/test_security_groups_driver.py --- networking-hyperv-5.0.0/networking_hyperv/tests/unit/neutron/test_security_groups_driver.py 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/networking_hyperv/tests/unit/neutron/test_security_groups_driver.py 2018-01-26 00:52:28.000000000 +0000 @@ -60,6 +60,10 @@ class TestHyperVSecurityGroupsDriver(SecurityGroupRuleTestHelper): + _autospec_classes = [ + sg_driver.SecurityGroupRuleGeneratorR2, + ] + _FAKE_DEVICE = 'fake_device' _FAKE_ID = 'fake_id' _FAKE_PARAM_NAME = 'fake_param_name' @@ -69,8 +73,7 @@ super(TestHyperVSecurityGroupsDriver, self).setUp() self._driver = sg_driver.HyperVSecurityGroupsDriver() - self._driver._utils = mock.MagicMock() - self._driver._sg_gen = mock.MagicMock() + self._driver._utils = mock.MagicMock(autospec=self._driver._utils) def test__select_sg_rules_for_port(self): mock_port = self._get_port() @@ -194,6 +197,7 @@ return_value=self._FAKE_SOURCE_IP_PREFIX) mock_gen_rules.return_value = {new_mock_port['id']: [fake_rule_new]} + self._driver._sg_gen.expand_wildcard_rules.return_value = [] self._driver._security_ports[mock_port['device']] = mock_port self._driver._sec_group_rules[new_mock_port['id']] = [] diff -Nru networking-hyperv-5.0.0/networking_hyperv/tests/unit/neutron/test_trunk_driver.py networking-hyperv-6.0.0/networking_hyperv/tests/unit/neutron/test_trunk_driver.py --- networking-hyperv-5.0.0/networking_hyperv/tests/unit/neutron/test_trunk_driver.py 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/networking_hyperv/tests/unit/neutron/test_trunk_driver.py 2018-01-26 00:52:28.000000000 +0000 @@ -31,8 +31,10 @@ class TestHyperVTrunkDriver(base.HyperVBaseTestCase): - @mock.patch.object(trunk_driver.trunk_rpc, 'TrunkStub', - lambda *args, **kwargs: None) + _autospec_classes = [ + trunk_driver.trunk_rpc.TrunkStub, + ] + @mock.patch.object(trunk_driver.trunk_rpc.TrunkSkeleton, '__init__', lambda *args, **kwargs: None) def setUp(self): @@ -40,8 +42,8 @@ self.trunk_driver = trunk_driver.HyperVTrunkDriver( mock.sentinel.context) - self.trunk_driver._utils = mock.MagicMock() - self.trunk_driver._trunk_rpc = mock.MagicMock() + self.trunk_driver._utils = mock.MagicMock( + autospec=self.trunk_driver._utils) def test_handle_trunks_deleted(self): mock_trunk = mock.MagicMock() @@ -143,7 +145,7 @@ self.trunk_driver._utils.set_vswitch_port_vlan_id( mock.sentinel.vlan_id, mock.sentinel.port_id, operation_mode=operation_mode, - vlan_trunk=vlan_trunk) + trunk_vlans=vlan_trunk) def test_set_port_vlan_trunk_mode(self): self._check_set_port_vlan(mock.sentinel.vlan_trunk, diff -Nru networking-hyperv-5.0.0/networking_hyperv.egg-info/entry_points.txt networking-hyperv-6.0.0/networking_hyperv.egg-info/entry_points.txt --- networking-hyperv-5.0.0/networking_hyperv.egg-info/entry_points.txt 2017-08-09 10:07:13.000000000 +0000 +++ networking-hyperv-6.0.0/networking_hyperv.egg-info/entry_points.txt 2018-01-26 01:01:19.000000000 +0000 @@ -12,3 +12,6 @@ [neutron.qos.agent_drivers] hyperv = networking_hyperv.neutron.qos.qos_driver:QosHyperVAgentDriver +[oslo.config.opts] +networking_hyperv = networking_hyperv.neutron.config:list_opts + diff -Nru networking-hyperv-5.0.0/networking_hyperv.egg-info/pbr.json networking-hyperv-6.0.0/networking_hyperv.egg-info/pbr.json --- networking-hyperv-5.0.0/networking_hyperv.egg-info/pbr.json 2017-08-09 10:07:13.000000000 +0000 +++ networking-hyperv-6.0.0/networking_hyperv.egg-info/pbr.json 2018-01-26 01:01:19.000000000 +0000 @@ -1 +1 @@ -{"git_version": "400c817", "is_release": true} \ No newline at end of file +{"git_version": "893048d", "is_release": true} \ No newline at end of file diff -Nru networking-hyperv-5.0.0/networking_hyperv.egg-info/PKG-INFO networking-hyperv-6.0.0/networking_hyperv.egg-info/PKG-INFO --- networking-hyperv-5.0.0/networking_hyperv.egg-info/PKG-INFO 2017-08-09 10:07:13.000000000 +0000 +++ networking-hyperv-6.0.0/networking_hyperv.egg-info/PKG-INFO 2018-01-26 01:01:19.000000000 +0000 @@ -1,11 +1,12 @@ Metadata-Version: 1.1 Name: networking-hyperv -Version: 5.0.0 +Version: 6.0.0 Summary: This project tracks the work to integrate the Hyper-V networking with Neutron. This project contains the Hyper-V Neutron Agent Mixin, Security Groups Driver, ML2 Mechanism Driver and the utils modules they use in order to properly bind neutron ports on a Hyper-V host. This project resulted from the neutron core vendor decomposition. Home-page: https://github.com/openstack/networking-hyperv Author: OpenStack Author-email: openstack-dev@lists.openstack.org License: Apache License, Version 2.0 +Description-Content-Type: UNKNOWN Description: ======================== Team and repository tags ======================== diff -Nru networking-hyperv-5.0.0/networking_hyperv.egg-info/requires.txt networking-hyperv-6.0.0/networking_hyperv.egg-info/requires.txt --- networking-hyperv-5.0.0/networking_hyperv.egg-info/requires.txt 2017-08-09 10:07:13.000000000 +0000 +++ networking-hyperv-6.0.0/networking_hyperv.egg-info/requires.txt 2018-01-26 01:01:19.000000000 +0000 @@ -1,11 +1,11 @@ pbr!=2.1.0,>=2.0.0 Babel!=2.4.0,>=2.3.4 eventlet!=0.18.3,!=0.20.1,<0.21.0,>=0.18.2 -neutron-lib>=1.9.0 +neutron-lib>=1.12.0 os-win>=2.0.0 -oslo.config!=4.3.0,!=4.4.0,>=4.0.0 -oslo.i18n!=3.15.2,>=2.1.0 -oslo.log>=3.22.0 -oslo.serialization!=2.19.1,>=1.10.0 -oslo.utils>=3.20.0 +oslo.config>=5.1.0 +oslo.i18n>=3.15.3 +oslo.log>=3.36.0 +oslo.serialization!=2.19.1,>=2.18.0 +oslo.utils>=3.33.0 python-neutronclient>=6.3.0 diff -Nru networking-hyperv-5.0.0/networking_hyperv.egg-info/SOURCES.txt networking-hyperv-6.0.0/networking_hyperv.egg-info/SOURCES.txt --- networking-hyperv-5.0.0/networking_hyperv.egg-info/SOURCES.txt 2017-08-09 10:07:16.000000000 +0000 +++ networking-hyperv-6.0.0/networking_hyperv.egg-info/SOURCES.txt 2018-01-26 01:01:22.000000000 +0000 @@ -6,7 +6,6 @@ ChangeLog HACKING.rst LICENSE -MANIFEST.in README.rst babel.cfg requirements.txt @@ -14,14 +13,17 @@ setup.py test-requirements.txt tox.ini +devstack/plugin.sh doc/source/conf.py doc/source/contributing.rst doc/source/index.rst doc/source/installation.rst doc/source/readme.rst +doc/source/sample_config.rst doc/source/usage.rst doc/specs/hyper-v-nvgre.rst doc/specs/scale-hyperv-neutron-agent.rst +etc/networking-hyperv-config-generator.conf networking_hyperv/__init__.py networking_hyperv/version.py networking_hyperv.egg-info/PKG-INFO @@ -76,8 +78,12 @@ networking_hyperv/tests/unit/neutron/qos/__init__.py networking_hyperv/tests/unit/neutron/qos/test_qos_driver.py releasenotes/notes/.placeholder +releasenotes/notes/add_devstack_plugin-05fcfd36c8c1c110.yaml +releasenotes/notes/no-implicit-vswitches-5e3a28677871189b.yaml +releasenotes/notes/validate-vswitches-e0c9d79ea3c0937f.yaml releasenotes/source/conf.py releasenotes/source/index.rst +releasenotes/source/pike.rst releasenotes/source/unreleased.rst releasenotes/source/_static/.placeholder releasenotes/source/_templates/.placeholder diff -Nru networking-hyperv-5.0.0/PKG-INFO networking-hyperv-6.0.0/PKG-INFO --- networking-hyperv-5.0.0/PKG-INFO 2017-08-09 10:07:16.000000000 +0000 +++ networking-hyperv-6.0.0/PKG-INFO 2018-01-26 01:01:22.000000000 +0000 @@ -1,11 +1,12 @@ Metadata-Version: 1.1 Name: networking-hyperv -Version: 5.0.0 +Version: 6.0.0 Summary: This project tracks the work to integrate the Hyper-V networking with Neutron. This project contains the Hyper-V Neutron Agent Mixin, Security Groups Driver, ML2 Mechanism Driver and the utils modules they use in order to properly bind neutron ports on a Hyper-V host. This project resulted from the neutron core vendor decomposition. Home-page: https://github.com/openstack/networking-hyperv Author: OpenStack Author-email: openstack-dev@lists.openstack.org License: Apache License, Version 2.0 +Description-Content-Type: UNKNOWN Description: ======================== Team and repository tags ======================== diff -Nru networking-hyperv-5.0.0/releasenotes/notes/add_devstack_plugin-05fcfd36c8c1c110.yaml networking-hyperv-6.0.0/releasenotes/notes/add_devstack_plugin-05fcfd36c8c1c110.yaml --- networking-hyperv-5.0.0/releasenotes/notes/add_devstack_plugin-05fcfd36c8c1c110.yaml 1970-01-01 00:00:00.000000000 +0000 +++ networking-hyperv-6.0.0/releasenotes/notes/add_devstack_plugin-05fcfd36c8c1c110.yaml 2018-01-26 00:51:46.000000000 +0000 @@ -0,0 +1,9 @@ +--- +features: + - | + networking-hyperv can now be installed through its own devstack plugin. + This is mandatory when using the "hyperv" ML2 mechanism driver. + + Including the following line in the devstack local.conf file will enable + the plugin: + enable_plugin networking-hyperv https://github.com/openstack/networking-hyperv diff -Nru networking-hyperv-5.0.0/releasenotes/notes/no-implicit-vswitches-5e3a28677871189b.yaml networking-hyperv-6.0.0/releasenotes/notes/no-implicit-vswitches-5e3a28677871189b.yaml --- networking-hyperv-5.0.0/releasenotes/notes/no-implicit-vswitches-5e3a28677871189b.yaml 1970-01-01 00:00:00.000000000 +0000 +++ networking-hyperv-6.0.0/releasenotes/notes/no-implicit-vswitches-5e3a28677871189b.yaml 2018-01-26 00:51:46.000000000 +0000 @@ -0,0 +1,8 @@ +--- +upgrade: + - | + The agents no longer use implicit/default vSwitches. The default 'private' + local network vSwitch is no longer used and need to be explicitly + configured. Also, in case of physical networks that are not included in + the physical network mappings, the agent no longer attempts to implicitly + use a vSwitch that has the same name. diff -Nru networking-hyperv-5.0.0/releasenotes/notes/validate-vswitches-e0c9d79ea3c0937f.yaml networking-hyperv-6.0.0/releasenotes/notes/validate-vswitches-e0c9d79ea3c0937f.yaml --- networking-hyperv-5.0.0/releasenotes/notes/validate-vswitches-e0c9d79ea3c0937f.yaml 1970-01-01 00:00:00.000000000 +0000 +++ networking-hyperv-6.0.0/releasenotes/notes/validate-vswitches-e0c9d79ea3c0937f.yaml 2018-01-26 00:51:46.000000000 +0000 @@ -0,0 +1,6 @@ +--- +upgrade: + - | + Configured vSwitches are now validated before the agent starts. If any + vSwitch is unavailable (missing or having OVS extension enabled), the + agent will fail to start. diff -Nru networking-hyperv-5.0.0/releasenotes/source/conf.py networking-hyperv-6.0.0/releasenotes/source/conf.py --- networking-hyperv-5.0.0/releasenotes/source/conf.py 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/releasenotes/source/conf.py 2018-01-26 00:51:46.000000000 +0000 @@ -63,15 +63,11 @@ bug_project = 'networking-hyperv' bug_tag = '' -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -from networking_hyperv.version import version_info +# Release notes are version independent. # The full version, including alpha/beta/rc tags. -release = version_info.version_string_with_vcs() +release = '' # The short X.Y version. -version = version_info.canonical_version_string() +version = '' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff -Nru networking-hyperv-5.0.0/releasenotes/source/index.rst networking-hyperv-6.0.0/releasenotes/source/index.rst --- networking-hyperv-5.0.0/releasenotes/source/index.rst 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/releasenotes/source/index.rst 2018-01-26 00:51:46.000000000 +0000 @@ -6,3 +6,4 @@ :maxdepth: 1 unreleased + pike diff -Nru networking-hyperv-5.0.0/releasenotes/source/pike.rst networking-hyperv-6.0.0/releasenotes/source/pike.rst --- networking-hyperv-5.0.0/releasenotes/source/pike.rst 1970-01-01 00:00:00.000000000 +0000 +++ networking-hyperv-6.0.0/releasenotes/source/pike.rst 2018-01-26 00:51:46.000000000 +0000 @@ -0,0 +1,6 @@ +=================================== + Pike Series Release Notes +=================================== + +.. release-notes:: + :branch: stable/pike diff -Nru networking-hyperv-5.0.0/requirements.txt networking-hyperv-6.0.0/requirements.txt --- networking-hyperv-5.0.0/requirements.txt 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/requirements.txt 2018-01-26 00:51:46.000000000 +0000 @@ -6,12 +6,12 @@ Babel!=2.4.0,>=2.3.4 # BSD eventlet!=0.18.3,!=0.20.1,<0.21.0,>=0.18.2 # MIT -neutron-lib>=1.9.0 # Apache-2.0 +neutron-lib>=1.12.0 # Apache-2.0 os-win>=2.0.0 # Apache-2.0 -oslo.config!=4.3.0,!=4.4.0,>=4.0.0 # Apache-2.0 -oslo.i18n!=3.15.2,>=2.1.0 # Apache-2.0 -oslo.log>=3.22.0 # Apache-2.0 -oslo.serialization!=2.19.1,>=1.10.0 # Apache-2.0 -oslo.utils>=3.20.0 # Apache-2.0 +oslo.config>=5.1.0 # Apache-2.0 +oslo.i18n>=3.15.3 # Apache-2.0 +oslo.log>=3.36.0 # Apache-2.0 +oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0 +oslo.utils>=3.33.0 # Apache-2.0 python-neutronclient>=6.3.0 # Apache-2.0 diff -Nru networking-hyperv-5.0.0/setup.cfg networking-hyperv-6.0.0/setup.cfg --- networking-hyperv-5.0.0/setup.cfg 2017-08-09 10:07:16.000000000 +0000 +++ networking-hyperv-6.0.0/setup.cfg 2018-01-26 01:01:22.000000000 +0000 @@ -25,6 +25,8 @@ networking_hyperv [entry_points] +oslo.config.opts = + networking_hyperv = networking_hyperv.neutron.config:list_opts console_scripts = neutron-hyperv-agent = networking_hyperv.neutron.agent.hyperv_neutron_agent:main neutron-hnv-agent = networking_hyperv.neutron.agent.hnv_neutron_agent:main diff -Nru networking-hyperv-5.0.0/test-requirements.txt networking-hyperv-6.0.0/test-requirements.txt --- networking-hyperv-5.0.0/test-requirements.txt 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/test-requirements.txt 2018-01-26 00:52:28.000000000 +0000 @@ -7,15 +7,14 @@ coverage!=4.4,>=4.0 # Apache-2.0 ddt>=1.0.1 # MIT fixtures>=3.0.0 # Apache-2.0/BSD -mock>=2.0 # BSD -python-subunit>=0.0.18 # Apache-2.0/BSD +mock>=2.0.0 # BSD docutils>=0.11 # OSI-Approved Open Source, Public Domain -sphinx>=1.6.2 # BSD -oslosphinx>=4.7.0 # Apache-2.0 -oslotest>=1.10.0 # Apache-2.0 +sphinx!=1.6.6,>=1.6.2 # BSD +oslo.config>=5.1.0 # Apache-2.0 +oslotest>=3.2.0 # Apache-2.0 testrepository>=0.0.18 # Apache-2.0/BSD testscenarios>=0.4 # Apache-2.0/BSD -testtools>=1.4.0 # MIT -openstackdocstheme>=1.16.0 # Apache-2.0 +testtools>=2.2.0 # MIT +openstackdocstheme>=1.18.1 # Apache-2.0 # releasenotes -reno!=2.3.1,>=1.8.0 # Apache-2.0 +reno>=2.5.0 # Apache-2.0 diff -Nru networking-hyperv-5.0.0/tools/tox_install.sh networking-hyperv-6.0.0/tools/tox_install.sh --- networking-hyperv-5.0.0/tools/tox_install.sh 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/tools/tox_install.sh 2018-01-26 00:51:46.000000000 +0000 @@ -1,85 +1,65 @@ #!/usr/bin/env bash -# Client constraint file contains this client version pin that is in conflict -# with installing the client from source. We should remove the version pin in -# the constraints file before applying it for from-source installation. -# The script also has a secondary purpose to install certain special -# dependencies directly from git. - -# Wrapper for pip install that always uses constraints. -function pip_install() { - pip install -c"$localfile" -U "$@" -} +# Many of neutron's repos suffer from the problem of depending on neutron, +# but it not existing on pypi. -# Grab the library from git using either zuul-cloner or pip. The former is -# there to a take advantage of the setup done by the gate infrastructure -# and honour any/all Depends-On headers in the commit message -function install_from_git() { - ZUUL_CLONER=/usr/zuul-env/bin/zuul-cloner - GIT_HOST=git.openstack.org - PROJ=$1 - EGG=$2 - - edit-constraints "$localfile" -- "$EGG" - if [ -x "$ZUUL_CLONER" ]; then - SRC_DIR="$VIRTUAL_ENV/src" - mkdir -p "$SRC_DIR" - cd "$SRC_DIR" >/dev/null - ZUUL_CACHE_DIR=${ZUUL_CACHE_DIR:-/opt/git} $ZUUL_CLONER \ - --branch "$BRANCH_NAME" \ - "git://$GIT_HOST" "$PROJ" - pip_install -e "$PROJ/." - cd - >/dev/null +# This wrapper for tox's package installer will use the existing package +# if it exists, else use zuul-cloner if that program exists, else grab it +# from neutron master via a hard-coded URL. That last case should only +# happen with devs running unit tests locally. + +# From the tox.ini config page: +# install_command=ARGV +# default: +# pip install {opts} {packages} + +ZUUL_CLONER=/usr/zuul-env/bin/zuul-cloner +BRANCH_NAME=master +GIT_BASE=${GIT_BASE:-https://git.openstack.org/} + +install_project() { + local project=$1 + local branch=${2:-$BRANCH_NAME} + local module_name=${project//-/_} + + set +e + project_installed=$(echo "import $module_name" | python 2>/dev/null ; echo $?) + set -e + + if [ $project_installed -eq 0 ]; then + echo "ALREADY INSTALLED" > /tmp/tox_install.txt + echo "$project already installed; using existing package" + elif [ -x "$ZUUL_CLONER" ]; then + echo "ZUUL CLONER" > /tmp/tox_install.txt + # Make this relative to current working directory so that + # git clean can remove it. We cannot remove the directory directly + # since it is referenced after $install_cmd -e + mkdir -p .tmp + PROJECT_DIR=$(/bin/mktemp -d -p $(pwd)/.tmp) + pushd $PROJECT_DIR + $ZUUL_CLONER --cache-dir \ + /opt/git \ + --branch $branch \ + http://git.openstack.org \ + openstack/$project + cd openstack/$project + $install_cmd -e . + popd else - pip_install -e"git+https://$GIT_HOST/$PROJ@$BRANCH_NAME#egg=${EGG}" + echo "PIP HARDCODE" > /tmp/tox_install.txt + local GIT_REPO="$GIT_BASE/openstack/$project" + SRC_DIR="$VIRTUAL_ENV/src/$project" + git clone --depth 1 --branch $branch $GIT_REPO $SRC_DIR + $install_cmd -U -e $SRC_DIR fi } +set -e +install_cmd="pip install -c$1" +shift -CONSTRAINTS_FILE="$1" -shift 1 - -# This script will either complete with a return code of 0 or the return code -# of whatever failed. -set -e +install_project neutron -# NOTE(tonyb): Place this in the tox environment's log dir so it will get -# published to logs.openstack.org for easy debugging. -mkdir -p "$VIRTUAL_ENV/log/" -localfile="$VIRTUAL_ENV/log/upper-constraints.txt" - -if [[ "$CONSTRAINTS_FILE" != http* ]]; then - CONSTRAINTS_FILE="file://$CONSTRAINTS_FILE" -fi -# NOTE(tonyb): need to add curl to bindep.txt if the project supports bindep -curl "$CONSTRAINTS_FILE" --insecure --progress-bar --output "$localfile" - -pip_install openstack-requirements - -# This is the main purpose of the script: Allow local installation of -# the current repo. It is listed in constraints file and thus any -# install will be constrained and we need to unconstrain it. -edit-constraints "$localfile" -- "$CLIENT_NAME" - -declare -a passthrough_args -while [ $# -gt 0 ] ; do - case "$1" in - # If we have any special os: deps then process them - os:*) - declare -a pkg_spec - IFS=: pkg_spec=($1) - install_from_git "${pkg_spec[1]}" "${pkg_spec[2]}" - ;; - # Otherwise just pass the other deps through to the constrained pip install - *) - passthrough_args+=("$1") - ;; - esac - shift 1 -done - -# If *only* had special args then then isn't any need to run pip. -if [ -n "$passthrough_args" ] ; then - pip_install "${passthrough_args[@]}" -fi +$install_cmd -U $* +exit $? diff -Nru networking-hyperv-5.0.0/tox.ini networking-hyperv-6.0.0/tox.ini --- networking-hyperv-5.0.0/tox.ini 2017-08-09 10:00:52.000000000 +0000 +++ networking-hyperv-6.0.0/tox.ini 2018-01-26 00:51:46.000000000 +0000 @@ -13,7 +13,6 @@ PYTHONWARNINGS=default::DeprecationWarning deps = -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt - os:openstack/neutron:neutron commands = python setup.py testr --slowest --testr-args='{posargs}' @@ -43,7 +42,7 @@ # check None values. (temporarily disable) ignore = N530,N536 builtins = _ -exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build +exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build,.tmp # H106: Don't put vim configuration in source files # H203: Use assertIs(Not)None to check for None # H904: Delay string interpolations at logging calls