Merge "NsxV3: Router preparation for GW/intf/FIP support"
This commit is contained in:
commit
6c6a539de7
@ -23,12 +23,22 @@ from vmware_nsx.neutron.plugins.vmware.nsxlib.v3 import client
|
|||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
ROUTER_INTF_PORT_NAME = "Tier1-RouterDownLinkPort"
|
||||||
|
|
||||||
|
|
||||||
def get_edge_cluster(edge_cluster_uuid):
|
def get_edge_cluster(edge_cluster_uuid):
|
||||||
resource = "edge-clusters/%s" % edge_cluster_uuid
|
resource = "edge-clusters/%s" % edge_cluster_uuid
|
||||||
return client.get_resource(resource)
|
return client.get_resource(resource)
|
||||||
|
|
||||||
|
|
||||||
|
@utils.retry_upon_exception_nsxv3(nsx_exc.StaleRevision)
|
||||||
|
def update_resource_with_retry(resource, payload):
|
||||||
|
revised_payload = client.get_resource(resource)
|
||||||
|
for key_name in payload.keys():
|
||||||
|
revised_payload[key_name] = payload[key_name]
|
||||||
|
return client.update_resource(resource, revised_payload)
|
||||||
|
|
||||||
|
|
||||||
def create_logical_switch(display_name, transport_zone_id, tags,
|
def create_logical_switch(display_name, transport_zone_id, tags,
|
||||||
replication_mode=nsx_constants.MTEP,
|
replication_mode=nsx_constants.MTEP,
|
||||||
admin_state=True, vlan_id=None):
|
admin_state=True, vlan_id=None):
|
||||||
@ -145,8 +155,8 @@ def update_logical_port(lport_id, name=None, admin_state=None):
|
|||||||
return client.update_resource(resource, lport)
|
return client.update_resource(resource, lport)
|
||||||
|
|
||||||
|
|
||||||
def create_logical_router(display_name, tags, edge_cluster_uuid=None,
|
def create_logical_router(display_name, tags,
|
||||||
tier_0=False):
|
edge_cluster_uuid=None, tier_0=False):
|
||||||
# TODO(salv-orlando): If possible do not manage edge clusters in the main
|
# TODO(salv-orlando): If possible do not manage edge clusters in the main
|
||||||
# plugin logic.
|
# plugin logic.
|
||||||
router_type = (nsx_constants.ROUTER_TYPE_TIER0 if tier_0 else
|
router_type = (nsx_constants.ROUTER_TYPE_TIER0 if tier_0 else
|
||||||
@ -155,8 +165,6 @@ def create_logical_router(display_name, tags, edge_cluster_uuid=None,
|
|||||||
body = {'display_name': display_name,
|
body = {'display_name': display_name,
|
||||||
'router_type': router_type,
|
'router_type': router_type,
|
||||||
'tags': tags}
|
'tags': tags}
|
||||||
# TODO(salv-orlando): raise if tier_0 but no edge_cluster_uuid was
|
|
||||||
# specified
|
|
||||||
if edge_cluster_uuid:
|
if edge_cluster_uuid:
|
||||||
body['edge_cluster_id'] = edge_cluster_uuid
|
body['edge_cluster_id'] = edge_cluster_uuid
|
||||||
return client.create_resource(resource, body)
|
return client.create_resource(resource, body)
|
||||||
@ -167,6 +175,11 @@ def get_logical_router(lrouter_id):
|
|||||||
return client.get_resource(resource)
|
return client.get_resource(resource)
|
||||||
|
|
||||||
|
|
||||||
|
def update_logical_router(lrouter_id, **kwargs):
|
||||||
|
resource = 'logical-routers/%s' % lrouter_id
|
||||||
|
return update_resource_with_retry(resource, kwargs)
|
||||||
|
|
||||||
|
|
||||||
def delete_logical_router(lrouter_id):
|
def delete_logical_router(lrouter_id):
|
||||||
resource = 'logical-routers/%s/' % lrouter_id
|
resource = 'logical-routers/%s/' % lrouter_id
|
||||||
|
|
||||||
@ -174,21 +187,70 @@ def delete_logical_router(lrouter_id):
|
|||||||
return client.delete_resource(resource)
|
return client.delete_resource(resource)
|
||||||
|
|
||||||
|
|
||||||
|
def get_logical_router_port_by_ls_id(logical_switch_id):
|
||||||
|
resource = 'logical-router-ports?logical_switch_id=%s' % logical_switch_id
|
||||||
|
router_ports = client.get_resource(resource)
|
||||||
|
if int(router_ports['result_count']) >= 2:
|
||||||
|
raise nsx_exc.NsxPluginException(
|
||||||
|
err_msg=_("Can't support more than one logical router ports "
|
||||||
|
"on same logical switch %s ") % logical_switch_id)
|
||||||
|
elif int(router_ports['result_count']) == 1:
|
||||||
|
return router_ports['results'][0]
|
||||||
|
else:
|
||||||
|
err_msg = (_("Logical router link port not found on logical "
|
||||||
|
"switch %s") % logical_switch_id)
|
||||||
|
raise nsx_exc.ResourceNotFound(manager=client._get_manager_ip(),
|
||||||
|
operation=err_msg)
|
||||||
|
|
||||||
|
|
||||||
|
def create_logical_router_port_by_ls_id(logical_router_id,
|
||||||
|
ls_id,
|
||||||
|
logical_switch_port_id,
|
||||||
|
resource_type,
|
||||||
|
address_groups):
|
||||||
|
try:
|
||||||
|
port = get_logical_router_port_by_ls_id(ls_id)
|
||||||
|
except nsx_exc.ResourceNotFound:
|
||||||
|
return create_logical_router_port(logical_router_id,
|
||||||
|
ROUTER_INTF_PORT_NAME,
|
||||||
|
logical_switch_port_id,
|
||||||
|
resource_type,
|
||||||
|
address_groups)
|
||||||
|
else:
|
||||||
|
return update_logical_router_port(port['id'], subnets=address_groups)
|
||||||
|
|
||||||
|
|
||||||
def create_logical_router_port(logical_router_id,
|
def create_logical_router_port(logical_router_id,
|
||||||
|
display_name,
|
||||||
logical_switch_port_id,
|
logical_switch_port_id,
|
||||||
resource_type,
|
resource_type,
|
||||||
cidr_length,
|
address_groups):
|
||||||
ip_address):
|
|
||||||
resource = 'logical-router-ports'
|
resource = 'logical-router-ports'
|
||||||
body = {'resource_type': resource_type,
|
body = {'display_name': display_name,
|
||||||
|
'resource_type': resource_type,
|
||||||
'logical_router_id': logical_router_id,
|
'logical_router_id': logical_router_id,
|
||||||
'subnets': [{"prefix_length": cidr_length,
|
'subnets': address_groups,
|
||||||
"ip_addresses": [ip_address]}],
|
|
||||||
'linked_logical_switch_port_id': logical_switch_port_id}
|
'linked_logical_switch_port_id': logical_switch_port_id}
|
||||||
|
|
||||||
return client.create_resource(resource, body)
|
return client.create_resource(resource, body)
|
||||||
|
|
||||||
|
|
||||||
|
def update_logical_router_port_by_ls_id(logical_router_id, ls_id,
|
||||||
|
**payload):
|
||||||
|
port = get_logical_router_port_by_ls_id(ls_id)
|
||||||
|
return update_logical_router_port(port['id'], **payload)
|
||||||
|
|
||||||
|
|
||||||
|
def update_logical_router_port(logical_port_id, **kwargs):
|
||||||
|
resource = 'logical-router-ports/%s?detach=true' % logical_port_id
|
||||||
|
return update_resource_with_retry(resource, kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def delete_logical_router_port_by_ls_id(ls_id):
|
||||||
|
port = get_logical_router_port_by_ls_id(ls_id)
|
||||||
|
delete_logical_router_port(port['id'])
|
||||||
|
|
||||||
|
|
||||||
def delete_logical_router_port(logical_port_id):
|
def delete_logical_router_port(logical_port_id):
|
||||||
resource = 'logical-router-ports/%s?detach=true' % logical_port_id
|
resource = 'logical-router-ports/%s?detach=true' % logical_port_id
|
||||||
client.delete_resource(resource)
|
client.delete_resource(resource)
|
||||||
|
@ -43,11 +43,13 @@ from neutron.db import agentschedulers_db
|
|||||||
from neutron.db import db_base_plugin_v2
|
from neutron.db import db_base_plugin_v2
|
||||||
from neutron.db import external_net_db
|
from neutron.db import external_net_db
|
||||||
from neutron.db import extradhcpopt_db
|
from neutron.db import extradhcpopt_db
|
||||||
|
from neutron.db import extraroute_db
|
||||||
from neutron.db import l3_db
|
from neutron.db import l3_db
|
||||||
|
from neutron.db import l3_gwmode_db
|
||||||
from neutron.db import models_v2
|
from neutron.db import models_v2
|
||||||
from neutron.db import portbindings_db
|
from neutron.db import portbindings_db
|
||||||
from neutron.db import securitygroups_db
|
from neutron.db import securitygroups_db
|
||||||
from neutron.i18n import _LE, _LW
|
from neutron.i18n import _LE, _LI, _LW
|
||||||
from neutron.plugins.common import constants as plugin_const
|
from neutron.plugins.common import constants as plugin_const
|
||||||
from neutron.plugins.common import utils as n_utils
|
from neutron.plugins.common import utils as n_utils
|
||||||
|
|
||||||
@ -65,7 +67,8 @@ LOG = log.getLogger(__name__)
|
|||||||
class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
securitygroups_db.SecurityGroupDbMixin,
|
securitygroups_db.SecurityGroupDbMixin,
|
||||||
external_net_db.External_net_db_mixin,
|
external_net_db.External_net_db_mixin,
|
||||||
l3_db.L3_NAT_dbonly_mixin,
|
extraroute_db.ExtraRoute_db_mixin,
|
||||||
|
l3_gwmode_db.L3_NAT_db_mixin,
|
||||||
portbindings_db.PortBindingMixin,
|
portbindings_db.PortBindingMixin,
|
||||||
agentschedulers_db.DhcpAgentSchedulerDbMixin,
|
agentschedulers_db.DhcpAgentSchedulerDbMixin,
|
||||||
extradhcpopt_db.ExtraDhcpOptMixin):
|
extradhcpopt_db.ExtraDhcpOptMixin):
|
||||||
@ -77,9 +80,11 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
supported_extension_aliases = ["quotas",
|
supported_extension_aliases = ["quotas",
|
||||||
"binding",
|
"binding",
|
||||||
"extra_dhcp_opt",
|
"extra_dhcp_opt",
|
||||||
|
"ext-gw-mode",
|
||||||
"security-group",
|
"security-group",
|
||||||
"provider",
|
"provider",
|
||||||
"external-net",
|
"external-net",
|
||||||
|
"extraroute",
|
||||||
"router"]
|
"router"]
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -320,6 +325,8 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
pnet._raise_if_updates_provider_attributes(net_data)
|
pnet._raise_if_updates_provider_attributes(net_data)
|
||||||
updated_net = super(NsxV3Plugin, self).update_network(context, id,
|
updated_net = super(NsxV3Plugin, self).update_network(context, id,
|
||||||
network)
|
network)
|
||||||
|
self._process_l3_update(context, updated_net, network['network'])
|
||||||
|
self._extend_network_dict_provider(context, updated_net)
|
||||||
|
|
||||||
if (not self._network_is_external(context, id) and
|
if (not self._network_is_external(context, id) and
|
||||||
'name' in net_data or 'admin_state_up' in net_data):
|
'name' in net_data or 'admin_state_up' in net_data):
|
||||||
@ -491,6 +498,7 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
_net_id, nsx_port_id = nsx_db.get_nsx_switch_and_port_id(
|
_net_id, nsx_port_id = nsx_db.get_nsx_switch_and_port_id(
|
||||||
context.session, port_id)
|
context.session, port_id)
|
||||||
nsxlib.delete_logical_port(nsx_port_id)
|
nsxlib.delete_logical_port(nsx_port_id)
|
||||||
|
self.disassociate_floatingips(context, port_id)
|
||||||
ret_val = super(NsxV3Plugin, self).delete_port(context, port_id)
|
ret_val = super(NsxV3Plugin, self).delete_port(context, port_id)
|
||||||
|
|
||||||
return ret_val
|
return ret_val
|
||||||
@ -532,13 +540,32 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
|
|
||||||
return updated_port
|
return updated_port
|
||||||
|
|
||||||
|
def _extract_external_gw(self, context, router, is_extract=True):
|
||||||
|
r = router['router']
|
||||||
|
gw_info = attributes.ATTR_NOT_SPECIFIED
|
||||||
|
# First extract the gateway info in case of updating
|
||||||
|
# gateway before edge is deployed.
|
||||||
|
if 'external_gateway_info' in r:
|
||||||
|
gw_info = r.get('external_gateway_info', {})
|
||||||
|
if is_extract:
|
||||||
|
del r['external_gateway_info']
|
||||||
|
network_id = (gw_info.get('network_id') if gw_info
|
||||||
|
else None)
|
||||||
|
if network_id:
|
||||||
|
ext_net = self._get_network(context, network_id)
|
||||||
|
if not ext_net.external:
|
||||||
|
msg = (_("Network '%s' is not a valid external network") %
|
||||||
|
network_id)
|
||||||
|
raise n_exc.BadRequest(resource='router', msg=msg)
|
||||||
|
return gw_info
|
||||||
|
|
||||||
def create_router(self, context, router):
|
def create_router(self, context, router):
|
||||||
|
# TODO(berlin): admin_state_up support
|
||||||
|
gw_info = self._extract_external_gw(context, router, is_extract=True)
|
||||||
tags = utils.build_v3_tags_payload(router['router'])
|
tags = utils.build_v3_tags_payload(router['router'])
|
||||||
result = nsxlib.create_logical_router(
|
result = nsxlib.create_logical_router(
|
||||||
display_name=router['router'].get('name', 'a_router_with_no_name'),
|
display_name=router['router'].get('name'),
|
||||||
tags=tags,
|
tags=tags)
|
||||||
tier_0=True,
|
|
||||||
edge_cluster_uuid=cfg.CONF.nsx_v3.default_edge_cluster_uuid)
|
|
||||||
|
|
||||||
with context.session.begin():
|
with context.session.begin():
|
||||||
router = super(NsxV3Plugin, self).create_router(
|
router = super(NsxV3Plugin, self).create_router(
|
||||||
@ -546,7 +573,21 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
nsx_db.add_neutron_nsx_router_mapping(
|
nsx_db.add_neutron_nsx_router_mapping(
|
||||||
context.session, router['id'], result['id'])
|
context.session, router['id'], result['id'])
|
||||||
|
|
||||||
return router
|
if gw_info != attributes.ATTR_NOT_SPECIFIED:
|
||||||
|
try:
|
||||||
|
self._update_router_gw_info(context, router['id'], gw_info)
|
||||||
|
except nsx_exc.ManagerError:
|
||||||
|
with excutils.save_and_reraise_exception():
|
||||||
|
LOG.error(_LE("Failed to set gateway info for router "
|
||||||
|
"being created: %s - removing router"),
|
||||||
|
router['id'])
|
||||||
|
self.delete_router(context, router['id'])
|
||||||
|
LOG.info(_LI("Create router failed while setting external "
|
||||||
|
"gateway. Router:%s has been removed from "
|
||||||
|
"DB and backend"),
|
||||||
|
router['id'])
|
||||||
|
|
||||||
|
return self.get_router(context, router['id'])
|
||||||
|
|
||||||
def delete_router(self, context, router_id):
|
def delete_router(self, context, router_id):
|
||||||
nsx_router_id = nsx_db.get_nsx_router_id(context.session,
|
nsx_router_id = nsx_db.get_nsx_router_id(context.session,
|
||||||
@ -558,12 +599,12 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
# passed (and indeed the resource was removed from the Neutron DB
|
# passed (and indeed the resource was removed from the Neutron DB
|
||||||
try:
|
try:
|
||||||
nsxlib.delete_logical_router(nsx_router_id)
|
nsxlib.delete_logical_router(nsx_router_id)
|
||||||
except nsx_exc.LogicalRouterNotFound:
|
except nsx_exc.ResourceNotFound:
|
||||||
# If the logical router was not found on the backend do not worry
|
# If the logical router was not found on the backend do not worry
|
||||||
# about it. The conditions has already been logged, so there is no
|
# about it. The conditions has already been logged, so there is no
|
||||||
# need to do further logging
|
# need to do further logging
|
||||||
pass
|
pass
|
||||||
except nsx_exc.NsxPluginException:
|
except nsx_exc.ManagerError:
|
||||||
# if there is a failure in deleting the router do not fail the
|
# if there is a failure in deleting the router do not fail the
|
||||||
# operation, especially since the router object has already been
|
# operation, especially since the router object has already been
|
||||||
# removed from the neutron DB. Take corrective steps to ensure the
|
# removed from the neutron DB. Take corrective steps to ensure the
|
||||||
@ -571,44 +612,92 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
# eventually removed.
|
# eventually removed.
|
||||||
LOG.warning(_LW("Backend router deletion for neutron router %s "
|
LOG.warning(_LW("Backend router deletion for neutron router %s "
|
||||||
"failed. The object was however removed from the "
|
"failed. The object was however removed from the "
|
||||||
"Neutron datanase"), router_id)
|
"Neutron database"), router_id)
|
||||||
|
|
||||||
return ret_val
|
return ret_val
|
||||||
|
|
||||||
def update_router(self, context, router_id, router):
|
def update_router(self, context, router_id, router):
|
||||||
# TODO(arosen) - call to backend
|
# TODO(berlin): admin_state_up support
|
||||||
return super(NsxV3Plugin, self).update_router(context, id,
|
try:
|
||||||
router)
|
return super(NsxV3Plugin, self).update_router(context, router_id,
|
||||||
|
router)
|
||||||
|
except nsx_exc.ResourceNotFound:
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
router_db = self._get_router(context, router_id)
|
||||||
|
router_db['status'] = const.NET_STATUS_ERROR
|
||||||
|
raise nsx_exc.NsxPluginException(
|
||||||
|
err_msg=(_("logical router %s not found at the backend")
|
||||||
|
% router_id))
|
||||||
|
except nsx_exc.ManagerError:
|
||||||
|
raise nsx_exc.NsxPluginException(
|
||||||
|
err_msg=(_("Unable to update router %s at the backend")
|
||||||
|
% router_id))
|
||||||
|
|
||||||
|
def _get_router_interface_ports_by_network(
|
||||||
|
self, context, router_id, network_id):
|
||||||
|
port_filters = {'device_id': [router_id],
|
||||||
|
'device_owner': [l3_db.DEVICE_OWNER_ROUTER_INTF],
|
||||||
|
'network_id': [network_id]}
|
||||||
|
return self.get_ports(context, filters=port_filters)
|
||||||
|
|
||||||
|
def _get_ports_and_address_groups(self, context, router_id, network_id,
|
||||||
|
exclude_sub_ids=None):
|
||||||
|
exclude_sub_ids = [] if not exclude_sub_ids else exclude_sub_ids
|
||||||
|
address_groups = []
|
||||||
|
ports = self._get_router_interface_ports_by_network(
|
||||||
|
context, router_id, network_id)
|
||||||
|
ports = [port for port in ports
|
||||||
|
if port['fixed_ips'] and
|
||||||
|
port['fixed_ips'][0]['subnet_id'] not in exclude_sub_ids]
|
||||||
|
for port in ports:
|
||||||
|
address_group = {}
|
||||||
|
gateway_ip = port['fixed_ips'][0]['ip_address']
|
||||||
|
subnet = self.get_subnet(context,
|
||||||
|
port['fixed_ips'][0]['subnet_id'])
|
||||||
|
prefixlen = str(netaddr.IPNetwork(subnet['cidr']).prefixlen)
|
||||||
|
address_group['ip_addresses'] = [gateway_ip]
|
||||||
|
address_group['prefix_length'] = prefixlen
|
||||||
|
address_groups.append(address_group)
|
||||||
|
return (ports, address_groups)
|
||||||
|
|
||||||
def add_router_interface(self, context, router_id, interface_info):
|
def add_router_interface(self, context, router_id, interface_info):
|
||||||
# NOTE(arosen): I think there is a bug here since I believe we
|
# TODO(berlin): disallow multiple subnets attached to different routers
|
||||||
# can also get a port or ip here....
|
info = super(NsxV3Plugin, self).add_router_interface(
|
||||||
subnet = self.get_subnet(context, interface_info['subnet_id'])
|
context, router_id, interface_info)
|
||||||
port = {'port': {'network_id': subnet['network_id'], 'name': '',
|
subnet = self.get_subnet(context, info['subnet_ids'][0])
|
||||||
'admin_state_up': True, 'device_id': '',
|
port = self.get_port(context, info['port_id'])
|
||||||
'device_owner': l3_db.DEVICE_OWNER_ROUTER_INTF,
|
network_id = subnet['network_id']
|
||||||
'mac_address': attributes.ATTR_NOT_SPECIFIED,
|
nsx_net_id, nsx_port_id = nsx_db.get_nsx_switch_and_port_id(
|
||||||
'fixed_ips': [{'subnet_id': subnet['id'],
|
|
||||||
'ip_address': subnet['gateway_ip']}]}}
|
|
||||||
port = self.create_port(context, port)
|
|
||||||
_net_id, nsx_port_id = nsx_db.get_nsx_switch_and_port_id(
|
|
||||||
context.session, port['id'])
|
context.session, port['id'])
|
||||||
|
|
||||||
nsx_router_id = nsx_db.get_nsx_router_id(context.session,
|
nsx_router_id = nsx_db.get_nsx_router_id(context.session,
|
||||||
router_id)
|
router_id)
|
||||||
result = nsxlib.create_logical_router_port(
|
_ports, address_groups = self._get_ports_and_address_groups(
|
||||||
|
context, router_id, network_id)
|
||||||
|
nsxlib.create_logical_router_port_by_ls_id(
|
||||||
logical_router_id=nsx_router_id,
|
logical_router_id=nsx_router_id,
|
||||||
|
ls_id=nsx_net_id,
|
||||||
logical_switch_port_id=nsx_port_id,
|
logical_switch_port_id=nsx_port_id,
|
||||||
resource_type="LogicalRouterDownLinkPort",
|
resource_type="LogicalRouterDownLinkPort",
|
||||||
cidr_length=24, ip_address=subnet['gateway_ip'])
|
address_groups=address_groups)
|
||||||
interface_info['port_id'] = port['id']
|
return info
|
||||||
del interface_info['subnet_id']
|
|
||||||
result = super(NsxV3Plugin, self).add_router_interface(
|
|
||||||
context, router_id, interface_info)
|
|
||||||
return result
|
|
||||||
|
|
||||||
def remove_router_interface(self, context, router_id, interface_info):
|
def remove_router_interface(self, context, router_id, interface_info):
|
||||||
if 'subnet_id' in interface_info:
|
subnet = None
|
||||||
|
subnet_id = None
|
||||||
|
port_id = None
|
||||||
|
self._validate_interface_info(interface_info, for_removal=True)
|
||||||
|
if 'port_id' in interface_info:
|
||||||
|
port_id = interface_info['port_id']
|
||||||
|
# find subnet_id - it is need for removing the SNAT rule
|
||||||
|
port = self._get_port(context, port_id)
|
||||||
|
if port.get('fixed_ips'):
|
||||||
|
subnet_id = port['fixed_ips'][0]['subnet_id']
|
||||||
|
if not (port['device_owner'] in const.ROUTER_INTERFACE_OWNERS
|
||||||
|
and port['device_id'] == router_id):
|
||||||
|
raise l3.RouterInterfaceNotFound(router_id=router_id,
|
||||||
|
port_id=port_id)
|
||||||
|
elif 'subnet_id' in interface_info:
|
||||||
subnet_id = interface_info['subnet_id']
|
subnet_id = interface_info['subnet_id']
|
||||||
subnet = self._get_subnet(context, subnet_id)
|
subnet = self._get_subnet(context, subnet_id)
|
||||||
rport_qry = context.session.query(models_v2.Port)
|
rport_qry = context.session.query(models_v2.Port)
|
||||||
@ -623,9 +712,30 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
else:
|
else:
|
||||||
raise l3.RouterInterfaceNotFoundForSubnet(router_id=router_id,
|
raise l3.RouterInterfaceNotFoundForSubnet(router_id=router_id,
|
||||||
subnet_id=subnet_id)
|
subnet_id=subnet_id)
|
||||||
_net_id, nsx_port_id = nsx_db.get_nsx_switch_and_port_id(
|
try:
|
||||||
|
nsx_net_id, _nsx_port_id = nsx_db.get_nsx_switch_and_port_id(
|
||||||
context.session, port_id)
|
context.session, port_id)
|
||||||
nsxlib.delete_logical_router_port(nsx_port_id)
|
subnet = self.get_subnet(context, subnet_id)
|
||||||
|
ports, address_groups = self._get_ports_and_address_groups(
|
||||||
|
context, router_id, subnet['network_id'],
|
||||||
|
exclude_sub_ids=[subnet['id']])
|
||||||
|
nsx_router_id = nsx_db.get_nsx_router_id(
|
||||||
|
context.session, router_id)
|
||||||
|
if len(ports) >= 1:
|
||||||
|
new_using_port_id = ports[0]['id']
|
||||||
|
_net_id, new_nsx_port_id = nsx_db.get_nsx_switch_and_port_id(
|
||||||
|
context.session, new_using_port_id)
|
||||||
|
nsxlib.update_logical_router_port_by_ls_id(
|
||||||
|
nsx_router_id, nsx_net_id,
|
||||||
|
linked_logical_switch_port_id=new_nsx_port_id,
|
||||||
|
subnets=address_groups)
|
||||||
|
else:
|
||||||
|
nsxlib.delete_logical_router_port_by_ls_id(nsx_net_id)
|
||||||
|
except nsx_exc.ResourceNotFound:
|
||||||
|
LOG.error(_LE("router port on router %(router_id)s for net "
|
||||||
|
"%(net_id)s not found at the backend"),
|
||||||
|
{'router_id': router_id,
|
||||||
|
'net_id': subnet['network_id']})
|
||||||
return super(NsxV3Plugin, self).remove_router_interface(
|
return super(NsxV3Plugin, self).remove_router_interface(
|
||||||
context, router_id, interface_info)
|
context, router_id, interface_info)
|
||||||
|
|
||||||
|
@ -16,10 +16,13 @@
|
|||||||
|
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
|
|
||||||
|
from vmware_nsx.neutron.plugins.vmware.common import exceptions as nsx_exc
|
||||||
from vmware_nsx.neutron.plugins.vmware.common import nsx_constants
|
from vmware_nsx.neutron.plugins.vmware.common import nsx_constants
|
||||||
|
|
||||||
|
|
||||||
FAKE_NAME = "fake_name"
|
FAKE_NAME = "fake_name"
|
||||||
|
DEFAULT_TIER0_ROUTER_UUID = "fake_default_tier0_router_uuid"
|
||||||
|
FAKE_MANAGER = "fake_manager_ip"
|
||||||
|
|
||||||
|
|
||||||
def make_fake_switch(switch_uuid=None, tz_uuid=None, name=FAKE_NAME):
|
def make_fake_switch(switch_uuid=None, tz_uuid=None, name=FAKE_NAME):
|
||||||
@ -179,22 +182,6 @@ def update_logical_port(lport_id, name=None, admin_state=None):
|
|||||||
return lport
|
return lport
|
||||||
|
|
||||||
|
|
||||||
def get_edge_cluster(edge_cluster_uuid):
|
|
||||||
FAKE_CLUSTER = {
|
|
||||||
"id": edge_cluster_uuid,
|
|
||||||
"members": [
|
|
||||||
{"member_index": 0},
|
|
||||||
{"member_index": 1}]}
|
|
||||||
return FAKE_CLUSTER
|
|
||||||
|
|
||||||
|
|
||||||
def get_logical_router(lrouter_uuid):
|
|
||||||
FAKE_LROUTER = {
|
|
||||||
"id": lrouter_uuid,
|
|
||||||
"edge_cluster_uuid": uuidutils.generate_uuid()}
|
|
||||||
return FAKE_LROUTER
|
|
||||||
|
|
||||||
|
|
||||||
def add_rules_in_section(rules, section_id):
|
def add_rules_in_section(rules, section_id):
|
||||||
for rule in rules:
|
for rule in rules:
|
||||||
rule['id'] = uuidutils.generate_uuid()
|
rule['id'] = uuidutils.generate_uuid()
|
||||||
@ -216,3 +203,135 @@ def update_resource(resource, data):
|
|||||||
|
|
||||||
def delete_resource(resource):
|
def delete_resource(resource):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class NsxV3Mock(object):
|
||||||
|
def __init__(self, default_tier0_router_uuid=DEFAULT_TIER0_ROUTER_UUID):
|
||||||
|
self.logical_routers = {}
|
||||||
|
self.logical_router_ports = {}
|
||||||
|
self.logical_ports = {}
|
||||||
|
if default_tier0_router_uuid:
|
||||||
|
self.create_logical_router(
|
||||||
|
DEFAULT_TIER0_ROUTER_UUID, None,
|
||||||
|
edge_cluster_uuid="fake_edge_cluster_uuid",
|
||||||
|
tier_0=True)
|
||||||
|
|
||||||
|
def get_edge_cluster(self, edge_cluster_uuid):
|
||||||
|
FAKE_CLUSTER = {
|
||||||
|
"id": edge_cluster_uuid,
|
||||||
|
"members": [
|
||||||
|
{"member_index": 0},
|
||||||
|
{"member_index": 1}]}
|
||||||
|
return FAKE_CLUSTER
|
||||||
|
|
||||||
|
def create_logical_router(self, display_name, tags,
|
||||||
|
edge_cluster_uuid=None,
|
||||||
|
tier_0=False):
|
||||||
|
router_type = (nsx_constants.ROUTER_TYPE_TIER0 if tier_0 else
|
||||||
|
nsx_constants.ROUTER_TYPE_TIER1)
|
||||||
|
if display_name == DEFAULT_TIER0_ROUTER_UUID:
|
||||||
|
fake_router_uuid = DEFAULT_TIER0_ROUTER_UUID
|
||||||
|
else:
|
||||||
|
fake_router_uuid = uuidutils.generate_uuid()
|
||||||
|
result = {'display_name': display_name,
|
||||||
|
'router_type': router_type,
|
||||||
|
'tags': tags,
|
||||||
|
'id': fake_router_uuid}
|
||||||
|
if edge_cluster_uuid:
|
||||||
|
result['edge_cluster_id'] = edge_cluster_uuid
|
||||||
|
self.logical_routers[fake_router_uuid] = result
|
||||||
|
return result
|
||||||
|
|
||||||
|
def get_logical_router(self, lrouter_id):
|
||||||
|
if lrouter_id in self.logical_routers:
|
||||||
|
return self.logical_routers[lrouter_id]
|
||||||
|
else:
|
||||||
|
raise nsx_exc.ResourceNotFound(manager=FAKE_MANAGER,
|
||||||
|
operation="get_logical_router")
|
||||||
|
|
||||||
|
def update_logical_router(self, lrouter_id, **kwargs):
|
||||||
|
if lrouter_id in self.logical_routers:
|
||||||
|
payload = self.logical_routers[lrouter_id]
|
||||||
|
payload.update(kwargs)
|
||||||
|
return payload
|
||||||
|
else:
|
||||||
|
raise nsx_exc.ResourceNotFound(manager=FAKE_MANAGER,
|
||||||
|
operation="update_logical_router")
|
||||||
|
|
||||||
|
def delete_logical_router(self, lrouter_id):
|
||||||
|
if lrouter_id in self.logical_routers:
|
||||||
|
del self.logical_routers[lrouter_id]
|
||||||
|
else:
|
||||||
|
raise nsx_exc.ResourceNotFound(manager=FAKE_MANAGER,
|
||||||
|
operation="delete_logical_router")
|
||||||
|
|
||||||
|
def get_logical_router_port_by_ls_id(self, logical_switch_id):
|
||||||
|
router_ports = []
|
||||||
|
for router_port in self.logical_router_ports.values():
|
||||||
|
ls_port_id = router_port['linked_logical_switch_port_id']
|
||||||
|
port = self.get_logical_port(ls_port_id)
|
||||||
|
if port['logical_switch_id'] == logical_switch_id:
|
||||||
|
router_ports.append(router_port)
|
||||||
|
if len(router_ports) >= 2:
|
||||||
|
raise nsx_exc.NsxPluginException(
|
||||||
|
err_msg=_("Can't support more than one logical router ports "
|
||||||
|
"on same logical switch %s ") % logical_switch_id)
|
||||||
|
elif len(router_ports) == 1:
|
||||||
|
return router_ports[0]
|
||||||
|
else:
|
||||||
|
err_msg = (_("Logical router link port not found on logical "
|
||||||
|
"switch %s") % logical_switch_id)
|
||||||
|
raise nsx_exc.ResourceNotFound(manager=FAKE_MANAGER,
|
||||||
|
operation=err_msg)
|
||||||
|
|
||||||
|
def create_logical_port(self, lswitch_id, vif_uuid, tags,
|
||||||
|
attachment_type=nsx_constants.ATTACHMENT_VIF,
|
||||||
|
admin_state=True, name=None, address_bindings=None,
|
||||||
|
parent_name=None, parent_tag=None):
|
||||||
|
fake_port = create_logical_port(
|
||||||
|
lswitch_id, vif_uuid, tags,
|
||||||
|
attachment_type=attachment_type,
|
||||||
|
admin_state=admin_state, name=name,
|
||||||
|
address_bindings=address_bindings,
|
||||||
|
parent_name=parent_name, parent_tag=parent_tag)
|
||||||
|
fake_port_uuid = fake_port['id']
|
||||||
|
self.logical_ports[fake_port_uuid] = fake_port
|
||||||
|
return fake_port
|
||||||
|
|
||||||
|
def get_logical_port(self, logical_port_id):
|
||||||
|
if logical_port_id in self.logical_ports:
|
||||||
|
return self.logical_ports[logical_port_id]
|
||||||
|
else:
|
||||||
|
raise nsx_exc.ResourceNotFound(
|
||||||
|
manager=FAKE_MANAGER, operation="get_logical_port")
|
||||||
|
|
||||||
|
def create_logical_router_port(self, logical_router_id,
|
||||||
|
display_name,
|
||||||
|
logical_switch_port_id,
|
||||||
|
resource_type,
|
||||||
|
address_groups):
|
||||||
|
fake_router_port_uuid = uuidutils.generate_uuid()
|
||||||
|
body = {'id': fake_router_port_uuid,
|
||||||
|
'display_name': display_name,
|
||||||
|
'resource_type': resource_type,
|
||||||
|
'logical_router_id': logical_router_id,
|
||||||
|
'subnets': address_groups,
|
||||||
|
'linked_logical_switch_port_id': logical_switch_port_id}
|
||||||
|
self.logical_router_ports[fake_router_port_uuid] = body
|
||||||
|
return body
|
||||||
|
|
||||||
|
def update_logical_router_port(self, logical_port_id, **kwargs):
|
||||||
|
if logical_port_id in self.logical_router_ports:
|
||||||
|
payload = self.logical_router_ports[logical_port_id]
|
||||||
|
payload.update(kwargs)
|
||||||
|
return payload
|
||||||
|
else:
|
||||||
|
raise nsx_exc.ResourceNotFound(
|
||||||
|
manager=FAKE_MANAGER, operation="update_logical_router_port")
|
||||||
|
|
||||||
|
def delete_logical_router_port(self, logical_port_id):
|
||||||
|
if logical_port_id in self.logical_router_ports:
|
||||||
|
del self.logical_router_ports[logical_port_id]
|
||||||
|
else:
|
||||||
|
raise nsx_exc.ResourceNotFound(
|
||||||
|
manager=FAKE_MANAGER, operation="update_logical_router_port")
|
||||||
|
@ -15,12 +15,26 @@
|
|||||||
|
|
||||||
import mock
|
import mock
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
import six
|
||||||
|
|
||||||
|
from neutron.api.v2 import attributes
|
||||||
|
from neutron import context
|
||||||
|
from neutron.extensions import external_net
|
||||||
|
from neutron.extensions import extraroute
|
||||||
|
from neutron.extensions import l3
|
||||||
|
from neutron.extensions import l3_ext_gw_mode
|
||||||
|
from neutron.extensions import providernet as pnet
|
||||||
|
from neutron import manager
|
||||||
import neutron.tests.unit.db.test_db_base_plugin_v2 as test_plugin
|
import neutron.tests.unit.db.test_db_base_plugin_v2 as test_plugin
|
||||||
from neutron.tests.unit.extensions import test_extra_dhcp_opt as test_dhcpopts
|
from neutron.tests.unit.extensions import test_extra_dhcp_opt as test_dhcpopts
|
||||||
|
import neutron.tests.unit.extensions.test_extraroute as test_ext_route
|
||||||
|
import neutron.tests.unit.extensions.test_l3 as test_l3_plugin
|
||||||
|
import neutron.tests.unit.extensions.test_l3_ext_gw_mode as test_ext_gw_mode
|
||||||
import neutron.tests.unit.extensions.test_securitygroup as ext_sg
|
import neutron.tests.unit.extensions.test_securitygroup as ext_sg
|
||||||
|
from vmware_nsx.neutron.plugins.vmware.common import utils
|
||||||
from vmware_nsx.neutron.plugins.vmware.nsxlib import v3 as nsxlib
|
from vmware_nsx.neutron.plugins.vmware.nsxlib import v3 as nsxlib
|
||||||
from vmware_nsx.neutron.plugins.vmware.nsxlib.v3 import dfw_api as firewall
|
from vmware_nsx.neutron.plugins.vmware.nsxlib.v3 import dfw_api as firewall
|
||||||
|
from vmware_nsx.neutron.tests.unit import vmware
|
||||||
from vmware_nsx.neutron.tests.unit.vmware import nsx_v3_mocks
|
from vmware_nsx.neutron.tests.unit.vmware import nsx_v3_mocks
|
||||||
|
|
||||||
PLUGIN_NAME = ('vmware_nsx.neutron.plugins.vmware.'
|
PLUGIN_NAME = ('vmware_nsx.neutron.plugins.vmware.'
|
||||||
@ -45,9 +59,6 @@ class NsxPluginV3TestCase(test_plugin.NeutronDbPluginV2TestCase):
|
|||||||
nsxlib.delete_logical_port = mock.Mock()
|
nsxlib.delete_logical_port = mock.Mock()
|
||||||
nsxlib.get_logical_port = nsx_v3_mocks.get_logical_port
|
nsxlib.get_logical_port = nsx_v3_mocks.get_logical_port
|
||||||
nsxlib.update_logical_port = nsx_v3_mocks.update_logical_port
|
nsxlib.update_logical_port = nsx_v3_mocks.update_logical_port
|
||||||
# TODO(berlin): fill valid data
|
|
||||||
nsxlib.get_edge_cluster = nsx_v3_mocks.get_edge_cluster
|
|
||||||
nsxlib.get_logical_router = nsx_v3_mocks.get_logical_router
|
|
||||||
firewall.add_rules_in_section = nsx_v3_mocks.add_rules_in_section
|
firewall.add_rules_in_section = nsx_v3_mocks.add_rules_in_section
|
||||||
firewall.nsclient.create_resource = nsx_v3_mocks.create_resource
|
firewall.nsclient.create_resource = nsx_v3_mocks.create_resource
|
||||||
firewall.nsclient.update_resource = nsx_v3_mocks.update_resource
|
firewall.nsclient.update_resource = nsx_v3_mocks.update_resource
|
||||||
@ -56,6 +67,36 @@ class NsxPluginV3TestCase(test_plugin.NeutronDbPluginV2TestCase):
|
|||||||
|
|
||||||
super(NsxPluginV3TestCase, self).setUp(plugin=plugin,
|
super(NsxPluginV3TestCase, self).setUp(plugin=plugin,
|
||||||
ext_mgr=ext_mgr)
|
ext_mgr=ext_mgr)
|
||||||
|
self.v3_mock = nsx_v3_mocks.NsxV3Mock()
|
||||||
|
nsxlib.get_edge_cluster = self.v3_mock.get_edge_cluster
|
||||||
|
nsxlib.get_logical_router = self.v3_mock.get_logical_router
|
||||||
|
|
||||||
|
def _create_network(self, fmt, name, admin_state_up,
|
||||||
|
arg_list=None, providernet_args=None, **kwargs):
|
||||||
|
data = {'network': {'name': name,
|
||||||
|
'admin_state_up': admin_state_up,
|
||||||
|
'tenant_id': self._tenant_id}}
|
||||||
|
# Fix to allow the router:external attribute and any other
|
||||||
|
# attributes containing a colon to be passed with
|
||||||
|
# a double underscore instead
|
||||||
|
kwargs = dict((k.replace('__', ':'), v) for k, v in kwargs.items())
|
||||||
|
if external_net.EXTERNAL in kwargs:
|
||||||
|
arg_list = (external_net.EXTERNAL, ) + (arg_list or ())
|
||||||
|
|
||||||
|
attrs = kwargs
|
||||||
|
if providernet_args:
|
||||||
|
attrs.update(providernet_args)
|
||||||
|
for arg in (('admin_state_up', 'tenant_id', 'shared') +
|
||||||
|
(arg_list or ())):
|
||||||
|
# Arg must be present and not empty
|
||||||
|
if arg in kwargs and kwargs[arg]:
|
||||||
|
data['network'][arg] = kwargs[arg]
|
||||||
|
network_req = self.new_create_request('networks', data, fmt)
|
||||||
|
if (kwargs.get('set_context') and 'tenant_id' in kwargs):
|
||||||
|
# create a specific auth context for this request
|
||||||
|
network_req.environ['neutron.context'] = context.Context(
|
||||||
|
'', kwargs['tenant_id'])
|
||||||
|
return network_req.get_response(self.api)
|
||||||
|
|
||||||
|
|
||||||
class TestNetworksV2(test_plugin.TestNetworksV2, NsxPluginV3TestCase):
|
class TestNetworksV2(test_plugin.TestNetworksV2, NsxPluginV3TestCase):
|
||||||
@ -97,3 +138,111 @@ class DHCPOptsTestCase(test_dhcpopts.TestExtraDhcpOpt, NsxPluginV3TestCase):
|
|||||||
def setUp(self, plugin=None):
|
def setUp(self, plugin=None):
|
||||||
super(test_dhcpopts.ExtraDhcpOptDBTestCase, self).setUp(
|
super(test_dhcpopts.ExtraDhcpOptDBTestCase, self).setUp(
|
||||||
plugin=PLUGIN_NAME)
|
plugin=PLUGIN_NAME)
|
||||||
|
|
||||||
|
|
||||||
|
class TestL3ExtensionManager(object):
|
||||||
|
|
||||||
|
def get_resources(self):
|
||||||
|
# Simulate extension of L3 attribute map
|
||||||
|
# First apply attribute extensions
|
||||||
|
for key in l3.RESOURCE_ATTRIBUTE_MAP.keys():
|
||||||
|
l3.RESOURCE_ATTRIBUTE_MAP[key].update(
|
||||||
|
l3_ext_gw_mode.EXTENDED_ATTRIBUTES_2_0.get(key, {}))
|
||||||
|
l3.RESOURCE_ATTRIBUTE_MAP[key].update(
|
||||||
|
extraroute.EXTENDED_ATTRIBUTES_2_0.get(key, {}))
|
||||||
|
# Finally add l3 resources to the global attribute map
|
||||||
|
attributes.RESOURCE_ATTRIBUTE_MAP.update(
|
||||||
|
l3.RESOURCE_ATTRIBUTE_MAP)
|
||||||
|
return l3.L3.get_resources()
|
||||||
|
|
||||||
|
def get_actions(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_request_extensions(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def backup_l3_attribute_map():
|
||||||
|
"""Return a backup of the original l3 attribute map."""
|
||||||
|
return dict((res, attrs.copy()) for
|
||||||
|
(res, attrs) in six.iteritems(l3.RESOURCE_ATTRIBUTE_MAP))
|
||||||
|
|
||||||
|
|
||||||
|
def restore_l3_attribute_map(map_to_restore):
|
||||||
|
"""Ensure changes made by fake ext mgrs are reverted."""
|
||||||
|
l3.RESOURCE_ATTRIBUTE_MAP = map_to_restore
|
||||||
|
|
||||||
|
|
||||||
|
class L3NatTest(test_l3_plugin.L3BaseForIntTests, NsxPluginV3TestCase):
|
||||||
|
|
||||||
|
def _restore_l3_attribute_map(self):
|
||||||
|
l3.RESOURCE_ATTRIBUTE_MAP = self._l3_attribute_map_bk
|
||||||
|
|
||||||
|
def setUp(self, plugin=PLUGIN_NAME, ext_mgr=None,
|
||||||
|
service_plugins=None):
|
||||||
|
self._l3_attribute_map_bk = backup_l3_attribute_map()
|
||||||
|
cfg.CONF.set_override('api_extensions_path', vmware.NSXEXT_PATH)
|
||||||
|
cfg.CONF.set_default('max_routes', 3)
|
||||||
|
self.addCleanup(restore_l3_attribute_map, self._l3_attribute_map_bk)
|
||||||
|
ext_mgr = ext_mgr or TestL3ExtensionManager()
|
||||||
|
super(L3NatTest, self).setUp(
|
||||||
|
plugin=plugin, ext_mgr=ext_mgr, service_plugins=service_plugins)
|
||||||
|
plugin_instance = manager.NeutronManager.get_plugin()
|
||||||
|
self._plugin_name = "%s.%s" % (
|
||||||
|
plugin_instance.__module__,
|
||||||
|
plugin_instance.__class__.__name__)
|
||||||
|
self._plugin_class = plugin_instance.__class__
|
||||||
|
nsxlib.create_logical_port = self.v3_mock.create_logical_port
|
||||||
|
nsxlib.create_logical_router = self.v3_mock.create_logical_router
|
||||||
|
nsxlib.update_logical_router = self.v3_mock.update_logical_router
|
||||||
|
nsxlib.delete_logical_router = self.v3_mock.delete_logical_router
|
||||||
|
nsxlib.get_logical_router_port_by_ls_id = (
|
||||||
|
self.v3_mock.get_logical_router_port_by_ls_id)
|
||||||
|
nsxlib.create_logical_router_port = (
|
||||||
|
self.v3_mock.create_logical_router_port)
|
||||||
|
nsxlib.update_logical_router_port = (
|
||||||
|
self.v3_mock.update_logical_router_port)
|
||||||
|
nsxlib.delete_logical_router_port = (
|
||||||
|
self.v3_mock.delete_logical_router_port)
|
||||||
|
|
||||||
|
def _create_l3_ext_network(
|
||||||
|
self, physical_network=nsx_v3_mocks.DEFAULT_TIER0_ROUTER_UUID):
|
||||||
|
name = 'l3_ext_net'
|
||||||
|
net_type = utils.NetworkTypes.L3_EXT
|
||||||
|
providernet_args = {pnet.NETWORK_TYPE: net_type,
|
||||||
|
pnet.PHYSICAL_NETWORK: physical_network}
|
||||||
|
return self.network(name=name,
|
||||||
|
router__external=True,
|
||||||
|
providernet_args=providernet_args,
|
||||||
|
arg_list=(pnet.NETWORK_TYPE,
|
||||||
|
pnet.PHYSICAL_NETWORK))
|
||||||
|
|
||||||
|
|
||||||
|
class TestL3NatTestCase(L3NatTest,
|
||||||
|
test_l3_plugin.L3NatDBIntTestCase,
|
||||||
|
NsxPluginV3TestCase,
|
||||||
|
test_ext_route.ExtraRouteDBTestCaseBase):
|
||||||
|
|
||||||
|
def _test_create_l3_ext_network(
|
||||||
|
self, physical_network=nsx_v3_mocks.DEFAULT_TIER0_ROUTER_UUID):
|
||||||
|
name = 'l3_ext_net'
|
||||||
|
net_type = utils.NetworkTypes.L3_EXT
|
||||||
|
expected = [('subnets', []), ('name', name), ('admin_state_up', True),
|
||||||
|
('status', 'ACTIVE'), ('shared', False),
|
||||||
|
(external_net.EXTERNAL, True),
|
||||||
|
(pnet.NETWORK_TYPE, net_type),
|
||||||
|
(pnet.PHYSICAL_NETWORK, physical_network)]
|
||||||
|
with self._create_l3_ext_network(physical_network) as net:
|
||||||
|
for k, v in expected:
|
||||||
|
self.assertEqual(net['network'][k], v)
|
||||||
|
|
||||||
|
def test_create_l3_ext_network_with_default_tier0(self):
|
||||||
|
self._test_create_l3_ext_network()
|
||||||
|
|
||||||
|
def test_floatingip_with_invalid_create_port(self):
|
||||||
|
self._test_floatingip_with_invalid_create_port(self._plugin_name)
|
||||||
|
|
||||||
|
|
||||||
|
class ExtGwModeTestCase(L3NatTest,
|
||||||
|
test_ext_gw_mode.ExtGwModeIntTestCase):
|
||||||
|
pass
|
||||||
|
Loading…
x
Reference in New Issue
Block a user