There exist a case where deleting router from neutron without deleting router-interface deletes router from VSD but not from neutron. If router has an interface with subnet router deletion is not allowed. Needs to precheck this condition before deleting router from backend (VSD). Change-Id: I4ba7eff399acda0427505328355dbfb931d62587 Closes-Bug: #1298635
706 lines
34 KiB
Python
706 lines
34 KiB
Python
# Copyright 2014 Alcatel-Lucent USA 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.
|
|
#
|
|
# @author: Ronak Shah, Nuage Networks, Alcatel-Lucent USA Inc.
|
|
|
|
|
|
import re
|
|
|
|
import netaddr
|
|
from oslo.config import cfg
|
|
from sqlalchemy.orm import exc
|
|
|
|
from neutron.api import extensions as neutron_extensions
|
|
from neutron.api.v2 import attributes
|
|
from neutron.common import constants as os_constants
|
|
from neutron.common import exceptions as n_exc
|
|
from neutron.db import api as db
|
|
from neutron.db import db_base_plugin_v2
|
|
from neutron.db import external_net_db
|
|
from neutron.db import l3_db
|
|
from neutron.db import models_v2
|
|
from neutron.db import quota_db # noqa
|
|
from neutron.extensions import l3
|
|
from neutron.extensions import portbindings
|
|
from neutron.openstack.common import excutils
|
|
from neutron.openstack.common import importutils
|
|
from neutron.plugins.nuage.common import config
|
|
from neutron.plugins.nuage.common import constants
|
|
from neutron.plugins.nuage.common import exceptions as nuage_exc
|
|
from neutron.plugins.nuage import extensions
|
|
from neutron.plugins.nuage.extensions import netpartition
|
|
from neutron.plugins.nuage import nuagedb
|
|
from neutron import policy
|
|
|
|
|
|
class NuagePlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|
external_net_db.External_net_db_mixin,
|
|
l3_db.L3_NAT_db_mixin,
|
|
netpartition.NetPartitionPluginBase):
|
|
"""Class that implements Nuage Networks' plugin functionality."""
|
|
supported_extension_aliases = ["router", "binding", "external-net",
|
|
"net-partition", "nuage-router",
|
|
"nuage-subnet", "quotas"]
|
|
|
|
binding_view = "extension:port_binding:view"
|
|
|
|
def __init__(self):
|
|
super(NuagePlugin, self).__init__()
|
|
neutron_extensions.append_api_extensions_path(extensions.__path__)
|
|
config.nuage_register_cfg_opts()
|
|
self.nuageclient_init()
|
|
net_partition = cfg.CONF.RESTPROXY.default_net_partition_name
|
|
self._create_default_net_partition(net_partition)
|
|
|
|
def nuageclient_init(self):
|
|
server = cfg.CONF.RESTPROXY.server
|
|
serverauth = cfg.CONF.RESTPROXY.serverauth
|
|
serverssl = cfg.CONF.RESTPROXY.serverssl
|
|
base_uri = cfg.CONF.RESTPROXY.base_uri
|
|
auth_resource = cfg.CONF.RESTPROXY.auth_resource
|
|
organization = cfg.CONF.RESTPROXY.organization
|
|
nuageclient = importutils.import_module('nuagenetlib.nuageclient')
|
|
self.nuageclient = nuageclient.NuageClient(server, base_uri,
|
|
serverssl, serverauth,
|
|
auth_resource,
|
|
organization)
|
|
|
|
def _resource_finder(self, context, for_resource, resource, user_req):
|
|
match = re.match(attributes.UUID_PATTERN, user_req[resource])
|
|
if match:
|
|
obj_lister = getattr(self, "get_%s" % resource)
|
|
found_resource = obj_lister(context, user_req[resource])
|
|
if not found_resource:
|
|
msg = (_("%(resource)s with id %(resource_id)s does not "
|
|
"exist") % {'resource': resource,
|
|
'resource_id': user_req[resource]})
|
|
raise n_exc.BadRequest(resource=for_resource, msg=msg)
|
|
else:
|
|
filter = {'name': [user_req[resource]]}
|
|
obj_lister = getattr(self, "get_%ss" % resource)
|
|
found_resource = obj_lister(context, filters=filter)
|
|
if not found_resource:
|
|
msg = (_("Either %(resource)s %(req_resource)s not found "
|
|
"or you dont have credential to access it")
|
|
% {'resource': resource,
|
|
'req_resource': user_req[resource]})
|
|
raise n_exc.BadRequest(resource=for_resource, msg=msg)
|
|
if len(found_resource) > 1:
|
|
msg = (_("More than one entry found for %(resource)s "
|
|
"%(req_resource)s. Use id instead")
|
|
% {'resource': resource,
|
|
'req_resource': user_req[resource]})
|
|
raise n_exc.BadRequest(resource=for_resource, msg=msg)
|
|
found_resource = found_resource[0]
|
|
return found_resource
|
|
|
|
def _update_port_ip(self, context, port, new_ip):
|
|
subid = port['fixed_ips'][0]['subnet_id']
|
|
new_fixed_ips = {}
|
|
new_fixed_ips['subnet_id'] = subid
|
|
new_fixed_ips['ip_address'] = new_ip
|
|
ips, prev_ips = self._update_ips_for_port(context,
|
|
port["network_id"],
|
|
port['id'],
|
|
port["fixed_ips"],
|
|
[new_fixed_ips])
|
|
|
|
# Update ips if necessary
|
|
for ip in ips:
|
|
allocated = models_v2.IPAllocation(
|
|
network_id=port['network_id'], port_id=port['id'],
|
|
ip_address=ip['ip_address'], subnet_id=ip['subnet_id'])
|
|
context.session.add(allocated)
|
|
|
|
def _create_update_port(self, context, port,
|
|
port_mapping, subnet_mapping):
|
|
filters = {'device_id': [port['device_id']]}
|
|
ports = self.get_ports(context, filters)
|
|
netpart_id = subnet_mapping['net_partition_id']
|
|
net_partition = nuagedb.get_net_partition_by_id(context.session,
|
|
netpart_id)
|
|
params = {
|
|
'id': port['device_id'],
|
|
'mac': port['mac_address'],
|
|
'parent_id': subnet_mapping['nuage_subnet_id'],
|
|
'net_partition': net_partition,
|
|
'ip': None,
|
|
'no_of_ports': len(ports),
|
|
'tenant': port['tenant_id']
|
|
}
|
|
if port_mapping['static_ip']:
|
|
params['ip'] = port['fixed_ips'][0]['ip_address']
|
|
|
|
nuage_vm = self.nuageclient.create_vms(params)
|
|
if nuage_vm:
|
|
if port['fixed_ips'][0]['ip_address'] != str(nuage_vm['ip']):
|
|
self._update_port_ip(context, port, nuage_vm['ip'])
|
|
port_dict = {
|
|
'nuage_vport_id': nuage_vm['vport_id'],
|
|
'nuage_vif_id': nuage_vm['vif_id']
|
|
}
|
|
nuagedb.update_port_vport_mapping(port_mapping,
|
|
port_dict)
|
|
|
|
def create_port(self, context, port):
|
|
session = context.session
|
|
with session.begin(subtransactions=True):
|
|
p = port['port']
|
|
port = super(NuagePlugin, self).create_port(context, port)
|
|
device_owner = port.get('device_owner', None)
|
|
if (device_owner and
|
|
device_owner not in constants.AUTO_CREATE_PORT_OWNERS):
|
|
if 'fixed_ips' not in port or len(port['fixed_ips']) == 0:
|
|
return self._extend_port_dict_binding(context, port)
|
|
subnet_id = port['fixed_ips'][0]['subnet_id']
|
|
subnet_mapping = nuagedb.get_subnet_l2dom_by_id(session,
|
|
subnet_id)
|
|
if subnet_mapping:
|
|
static_ip = False
|
|
if (attributes.is_attr_set(p['fixed_ips']) and
|
|
'ip_address' in p['fixed_ips'][0]):
|
|
static_ip = True
|
|
nuage_vport_id = None
|
|
nuage_vif_id = None
|
|
port_mapping = nuagedb.add_port_vport_mapping(
|
|
session,
|
|
port['id'],
|
|
nuage_vport_id,
|
|
nuage_vif_id,
|
|
static_ip)
|
|
port_prefix = constants.NOVA_PORT_OWNER_PREF
|
|
if port['device_owner'].startswith(port_prefix):
|
|
#This request is coming from nova
|
|
try:
|
|
self._create_update_port(context, port,
|
|
port_mapping,
|
|
subnet_mapping)
|
|
except Exception:
|
|
with excutils.save_and_reraise_exception():
|
|
super(NuagePlugin, self).delete_port(
|
|
context,
|
|
port['id'])
|
|
return self._extend_port_dict_binding(context, port)
|
|
|
|
def update_port(self, context, id, port):
|
|
p = port['port']
|
|
if p.get('device_owner', '').startswith(
|
|
constants.NOVA_PORT_OWNER_PREF):
|
|
session = context.session
|
|
with session.begin(subtransactions=True):
|
|
port = self._get_port(context, id)
|
|
port.update(p)
|
|
if 'fixed_ips' not in port or len(port['fixed_ips']) == 0:
|
|
return self._make_port_dict(port)
|
|
subnet_id = port['fixed_ips'][0]['subnet_id']
|
|
subnet_mapping = nuagedb.get_subnet_l2dom_by_id(session,
|
|
subnet_id)
|
|
if not subnet_mapping:
|
|
msg = (_("Subnet %s not found on VSD") % subnet_id)
|
|
raise n_exc.BadRequest(resource='port', msg=msg)
|
|
port_mapping = nuagedb.get_port_mapping_by_id(session,
|
|
id)
|
|
if not port_mapping:
|
|
msg = (_("Port-Mapping for port %s not "
|
|
" found on VSD") % id)
|
|
raise n_exc.BadRequest(resource='port', msg=msg)
|
|
if not port_mapping['nuage_vport_id']:
|
|
self._create_update_port(context, port,
|
|
port_mapping, subnet_mapping)
|
|
updated_port = self._make_port_dict(port)
|
|
else:
|
|
updated_port = super(NuagePlugin, self).update_port(context, id,
|
|
port)
|
|
return updated_port
|
|
|
|
def delete_port(self, context, id, l3_port_check=True):
|
|
if l3_port_check:
|
|
self.prevent_l3_port_deletion(context, id)
|
|
port = self._get_port(context, id)
|
|
port_mapping = nuagedb.get_port_mapping_by_id(context.session,
|
|
id)
|
|
# This is required for to pass ut test_floatingip_port_delete
|
|
self.disassociate_floatingips(context, id)
|
|
if not port['fixed_ips']:
|
|
return super(NuagePlugin, self).delete_port(context, id)
|
|
|
|
sub_id = port['fixed_ips'][0]['subnet_id']
|
|
subnet_mapping = nuagedb.get_subnet_l2dom_by_id(context.session,
|
|
sub_id)
|
|
if not subnet_mapping:
|
|
return super(NuagePlugin, self).delete_port(context, id)
|
|
|
|
netpart_id = subnet_mapping['net_partition_id']
|
|
net_partition = nuagedb.get_net_partition_by_id(context.session,
|
|
netpart_id)
|
|
# Need to call this explicitly to delete vport_vporttag_mapping
|
|
if constants.NOVA_PORT_OWNER_PREF in port['device_owner']:
|
|
# This was a VM Port
|
|
filters = {'device_id': [port['device_id']]}
|
|
ports = self.get_ports(context, filters)
|
|
params = {
|
|
'no_of_ports': len(ports),
|
|
'net_partition': net_partition,
|
|
'tenant': port['tenant_id'],
|
|
'mac': port['mac_address'],
|
|
'nuage_vif_id': port_mapping['nuage_vif_id'],
|
|
'id': port['device_id']
|
|
}
|
|
self.nuageclient.delete_vms(params)
|
|
super(NuagePlugin, self).delete_port(context, id)
|
|
|
|
def _check_view_auth(self, context, resource, action):
|
|
return policy.check(context, action, resource)
|
|
|
|
def _extend_port_dict_binding(self, context, port):
|
|
if self._check_view_auth(context, port, self.binding_view):
|
|
port[portbindings.VIF_TYPE] = portbindings.VIF_TYPE_OVS
|
|
port[portbindings.VIF_DETAILS] = {
|
|
portbindings.CAP_PORT_FILTER: False
|
|
}
|
|
return port
|
|
|
|
def get_port(self, context, id, fields=None):
|
|
port = super(NuagePlugin, self).get_port(context, id, fields)
|
|
return self._fields(self._extend_port_dict_binding(context, port),
|
|
fields)
|
|
|
|
def get_ports(self, context, filters=None, fields=None):
|
|
ports = super(NuagePlugin, self).get_ports(context, filters, fields)
|
|
return [self._fields(self._extend_port_dict_binding(context, port),
|
|
fields) for port in ports]
|
|
|
|
def _check_router_subnet_for_tenant(self, context):
|
|
# Search router and subnet tables.
|
|
# If no entry left delete user and group from VSD
|
|
filters = {'tenant_id': [context.tenant]}
|
|
routers = self.get_routers(context, filters=filters)
|
|
subnets = self.get_subnets(context, filters=filters)
|
|
return bool(routers or subnets)
|
|
|
|
def create_network(self, context, network):
|
|
net = network['network']
|
|
with context.session.begin(subtransactions=True):
|
|
net = super(NuagePlugin, self).create_network(context,
|
|
network)
|
|
self._process_l3_create(context, net, network['network'])
|
|
return net
|
|
|
|
def update_network(self, context, id, network):
|
|
with context.session.begin(subtransactions=True):
|
|
net = super(NuagePlugin, self).update_network(context, id,
|
|
network)
|
|
self._process_l3_update(context, net, network['network'])
|
|
return net
|
|
|
|
def delete_network(self, context, id):
|
|
filter = {'network_id': [id]}
|
|
subnets = self.get_subnets(context, filters=filter)
|
|
for subnet in subnets:
|
|
self.delete_subnet(context, subnet['id'])
|
|
super(NuagePlugin, self).delete_network(context, id)
|
|
|
|
def _get_net_partition_for_subnet(self, context, subnet):
|
|
subn = subnet['subnet']
|
|
ent = subn.get('net_partition', None)
|
|
if not ent:
|
|
def_net_part = cfg.CONF.RESTPROXY.default_net_partition_name
|
|
net_partition = nuagedb.get_net_partition_by_name(context.session,
|
|
def_net_part)
|
|
else:
|
|
net_partition = self._resource_finder(context, 'subnet',
|
|
'net_partition', subn)
|
|
if not net_partition:
|
|
msg = _('Either net_partition is not provided with subnet OR '
|
|
'default net_partition is not created at the start')
|
|
raise n_exc.BadRequest(resource='subnet', msg=msg)
|
|
return net_partition
|
|
|
|
def _validate_create_subnet(self, subnet):
|
|
if ('host_routes' in subnet and
|
|
attributes.is_attr_set(subnet['host_routes'])):
|
|
msg = 'host_routes extensions not supported for subnets'
|
|
raise nuage_exc.OperationNotSupported(msg=msg)
|
|
if subnet['gateway_ip'] is None:
|
|
msg = "no-gateway option not supported with subnets"
|
|
raise nuage_exc.OperationNotSupported(msg=msg)
|
|
|
|
def create_subnet(self, context, subnet):
|
|
subn = subnet['subnet']
|
|
net_id = subn['network_id']
|
|
|
|
if self._network_is_external(context, net_id):
|
|
return super(NuagePlugin, self).create_subnet(context, subnet)
|
|
|
|
self._validate_create_subnet(subn)
|
|
|
|
net_partition = self._get_net_partition_for_subnet(context, subnet)
|
|
neutron_subnet = super(NuagePlugin, self).create_subnet(context,
|
|
subnet)
|
|
net = netaddr.IPNetwork(neutron_subnet['cidr'])
|
|
params = {
|
|
'net_partition': net_partition,
|
|
'tenant_id': neutron_subnet['tenant_id'],
|
|
'net': net
|
|
}
|
|
try:
|
|
nuage_subnet = self.nuageclient.create_subnet(neutron_subnet,
|
|
params)
|
|
except Exception:
|
|
with excutils.save_and_reraise_exception():
|
|
super(NuagePlugin, self).delete_subnet(context,
|
|
neutron_subnet['id'])
|
|
|
|
if nuage_subnet:
|
|
l2dom_id = str(nuage_subnet['nuage_l2template_id'])
|
|
user_id = nuage_subnet['nuage_userid']
|
|
group_id = nuage_subnet['nuage_groupid']
|
|
id = nuage_subnet['nuage_l2domain_id']
|
|
session = context.session
|
|
with session.begin(subtransactions=True):
|
|
nuagedb.add_subnetl2dom_mapping(session,
|
|
neutron_subnet['id'],
|
|
id,
|
|
net_partition['id'],
|
|
l2dom_id=l2dom_id,
|
|
nuage_user_id=user_id,
|
|
nuage_group_id=group_id)
|
|
return neutron_subnet
|
|
|
|
def delete_subnet(self, context, id):
|
|
subnet = self.get_subnet(context, id)
|
|
if self._network_is_external(context, subnet['network_id']):
|
|
return super(NuagePlugin, self).delete_subnet(context, id)
|
|
|
|
subnet_l2dom = nuagedb.get_subnet_l2dom_by_id(context.session, id)
|
|
if subnet_l2dom:
|
|
template_id = subnet_l2dom['nuage_l2dom_tmplt_id']
|
|
try:
|
|
self.nuageclient.delete_subnet(subnet_l2dom['nuage_subnet_id'],
|
|
template_id)
|
|
except Exception:
|
|
msg = (_('Unable to complete operation on subnet %s.'
|
|
'One or more ports have an IP allocation '
|
|
'from this subnet.') % id)
|
|
raise n_exc.BadRequest(resource='subnet', msg=msg)
|
|
super(NuagePlugin, self).delete_subnet(context, id)
|
|
if subnet_l2dom and not self._check_router_subnet_for_tenant(context):
|
|
self.nuageclient.delete_user(subnet_l2dom['nuage_user_id'])
|
|
self.nuageclient.delete_group(subnet_l2dom['nuage_group_id'])
|
|
|
|
def add_router_interface(self, context, router_id, interface_info):
|
|
session = context.session
|
|
with session.begin(subtransactions=True):
|
|
rtr_if_info = super(NuagePlugin,
|
|
self).add_router_interface(context,
|
|
router_id,
|
|
interface_info)
|
|
subnet_id = rtr_if_info['subnet_id']
|
|
subn = self.get_subnet(context, subnet_id)
|
|
|
|
rtr_zone_mapping = nuagedb.get_rtr_zone_mapping(session,
|
|
router_id)
|
|
ent_rtr_mapping = nuagedb.get_ent_rtr_mapping_by_rtrid(session,
|
|
router_id)
|
|
subnet_l2dom = nuagedb.get_subnet_l2dom_by_id(session,
|
|
subnet_id)
|
|
if not rtr_zone_mapping or not ent_rtr_mapping:
|
|
super(NuagePlugin,
|
|
self).remove_router_interface(context,
|
|
router_id,
|
|
interface_info)
|
|
msg = (_("Router %s does not hold default zone OR "
|
|
"net_partition mapping. Router-IF add failed")
|
|
% router_id)
|
|
raise n_exc.BadRequest(resource='router', msg=msg)
|
|
|
|
if not subnet_l2dom:
|
|
super(NuagePlugin,
|
|
self).remove_router_interface(context,
|
|
router_id,
|
|
interface_info)
|
|
msg = (_("Subnet %s does not hold Nuage VSD reference. "
|
|
"Router-IF add failed") % subnet_id)
|
|
raise n_exc.BadRequest(resource='subnet', msg=msg)
|
|
|
|
if (subnet_l2dom['net_partition_id'] !=
|
|
ent_rtr_mapping['net_partition_id']):
|
|
super(NuagePlugin,
|
|
self).remove_router_interface(context,
|
|
router_id,
|
|
interface_info)
|
|
msg = (_("Subnet %(subnet)s and Router %(router)s belong to "
|
|
"different net_partition Router-IF add "
|
|
"not permitted") % {'subnet': subnet_id,
|
|
'router': router_id})
|
|
raise n_exc.BadRequest(resource='subnet', msg=msg)
|
|
nuage_subnet_id = subnet_l2dom['nuage_subnet_id']
|
|
nuage_l2dom_tmplt_id = subnet_l2dom['nuage_l2dom_tmplt_id']
|
|
if self.nuageclient.vms_on_l2domain(nuage_subnet_id):
|
|
super(NuagePlugin,
|
|
self).remove_router_interface(context,
|
|
router_id,
|
|
interface_info)
|
|
msg = (_("Subnet %s has one or more active VMs "
|
|
"Router-IF add not permitted") % subnet_id)
|
|
raise n_exc.BadRequest(resource='subnet', msg=msg)
|
|
self.nuageclient.delete_subnet(nuage_subnet_id,
|
|
nuage_l2dom_tmplt_id)
|
|
net = netaddr.IPNetwork(subn['cidr'])
|
|
params = {
|
|
'net': net,
|
|
'zone_id': rtr_zone_mapping['nuage_zone_id']
|
|
}
|
|
if not attributes.is_attr_set(subn['gateway_ip']):
|
|
subn['gateway_ip'] = str(netaddr.IPAddress(net.first + 1))
|
|
try:
|
|
nuage_subnet = self.nuageclient.create_domain_subnet(subn,
|
|
params)
|
|
except Exception:
|
|
with excutils.save_and_reraise_exception():
|
|
super(NuagePlugin,
|
|
self).remove_router_interface(context,
|
|
router_id,
|
|
interface_info)
|
|
if nuage_subnet:
|
|
ns_dict = {}
|
|
ns_dict['nuage_subnet_id'] = nuage_subnet['nuage_subnetid']
|
|
ns_dict['nuage_l2dom_tmplt_id'] = None
|
|
nuagedb.update_subnetl2dom_mapping(subnet_l2dom,
|
|
ns_dict)
|
|
return rtr_if_info
|
|
|
|
def remove_router_interface(self, context, router_id, interface_info):
|
|
if 'subnet_id' in interface_info:
|
|
subnet_id = interface_info['subnet_id']
|
|
subnet = self.get_subnet(context, subnet_id)
|
|
found = False
|
|
try:
|
|
filters = {'device_id': [router_id],
|
|
'device_owner':
|
|
[os_constants.DEVICE_OWNER_ROUTER_INTF],
|
|
'network_id': [subnet['network_id']]}
|
|
ports = self.get_ports(context, filters)
|
|
|
|
for p in ports:
|
|
if p['fixed_ips'][0]['subnet_id'] == subnet_id:
|
|
found = True
|
|
break
|
|
except exc.NoResultFound:
|
|
msg = (_("No router interface found for Router %s. "
|
|
"Router-IF delete failed") % router_id)
|
|
raise n_exc.BadRequest(resource='router', msg=msg)
|
|
|
|
if not found:
|
|
msg = (_("No router interface found for Router %s. "
|
|
"Router-IF delete failed") % router_id)
|
|
raise n_exc.BadRequest(resource='router', msg=msg)
|
|
elif 'port_id' in interface_info:
|
|
port_db = self._get_port(context, interface_info['port_id'])
|
|
if not port_db:
|
|
msg = (_("No router interface found for Router %s. "
|
|
"Router-IF delete failed") % router_id)
|
|
raise n_exc.BadRequest(resource='router', msg=msg)
|
|
subnet_id = port_db['fixed_ips'][0]['subnet_id']
|
|
|
|
session = context.session
|
|
with session.begin(subtransactions=True):
|
|
subnet_l2dom = nuagedb.get_subnet_l2dom_by_id(session,
|
|
subnet_id)
|
|
nuage_subn_id = subnet_l2dom['nuage_subnet_id']
|
|
if self.nuageclient.vms_on_l2domain(nuage_subn_id):
|
|
msg = (_("Subnet %s has one or more active VMs "
|
|
"Router-IF delete not permitted") % subnet_id)
|
|
raise n_exc.BadRequest(resource='subnet', msg=msg)
|
|
|
|
neutron_subnet = self.get_subnet(context, subnet_id)
|
|
ent_rtr_mapping = nuagedb.get_ent_rtr_mapping_by_rtrid(
|
|
context.session,
|
|
router_id)
|
|
if not ent_rtr_mapping:
|
|
msg = (_("Router %s does not hold net_partition "
|
|
"assoc on Nuage VSD. Router-IF delete failed")
|
|
% router_id)
|
|
raise n_exc.BadRequest(resource='router', msg=msg)
|
|
net = netaddr.IPNetwork(neutron_subnet['cidr'])
|
|
net_part_id = ent_rtr_mapping['net_partition_id']
|
|
net_partition = self.get_net_partition(context,
|
|
net_part_id)
|
|
params = {
|
|
'net_partition': net_partition,
|
|
'tenant_id': neutron_subnet['tenant_id'],
|
|
'net': net
|
|
}
|
|
nuage_subnet = self.nuageclient.create_subnet(neutron_subnet,
|
|
params)
|
|
self.nuageclient.delete_domain_subnet(nuage_subn_id)
|
|
info = super(NuagePlugin,
|
|
self).remove_router_interface(context, router_id,
|
|
interface_info)
|
|
if nuage_subnet:
|
|
tmplt_id = str(nuage_subnet['nuage_l2template_id'])
|
|
ns_dict = {}
|
|
ns_dict['nuage_subnet_id'] = nuage_subnet['nuage_l2domain_id']
|
|
ns_dict['nuage_l2dom_tmplt_id'] = tmplt_id
|
|
nuagedb.update_subnetl2dom_mapping(subnet_l2dom,
|
|
ns_dict)
|
|
return info
|
|
|
|
def _get_net_partition_for_router(self, context, router):
|
|
rtr = router['router']
|
|
ent = rtr.get('net_partition', None)
|
|
if not ent:
|
|
def_net_part = cfg.CONF.RESTPROXY.default_net_partition_name
|
|
net_partition = nuagedb.get_net_partition_by_name(context.session,
|
|
def_net_part)
|
|
else:
|
|
net_partition = self._resource_finder(context, 'router',
|
|
'net_partition', rtr)
|
|
if not net_partition:
|
|
msg = _("Either net_partition is not provided with router OR "
|
|
"default net_partition is not created at the start")
|
|
raise n_exc.BadRequest(resource='router', msg=msg)
|
|
return net_partition
|
|
|
|
def create_router(self, context, router):
|
|
net_partition = self._get_net_partition_for_router(context, router)
|
|
neutron_router = super(NuagePlugin, self).create_router(context,
|
|
router)
|
|
params = {
|
|
'net_partition': net_partition,
|
|
'tenant_id': neutron_router['tenant_id']
|
|
}
|
|
try:
|
|
nuage_router = self.nuageclient.create_router(neutron_router,
|
|
router['router'],
|
|
params)
|
|
except Exception:
|
|
with excutils.save_and_reraise_exception():
|
|
super(NuagePlugin, self).delete_router(context,
|
|
neutron_router['id'])
|
|
if nuage_router:
|
|
user_id = nuage_router['nuage_userid']
|
|
group_id = nuage_router['nuage_groupid']
|
|
with context.session.begin(subtransactions=True):
|
|
nuagedb.add_entrouter_mapping(context.session,
|
|
net_partition['id'],
|
|
neutron_router['id'],
|
|
nuage_router['nuage_domain_id'])
|
|
nuagedb.add_rtrzone_mapping(context.session,
|
|
neutron_router['id'],
|
|
nuage_router['nuage_def_zone_id'],
|
|
nuage_user_id=user_id,
|
|
nuage_group_id=group_id)
|
|
return neutron_router
|
|
|
|
def delete_router(self, context, id):
|
|
session = context.session
|
|
ent_rtr_mapping = nuagedb.get_ent_rtr_mapping_by_rtrid(session,
|
|
id)
|
|
if ent_rtr_mapping:
|
|
filters = {
|
|
'device_id': [id],
|
|
'device_owner': [os_constants.DEVICE_OWNER_ROUTER_INTF]
|
|
}
|
|
ports = self.get_ports(context, filters)
|
|
if ports:
|
|
raise l3.RouterInUse(router_id=id)
|
|
nuage_router_id = ent_rtr_mapping['nuage_router_id']
|
|
self.nuageclient.delete_router(nuage_router_id)
|
|
router_zone = nuagedb.get_rtr_zone_mapping(session, id)
|
|
super(NuagePlugin, self).delete_router(context, id)
|
|
if router_zone and not self._check_router_subnet_for_tenant(context):
|
|
self.nuageclient.delete_user(router_zone['nuage_user_id'])
|
|
self.nuageclient.delete_group(router_zone['nuage_group_id'])
|
|
|
|
def _make_net_partition_dict(self, net_partition, fields=None):
|
|
res = {
|
|
'id': net_partition['id'],
|
|
'name': net_partition['name'],
|
|
'l3dom_tmplt_id': net_partition['l3dom_tmplt_id'],
|
|
'l2dom_tmplt_id': net_partition['l2dom_tmplt_id'],
|
|
}
|
|
return self._fields(res, fields)
|
|
|
|
def _create_net_partition(self, session, net_part_name):
|
|
fip_quota = cfg.CONF.RESTPROXY.default_floatingip_quota
|
|
params = {
|
|
"name": net_part_name,
|
|
"fp_quota": str(fip_quota)
|
|
}
|
|
nuage_net_partition = self.nuageclient.create_net_partition(params)
|
|
net_partitioninst = None
|
|
if nuage_net_partition:
|
|
nuage_entid = nuage_net_partition['nuage_entid']
|
|
l3dom_id = nuage_net_partition['l3dom_id']
|
|
l2dom_id = nuage_net_partition['l2dom_id']
|
|
with session.begin():
|
|
net_partitioninst = nuagedb.add_net_partition(session,
|
|
nuage_entid,
|
|
l3dom_id,
|
|
l2dom_id,
|
|
net_part_name)
|
|
if not net_partitioninst:
|
|
return {}
|
|
return self._make_net_partition_dict(net_partitioninst)
|
|
|
|
def _create_default_net_partition(self, default_net_part):
|
|
self.nuageclient.check_del_def_net_partition(default_net_part)
|
|
session = db.get_session()
|
|
net_partition = nuagedb.get_net_partition_by_name(session,
|
|
default_net_part)
|
|
if net_partition:
|
|
with session.begin(subtransactions=True):
|
|
nuagedb.delete_net_partition(session, net_partition)
|
|
|
|
self._create_net_partition(session, default_net_part)
|
|
|
|
def create_net_partition(self, context, net_partition):
|
|
ent = net_partition['net_partition']
|
|
session = context.session
|
|
return self._create_net_partition(session, ent["name"])
|
|
|
|
def delete_net_partition(self, context, id):
|
|
ent_rtr_mapping = nuagedb.get_ent_rtr_mapping_by_entid(
|
|
context.session,
|
|
id)
|
|
if ent_rtr_mapping:
|
|
msg = (_("One or more router still attached to "
|
|
"net_partition %s.") % id)
|
|
raise n_exc.BadRequest(resource='net_partition', msg=msg)
|
|
net_partition = nuagedb.get_net_partition_by_id(context.session, id)
|
|
if not net_partition:
|
|
msg = (_("NetPartition with %s does not exist") % id)
|
|
raise n_exc.BadRequest(resource='net_partition', msg=msg)
|
|
l3dom_tmplt_id = net_partition['l3dom_tmplt_id']
|
|
l2dom_tmplt_id = net_partition['l2dom_tmplt_id']
|
|
self.nuageclient.delete_net_partition(net_partition['id'],
|
|
l3dom_id=l3dom_tmplt_id,
|
|
l2dom_id=l2dom_tmplt_id)
|
|
with context.session.begin(subtransactions=True):
|
|
nuagedb.delete_net_partition(context.session,
|
|
net_partition)
|
|
|
|
def get_net_partition(self, context, id, fields=None):
|
|
net_partition = nuagedb.get_net_partition_by_id(context.session,
|
|
id)
|
|
return self._make_net_partition_dict(net_partition)
|
|
|
|
def get_net_partitions(self, context, filters=None, fields=None):
|
|
net_partitions = nuagedb.get_net_partitions(context.session,
|
|
filters=filters,
|
|
fields=fields)
|
|
return [self._make_net_partition_dict(net_partition, fields)
|
|
for net_partition in net_partitions]
|