From: Cedric Brandily Date: Thu, 28 May 2015 16:35:17 +0000 (+0200) Subject: Ensure non-overlapping cidrs in subnetpools with galera X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=03b70b109449f3b9329834c7aa88fd26ed71cf26;p=openstack-build%2Fneutron-build.git Ensure non-overlapping cidrs in subnetpools with galera This change enables galera support in _lock_subnetpool[1]. It uses an update to disallow 2 transactions performing concurrent subnet allocation in the same subnetpool to succeed: the 2 transactions will conflict because they update the same row so the db (including Galera multi-writer cluster) will discard the last transaction and Controller.create[2] will catch and retry the "discarded" allocation. This change adds the "hash" attribute in "subnetpools" table to enable previous update. [1] neutron.ipam.subnet_alloc.SubnetAllocator [2] neutron.api.v2.base Change-Id: I74f7100a6fd9b7787be693adffec15ec468d0018 Closes-Bug: #1451576 --- diff --git a/neutron/db/migration/alembic_migrations/versions/HEADS b/neutron/db/migration/alembic_migrations/versions/HEADS index 9fef83520..c2e3e7714 100644 --- a/neutron/db/migration/alembic_migrations/versions/HEADS +++ b/neutron/db/migration/alembic_migrations/versions/HEADS @@ -1,3 +1,3 @@ 1c844d1677f7 -45f955889773 +26c371498592 kilo diff --git a/neutron/db/migration/alembic_migrations/versions/liberty/expand/26c371498592_subnetpool_hash.py b/neutron/db/migration/alembic_migrations/versions/liberty/expand/26c371498592_subnetpool_hash.py new file mode 100644 index 000000000..5bff7c888 --- /dev/null +++ b/neutron/db/migration/alembic_migrations/versions/liberty/expand/26c371498592_subnetpool_hash.py @@ -0,0 +1,35 @@ +# Copyright (c) 2015 Thales Services SAS +# +# 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. +# + +"""subnetpool hash + +Revision ID: 26c371498592 +Revises: 45f955889773 +Create Date: 2015-06-02 21:18:19.942076 + +""" + +# revision identifiers, used by Alembic. +revision = '26c371498592' +down_revision = '45f955889773' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.add_column( + 'subnetpools', + sa.Column('hash', sa.String(36), nullable=False, server_default='')) diff --git a/neutron/db/models_v2.py b/neutron/db/models_v2.py index 6e6d270ef..a3c0bd276 100644 --- a/neutron/db/models_v2.py +++ b/neutron/db/models_v2.py @@ -244,6 +244,7 @@ class SubnetPool(model_base.BASEV2, HasId, HasTenant): max_prefixlen = sa.Column(sa.Integer, nullable=False) shared = sa.Column(sa.Boolean, nullable=False) default_quota = sa.Column(sa.Integer, nullable=True) + hash = sa.Column(sa.String(36), nullable=False, server_default='') prefixes = orm.relationship(SubnetPoolPrefix, backref='subnetpools', cascade='all, delete, delete-orphan', diff --git a/neutron/ipam/subnet_alloc.py b/neutron/ipam/subnet_alloc.py index 1bc213ec4..4a1fd3861 100644 --- a/neutron/ipam/subnet_alloc.py +++ b/neutron/ipam/subnet_alloc.py @@ -17,6 +17,7 @@ import math import operator import netaddr +from oslo_db import exception as db_exc from oslo_utils import uuidutils from neutron.api.v2 import attributes @@ -46,10 +47,23 @@ class SubnetAllocator(driver.Pool): subnetpool, it's required to ensure non-overlapping cidrs in the same subnetpool. """ - # FIXME(cbrandily): not working with Galera - (self._context.session.query(models_v2.SubnetPool.id). - filter_by(id=self._subnetpool['id']). - with_lockmode('update').first()) + + current_hash = (self._context.session.query(models_v2.SubnetPool.hash) + .filter_by(id=self._subnetpool['id']).scalar()) + if current_hash is None: + # NOTE(cbrandily): subnetpool has been deleted + raise n_exc.SubnetPoolNotFound( + subnetpool_id=self._subnetpool['id']) + new_hash = uuidutils.generate_uuid() + + # NOTE(cbrandily): the update disallows 2 concurrent subnet allocation + # to succeed: at most 1 transaction will succeed, others will be + # rollbacked and be caught in neutron.db.v2.base + query = self._context.session.query(models_v2.SubnetPool).filter_by( + id=self._subnetpool['id'], hash=current_hash) + count = query.update({'hash': new_hash}) + if not count: + raise db_exc.RetryRequest() def _get_allocated_cidrs(self): query = self._context.session.query(models_v2.Subnet)