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__)
|
||||
|
||||
ROUTER_INTF_PORT_NAME = "Tier1-RouterDownLinkPort"
|
||||
|
||||
|
||||
def get_edge_cluster(edge_cluster_uuid):
|
||||
resource = "edge-clusters/%s" % edge_cluster_uuid
|
||||
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,
|
||||
replication_mode=nsx_constants.MTEP,
|
||||
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)
|
||||
|
||||
|
||||
def create_logical_router(display_name, tags, edge_cluster_uuid=None,
|
||||
tier_0=False):
|
||||
def create_logical_router(display_name, tags,
|
||||
edge_cluster_uuid=None, tier_0=False):
|
||||
# TODO(salv-orlando): If possible do not manage edge clusters in the main
|
||||
# plugin logic.
|
||||
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,
|
||||
'router_type': router_type,
|
||||
'tags': tags}
|
||||
# TODO(salv-orlando): raise if tier_0 but no edge_cluster_uuid was
|
||||
# specified
|
||||
if edge_cluster_uuid:
|
||||
body['edge_cluster_id'] = edge_cluster_uuid
|
||||
return client.create_resource(resource, body)
|
||||
@ -167,6 +175,11 @@ def get_logical_router(lrouter_id):
|
||||
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):
|
||||
resource = 'logical-routers/%s/' % lrouter_id
|
||||
|
||||
@ -174,21 +187,70 @@ def delete_logical_router(lrouter_id):
|
||||
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,
|
||||
display_name,
|
||||
logical_switch_port_id,
|
||||
resource_type,
|
||||
cidr_length,
|
||||
ip_address):
|
||||
address_groups):
|
||||
resource = 'logical-router-ports'
|
||||
body = {'resource_type': resource_type,
|
||||
body = {'display_name': display_name,
|
||||
'resource_type': resource_type,
|
||||
'logical_router_id': logical_router_id,
|
||||
'subnets': [{"prefix_length": cidr_length,
|
||||
"ip_addresses": [ip_address]}],
|
||||
'subnets': address_groups,
|
||||
'linked_logical_switch_port_id': logical_switch_port_id}
|
||||
|
||||
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):
|
||||
resource = 'logical-router-ports/%s?detach=true' % logical_port_id
|
||||
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 external_net_db
|
||||
from neutron.db import extradhcpopt_db
|
||||
from neutron.db import extraroute_db
|
||||
from neutron.db import l3_db
|
||||
from neutron.db import l3_gwmode_db
|
||||
from neutron.db import models_v2
|
||||
from neutron.db import portbindings_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 utils as n_utils
|
||||
|
||||
@ -65,7 +67,8 @@ LOG = log.getLogger(__name__)
|
||||
class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
securitygroups_db.SecurityGroupDbMixin,
|
||||
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,
|
||||
agentschedulers_db.DhcpAgentSchedulerDbMixin,
|
||||
extradhcpopt_db.ExtraDhcpOptMixin):
|
||||
@ -77,9 +80,11 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
supported_extension_aliases = ["quotas",
|
||||
"binding",
|
||||
"extra_dhcp_opt",
|
||||
"ext-gw-mode",
|
||||
"security-group",
|
||||
"provider",
|
||||
"external-net",
|
||||
"extraroute",
|
||||
"router"]
|
||||
|
||||
def __init__(self):
|
||||
@ -320,6 +325,8 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
pnet._raise_if_updates_provider_attributes(net_data)
|
||||
updated_net = super(NsxV3Plugin, self).update_network(context, id,
|
||||
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
|
||||
'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(
|
||||
context.session, 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)
|
||||
|
||||
return ret_val
|
||||
@ -532,13 +540,32 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
|
||||
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):
|
||||
# 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'])
|
||||
result = nsxlib.create_logical_router(
|
||||
display_name=router['router'].get('name', 'a_router_with_no_name'),
|
||||
tags=tags,
|
||||
tier_0=True,
|
||||
edge_cluster_uuid=cfg.CONF.nsx_v3.default_edge_cluster_uuid)
|
||||
display_name=router['router'].get('name'),
|
||||
tags=tags)
|
||||
|
||||
with context.session.begin():
|
||||
router = super(NsxV3Plugin, self).create_router(
|
||||
@ -546,7 +573,21 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
nsx_db.add_neutron_nsx_router_mapping(
|
||||
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):
|
||||
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
|
||||
try:
|
||||
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
|
||||
# about it. The conditions has already been logged, so there is no
|
||||
# need to do further logging
|
||||
pass
|
||||
except nsx_exc.NsxPluginException:
|
||||
except nsx_exc.ManagerError:
|
||||
# if there is a failure in deleting the router do not fail the
|
||||
# operation, especially since the router object has already been
|
||||
# removed from the neutron DB. Take corrective steps to ensure the
|
||||
@ -571,44 +612,92 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
# eventually removed.
|
||||
LOG.warning(_LW("Backend router deletion for neutron router %s "
|
||||
"failed. The object was however removed from the "
|
||||
"Neutron datanase"), router_id)
|
||||
"Neutron database"), router_id)
|
||||
|
||||
return ret_val
|
||||
|
||||
def update_router(self, context, router_id, router):
|
||||
# TODO(arosen) - call to backend
|
||||
return super(NsxV3Plugin, self).update_router(context, id,
|
||||
router)
|
||||
# TODO(berlin): admin_state_up support
|
||||
try:
|
||||
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):
|
||||
# NOTE(arosen): I think there is a bug here since I believe we
|
||||
# can also get a port or ip here....
|
||||
subnet = self.get_subnet(context, interface_info['subnet_id'])
|
||||
port = {'port': {'network_id': subnet['network_id'], 'name': '',
|
||||
'admin_state_up': True, 'device_id': '',
|
||||
'device_owner': l3_db.DEVICE_OWNER_ROUTER_INTF,
|
||||
'mac_address': attributes.ATTR_NOT_SPECIFIED,
|
||||
'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(
|
||||
# TODO(berlin): disallow multiple subnets attached to different routers
|
||||
info = super(NsxV3Plugin, self).add_router_interface(
|
||||
context, router_id, interface_info)
|
||||
subnet = self.get_subnet(context, info['subnet_ids'][0])
|
||||
port = self.get_port(context, info['port_id'])
|
||||
network_id = subnet['network_id']
|
||||
nsx_net_id, nsx_port_id = nsx_db.get_nsx_switch_and_port_id(
|
||||
context.session, port['id'])
|
||||
|
||||
nsx_router_id = nsx_db.get_nsx_router_id(context.session,
|
||||
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,
|
||||
ls_id=nsx_net_id,
|
||||
logical_switch_port_id=nsx_port_id,
|
||||
resource_type="LogicalRouterDownLinkPort",
|
||||
cidr_length=24, ip_address=subnet['gateway_ip'])
|
||||
interface_info['port_id'] = port['id']
|
||||
del interface_info['subnet_id']
|
||||
result = super(NsxV3Plugin, self).add_router_interface(
|
||||
context, router_id, interface_info)
|
||||
return result
|
||||
address_groups=address_groups)
|
||||
return 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 = self._get_subnet(context, subnet_id)
|
||||
rport_qry = context.session.query(models_v2.Port)
|
||||
@ -623,9 +712,30 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
else:
|
||||
raise l3.RouterInterfaceNotFoundForSubnet(router_id=router_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)
|
||||
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(
|
||||
context, router_id, interface_info)
|
||||
|
||||
|
@ -16,10 +16,13 @@
|
||||
|
||||
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
|
||||
|
||||
|
||||
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):
|
||||
@ -179,22 +182,6 @@ def update_logical_port(lport_id, name=None, admin_state=None):
|
||||
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):
|
||||
for rule in rules:
|
||||
rule['id'] = uuidutils.generate_uuid()
|
||||
@ -216,3 +203,135 @@ def update_resource(resource, data):
|
||||
|
||||
def delete_resource(resource):
|
||||
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
|
||||
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
|
||||
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
|
||||
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.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
|
||||
|
||||
PLUGIN_NAME = ('vmware_nsx.neutron.plugins.vmware.'
|
||||
@ -45,9 +59,6 @@ class NsxPluginV3TestCase(test_plugin.NeutronDbPluginV2TestCase):
|
||||
nsxlib.delete_logical_port = mock.Mock()
|
||||
nsxlib.get_logical_port = nsx_v3_mocks.get_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.nsclient.create_resource = nsx_v3_mocks.create_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,
|
||||
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):
|
||||
@ -97,3 +138,111 @@ class DHCPOptsTestCase(test_dhcpopts.TestExtraDhcpOpt, NsxPluginV3TestCase):
|
||||
def setUp(self, plugin=None):
|
||||
super(test_dhcpopts.ExtraDhcpOptDBTestCase, self).setUp(
|
||||
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