12
12
# License for the specific language governing permissions and limitations
13
13
# under the License.
19
from oslo.config import cfg
20
from oslo.utils import excutils
21
from oslo.utils import importutils
22
from oslo_concurrency import lockutils
23
from sqlalchemy.orm import exc
25
from neutron.api import extensions as neutron_extensions
26
from neutron.api.v2 import attributes
27
from neutron.common import constants as os_constants
28
from neutron.common import exceptions as n_exc
29
from neutron.common import utils
30
from neutron.db import api as db
31
from neutron.db import db_base_plugin_v2
32
from neutron.db import external_net_db
33
from neutron.db import extraroute_db
34
from neutron.db import l3_db
35
from neutron.db import quota_db # noqa
36
from neutron.db import securitygroups_db as sg_db
37
from neutron.extensions import external_net
38
from neutron.extensions import l3
39
from neutron.extensions import portbindings
40
from neutron.extensions import providernet as pnet
41
from neutron.extensions import securitygroup as ext_sg
42
from neutron.openstack.common import log as logging
43
from neutron.openstack.common import loopingcall
44
from neutron.plugins.nuage.common import config
45
from neutron.plugins.nuage.common import constants
46
from neutron.plugins.nuage.common import exceptions as nuage_exc
47
from neutron.plugins.nuage import extensions
48
from neutron.plugins.nuage.extensions import netpartition
49
from neutron.plugins.nuage import nuagedb
50
from neutron.plugins.nuage import syncmanager
51
from neutron import policy
53
LOG = logging.getLogger(__name__)
56
class NuagePlugin(db_base_plugin_v2.NeutronDbPluginV2,
57
external_net_db.External_net_db_mixin,
58
extraroute_db.ExtraRoute_db_mixin,
59
l3_db.L3_NAT_db_mixin,
60
netpartition.NetPartitionPluginBase,
61
sg_db.SecurityGroupDbMixin):
62
"""Class that implements Nuage Networks' plugin functionality."""
15
from nuage_neutron.plugins.nuage import plugin
18
class NuagePlugin(plugin.NuagePlugin):
20
vendor_extensions = plugin.NuagePlugin.vendor_extensions
63
21
supported_extension_aliases = ["router", "binding", "external-net",
64
"net-partition", "nuage-router",
65
"nuage-subnet", "quotas", "provider",
66
"extraroute", "security-group"]
68
binding_view = "extension:port_binding:view"
22
"quotas", "provider", "extraroute",
23
"security-group"] + vendor_extensions
70
25
def __init__(self):
71
26
super(NuagePlugin, self).__init__()
72
neutron_extensions.append_api_extensions_path(extensions.__path__)
73
config.nuage_register_cfg_opts()
74
self.nuageclient_init()
75
net_partition = cfg.CONF.RESTPROXY.default_net_partition_name
76
self._create_default_net_partition(net_partition)
77
if cfg.CONF.SYNCMANAGER.enable_sync:
78
self.syncmanager = syncmanager.SyncManager(self.nuageclient)
79
self._synchronization_thread()
81
db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(
82
attributes.NETWORKS, ['_extend_network_dict_provider_nuage'])
84
def nuageclient_init(self):
85
server = cfg.CONF.RESTPROXY.server
86
serverauth = cfg.CONF.RESTPROXY.serverauth
87
serverssl = cfg.CONF.RESTPROXY.serverssl
88
base_uri = cfg.CONF.RESTPROXY.base_uri
89
auth_resource = cfg.CONF.RESTPROXY.auth_resource
90
organization = cfg.CONF.RESTPROXY.organization
91
nuageclient = importutils.import_module('nuagenetlib.nuageclient')
92
self.nuageclient = nuageclient.NuageClient(server, base_uri,
93
serverssl, serverauth,
97
def _synchronization_thread(self):
98
sync_interval = cfg.CONF.SYNCMANAGER.sync_interval
99
fip_quota = str(cfg.CONF.RESTPROXY.default_floatingip_quota)
100
if sync_interval > 0:
101
sync_loop = loopingcall.FixedIntervalLoopingCall(
102
self.syncmanager.synchronize, fip_quota)
103
sync_loop.start(interval=sync_interval)
105
self.syncmanager.synchronize(fip_quota)
107
def _resource_finder(self, context, for_resource, resource, user_req):
108
match = re.match(attributes.UUID_PATTERN, user_req[resource])
110
obj_lister = getattr(self, "get_%s" % resource)
111
found_resource = obj_lister(context, user_req[resource])
112
if not found_resource:
113
msg = (_("%(resource)s with id %(resource_id)s does not "
114
"exist") % {'resource': resource,
115
'resource_id': user_req[resource]})
116
raise n_exc.BadRequest(resource=for_resource, msg=msg)
118
filter = {'name': [user_req[resource]]}
119
obj_lister = getattr(self, "get_%ss" % resource)
120
found_resource = obj_lister(context, filters=filter)
121
if not found_resource:
122
msg = (_("Either %(resource)s %(req_resource)s not found "
123
"or you dont have credential to access it")
124
% {'resource': resource,
125
'req_resource': user_req[resource]})
126
raise n_exc.BadRequest(resource=for_resource, msg=msg)
127
if len(found_resource) > 1:
128
msg = (_("More than one entry found for %(resource)s "
129
"%(req_resource)s. Use id instead")
130
% {'resource': resource,
131
'req_resource': user_req[resource]})
132
raise n_exc.BadRequest(resource=for_resource, msg=msg)
133
found_resource = found_resource[0]
134
return found_resource
136
def _create_update_port(self, context, port, np_name):
137
filters = {'device_id': [port['device_id']]}
138
ports = self.get_ports(context, filters)
140
'port_id': port['id'],
141
'id': port['device_id'],
142
'mac': port['mac_address'],
143
'netpart_name': np_name,
144
'ip': port['fixed_ips'][0]['ip_address'],
145
'no_of_ports': len(ports),
146
'tenant': port['tenant_id'],
147
'neutron_id': port['fixed_ips'][0]['subnet_id']
149
self.nuageclient.create_vms(params)
151
def _get_router_by_subnet(self, context, subnet_id):
153
'fixed_ips': {'subnet_id': [subnet_id]},
154
'device_owner': [os_constants.DEVICE_OWNER_ROUTER_INTF]
156
router_port = self.get_ports(context, filters=filters)
158
msg = (_("Router for subnet %s not found ") % subnet_id)
159
raise n_exc.BadRequest(resource='port', msg=msg)
160
return router_port[0]['device_id']
162
def _process_port_create_security_group(self, context, port,
164
if not attributes.is_attr_set(sec_group):
165
port[ext_sg.SECURITYGROUPS] = []
168
with context.session.begin(subtransactions=True):
169
for sg_id in sec_group:
171
self)._create_port_security_group_binding(context,
175
vptag_vport_list = []
176
for sg_id in sec_group:
178
'neutron_port_id': port_id
180
nuage_port = self.nuageclient.get_nuage_port_by_id(params)
181
if nuage_port and nuage_port.get('nuage_vport_id'):
182
nuage_vport_id = nuage_port['nuage_vport_id']
183
sg = self._get_security_group(context, sg_id)
184
sg_rules = self.get_security_group_rules(
186
{'security_group_id': [sg_id]})
188
'nuage_port': nuage_port,
193
self.nuageclient.process_port_create_security_group(
196
'nuage_vporttag_id': nuage_vptag_id
198
vptag_vport_list.append(vptag_vport)
202
'vptag_vport_list': vptag_vport_list,
203
'nuage_vport_id': nuage_vport_id
205
self.nuageclient.update_nuage_vport(params)
207
with excutils.save_and_reraise_exception():
208
for sg_id in sec_group:
210
self)._delete_port_security_group_bindings(context,
212
# Convert to list as a set might be passed here and
213
# this has to be serialized
214
port[ext_sg.SECURITYGROUPS] = (list(sec_group) if sec_group else [])
216
def _delete_port_security_group_bindings(self, context, port_id):
218
self)._delete_port_security_group_bindings(context, port_id)
219
self.nuageclient.delete_port_security_group_bindings(port_id)
221
@lockutils.synchronized('create_port', 'nuage-port', external=True)
222
def create_port(self, context, port):
223
session = context.session
224
with session.begin(subtransactions=True):
226
self._ensure_default_security_group_on_port(context, port)
227
port = super(NuagePlugin, self).create_port(context, port)
228
device_owner = port.get('device_owner', None)
229
if device_owner not in constants.AUTO_CREATE_PORT_OWNERS:
230
if 'fixed_ips' not in port or len(port['fixed_ips']) == 0:
231
return self._extend_port_dict_binding(context, port)
232
subnet_id = port['fixed_ips'][0]['subnet_id']
233
subnet_mapping = nuagedb.get_subnet_l2dom_by_id(session,
236
port_prefix = constants.NOVA_PORT_OWNER_PREF
237
if port['device_owner'].startswith(port_prefix):
238
#This request is coming from nova
240
net_partition = nuagedb.get_net_partition_by_id(
242
subnet_mapping['net_partition_id'])
243
self._create_update_port(
246
net_partition['name'])
248
with excutils.save_and_reraise_exception():
249
super(NuagePlugin, self).delete_port(
252
if ext_sg.SECURITYGROUPS in p:
253
self._process_port_create_security_group(
256
p[ext_sg.SECURITYGROUPS])
257
return self._extend_port_dict_binding(context, port)
259
def update_port(self, context, id, port):
262
if p.get('device_owner', '').startswith(
263
constants.NOVA_PORT_OWNER_PREF):
264
session = context.session
265
with session.begin(subtransactions=True):
266
port = self._get_port(context, id)
268
if not port.get('fixed_ips'):
269
return self._make_port_dict(port)
270
subnet_id = port['fixed_ips'][0]['subnet_id']
272
subnet_mapping = nuagedb.get_subnet_l2dom_by_id(session,
274
if not subnet_mapping:
275
msg = (_("Subnet %s not found on VSD") % subnet_id)
276
raise n_exc.BadRequest(resource='port', msg=msg)
279
'neutron_port_id': id,
281
nuage_port = self.nuageclient.get_nuage_port_by_id(params)
282
if not nuage_port or not nuage_port.get('nuage_vport_id'):
283
net_partition = nuagedb.get_net_partition_by_id(
284
session, subnet_mapping['net_partition_id'])
285
self._create_update_port(context, port,
286
net_partition['name'])
287
self._check_floatingip_update(context, port)
288
updated_port = self._make_port_dict(port)
289
sg_port = self._extend_port_dict_security_group(
293
sg_groups = sg_port[ext_sg.SECURITYGROUPS]
295
updated_port = super(NuagePlugin, self).update_port(context, id,
297
if not updated_port.get('fixed_ips'):
299
subnet_id = updated_port['fixed_ips'][0]['subnet_id']
300
subnet_mapping = nuagedb.get_subnet_l2dom_by_id(context.session,
304
self._delete_port_security_group_bindings(context,
306
self._process_port_create_security_group(context,
309
elif ext_sg.SECURITYGROUPS in p:
310
self._delete_port_security_group_bindings(context,
312
self._process_port_create_security_group(
315
p[ext_sg.SECURITYGROUPS]
319
def _delete_nuage_vport(self, context, port, np_name):
322
'neutron_port_id': port['id'],
324
nuage_port = self.nuageclient.get_nuage_port_by_id(params)
326
if constants.NOVA_PORT_OWNER_PREF in port['device_owner']:
329
nuage_vif_id = nuage_port['nuage_vif_id']
330
filters = {'device_id': [port['device_id']]}
331
ports = self.get_ports(context, filters)
333
'no_of_ports': len(ports),
334
'netpart_name': np_name,
335
'tenant': port['tenant_id'],
336
'mac': port['mac_address'],
337
'nuage_vif_id': nuage_vif_id,
338
'id': port['device_id']
340
self.nuageclient.delete_vms(params)
342
@lockutils.synchronized('delete-port', 'nuage-del', external=True)
343
def delete_port(self, context, id, l3_port_check=True):
345
self.prevent_l3_port_deletion(context, id)
346
port = self._get_port(context, id)
347
# This is required for to pass ut test_floatingip_port_delete
348
self.disassociate_floatingips(context, id)
349
if not port['fixed_ips']:
350
return super(NuagePlugin, self).delete_port(context, id)
352
sub_id = port['fixed_ips'][0]['subnet_id']
354
subnet_mapping = nuagedb.get_subnet_l2dom_by_id(context.session,
356
if not subnet_mapping:
357
return super(NuagePlugin, self).delete_port(context, id)
359
# Need to call this explicitly to delete vport to vporttag binding
360
if ext_sg.SECURITYGROUPS in port:
361
self.nuageclient.delete_port_security_group_bindings(id)
363
netpart_id = subnet_mapping['net_partition_id']
364
net_partition = nuagedb.get_net_partition_by_id(context.session,
366
self._delete_nuage_vport(context, port, net_partition['name'])
367
super(NuagePlugin, self).delete_port(context, id)
369
def _check_view_auth(self, context, resource, action):
370
return policy.check(context, action, resource)
372
def _extend_port_dict_binding(self, context, port):
373
if self._check_view_auth(context, port, self.binding_view):
374
port[portbindings.VIF_TYPE] = portbindings.VIF_TYPE_OVS
375
port[portbindings.VIF_DETAILS] = {
376
portbindings.CAP_PORT_FILTER: False
380
def get_port(self, context, id, fields=None):
381
port = super(NuagePlugin, self).get_port(context, id, fields)
382
return self._fields(self._extend_port_dict_binding(context, port),
385
def get_ports(self, context, filters=None, fields=None):
386
ports = super(NuagePlugin, self).get_ports(context, filters, fields)
387
return [self._fields(self._extend_port_dict_binding(context, port),
388
fields) for port in ports]
390
def _check_router_subnet_for_tenant(self, context, tenant_id):
391
# Search router and subnet tables.
392
# If no entry left delete user and group from VSD
393
filters = {'tenant_id': [tenant_id]}
394
routers = self.get_routers(context, filters=filters)
395
subnets = self.get_subnets(context, filters=filters)
396
return bool(routers or subnets)
398
def _extend_network_dict_provider_nuage(self, network, net_db,
400
binding = net_db.pnetbinding if net_db else net_binding
402
network[pnet.NETWORK_TYPE] = binding.network_type
403
network[pnet.PHYSICAL_NETWORK] = binding.physical_network
404
network[pnet.SEGMENTATION_ID] = binding.vlan_id
406
def _process_provider_create(self, context, attrs):
407
network_type = attrs.get(pnet.NETWORK_TYPE)
408
physical_network = attrs.get(pnet.PHYSICAL_NETWORK)
409
segmentation_id = attrs.get(pnet.SEGMENTATION_ID)
411
network_type_set = attributes.is_attr_set(network_type)
412
physical_network_set = attributes.is_attr_set(physical_network)
413
segmentation_id_set = attributes.is_attr_set(segmentation_id)
415
if not (network_type_set or physical_network_set or
416
segmentation_id_set):
417
return None, None, None
418
if not network_type_set:
419
msg = _("provider:network_type required")
420
raise n_exc.InvalidInput(error_message=msg)
421
elif network_type != 'vlan':
422
msg = (_("provider:network_type %s not supported in VSP")
424
raise nuage_exc.NuageBadRequest(msg=msg)
425
if not physical_network_set:
426
msg = _("provider:physical_network required")
427
raise nuage_exc.NuageBadRequest(msg=msg)
428
if not segmentation_id_set:
429
msg = _("provider:segmentation_id required")
430
raise nuage_exc.NuageBadRequest(msg=msg)
432
self.nuageclient.validate_provider_network(network_type,
436
return network_type, physical_network, segmentation_id
438
def create_network(self, context, network):
440
(network_type, physical_network,
441
vlan_id) = self._process_provider_create(context,
443
with context.session.begin(subtransactions=True):
444
self._ensure_default_security_group(
446
network['network']['tenant_id']
448
net = super(NuagePlugin, self).create_network(context,
450
self._process_l3_create(context, net, network['network'])
451
if network_type == 'vlan':
452
binding = nuagedb.add_network_binding(context.session,
455
physical_network, vlan_id)
456
self._extend_network_dict_provider_nuage(net, None, binding)
459
def _validate_update_network(self, context, id, network):
460
req_data = network['network']
461
is_external_set = req_data.get(external_net.EXTERNAL)
462
if not attributes.is_attr_set(is_external_set):
464
neutron_net = self.get_network(context, id)
465
if neutron_net.get(external_net.EXTERNAL) == is_external_set:
467
subnet = self._validate_nuage_sharedresource(context, 'network', id)
468
if subnet and not is_external_set:
469
msg = _('External network with subnets can not be '
470
'changed to non-external network')
471
raise nuage_exc.OperationNotSupported(msg=msg)
473
# Check if there are vm ports attached to this network
474
# If there are, then updating the network is not allowed
475
ports = self.get_ports(context, filters={'network_id': [id]})
477
if p['device_owner'].startswith(
478
constants.NOVA_PORT_OWNER_PREF):
479
raise n_exc.NetworkInUse(net_id=id)
480
return (is_external_set, subnet)
482
def update_network(self, context, id, network):
483
pnet._raise_if_updates_provider_attributes(network['network'])
484
with context.session.begin(subtransactions=True):
485
is_external_set, subnet = self._validate_update_network(context,
488
net = super(NuagePlugin, self).update_network(context, id,
490
self._process_l3_update(context, net, network['network'])
491
if subnet and is_external_set:
493
subnet_l2dom = nuagedb.get_subnet_l2dom_by_id(context.session,
496
user_id = subnet_l2dom['nuage_user_id']
497
group_id = subnet_l2dom['nuage_group_id']
498
self.nuageclient.delete_subnet(subn['id'])
499
nuagedb.delete_subnetl2dom_mapping(context.session,
501
if not self._check_router_subnet_for_tenant(
502
context, subn['tenant_id']):
503
self.nuageclient.delete_user(user_id)
504
self.nuageclient.delete_group(group_id)
506
self._add_nuage_sharedresource(subnet[0],
508
constants.SR_TYPE_FLOATING)
511
def delete_network(self, context, id):
512
with context.session.begin(subtransactions=True):
513
self._process_l3_delete(context, id)
514
filter = {'network_id': [id]}
515
subnets = self.get_subnets(context, filters=filter)
516
for subnet in subnets:
517
self.delete_subnet(context, subnet['id'])
518
super(NuagePlugin, self).delete_network(context, id)
520
def _get_net_partition_for_subnet(self, context, subnet):
521
ent = subnet.get('net_partition', None)
523
def_net_part = cfg.CONF.RESTPROXY.default_net_partition_name
524
net_partition = nuagedb.get_net_partition_by_name(context.session,
527
net_partition = self._resource_finder(context, 'subnet',
528
'net_partition', subnet)
529
if not net_partition:
530
msg = _('Either net_partition is not provided with subnet OR '
531
'default net_partition is not created at the start')
532
raise n_exc.BadRequest(resource='subnet', msg=msg)
536
def _validate_create_subnet(subnet):
537
if (attributes.is_attr_set(subnet['gateway_ip'])
538
and netaddr.IPAddress(subnet['gateway_ip'])
539
not in netaddr.IPNetwork(subnet['cidr'])):
540
msg = "Gateway IP outside of the subnet CIDR "
541
raise nuage_exc.NuageBadRequest(msg=msg)
543
def _validate_create_provider_subnet(self, context, net_id):
544
net_filter = {'network_id': [net_id]}
545
existing_subn = self.get_subnets(context, filters=net_filter)
546
if len(existing_subn) > 0:
547
msg = _('Only one subnet is allowed per '
548
'Provider network %s') % net_id
549
raise nuage_exc.OperationNotSupported(msg=msg)
551
def _delete_nuage_sharedresource(self, net_id):
552
self.nuageclient.delete_nuage_sharedresource(net_id)
554
def _validate_nuage_sharedresource(self, context, resource, net_id):
555
filter = {'network_id': [net_id]}
556
existing_subn = self.get_subnets(context, filters=filter)
557
if len(existing_subn) > 1:
558
msg = _('Only one subnet is allowed per '
559
'external network %s') % net_id
560
raise nuage_exc.OperationNotSupported(msg=msg)
563
def _add_nuage_sharedresource(self, subnet, net_id, type):
564
net = netaddr.IPNetwork(subnet['cidr'])
566
'neutron_subnet': subnet,
571
self.nuageclient.create_nuage_sharedresource(params)
573
def _create_nuage_sharedresource(self, context, subnet, type):
574
subn = subnet['subnet']
575
net_id = subn['network_id']
576
self._validate_nuage_sharedresource(context, 'subnet', net_id)
577
with context.session.begin(subtransactions=True):
578
subn = super(NuagePlugin, self).create_subnet(context, subnet)
579
self._add_nuage_sharedresource(subn, net_id, type)
582
def _create_port_gateway(self, context, subnet, gw_ip=None):
583
if gw_ip is not None:
584
fixed_ip = [{'ip_address': gw_ip, 'subnet_id': subnet['id']}]
586
fixed_ip = [{'subnet_id': subnet['id']}]
588
port_dict = dict(port=dict(
592
network_id=subnet['network_id'],
593
tenant_id=subnet['tenant_id'],
595
mac_address=attributes.ATTR_NOT_SPECIFIED,
596
device_owner=os_constants.DEVICE_OWNER_DHCP))
597
port = super(NuagePlugin, self).create_port(context, port_dict)
600
def _delete_port_gateway(self, context, ports):
602
super(NuagePlugin, self).delete_port(context, port['id'])
604
def _create_nuage_subnet(self, context, neutron_subnet, netpart_id,
605
l2dom_template_id, pnet_binding):
606
net = netaddr.IPNetwork(neutron_subnet['cidr'])
607
# list(net)[-1] is the broadcast
608
last_address = neutron_subnet['allocation_pools'][-1]['end']
609
gw_port = self._create_port_gateway(context, neutron_subnet,
612
'netpart_id': netpart_id,
613
'tenant_id': neutron_subnet['tenant_id'],
615
'l2dom_tmplt_id': l2dom_template_id,
616
'pnet_binding': pnet_binding,
617
'dhcp_ip': gw_port['fixed_ips'][0]['ip_address']
620
nuage_subnet = self.nuageclient.create_subnet(neutron_subnet,
623
with excutils.save_and_reraise_exception():
624
self._delete_port_gateway(context, [gw_port])
625
super(NuagePlugin, self).delete_subnet(context,
626
neutron_subnet['id'])
629
l2dom_id = str(nuage_subnet['nuage_l2template_id'])
630
user_id = nuage_subnet['nuage_userid']
631
group_id = nuage_subnet['nuage_groupid']
632
id = nuage_subnet['nuage_l2domain_id']
633
with context.session.begin(subtransactions=True):
634
nuagedb.add_subnetl2dom_mapping(context.session,
635
neutron_subnet['id'],
639
nuage_user_id=user_id,
640
nuage_group_id=group_id)
642
def create_subnet(self, context, subnet):
643
subn = subnet['subnet']
644
net_id = subn['network_id']
646
if self._network_is_external(context, net_id):
647
return self._create_nuage_sharedresource(
648
context, subnet, constants.SR_TYPE_FLOATING)
649
pnet_binding = nuagedb.get_network_binding(context.session, net_id)
651
self._validate_create_provider_subnet(context, net_id)
653
self._validate_create_subnet(subn)
655
net_partition = self._get_net_partition_for_subnet(context, subn)
656
neutron_subnet = super(NuagePlugin, self).create_subnet(context,
658
self._create_nuage_subnet(context, neutron_subnet, net_partition['id'],
659
subn['nuage_subnet_template'],
661
return neutron_subnet
663
def update_subnet(self, context, id, subnet):
664
subn = copy.deepcopy(subnet['subnet'])
665
subnet_l2dom = nuagedb.get_subnet_l2dom_by_id(context.session,
668
'parent_id': subnet_l2dom['nuage_subnet_id'],
669
'type': subnet_l2dom['nuage_l2dom_tmplt_id']
671
with context.session.begin(subtransactions=True):
672
neutron_subnet = super(NuagePlugin, self).update_subnet(context,
674
self.nuageclient.update_subnet(subn, params)
675
return neutron_subnet
677
def delete_subnet(self, context, id):
678
subnet = self.get_subnet(context, id)
679
if self._network_is_external(context, subnet['network_id']):
680
super(NuagePlugin, self).delete_subnet(context, id)
681
return self._delete_nuage_sharedresource(id)
683
filters = {'fixed_ips': {'subnet_id': [id]}}
684
ports = self.get_ports(context, filters)
686
if port['device_owner'] != os_constants.DEVICE_OWNER_DHCP:
687
raise n_exc.SubnetInUse(subnet_id=id)
689
subnet_l2dom = nuagedb.get_subnet_l2dom_by_id(context.session, id)
692
self.nuageclient.delete_subnet(id)
694
msg = (_('Unable to complete operation on subnet %s.'
695
'One or more ports have an IP allocation '
696
'from this subnet.') % id)
697
raise n_exc.BadRequest(resource='subnet', msg=msg)
698
super(NuagePlugin, self).delete_subnet(context, id)
699
if subnet_l2dom and not self._check_router_subnet_for_tenant(
700
context, subnet['tenant_id']):
701
self.nuageclient.delete_user(subnet_l2dom['nuage_user_id'])
702
self.nuageclient.delete_group(subnet_l2dom['nuage_group_id'])
704
def add_router_interface(self, context, router_id, interface_info):
705
session = context.session
706
with session.begin(subtransactions=True):
707
rtr_if_info = super(NuagePlugin,
708
self).add_router_interface(context,
711
subnet_id = rtr_if_info['subnet_id']
712
subn = self.get_subnet(context, subnet_id)
713
ent_rtr_mapping = nuagedb.get_ent_rtr_mapping_by_rtrid(session,
715
nuage_zone = self.nuageclient.get_zone_by_routerid(router_id)
716
if not nuage_zone or not ent_rtr_mapping:
718
self).remove_router_interface(context,
721
msg = (_("Router %s does not hold default zone OR "
722
"domain in VSD. Router-IF add failed")
724
raise n_exc.BadRequest(resource='router', msg=msg)
726
subnet_l2dom = nuagedb.get_subnet_l2dom_by_id(session,
730
self).remove_router_interface(context,
733
msg = (_("Subnet %s does not hold Nuage VSD reference. "
734
"Router-IF add failed") % subnet_id)
735
raise n_exc.BadRequest(resource='subnet', msg=msg)
737
if (subnet_l2dom['net_partition_id'] !=
738
ent_rtr_mapping['net_partition_id']):
740
self).remove_router_interface(context,
743
msg = (_("Subnet %(subnet)s and Router %(router)s belong to "
744
"different net_partition Router-IF add "
745
"not permitted") % {'subnet': subnet_id,
746
'router': router_id})
747
raise n_exc.BadRequest(resource='subnet', msg=msg)
748
nuage_subnet_id = subnet_l2dom['nuage_subnet_id']
749
if self.nuageclient.vms_on_l2domain(nuage_subnet_id):
751
self).remove_router_interface(context,
754
msg = (_("Subnet %s has one or more active VMs "
755
"Router-IF add not permitted") % subnet_id)
756
raise n_exc.BadRequest(resource='subnet', msg=msg)
757
self.nuageclient.delete_subnet(subnet_id)
758
net = netaddr.IPNetwork(subn['cidr'])
759
pnet_binding = nuagedb.get_network_binding(context.session,
763
'zone_id': nuage_zone['nuage_zone_id'],
764
'neutron_subnet_id': subnet_id,
765
'pnet_binding': pnet_binding
767
if not attributes.is_attr_set(subn['gateway_ip']):
768
subn['gateway_ip'] = str(netaddr.IPAddress(net.first + 1))
771
nuage_subnet = self.nuageclient.create_domain_subnet(subn,
774
with excutils.save_and_reraise_exception():
776
self).remove_router_interface(context,
782
ns_dict['nuage_subnet_id'] = nuage_subnet['nuage_subnetid']
783
ns_dict['nuage_l2dom_tmplt_id'] = None
784
nuagedb.update_subnetl2dom_mapping(subnet_l2dom,
789
def remove_router_interface(self, context, router_id, interface_info):
790
if 'subnet_id' in interface_info:
791
subnet_id = interface_info['subnet_id']
792
subnet = self.get_subnet(context, subnet_id)
795
filters = {'device_id': [router_id],
797
[os_constants.DEVICE_OWNER_ROUTER_INTF],
798
'network_id': [subnet['network_id']]}
799
ports = self.get_ports(context, filters)
802
if p['fixed_ips'][0]['subnet_id'] == subnet_id:
805
except exc.NoResultFound:
806
msg = (_("No router interface found for Router %s. "
807
"Router-IF delete failed") % router_id)
808
raise n_exc.BadRequest(resource='router', msg=msg)
811
msg = (_("No router interface found for Router %s. "
812
"Router-IF delete failed") % router_id)
813
raise n_exc.BadRequest(resource='router', msg=msg)
814
elif 'port_id' in interface_info:
815
port_db = self._get_port(context, interface_info['port_id'])
817
msg = (_("No router interface found for Router %s. "
818
"Router-IF delete failed") % router_id)
819
raise n_exc.BadRequest(resource='router', msg=msg)
820
subnet_id = port_db['fixed_ips'][0]['subnet_id']
822
session = context.session
823
with session.begin(subtransactions=True):
824
subnet_l2dom = nuagedb.get_subnet_l2dom_by_id(session,
827
return super(NuagePlugin,
828
self).remove_router_interface(context,
831
nuage_subn_id = subnet_l2dom['nuage_subnet_id']
832
if self.nuageclient.vms_on_subnet(nuage_subn_id):
833
msg = (_("Subnet %s has one or more active VMs "
834
"Router-IF delete not permitted") % subnet_id)
835
raise n_exc.BadRequest(resource='subnet', msg=msg)
837
neutron_subnet = self.get_subnet(context, subnet_id)
838
ent_rtr_mapping = nuagedb.get_ent_rtr_mapping_by_rtrid(
841
if not ent_rtr_mapping:
842
msg = (_("Router %s does not hold net_partition "
843
"assoc on Nuage VSD. Router-IF delete failed")
845
raise n_exc.BadRequest(resource='router', msg=msg)
847
net = netaddr.IPNetwork(neutron_subnet['cidr'])
848
netpart_id = ent_rtr_mapping['net_partition_id']
849
pnet_binding = nuagedb.get_network_binding(
850
context.session, neutron_subnet['network_id'])
852
'tenant_id': neutron_subnet['tenant_id'],
854
'netpart_id': netpart_id,
855
'nuage_subn_id': nuage_subn_id,
856
'neutron_subnet': neutron_subnet,
857
'pnet_binding': pnet_binding
859
nuage_subnet = self.nuageclient.remove_router_interface(params)
860
info = super(NuagePlugin,
861
self).remove_router_interface(context, router_id,
865
tmplt_id = str(nuage_subnet['nuage_l2template_id'])
867
ns_dict['nuage_subnet_id'] = nuage_subnet['nuage_l2domain_id']
868
ns_dict['nuage_l2dom_tmplt_id'] = tmplt_id
869
nuagedb.update_subnetl2dom_mapping(subnet_l2dom,
873
def _get_net_partition_for_router(self, context, rtr):
874
ent = rtr.get('net_partition', None)
876
def_net_part = cfg.CONF.RESTPROXY.default_net_partition_name
877
net_partition = nuagedb.get_net_partition_by_name(context.session,
880
net_partition = self._resource_finder(context, 'router',
881
'net_partition', rtr)
882
if not net_partition:
883
msg = _("Either net_partition is not provided with router OR "
884
"default net_partition is not created at the start")
885
raise n_exc.BadRequest(resource='router', msg=msg)
888
def create_router(self, context, router):
889
net_partition = self._get_net_partition_for_router(context, router)
890
neutron_router = super(NuagePlugin, self).create_router(context,
893
'net_partition': net_partition,
894
'tenant_id': neutron_router['tenant_id']
897
nuage_router = self.nuageclient.create_router(neutron_router,
901
with excutils.save_and_reraise_exception():
902
super(NuagePlugin, self).delete_router(context,
903
neutron_router['id'])
906
with context.session.begin(subtransactions=True):
907
nuagedb.add_entrouter_mapping(context.session,
909
neutron_router['id'],
910
nuage_router['nuage_domain_id'])
912
return neutron_router
914
def _validate_nuage_staticroutes(self, old_routes, added, removed):
916
for old in old_routes:
917
if old not in removed:
918
ip = netaddr.IPNetwork(old['destination'])
921
ip = netaddr.IPNetwork(route['destination'])
922
matching = netaddr.all_matching_cidrs(ip.ip, cidrs)
924
msg = _('for same subnet, multiple static routes not allowed')
925
raise n_exc.BadRequest(resource='router', msg=msg)
928
def update_router(self, context, id, router):
930
with context.session.begin(subtransactions=True):
932
old_routes = self._get_extra_routes_by_router_id(context,
934
added, removed = utils.diff_list_of_dict(old_routes,
936
self._validate_nuage_staticroutes(old_routes, added, removed)
938
ent_rtr_mapping = nuagedb.get_ent_rtr_mapping_by_rtrid(
940
if not ent_rtr_mapping:
941
msg = (_("Router %s does not hold net-partition "
942
"assoc on VSD. extra-route failed") % id)
943
raise n_exc.BadRequest(resource='router', msg=msg)
944
# Let it do internal checks first and verify it.
945
router_updated = super(NuagePlugin,
946
self).update_router(context,
949
for route in removed:
950
destaddr = route['destination']
951
cidr = destaddr.split('/')
954
"nexthop": route['nexthop'],
955
"nuage_domain_id": ent_rtr_mapping['nuage_router_id']
957
self.nuageclient.delete_nuage_staticroute(params)
961
'parent_id': ent_rtr_mapping['nuage_router_id'],
962
'net': netaddr.IPNetwork(route['destination']),
963
'nexthop': route['nexthop']
965
self.nuageclient.create_nuage_staticroute(
968
router_updated = super(NuagePlugin, self).update_router(
970
return router_updated
972
def delete_router(self, context, id):
973
neutron_router = self.get_router(context, id)
974
session = context.session
975
ent_rtr_mapping = nuagedb.get_ent_rtr_mapping_by_rtrid(session,
980
'device_owner': [os_constants.DEVICE_OWNER_ROUTER_INTF]
982
ports = self.get_ports(context, filters)
984
raise l3.RouterInUse(router_id=id)
985
nuage_domain_id = ent_rtr_mapping['nuage_router_id']
986
self.nuageclient.delete_router(nuage_domain_id)
988
super(NuagePlugin, self).delete_router(context, id)
990
if not self._check_router_subnet_for_tenant(
991
context, neutron_router['tenant_id']):
992
user_id, group_id = self.nuageclient.get_usergroup(
993
neutron_router['tenant_id'],
994
ent_rtr_mapping['net_partition_id'])
995
self.nuageclient.delete_user(user_id)
996
self.nuageclient.delete_group(group_id)
998
def _make_net_partition_dict(self, net_partition, fields=None):
1000
'id': net_partition['id'],
1001
'name': net_partition['name'],
1002
'l3dom_tmplt_id': net_partition['l3dom_tmplt_id'],
1003
'l2dom_tmplt_id': net_partition['l2dom_tmplt_id'],
1005
return self._fields(res, fields)
1007
def _create_net_partition(self, session, net_part_name):
1008
fip_quota = cfg.CONF.RESTPROXY.default_floatingip_quota
1010
"name": net_part_name,
1011
"fp_quota": str(fip_quota)
1013
nuage_net_partition = self.nuageclient.create_net_partition(params)
1014
net_partitioninst = None
1015
if nuage_net_partition:
1016
nuage_entid = nuage_net_partition['nuage_entid']
1017
l3dom_id = nuage_net_partition['l3dom_id']
1018
l2dom_id = nuage_net_partition['l2dom_id']
1019
with session.begin():
1020
net_partitioninst = nuagedb.add_net_partition(session,
1025
if not net_partitioninst:
1027
return self._make_net_partition_dict(net_partitioninst)
1029
def _create_default_net_partition(self, default_net_part):
1030
def_netpart = self.nuageclient.get_def_netpartition_data(
1032
session = db.get_session()
1034
net_partition = nuagedb.get_net_partition_by_name(
1035
session, default_net_part)
1036
with session.begin(subtransactions=True):
1038
nuagedb.delete_net_partition(session, net_partition)
1039
net_part = nuagedb.add_net_partition(session,
1040
def_netpart['np_id'],
1041
def_netpart['l3dom_tid'],
1042
def_netpart['l2dom_tid'],
1044
return self._make_net_partition_dict(net_part)
1046
return self._create_net_partition(session, default_net_part)
1048
def create_net_partition(self, context, net_partition):
1049
ent = net_partition['net_partition']
1050
session = context.session
1051
return self._create_net_partition(session, ent["name"])
1053
def delete_net_partition(self, context, id):
1054
ent_rtr_mapping = nuagedb.get_ent_rtr_mapping_by_entid(context.session,
1057
msg = (_("One or more router still attached to "
1058
"net_partition %s.") % id)
1059
raise n_exc.BadRequest(resource='net_partition', msg=msg)
1060
net_partition = nuagedb.get_net_partition_by_id(context.session, id)
1061
if not net_partition:
1062
msg = (_("NetPartition with %s does not exist") % id)
1063
raise n_exc.BadRequest(resource='net_partition', msg=msg)
1064
l3dom_tmplt_id = net_partition['l3dom_tmplt_id']
1065
l2dom_tmplt_id = net_partition['l2dom_tmplt_id']
1066
self.nuageclient.delete_net_partition(net_partition['id'],
1067
l3dom_id=l3dom_tmplt_id,
1068
l2dom_id=l2dom_tmplt_id)
1069
with context.session.begin(subtransactions=True):
1070
nuagedb.delete_net_partition(context.session,
1073
def get_net_partition(self, context, id, fields=None):
1074
net_partition = nuagedb.get_net_partition_by_id(context.session,
1076
return self._make_net_partition_dict(net_partition)
1078
def get_net_partitions(self, context, filters=None, fields=None):
1079
net_partitions = nuagedb.get_net_partitions(context.session,
1082
return [self._make_net_partition_dict(net_partition, fields)
1083
for net_partition in net_partitions]
1085
def _check_floatingip_update(self, context, port):
1086
filter = {'fixed_port_id': [port['id']]}
1087
local_fip = self.get_floatingips(context,
1091
self._create_update_floatingip(context,
1094
def _create_update_floatingip(self, context,
1095
neutron_fip, port_id):
1096
rtr_id = neutron_fip['router_id']
1097
net_id = neutron_fip['floating_network_id']
1098
subn = nuagedb.get_ipalloc_for_fip(context.session,
1100
neutron_fip['floating_ip_address'])
1102
fip_pool = self.nuageclient.get_nuage_fip_pool_by_id(subn['subnet_id'])
1104
msg = _('sharedresource %s not found on VSD') % subn['subnet_id']
1105
raise n_exc.BadRequest(resource='floatingip',
1108
ent_rtr_mapping = nuagedb.get_ent_rtr_mapping_by_rtrid(context.session,
1110
if not ent_rtr_mapping:
1111
msg = _('router %s is not associated with '
1112
'any net-partition') % rtr_id
1113
raise n_exc.BadRequest(resource='floatingip',
1117
'router_id': ent_rtr_mapping['nuage_router_id'],
1118
'fip_id': neutron_fip['id'],
1119
'neutron_fip': neutron_fip
1122
fip = self.nuageclient.get_nuage_fip_by_id(params)
1125
'nuage_rtr_id': ent_rtr_mapping['nuage_router_id'],
1126
'nuage_fippool_id': fip_pool['nuage_fip_pool_id'],
1127
'neutron_fip_ip': neutron_fip['floating_ip_address'],
1128
'neutron_fip_id': neutron_fip['id']
1130
nuage_fip_id = self.nuageclient.create_nuage_floatingip(params)
1132
nuage_fip_id = fip['nuage_fip_id']
1134
# Update VM if required
1136
'neutron_port_id': port_id,
1137
'nuage_fip_id': nuage_fip_id,
1138
'nuage_rtr_id': ent_rtr_mapping['nuage_router_id']
1140
nuage_port = self.nuageclient.get_nuage_port_by_id(params)
1142
if (nuage_port['nuage_domain_id']) != (
1143
ent_rtr_mapping['nuage_router_id']):
1144
msg = _('Floating IP can not be associated to VM in '
1145
'different router context')
1146
raise nuage_exc.OperationNotSupported(msg=msg)
1149
'nuage_vport_id': nuage_port['nuage_vport_id'],
1150
'nuage_fip_id': nuage_fip_id
1152
self.nuageclient.update_nuage_vm_vport(params)
1154
def create_floatingip(self, context, floatingip):
1155
fip = floatingip['floatingip']
1156
with context.session.begin(subtransactions=True):
1157
neutron_fip = super(NuagePlugin, self).create_floatingip(
1158
context, floatingip)
1159
if not neutron_fip['router_id']:
1162
self._create_update_floatingip(context, neutron_fip,
1164
except (nuage_exc.OperationNotSupported, n_exc.BadRequest):
1165
with excutils.save_and_reraise_exception():
1166
super(NuagePlugin, self).delete_floatingip(
1167
context, neutron_fip['id'])
1170
def disassociate_floatingips(self, context, port_id, do_notify=True):
1171
router_ids = super(NuagePlugin, self).disassociate_floatingips(
1172
context, port_id, do_notify=do_notify)
1175
'neutron_port_id': port_id,
1177
nuage_port = self.nuageclient.get_nuage_port_by_id(params)
1180
'nuage_vport_id': nuage_port['nuage_vport_id'],
1181
'nuage_fip_id': None
1183
self.nuageclient.update_nuage_vm_vport(params)
1187
def update_floatingip(self, context, id, floatingip):
1188
fip = floatingip['floatingip']
1189
orig_fip = self._get_floatingip(context, id)
1190
port_id = orig_fip['fixed_port_id']
1192
with context.session.begin(subtransactions=True):
1193
neutron_fip = super(NuagePlugin, self).update_floatingip(
1194
context, id, floatingip)
1195
if fip['port_id'] is not None:
1196
if not neutron_fip['router_id']:
1197
ret_msg = 'floating-ip is not associated yet'
1198
raise n_exc.BadRequest(resource='floatingip',
1202
self._create_update_floatingip(context,
1205
except nuage_exc.OperationNotSupported:
1206
with excutils.save_and_reraise_exception():
1208
NuagePlugin, self).disassociate_floatingips(
1209
context, fip['port_id'], do_notify=False)
1210
except n_exc.BadRequest:
1211
with excutils.save_and_reraise_exception():
1212
super(NuagePlugin, self).delete_floatingip(context,
1216
'neutron_port_id': port_id,
1218
nuage_port = self.nuageclient.get_nuage_port_by_id(params)
1221
'nuage_vport_id': nuage_port['nuage_vport_id'],
1222
'nuage_fip_id': None
1224
self.nuageclient.update_nuage_vm_vport(params)
1226
# now that we've left db transaction, we are safe to notify
1227
self.notify_routers_updated(context, router_ids)
1231
def delete_floatingip(self, context, fip_id):
1232
fip = self._get_floatingip(context, fip_id)
1233
port_id = fip['fixed_port_id']
1234
with context.session.begin(subtransactions=True):
1237
'neutron_port_id': port_id,
1239
nuage_port = self.nuageclient.get_nuage_port_by_id(params)
1241
nuage_port['nuage_vport_id'] is not None):
1243
'nuage_vport_id': nuage_port['nuage_vport_id'],
1244
'nuage_fip_id': None
1246
self.nuageclient.update_nuage_vm_vport(params)
1247
LOG.debug("Floating-ip %(fip)s is disassociated from "
1250
'vport': nuage_port['nuage_vport_id']})
1252
router_id = fip['router_id']
1254
router_id = fip['last_known_router_id']
1257
ent_rtr_mapping = nuagedb.get_ent_rtr_mapping_by_rtrid(
1260
if not ent_rtr_mapping:
1261
msg = _('router %s is not associated with '
1262
'any net-partition') % router_id
1263
raise n_exc.BadRequest(resource='floatingip',
1266
'router_id': ent_rtr_mapping['nuage_router_id'],
1269
fip = self.nuageclient.get_nuage_fip_by_id(params)
1271
self.nuageclient.delete_nuage_floatingip(
1272
fip['nuage_fip_id'])
1273
LOG.debug('Floating-ip %s deleted from VSD', fip_id)
1275
super(NuagePlugin, self).delete_floatingip(context, fip_id)
1277
def delete_security_group(self, context, id):
1278
filters = {'security_group_id': [id]}
1279
ports = self._get_port_security_group_bindings(context,
1282
raise ext_sg.SecurityGroupInUse(id=id)
1283
sg_rules = self.get_security_group_rules(context,
1284
{'security_group_id': [id]})
1287
self.nuageclient.delete_nuage_sgrule(sg_rules)
1288
self.nuageclient.delete_nuage_secgroup(id)
1290
super(NuagePlugin, self).delete_security_group(context, id)
1292
def create_security_group_rule(self, context, security_group_rule):
1293
sg_rule = security_group_rule['security_group_rule']
1294
self.nuageclient.validate_nuage_sg_rule_definition(sg_rule)
1295
sg_id = sg_rule['security_group_id']
1297
local_sg_rule = super(NuagePlugin,
1298
self).create_security_group_rule(
1299
context, security_group_rule)
1302
nuage_vptag = self.nuageclient.get_sg_vptag_mapping(sg_id)
1306
'neutron_sg_rule': local_sg_rule,
1307
'vptag': nuage_vptag
1309
self.nuageclient.create_nuage_sgrule(sg_params)
1311
with excutils.save_and_reraise_exception():
1313
self).delete_security_group_rule(context,
1314
local_sg_rule['id'])
1316
return local_sg_rule
1318
def delete_security_group_rule(self, context, id):
1319
local_sg_rule = self.get_security_group_rule(context, id)
1320
super(NuagePlugin, self).delete_security_group_rule(context, id)
1321
self.nuageclient.delete_nuage_sgrule([local_sg_rule])