Merge "NSX|v3: provider networks updates"
This commit is contained in:
commit
bd6de55f7c
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
prelude: >
|
||||||
|
Adding support for Geneve and nSX-network provider networks.
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Deprecating the VXLAN provider network type.
|
||||||
|
Adding Geneve provider networks (with overlay transport zone).
|
||||||
|
Adding nsx-net provider networks attached to an existing nsx
|
@ -67,7 +67,8 @@ class NsxV3NetworkTypes(object):
|
|||||||
"""Allowed provider network types for the NSXv3 Plugin."""
|
"""Allowed provider network types for the NSXv3 Plugin."""
|
||||||
FLAT = 'flat'
|
FLAT = 'flat'
|
||||||
VLAN = 'vlan'
|
VLAN = 'vlan'
|
||||||
VXLAN = 'vxlan'
|
GENEVE = 'geneve'
|
||||||
|
NSX_NETWORK = 'nsx-net'
|
||||||
|
|
||||||
|
|
||||||
def is_nsx_version_1_1_0(nsx_version):
|
def is_nsx_version_1_1_0(nsx_version):
|
||||||
|
@ -1 +1 @@
|
|||||||
84ceffa27115
|
a1be06050b41
|
@ -0,0 +1,60 @@
|
|||||||
|
# Copyright 2017 VMware, Inc.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
"""update nsx binding types
|
||||||
|
|
||||||
|
Revision ID: a1be06050b41
|
||||||
|
Revises: 84ceffa27115
|
||||||
|
Create Date: 2017-09-04 23:58:22.003350
|
||||||
|
"""
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'a1be06050b41'
|
||||||
|
down_revision = '84ceffa27115'
|
||||||
|
depends_on = ('aede17d51d0f')
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
from neutron.db import migration as neutron_op
|
||||||
|
|
||||||
|
|
||||||
|
all_tz_binding_type_enum = sa.Enum('flat', 'vlan', 'stt', 'gre', 'l3_ext',
|
||||||
|
'vxlan', 'geneve', 'portgroup', 'nsx-net',
|
||||||
|
name='tz_network_bindings_binding_type')
|
||||||
|
|
||||||
|
new_tz_binding_type_enum = sa.Enum('flat', 'vlan', 'stt', 'gre', 'l3_ext',
|
||||||
|
'geneve', 'portgroup', 'nsx-net',
|
||||||
|
name='tz_network_bindings_binding_type')
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# add the new network types to the enum
|
||||||
|
neutron_op.alter_enum_add_value(
|
||||||
|
'tz_network_bindings',
|
||||||
|
'binding_type',
|
||||||
|
all_tz_binding_type_enum,
|
||||||
|
False)
|
||||||
|
|
||||||
|
# change existing entries with type 'vxlan' to 'geneve'
|
||||||
|
op.execute("UPDATE tz_network_bindings SET binding_type='geneve' "
|
||||||
|
"where binding_type='vxlan'")
|
||||||
|
|
||||||
|
# remove 'vxlan' from the enum
|
||||||
|
op.alter_column(
|
||||||
|
'tz_network_bindings',
|
||||||
|
'binding_type',
|
||||||
|
type_=new_tz_binding_type_enum,
|
||||||
|
existing_type=all_tz_binding_type_enum,
|
||||||
|
existing_nullable=False)
|
@ -43,9 +43,9 @@ class TzNetworkBinding(model_base.BASEV2, models.TimestampMixin):
|
|||||||
network_id = sa.Column(sa.String(36),
|
network_id = sa.Column(sa.String(36),
|
||||||
sa.ForeignKey('networks.id', ondelete="CASCADE"),
|
sa.ForeignKey('networks.id', ondelete="CASCADE"),
|
||||||
primary_key=True)
|
primary_key=True)
|
||||||
# 'flat', 'vlan', 'stt', 'gre', 'l3_ext', 'vxlan', 'portgroup'
|
# 'flat', 'vlan', 'stt', 'gre', 'l3_ext', 'geneve', 'portgroup', 'nsx-net'
|
||||||
binding_type = sa.Column(sa.Enum('flat', 'vlan', 'stt', 'gre', 'l3_ext',
|
binding_type = sa.Column(sa.Enum('flat', 'vlan', 'stt', 'gre', 'l3_ext',
|
||||||
'vxlan', 'portgroup',
|
'geneve', 'portgroup', 'nsx-net',
|
||||||
name='tz_network_bindings_binding_type'),
|
name='tz_network_bindings_binding_type'),
|
||||||
nullable=False, primary_key=True)
|
nullable=False, primary_key=True)
|
||||||
phy_uuid = sa.Column(sa.String(36), primary_key=True, default='')
|
phy_uuid = sa.Column(sa.String(36), primary_key=True, default='')
|
||||||
|
@ -693,12 +693,30 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
|||||||
if bindings:
|
if bindings:
|
||||||
raise n_exc.VlanIdInUse(
|
raise n_exc.VlanIdInUse(
|
||||||
vlan_id=vlan_id, physical_network=physical_net)
|
vlan_id=vlan_id, physical_network=physical_net)
|
||||||
elif net_type == utils.NsxV3NetworkTypes.VXLAN:
|
elif net_type == utils.NsxV3NetworkTypes.GENEVE:
|
||||||
if vlan_id:
|
if vlan_id:
|
||||||
err_msg = (_("Segmentation ID cannot be specified with "
|
err_msg = (_("Segmentation ID cannot be specified with "
|
||||||
"%s network type") %
|
"%s network type") %
|
||||||
utils.NsxV3NetworkTypes.VXLAN)
|
utils.NsxV3NetworkTypes.GENEVE)
|
||||||
tz_type = self.nsxlib.transport_zone.TRANSPORT_TYPE_OVERLAY
|
tz_type = self.nsxlib.transport_zone.TRANSPORT_TYPE_OVERLAY
|
||||||
|
elif net_type == utils.NsxV3NetworkTypes.NSX_NETWORK:
|
||||||
|
# Linking neutron networks to an existing NSX logical switch
|
||||||
|
if physical_net is None:
|
||||||
|
err_msg = (_("Physical network must be specified with "
|
||||||
|
"%s network type") % net_type)
|
||||||
|
# Validate the logical switch existence
|
||||||
|
try:
|
||||||
|
self.nsxlib.logical_switch.get(physical_net)
|
||||||
|
except nsx_lib_exc.ResourceNotFound:
|
||||||
|
err_msg = (_('Logical switch %s does not exist') %
|
||||||
|
physical_net)
|
||||||
|
# make sure no other neutron network is using it
|
||||||
|
bindings = (
|
||||||
|
nsx_db.get_network_bindings_by_vlanid_and_physical_net(
|
||||||
|
context.elevated().session, 0, physical_net))
|
||||||
|
if bindings:
|
||||||
|
err_msg = (_('Logical switch %s is already used by '
|
||||||
|
'another network') % physical_net)
|
||||||
else:
|
else:
|
||||||
err_msg = (_('%(net_type_param)s %(net_type_value)s not '
|
err_msg = (_('%(net_type_param)s %(net_type_value)s not '
|
||||||
'supported') %
|
'supported') %
|
||||||
@ -718,7 +736,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
|||||||
physical_net = az._default_overlay_tz_uuid
|
physical_net = az._default_overlay_tz_uuid
|
||||||
|
|
||||||
# validate the transport zone existence and type
|
# validate the transport zone existence and type
|
||||||
if not err_msg and is_provider_net and physical_net:
|
if (not err_msg and is_provider_net and physical_net and
|
||||||
|
net_type != utils.NsxV3NetworkTypes.NSX_NETWORK):
|
||||||
try:
|
try:
|
||||||
backend_type = self.nsxlib.transport_zone.get_transport_type(
|
backend_type = self.nsxlib.transport_zone.get_transport_type(
|
||||||
physical_net)
|
physical_net)
|
||||||
@ -752,43 +771,68 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
|||||||
def _create_network_at_the_backend(self, context, net_data, az):
|
def _create_network_at_the_backend(self, context, net_data, az):
|
||||||
is_provider_net, net_type, physical_net, vlan_id = (
|
is_provider_net, net_type, physical_net, vlan_id = (
|
||||||
self._validate_provider_create(context, net_data, az))
|
self._validate_provider_create(context, net_data, az))
|
||||||
neutron_net_id = net_data.get('id') or uuidutils.generate_uuid()
|
|
||||||
# To ensure that the correct tag will be set
|
|
||||||
net_data['id'] = neutron_net_id
|
|
||||||
# update the network name to indicate the neutron id too.
|
|
||||||
net_name = utils.get_name_and_uuid(net_data['name'] or 'network',
|
|
||||||
neutron_net_id)
|
|
||||||
tags = self.nsxlib.build_v3_tags_payload(
|
|
||||||
net_data, resource_type='os-neutron-net-id',
|
|
||||||
project_name=context.tenant_name)
|
|
||||||
|
|
||||||
admin_state = net_data.get('admin_state_up', True)
|
if is_provider_net and net_type == utils.NsxV3NetworkTypes.NSX_NETWORK:
|
||||||
|
# Network already exists on the NSX backend
|
||||||
|
nsx_id = physical_net
|
||||||
|
else:
|
||||||
|
# Create network on the backend
|
||||||
|
neutron_net_id = net_data.get('id') or uuidutils.generate_uuid()
|
||||||
|
# To ensure that the correct tag will be set
|
||||||
|
net_data['id'] = neutron_net_id
|
||||||
|
# update the network name to indicate the neutron id too.
|
||||||
|
net_name = utils.get_name_and_uuid(net_data['name'] or 'network',
|
||||||
|
neutron_net_id)
|
||||||
|
tags = self.nsxlib.build_v3_tags_payload(
|
||||||
|
net_data, resource_type='os-neutron-net-id',
|
||||||
|
project_name=context.tenant_name)
|
||||||
|
|
||||||
# Create network on the backend
|
admin_state = net_data.get('admin_state_up', True)
|
||||||
LOG.debug('create_network: %(net_name)s, %(physical_net)s, '
|
LOG.debug('create_network: %(net_name)s, %(physical_net)s, '
|
||||||
'%(tags)s, %(admin_state)s, %(vlan_id)s',
|
'%(tags)s, %(admin_state)s, %(vlan_id)s',
|
||||||
{'net_name': net_name,
|
{'net_name': net_name,
|
||||||
'physical_net': physical_net,
|
'physical_net': physical_net,
|
||||||
'tags': tags,
|
'tags': tags,
|
||||||
'admin_state': admin_state,
|
'admin_state': admin_state,
|
||||||
'vlan_id': vlan_id})
|
'vlan_id': vlan_id})
|
||||||
nsx_result = self.nsxlib.logical_switch.create(
|
nsx_result = self.nsxlib.logical_switch.create(
|
||||||
net_name, physical_net, tags,
|
net_name, physical_net, tags,
|
||||||
admin_state=admin_state,
|
admin_state=admin_state,
|
||||||
vlan_id=vlan_id,
|
vlan_id=vlan_id,
|
||||||
description=net_data.get('description'))
|
description=net_data.get('description'))
|
||||||
|
nsx_id = nsx_result['id']
|
||||||
|
|
||||||
return (is_provider_net,
|
return (is_provider_net,
|
||||||
net_type,
|
net_type,
|
||||||
physical_net,
|
physical_net,
|
||||||
vlan_id,
|
vlan_id,
|
||||||
nsx_result['id'])
|
nsx_id)
|
||||||
|
|
||||||
def _is_overlay_network(self, context, network_id):
|
def _is_overlay_network(self, context, network_id):
|
||||||
|
"""Return True if this is an overlay network
|
||||||
|
|
||||||
|
1. No binding ("normal" overlay networks will have no binding)
|
||||||
|
2. Geneve network
|
||||||
|
3. nsx network where the backend network is connected to an overlay TZ
|
||||||
|
"""
|
||||||
bindings = nsx_db.get_network_bindings(context.session, network_id)
|
bindings = nsx_db.get_network_bindings(context.session, network_id)
|
||||||
# With NSX plugin, "normal" overlay networks will have no binding
|
# With NSX plugin, "normal" overlay networks will have no binding
|
||||||
return (not bindings or
|
if not bindings:
|
||||||
bindings[0].binding_type == utils.NsxV3NetworkTypes.VXLAN)
|
return True
|
||||||
|
binding = bindings[0]
|
||||||
|
if binding.binding_type == utils.NsxV3NetworkTypes.GENEVE:
|
||||||
|
return True
|
||||||
|
if binding.binding_type == utils.NsxV3NetworkTypes.NSX_NETWORK:
|
||||||
|
# check the backend network
|
||||||
|
# TODO(asarfaty): Keep TZ type in DB to avoid going to the backend
|
||||||
|
ls = self.nsxlib.logical_switch.get(binding.phy_uuid)
|
||||||
|
tz = ls.get('transport_zone_id')
|
||||||
|
if tz:
|
||||||
|
backend_type = self.nsxlib.transport_zone.get_transport_type(
|
||||||
|
tz)
|
||||||
|
return (backend_type ==
|
||||||
|
self.nsxlib.transport_zone.TRANSPORT_TYPE_OVERLAY)
|
||||||
|
return False
|
||||||
|
|
||||||
def _extend_network_dict_provider(self, context, network, bindings=None):
|
def _extend_network_dict_provider(self, context, network, bindings=None):
|
||||||
if 'id' not in network:
|
if 'id' not in network:
|
||||||
@ -824,6 +868,13 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
|||||||
return super(NsxV3Plugin, self).get_subnets(
|
return super(NsxV3Plugin, self).get_subnets(
|
||||||
context, filters, fields, sorts, limit, marker, page_reverse)
|
context, filters, fields, sorts, limit, marker, page_reverse)
|
||||||
|
|
||||||
|
def _network_is_nsx_net(self, context, network_id):
|
||||||
|
bindings = nsx_db.get_network_bindings(context.session, network_id)
|
||||||
|
if not bindings:
|
||||||
|
return False
|
||||||
|
return (bindings[0].binding_type ==
|
||||||
|
utils.NsxV3NetworkTypes.NSX_NETWORK)
|
||||||
|
|
||||||
def create_network(self, context, network):
|
def create_network(self, context, network):
|
||||||
net_data = network['network']
|
net_data = network['network']
|
||||||
external = net_data.get(ext_net_extn.EXTERNAL)
|
external = net_data.get(ext_net_extn.EXTERNAL)
|
||||||
@ -979,17 +1030,27 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
|||||||
self._disable_native_dhcp(context, network_id)
|
self._disable_native_dhcp(context, network_id)
|
||||||
|
|
||||||
nsx_net_id = self._get_network_nsx_id(context, network_id)
|
nsx_net_id = self._get_network_nsx_id(context, network_id)
|
||||||
|
is_nsx_net = self._network_is_nsx_net(context, network_id)
|
||||||
|
is_overlay_network = self._is_overlay_network(context, network_id)
|
||||||
# First call DB operation for delete network as it will perform
|
# First call DB operation for delete network as it will perform
|
||||||
# checks on active ports
|
# checks on active ports
|
||||||
self._retry_delete_network(context, network_id)
|
self._retry_delete_network(context, network_id)
|
||||||
if not self._network_is_external(context, network_id):
|
if (not self._network_is_external(context, network_id) and
|
||||||
|
not is_nsx_net):
|
||||||
# TODO(salv-orlando): Handle backend failure, possibly without
|
# TODO(salv-orlando): Handle backend failure, possibly without
|
||||||
# requiring us to un-delete the DB object. For instance, ignore
|
# requiring us to un-delete the DB object. For instance, ignore
|
||||||
# failures occurring if logical switch is not found
|
# failures occurring if logical switch is not found
|
||||||
self.nsxlib.logical_switch.delete(nsx_net_id)
|
self.nsxlib.logical_switch.delete(nsx_net_id)
|
||||||
else:
|
else:
|
||||||
|
if (cfg.CONF.nsx_v3.native_dhcp_metadata and is_nsx_net and
|
||||||
|
is_overlay_network):
|
||||||
|
# Delete the mdproxy port manually
|
||||||
|
port_id = self.nsxlib.get_id_by_resource_and_tag(
|
||||||
|
self.nsxlib.logical_port.resource_type,
|
||||||
|
'os-neutron-net-id', network_id)
|
||||||
|
if port_id:
|
||||||
|
self.nsxlib.logical_port.delete(port_id)
|
||||||
# TODO(berlin): delete subnets public announce on the network
|
# TODO(berlin): delete subnets public announce on the network
|
||||||
pass
|
|
||||||
|
|
||||||
def _get_network_nsx_id(self, context, neutron_id):
|
def _get_network_nsx_id(self, context, neutron_id):
|
||||||
# get the nsx switch id from the DB mapping
|
# get the nsx switch id from the DB mapping
|
||||||
@ -1010,6 +1071,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
|||||||
# Neutron does not support changing provider network values
|
# Neutron does not support changing provider network values
|
||||||
providernet._raise_if_updates_provider_attributes(net_data)
|
providernet._raise_if_updates_provider_attributes(net_data)
|
||||||
extern_net = self._network_is_external(context, id)
|
extern_net = self._network_is_external(context, id)
|
||||||
|
is_nsx_net = self._network_is_nsx_net(context, id)
|
||||||
if extern_net:
|
if extern_net:
|
||||||
self._assert_on_external_net_with_qos(net_data)
|
self._assert_on_external_net_with_qos(net_data)
|
||||||
updated_net = super(NsxV3Plugin, self).update_network(context, id,
|
updated_net = super(NsxV3Plugin, self).update_network(context, id,
|
||||||
@ -1022,7 +1084,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
|||||||
self._process_l3_update(context, updated_net, network['network'])
|
self._process_l3_update(context, updated_net, network['network'])
|
||||||
self._extend_network_dict_provider(context, updated_net)
|
self._extend_network_dict_provider(context, updated_net)
|
||||||
|
|
||||||
if (not extern_net and
|
if (not extern_net and not is_nsx_net and
|
||||||
('name' in net_data or 'admin_state_up' in net_data or
|
('name' in net_data or 'admin_state_up' in net_data or
|
||||||
'description' in net_data)):
|
'description' in net_data)):
|
||||||
try:
|
try:
|
||||||
@ -3186,7 +3248,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
|||||||
def _validate_multiple_subnets_routers(self, context, router_id, net_id):
|
def _validate_multiple_subnets_routers(self, context, router_id, net_id):
|
||||||
network = self.get_network(context, net_id)
|
network = self.get_network(context, net_id)
|
||||||
net_type = network.get(pnet.NETWORK_TYPE)
|
net_type = network.get(pnet.NETWORK_TYPE)
|
||||||
if (net_type and net_type != utils.NsxV3NetworkTypes.VXLAN):
|
if (net_type and net_type != utils.NsxV3NetworkTypes.GENEVE):
|
||||||
err_msg = (_("Only overlay networks can be attached to a logical "
|
err_msg = (_("Only overlay networks can be attached to a logical "
|
||||||
"router. Network %(net_id)s is a %(net_type)s based "
|
"router. Network %(net_id)s is a %(net_type)s based "
|
||||||
"network") % {'net_id': net_id, 'net_type': net_type})
|
"network") % {'net_id': net_id, 'net_type': net_type})
|
||||||
|
@ -78,6 +78,10 @@ def _mock_create_firewall_rules(*args):
|
|||||||
]}
|
]}
|
||||||
|
|
||||||
|
|
||||||
|
def _return_id_key(*args, **kwargs):
|
||||||
|
return {'id': uuidutils.generate_uuid()}
|
||||||
|
|
||||||
|
|
||||||
def _mock_nsx_backend_calls():
|
def _mock_nsx_backend_calls():
|
||||||
mock.patch("vmware_nsxlib.v3.client.NSX3Client").start()
|
mock.patch("vmware_nsxlib.v3.client.NSX3Client").start()
|
||||||
|
|
||||||
@ -85,9 +89,6 @@ def _mock_nsx_backend_calls():
|
|||||||
'resource_type': 'FakeResource',
|
'resource_type': 'FakeResource',
|
||||||
'id': uuidutils.generate_uuid()}
|
'id': uuidutils.generate_uuid()}
|
||||||
|
|
||||||
def _return_id_key(*args, **kwargs):
|
|
||||||
return {'id': uuidutils.generate_uuid()}
|
|
||||||
|
|
||||||
def _return_id(*args, **kwargs):
|
def _return_id(*args, **kwargs):
|
||||||
return uuidutils.generate_uuid()
|
return uuidutils.generate_uuid()
|
||||||
|
|
||||||
@ -113,11 +114,6 @@ def _mock_nsx_backend_calls():
|
|||||||
"get_id_by_name_or_id",
|
"get_id_by_name_or_id",
|
||||||
return_value=uuidutils.generate_uuid()).start()
|
return_value=uuidutils.generate_uuid()).start()
|
||||||
|
|
||||||
mock.patch(
|
|
||||||
"vmware_nsxlib.v3.core_resources.NsxLibTransportZone."
|
|
||||||
"get_id_by_name_or_id",
|
|
||||||
return_value=uuidutils.generate_uuid()).start()
|
|
||||||
|
|
||||||
mock.patch(
|
mock.patch(
|
||||||
"vmware_nsxlib.v3.core_resources.NsxLibBridgeEndpoint.create",
|
"vmware_nsxlib.v3.core_resources.NsxLibBridgeEndpoint.create",
|
||||||
side_effect=_return_id_key).start()
|
side_effect=_return_id_key).start()
|
||||||
@ -284,6 +280,167 @@ class TestNetworksV2(test_plugin.TestNetworksV2, NsxV3PluginTestCaseMixin):
|
|||||||
networks = self.plugin.get_networks(ctx)
|
networks = self.plugin.get_networks(ctx)
|
||||||
self.assertListEqual([], networks)
|
self.assertListEqual([], networks)
|
||||||
|
|
||||||
|
def test_create_provider_flat_network(self):
|
||||||
|
providernet_args = {pnet.NETWORK_TYPE: 'flat'}
|
||||||
|
with mock.patch('vmware_nsxlib.v3.core_resources.NsxLibLogicalSwitch.'
|
||||||
|
'create', side_effect=_return_id_key) as nsx_create, \
|
||||||
|
mock.patch('vmware_nsxlib.v3.core_resources.NsxLibLogicalSwitch.'
|
||||||
|
'delete') as nsx_delete, \
|
||||||
|
mock.patch('vmware_nsxlib.v3.core_resources.NsxLibTransportZone.'
|
||||||
|
'get_transport_type', return_value='VLAN'),\
|
||||||
|
self.network(name='flat_net',
|
||||||
|
providernet_args=providernet_args,
|
||||||
|
arg_list=(pnet.NETWORK_TYPE, )) as net:
|
||||||
|
self.assertEqual('flat', net['network'].get(pnet.NETWORK_TYPE))
|
||||||
|
# make sure the network is created at the backend
|
||||||
|
nsx_create.assert_called_once()
|
||||||
|
|
||||||
|
# Delete the network and make sure it is deleted from the backend
|
||||||
|
req = self.new_delete_request('networks', net['network']['id'])
|
||||||
|
res = req.get_response(self.api)
|
||||||
|
self.assertEqual(exc.HTTPNoContent.code, res.status_int)
|
||||||
|
nsx_delete.assert_called_once()
|
||||||
|
|
||||||
|
def test_create_provider_flat_network_with_physical_net(self):
|
||||||
|
physical_network = nsx_v3_mocks.DEFAULT_TIER0_ROUTER_UUID
|
||||||
|
providernet_args = {pnet.NETWORK_TYPE: 'flat',
|
||||||
|
pnet.PHYSICAL_NETWORK: physical_network}
|
||||||
|
with mock.patch(
|
||||||
|
'vmware_nsxlib.v3.core_resources.NsxLibTransportZone.'
|
||||||
|
'get_transport_type', return_value='VLAN'),\
|
||||||
|
self.network(name='flat_net',
|
||||||
|
providernet_args=providernet_args,
|
||||||
|
arg_list=(pnet.NETWORK_TYPE,
|
||||||
|
pnet.PHYSICAL_NETWORK)) as net:
|
||||||
|
self.assertEqual('flat', net['network'].get(pnet.NETWORK_TYPE))
|
||||||
|
|
||||||
|
def test_create_provider_flat_network_with_vlan(self):
|
||||||
|
providernet_args = {pnet.NETWORK_TYPE: 'flat',
|
||||||
|
pnet.SEGMENTATION_ID: 11}
|
||||||
|
with mock.patch('vmware_nsxlib.v3.core_resources.NsxLibTransportZone.'
|
||||||
|
'get_transport_type', return_value='VLAN'):
|
||||||
|
result = self._create_network(fmt='json', name='bad_flat_net',
|
||||||
|
admin_state_up=True,
|
||||||
|
providernet_args=providernet_args,
|
||||||
|
arg_list=(pnet.NETWORK_TYPE,
|
||||||
|
pnet.SEGMENTATION_ID))
|
||||||
|
data = self.deserialize('json', result)
|
||||||
|
# should fail
|
||||||
|
self.assertEqual('InvalidInput', data['NeutronError']['type'])
|
||||||
|
|
||||||
|
def test_create_provider_geneve_network(self):
|
||||||
|
providernet_args = {pnet.NETWORK_TYPE: 'geneve'}
|
||||||
|
with mock.patch('vmware_nsxlib.v3.core_resources.NsxLibLogicalSwitch.'
|
||||||
|
'create', side_effect=_return_id_key) as nsx_create, \
|
||||||
|
mock.patch('vmware_nsxlib.v3.core_resources.NsxLibLogicalSwitch.'
|
||||||
|
'delete') as nsx_delete, \
|
||||||
|
mock.patch('vmware_nsxlib.v3.core_resources.NsxLibTransportZone.'
|
||||||
|
'get_transport_type', return_value='OVERLAY'),\
|
||||||
|
self.network(name='geneve_net',
|
||||||
|
providernet_args=providernet_args,
|
||||||
|
arg_list=(pnet.NETWORK_TYPE, )) as net:
|
||||||
|
self.assertEqual('geneve', net['network'].get(pnet.NETWORK_TYPE))
|
||||||
|
# make sure the network is created at the backend
|
||||||
|
nsx_create.assert_called_once()
|
||||||
|
|
||||||
|
# Delete the network and make sure it is deleted from the backend
|
||||||
|
req = self.new_delete_request('networks', net['network']['id'])
|
||||||
|
res = req.get_response(self.api)
|
||||||
|
self.assertEqual(exc.HTTPNoContent.code, res.status_int)
|
||||||
|
nsx_delete.assert_called_once()
|
||||||
|
|
||||||
|
def test_create_provider_geneve_network_with_physical_net(self):
|
||||||
|
physical_network = nsx_v3_mocks.DEFAULT_TIER0_ROUTER_UUID
|
||||||
|
providernet_args = {pnet.NETWORK_TYPE: 'geneve',
|
||||||
|
pnet.PHYSICAL_NETWORK: physical_network}
|
||||||
|
with mock.patch(
|
||||||
|
'vmware_nsxlib.v3.core_resources.NsxLibTransportZone.'
|
||||||
|
'get_transport_type', return_value='OVERLAY'),\
|
||||||
|
self.network(name='geneve_net',
|
||||||
|
providernet_args=providernet_args,
|
||||||
|
arg_list=(pnet.NETWORK_TYPE, )) as net:
|
||||||
|
self.assertEqual('geneve', net['network'].get(pnet.NETWORK_TYPE))
|
||||||
|
|
||||||
|
def test_create_provider_geneve_network_with_vlan(self):
|
||||||
|
providernet_args = {pnet.NETWORK_TYPE: 'geneve',
|
||||||
|
pnet.SEGMENTATION_ID: 11}
|
||||||
|
with mock.patch(
|
||||||
|
'vmware_nsxlib.v3.core_resources.NsxLibTransportZone.'
|
||||||
|
'get_transport_type', return_value='OVERLAY'):
|
||||||
|
result = self._create_network(fmt='json', name='bad_geneve_net',
|
||||||
|
admin_state_up=True,
|
||||||
|
providernet_args=providernet_args,
|
||||||
|
arg_list=(pnet.NETWORK_TYPE,
|
||||||
|
pnet.SEGMENTATION_ID))
|
||||||
|
data = self.deserialize('json', result)
|
||||||
|
# should fail
|
||||||
|
self.assertEqual('InvalidInput', data['NeutronError']['type'])
|
||||||
|
|
||||||
|
def test_create_provider_vlan_network(self):
|
||||||
|
providernet_args = {pnet.NETWORK_TYPE: 'vlan',
|
||||||
|
pnet.SEGMENTATION_ID: 11}
|
||||||
|
with mock.patch('vmware_nsxlib.v3.core_resources.NsxLibLogicalSwitch.'
|
||||||
|
'create', side_effect=_return_id_key) as nsx_create, \
|
||||||
|
mock.patch('vmware_nsxlib.v3.core_resources.NsxLibLogicalSwitch.'
|
||||||
|
'delete') as nsx_delete, \
|
||||||
|
mock.patch('vmware_nsxlib.v3.core_resources.NsxLibTransportZone.'
|
||||||
|
'get_transport_type', return_value='VLAN'),\
|
||||||
|
self.network(name='vlan_net',
|
||||||
|
providernet_args=providernet_args,
|
||||||
|
arg_list=(pnet.NETWORK_TYPE,
|
||||||
|
pnet.SEGMENTATION_ID)) as net:
|
||||||
|
self.assertEqual('vlan', net['network'].get(pnet.NETWORK_TYPE))
|
||||||
|
# make sure the network is created at the backend
|
||||||
|
nsx_create.assert_called_once()
|
||||||
|
|
||||||
|
# Delete the network and make sure it is deleted from the backend
|
||||||
|
req = self.new_delete_request('networks', net['network']['id'])
|
||||||
|
res = req.get_response(self.api)
|
||||||
|
self.assertEqual(exc.HTTPNoContent.code, res.status_int)
|
||||||
|
nsx_delete.assert_called_once()
|
||||||
|
|
||||||
|
def test_create_provider_nsx_network(self):
|
||||||
|
physical_network = 'Fake logical switch'
|
||||||
|
providernet_args = {pnet.NETWORK_TYPE: 'nsx-net',
|
||||||
|
pnet.PHYSICAL_NETWORK: physical_network}
|
||||||
|
|
||||||
|
with mock.patch(
|
||||||
|
'vmware_nsxlib.v3.core_resources.NsxLibLogicalSwitch.create',
|
||||||
|
side_effect=nsxlib_exc.ResourceNotFound) as nsx_create, \
|
||||||
|
mock.patch('vmware_nsxlib.v3.core_resources.NsxLibLogicalSwitch.'
|
||||||
|
'delete') as nsx_delete, \
|
||||||
|
self.network(name='nsx_net',
|
||||||
|
providernet_args=providernet_args,
|
||||||
|
arg_list=(pnet.NETWORK_TYPE,
|
||||||
|
pnet.PHYSICAL_NETWORK)) as net:
|
||||||
|
self.assertEqual('nsx-net', net['network'].get(pnet.NETWORK_TYPE))
|
||||||
|
self.assertEqual(physical_network,
|
||||||
|
net['network'].get(pnet.PHYSICAL_NETWORK))
|
||||||
|
# make sure the network is NOT created at the backend
|
||||||
|
nsx_create.assert_not_called()
|
||||||
|
|
||||||
|
# Delete the network. It should NOT deleted from the backend
|
||||||
|
req = self.new_delete_request('networks', net['network']['id'])
|
||||||
|
res = req.get_response(self.api)
|
||||||
|
self.assertEqual(exc.HTTPNoContent.code, res.status_int)
|
||||||
|
nsx_delete.assert_not_called()
|
||||||
|
|
||||||
|
def test_create_provider_bad_nsx_network(self):
|
||||||
|
physical_network = 'Bad logical switch'
|
||||||
|
providernet_args = {pnet.NETWORK_TYPE: 'nsx-net',
|
||||||
|
pnet.PHYSICAL_NETWORK: physical_network}
|
||||||
|
with mock.patch(
|
||||||
|
"vmware_nsxlib.v3.core_resources.NsxLibLogicalSwitch.get",
|
||||||
|
side_effect=nsxlib_exc.ResourceNotFound):
|
||||||
|
result = self._create_network(fmt='json', name='bad_nsx_net',
|
||||||
|
admin_state_up=True,
|
||||||
|
providernet_args=providernet_args,
|
||||||
|
arg_list=(pnet.NETWORK_TYPE,
|
||||||
|
pnet.PHYSICAL_NETWORK))
|
||||||
|
data = self.deserialize('json', result)
|
||||||
|
# should fail
|
||||||
|
self.assertEqual('InvalidInput', data['NeutronError']['type'])
|
||||||
|
|
||||||
|
|
||||||
class TestSubnetsV2(test_plugin.TestSubnetsV2, NsxV3PluginTestCaseMixin):
|
class TestSubnetsV2(test_plugin.TestSubnetsV2, NsxV3PluginTestCaseMixin):
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user