~ubuntu-branches/ubuntu/vivid/neutron/vivid-updates

« back to all changes in this revision

Viewing changes to neutron/db/db_base_plugin_v2.py

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2015-03-30 11:17:19 UTC
  • mfrom: (1.1.21)
  • Revision ID: package-import@ubuntu.com-20150330111719-h0gx7233p4jkkgfh
Tags: 1:2015.1~b3-0ubuntu1
* New upstream milestone release:
  - d/control: Align version requirements with upstream.
  - d/control: Add new dependency on oslo-log.
  - d/p/*: Rebase.
  - d/control,d/neutron-plugin-hyperv*: Dropped, decomposed into
    separate project upstream.
  - d/control,d/neutron-plugin-openflow*: Dropped, decomposed into
    separate project upstream.
  - d/neutron-common.install: Add neutron-rootwrap-daemon and 
    neutron-keepalived-state-change binaries.
  - d/rules: Ignore neutron-hyperv-agent when installing; only for Windows.
  - d/neutron-plugin-cisco.install: Drop neutron-cisco-cfg-agent as
    decomposed into separate project upstream.
  - d/neutron-plugin-vmware.install: Drop neutron-check-nsx-config and
    neutron-nsx-manage as decomposed into separate project upstream.
  - d/control: Add dependency on python-neutron-fwaas to neutron-l3-agent.
* d/pydist-overrides: Add overrides for oslo packages.
* d/control: Fixup type in package description (LP: #1263539).
* d/p/fixup-driver-test-execution.patch: Cherry pick fix from upstream VCS
  to support unit test exection in out-of-tree vendor drivers.
* d/neutron-common.postinst: Allow general access to /etc/neutron but limit
  access to root/neutron to /etc/neutron/neutron.conf to support execution
  of unit tests in decomposed vendor drivers.
* d/control: Add dependency on python-neutron-fwaas to neutron-l3-agent
  package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
#    under the License.
15
15
 
16
16
import netaddr
17
 
from oslo.config import cfg
18
 
from oslo.db import exception as db_exc
19
 
from oslo.utils import excutils
 
17
from oslo_config import cfg
 
18
from oslo_db import exception as db_exc
 
19
from oslo_log import log as logging
 
20
from oslo_utils import excutils
20
21
from sqlalchemy import and_
21
22
from sqlalchemy import event
22
23
from sqlalchemy import orm
35
36
from neutron.i18n import _LE, _LI
36
37
from neutron import manager
37
38
from neutron import neutron_plugin_base_v2
38
 
from neutron.openstack.common import log as logging
39
39
from neutron.openstack.common import uuidutils
40
40
from neutron.plugins.common import constants as service_constants
41
41
 
358
358
        IPs. Include the subnet_id in the result if only an IP address is
359
359
        configured.
360
360
 
361
 
        :raises: InvalidInput, IpAddressInUse
 
361
        :raises: InvalidInput, IpAddressInUse, InvalidIpForNetwork,
 
362
                 InvalidIpForSubnet
362
363
        """
363
364
        fixed_ip_set = []
364
365
        for fixed in fixed_ips:
377
378
                        subnet_id = subnet['id']
378
379
                        break
379
380
                if not found:
380
 
                    msg = _('IP address %s is not a valid IP for the defined '
381
 
                            'networks subnets') % fixed['ip_address']
382
 
                    raise n_exc.InvalidInput(error_message=msg)
 
381
                    raise n_exc.InvalidIpForNetwork(
 
382
                        ip_address=fixed['ip_address'])
383
383
            else:
384
384
                subnet = self._get_subnet(context, fixed['subnet_id'])
385
385
                if subnet['network_id'] != network_id:
391
391
                    raise n_exc.InvalidInput(error_message=msg)
392
392
                subnet_id = subnet['id']
393
393
 
 
394
            is_auto_addr_subnet = ipv6_utils.is_auto_address_subnet(subnet)
394
395
            if 'ip_address' in fixed:
395
396
                # Ensure that the IP's are unique
396
397
                if not NeutronDbPluginV2._check_unique_ip(context, network_id,
403
404
                if (not found and
404
405
                    not self._check_subnet_ip(subnet['cidr'],
405
406
                                              fixed['ip_address'])):
406
 
                    msg = _('IP address %s is not a valid IP for the defined '
407
 
                            'subnet') % fixed['ip_address']
408
 
                    raise n_exc.InvalidInput(error_message=msg)
409
 
                if (ipv6_utils.is_auto_address_subnet(subnet) and
 
407
                    raise n_exc.InvalidIpForSubnet(
 
408
                        ip_address=fixed['ip_address'])
 
409
                if (is_auto_addr_subnet and
410
410
                    device_owner not in
411
411
                        constants.ROUTER_INTERFACE_OWNERS):
412
412
                    msg = (_("IPv6 address %(address)s can not be directly "
418
418
                fixed_ip_set.append({'subnet_id': subnet_id,
419
419
                                     'ip_address': fixed['ip_address']})
420
420
            else:
421
 
                fixed_ip_set.append({'subnet_id': subnet_id})
 
421
                # A scan for auto-address subnets on the network is done
 
422
                # separately so that all such subnets (not just those
 
423
                # listed explicitly here by subnet ID) are associated
 
424
                # with the port.
 
425
                if (device_owner in constants.ROUTER_INTERFACE_OWNERS or
 
426
                    device_owner == constants.DEVICE_OWNER_ROUTER_SNAT or
 
427
                    not is_auto_addr_subnet):
 
428
                    fixed_ip_set.append({'subnet_id': subnet_id})
 
429
 
422
430
        if len(fixed_ip_set) > cfg.CONF.max_fixed_ips_per_port:
423
431
            msg = _('Exceeded maximim amount of fixed ips per port')
424
432
            raise n_exc.InvalidInput(error_message=msg)
498
506
        """
499
507
        p = port['port']
500
508
        ips = []
 
509
        v6_stateless = []
 
510
        net_id_filter = {'network_id': [p['network_id']]}
 
511
        subnets = self.get_subnets(context, filters=net_id_filter)
501
512
 
502
513
        fixed_configured = p['fixed_ips'] is not attributes.ATTR_NOT_SPECIFIED
503
514
        if fixed_configured:
508
519
            ips = self._allocate_fixed_ips(context,
509
520
                                           configured_ips,
510
521
                                           p['mac_address'])
 
522
 
 
523
            # For ports that are not router ports, implicitly include all
 
524
            # auto-address subnets for address association.
 
525
            if (not p['device_owner'] in constants.ROUTER_INTERFACE_OWNERS and
 
526
                p['device_owner'] != constants.DEVICE_OWNER_ROUTER_SNAT):
 
527
                v6_stateless += [subnet for subnet in subnets
 
528
                                 if ipv6_utils.is_auto_address_subnet(subnet)]
511
529
        else:
512
 
            filter = {'network_id': [p['network_id']]}
513
 
            subnets = self.get_subnets(context, filters=filter)
514
 
            # Split into v4 and v6 subnets
 
530
            # Split into v4, v6 stateless and v6 stateful subnets
515
531
            v4 = []
516
532
            v6_stateful = []
517
 
            v6_stateless = []
518
533
            for subnet in subnets:
519
534
                if subnet['ip_version'] == 4:
520
535
                    v4.append(subnet)
524
539
                    else:
525
540
                        v6_stateful.append(subnet)
526
541
 
527
 
            for subnet in v6_stateless:
528
 
                prefix = subnet['cidr']
529
 
                ip_address = ipv6_utils.get_ipv6_addr_by_EUI64(
530
 
                    prefix, p['mac_address'])
531
 
                if not self._check_unique_ip(
532
 
                    context, p['network_id'],
533
 
                    subnet['id'], ip_address.format()):
534
 
                    raise n_exc.IpAddressInUse(
535
 
                        net_id=p['network_id'],
536
 
                        ip_address=ip_address.format())
537
 
                ips.append({'ip_address': ip_address.format(),
538
 
                            'subnet_id': subnet['id']})
539
542
            version_subnets = [v4, v6_stateful]
540
543
            for subnets in version_subnets:
541
544
                if subnets:
542
545
                    result = NeutronDbPluginV2._generate_ip(context, subnets)
543
546
                    ips.append({'ip_address': result['ip_address'],
544
547
                                'subnet_id': result['subnet_id']})
 
548
 
 
549
        for subnet in v6_stateless:
 
550
            # IP addresses for IPv6 SLAAC and DHCPv6-stateless subnets
 
551
            # are implicitly included.
 
552
            prefix = subnet['cidr']
 
553
            ip_address = ipv6_utils.get_ipv6_addr_by_EUI64(prefix,
 
554
                                                           p['mac_address'])
 
555
            if not self._check_unique_ip(context, p['network_id'],
 
556
                                         subnet['id'], ip_address.format()):
 
557
                raise n_exc.IpAddressInUse(net_id=p['network_id'],
 
558
                                           ip_address=ip_address.format())
 
559
            ips.append({'ip_address': ip_address.format(),
 
560
                        'subnet_id': subnet['id']})
 
561
 
545
562
        return ips
546
563
 
547
564
    def _validate_subnet_cidr(self, context, network, new_subnet_cidr):
782
799
               'name': network['name'],
783
800
               'tenant_id': network['tenant_id'],
784
801
               'admin_state_up': network['admin_state_up'],
 
802
               'mtu': network.get('mtu', constants.DEFAULT_NETWORK_MTU),
785
803
               'status': network['status'],
786
804
               'shared': network['shared'],
 
805
               'vlan_transparent': network['vlan_transparent'],
787
806
               'subnets': [subnet['id']
788
807
                           for subnet in network['subnets']]}
789
808
        # Call auxiliary extend functions, if any
870
889
                    'id': n.get('id') or uuidutils.generate_uuid(),
871
890
                    'name': n['name'],
872
891
                    'admin_state_up': n['admin_state_up'],
 
892
                    'mtu': n.get('mtu', constants.DEFAULT_NETWORK_MTU),
873
893
                    'shared': n['shared'],
 
894
                    'vlan_transparent': n.get('vlan_transparent', False),
874
895
                    'status': n.get('status', constants.NET_STATUS_ACTIVE)}
875
896
            network = models_v2.Network(**args)
876
897
            context.session.add(network)
1222
1243
            models_v2.IPAllocation).filter_by(
1223
1244
                subnet_id=subnet_id).join(models_v2.Port).first()
1224
1245
 
 
1246
    def _subnet_check_ip_allocations_internal_router_ports(self, context,
 
1247
                                                           subnet_id):
 
1248
        # Do not delete the subnet if IP allocations for internal
 
1249
        # router ports still exist
 
1250
        allocs = context.session.query(models_v2.IPAllocation).filter_by(
 
1251
                subnet_id=subnet_id).join(models_v2.Port).filter(
 
1252
                        models_v2.Port.device_owner.in_(
 
1253
                            constants.ROUTER_INTERFACE_OWNERS)
 
1254
                ).first()
 
1255
        if allocs:
 
1256
            LOG.debug("Subnet %s still has internal router ports, "
 
1257
                      "cannot delete", subnet_id)
 
1258
            raise n_exc.SubnetInUse(subnet_id=id)
 
1259
 
1225
1260
    def delete_subnet(self, context, id):
1226
1261
        with context.session.begin(subtransactions=True):
1227
1262
            subnet = self._get_subnet(context, id)
1234
1269
            # for IPv6 addresses which were automatically generated
1235
1270
            # via SLAAC
1236
1271
            is_auto_addr_subnet = ipv6_utils.is_auto_address_subnet(subnet)
1237
 
            if not is_auto_addr_subnet:
 
1272
            if is_auto_addr_subnet:
 
1273
                self._subnet_check_ip_allocations_internal_router_ports(
 
1274
                        context, id)
 
1275
            else:
1238
1276
                qry_network_ports = (
1239
1277
                    qry_network_ports.filter(models_v2.Port.device_owner.
1240
1278
                    in_(AUTO_DELETE_PORT_OWNERS)))
1248
1286
            # the isolation level is set to READ COMMITTED allocations made
1249
1287
            # concurrently will be returned by this query
1250
1288
            if not is_auto_addr_subnet:
1251
 
                if self._subnet_check_ip_allocations(context, id):
1252
 
                    LOG.debug("Found IP allocations on subnet %s, "
1253
 
                              "cannot delete", id)
 
1289
                alloc = self._subnet_check_ip_allocations(context, id)
 
1290
                if alloc:
 
1291
                    LOG.info(_LI("Found IP allocation %(alloc)s on subnet "
 
1292
                                 "%(subnet)s, cannot delete"),
 
1293
                             {'alloc': alloc,
 
1294
                              'subnet': id})
1254
1295
                    raise n_exc.SubnetInUse(subnet_id=id)
1255
1296
 
1256
1297
            context.session.delete(subnet)
1321
1362
        # NOTE(jkoelker) Get the tenant_id outside of the session to avoid
1322
1363
        #                unneeded db action if the operation raises
1323
1364
        tenant_id = self._get_tenant_id_for_create(context, p)
1324
 
        if p.get('device_owner') == constants.DEVICE_OWNER_ROUTER_INTF:
1325
 
            self._enforce_device_owner_not_router_intf_or_device_id(context, p,
1326
 
                                                                    tenant_id)
 
1365
        if p.get('device_owner'):
 
1366
            self._enforce_device_owner_not_router_intf_or_device_id(
 
1367
                context, p.get('device_owner'), p.get('device_id'), tenant_id)
1327
1368
 
1328
1369
        port_data = dict(tenant_id=tenant_id,
1329
1370
                         name=p['name'],
1361
1402
        p = port['port']
1362
1403
 
1363
1404
        changed_ips = False
1364
 
        changed_device_id = False
1365
1405
        with context.session.begin(subtransactions=True):
1366
1406
            port = self._get_port(context, id)
1367
 
            if 'device_owner' in p:
1368
 
                current_device_owner = p['device_owner']
1369
 
                changed_device_owner = True
1370
 
            else:
1371
 
                current_device_owner = port['device_owner']
1372
 
                changed_device_owner = False
1373
 
            if p.get('device_id') != port['device_id']:
1374
 
                changed_device_id = True
 
1407
            changed_owner = 'device_owner' in p
 
1408
            current_owner = p.get('device_owner') or port['device_owner']
 
1409
            changed_device_id = p.get('device_id') != port['device_id']
 
1410
            current_device_id = p.get('device_id') or port['device_id']
1375
1411
 
1376
 
            # if the current device_owner is ROUTER_INF and the device_id or
1377
 
            # device_owner changed check device_id is not another tenants
1378
 
            # router
1379
 
            if ((current_device_owner == constants.DEVICE_OWNER_ROUTER_INTF)
1380
 
                    and (changed_device_id or changed_device_owner)):
 
1412
            if current_owner and changed_device_id or changed_owner:
1381
1413
                self._enforce_device_owner_not_router_intf_or_device_id(
1382
 
                    context, p, port['tenant_id'], port)
 
1414
                    context, current_owner, current_device_id,
 
1415
                    port['tenant_id'])
1383
1416
 
1384
1417
            new_mac = p.get('mac_address')
1385
1418
            if new_mac and new_mac != port['mac_address']:
1386
1419
                self._check_mac_addr_update(
1387
 
                    context, port, new_mac, current_device_owner)
 
1420
                    context, port, new_mac, current_owner)
1388
1421
 
1389
1422
            # Check if the IPs need to be updated
1390
1423
            network_id = port['network_id']
1490
1523
        return self._get_ports_query(context, filters).count()
1491
1524
 
1492
1525
    def _enforce_device_owner_not_router_intf_or_device_id(self, context,
1493
 
                                                           port_request,
1494
 
                                                           tenant_id,
1495
 
                                                           db_port=None):
 
1526
                                                           device_owner,
 
1527
                                                           device_id,
 
1528
                                                           tenant_id):
 
1529
        """Prevent tenants from replacing the device id of router ports with
 
1530
        a router uuid belonging to another tenant.
 
1531
        """
 
1532
        if device_owner not in constants.ROUTER_INTERFACE_OWNERS:
 
1533
            return
1496
1534
        if not context.is_admin:
1497
 
            # find the device_id. If the call was update_port and the
1498
 
            # device_id was not passed in we use the device_id from the
1499
 
            # db.
1500
 
            device_id = port_request.get('device_id')
1501
 
            if not device_id and db_port:
1502
 
                device_id = db_port.get('device_id')
1503
1535
            # check to make sure device_id does not match another tenants
1504
1536
            # router.
1505
1537
            if device_id: