]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Ensure non-overlapping cidrs in subnetpools with galera
authorCedric Brandily <zzelle@gmail.com>
Thu, 28 May 2015 16:35:17 +0000 (18:35 +0200)
committerCedric Brandily <zzelle@gmail.com>
Fri, 31 Jul 2015 09:33:52 +0000 (09:33 +0000)
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

neutron/db/migration/alembic_migrations/versions/HEADS
neutron/db/migration/alembic_migrations/versions/liberty/expand/26c371498592_subnetpool_hash.py [new file with mode: 0644]
neutron/db/models_v2.py
neutron/ipam/subnet_alloc.py

index 9fef8352067f536a6bb1b2c99056ebd8c3df9813..c2e3e77148ebdf3bfab8ddd0c63274ed0301ed3e 100644 (file)
@@ -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 (file)
index 0000000..5bff7c8
--- /dev/null
@@ -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=''))
index 6e6d270efb551a5adc608694d4789c826040a9e8..a3c0bd276b5867d4479b79ff83ee1669060a4c34 100644 (file)
@@ -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',
index 1bc213ec4ba3c25f84f4aede0b3184f8a8ada195..4a1fd3861b3275aa47cb3b9c87d34a16074c2c8a 100644 (file)
@@ -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)