Merge "Make "project_id" in "L3HARouterNetwork" unique constraint"

This commit is contained in:
Zuul 2023-06-09 20:37:03 +00:00 committed by Gerrit Code Review
commit ac0b0c50a2
6 changed files with 115 additions and 1 deletions

View File

@ -33,6 +33,7 @@ from neutron.db.extra_dhcp_opt import models as extra_dhcp_opt_models
from neutron.db.models import agent as agent_model
from neutron.db.models import external_net
from neutron.db.models import l3 as l3_models
from neutron.db.models import l3ha as l3ha_models
from neutron.db.models.plugins.ml2 import vlanallocation
from neutron.db.models import segment
from neutron.db import models_v2
@ -164,6 +165,16 @@ def get_fip_per_network_without_qos_policies(network_id):
return query.count()
def get_duplicated_ha_networks_per_project():
"""Return those HA network reg. that have more than 1 entry per project"""
ctx = context.get_admin_context()
with db_api.CONTEXT_READER.using(ctx):
query = ctx.session.query(l3ha_models.L3HARouterNetwork)
query = query.group_by(l3ha_models.L3HARouterNetwork.project_id)
query = query.having(func.count() > 1)
return query.all()
class CoreChecks(base.BaseChecks):
def get_checks(self):
@ -192,6 +203,8 @@ class CoreChecks(base.BaseChecks):
self.floatingip_inherit_qos_from_network),
(_('Port extra DHCP options check'),
self.extra_dhcp_options_check),
(_('Duplicated HA network per project check'),
self.extra_dhcp_options_check),
]
@staticmethod
@ -528,3 +541,32 @@ class CoreChecks(base.BaseChecks):
upgradecheck.Code.SUCCESS,
_('There are no extra_dhcp_opts with the newline character '
'in the option name or option value.'))
@staticmethod
def duplicated_ha_network_per_project_check(checker):
"""Check if there are duplicated HA networks per project
By definition there could be zero or one HA network per project. In
case of having more than one register associated to any existing
project (that should never happen), this check will fail.
"""
if not cfg.CONF.database.connection:
return upgradecheck.Result(
upgradecheck.Code.WARNING,
_("Database connection string is not set. Check for "
"extra_dhcp_opts can't be done."))
ha_networks = get_duplicated_ha_networks_per_project()
project_ids = {ha_network['project_id'] for ha_network in ha_networks}
network_ids = {ha_network['network_id'] for ha_network in ha_networks}
if project_ids:
return upgradecheck.Result(
upgradecheck.Code.WARNING,
_('The following projects have duplicated HA networks: '
'%(project_ids)s. This is the list of duplicated HA '
'networks: %(network_ids)s' %
{'project_ids': project_ids, 'network_ids': network_ids}))
return upgradecheck.Result(
upgradecheck.Code.SUCCESS,
_('There are no duplicated HA networks in the system.'))

View File

@ -0,0 +1,40 @@
# Copyright 2023 OpenStack Foundation
#
# 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.
#
from alembic import op
"""Create L3HARouterNetwork.project_id unique constraint
Revision ID: 682c319773d7
Revises: 6f1145bff34c
Create Date: 2023-04-27 13:45:05.103963
"""
# revision identifiers, used by Alembic.
revision = '682c319773d7'
down_revision = '6f1145bff34c'
TABLE = 'ha_router_networks'
COLUMN = 'project_id'
def upgrade():
op.create_unique_constraint(
constraint_name='uniq_%s0%s' % (TABLE, COLUMN),
table_name=TABLE,
columns=[COLUMN])

View File

@ -1 +1 @@
6f1145bff34c
682c319773d7

View File

@ -67,6 +67,11 @@ class L3HARouterNetwork(model_base.BASEV2, model_base.HasProjectPrimaryKey):
"""
__tablename__ = 'ha_router_networks'
__table_args__ = (
sa.UniqueConstraint('project_id',
name='uniq_ha_router_networks0project_id'),
model_base.BASEV2.__table_args__
)
network_id = sa.Column(sa.String(36),
sa.ForeignKey('networks.id', ondelete="CASCADE"),

View File

@ -278,3 +278,22 @@ class TestChecks(base.BaseTestCase):
opt_value='bar\nbar')]
result = checks.CoreChecks.extra_dhcp_options_check(mock.ANY)
self.assertEqual(Code.WARNING, result.code)
@mock.patch.object(checks, 'get_duplicated_ha_networks_per_project')
def test_duplicated_ha_network_per_project_check_success(self,
mock_ha_nets):
mock_ha_nets.return_value = []
result = checks.CoreChecks.duplicated_ha_network_per_project_check(
mock.ANY)
self.assertEqual(Code.SUCCESS, result.code)
@mock.patch.object(checks, 'get_duplicated_ha_networks_per_project')
def test_duplicated_ha_network_per_project_check_warning(self,
mock_ha_nets):
mock_ha_nets.return_value = [
{'project_id': 'project1', 'network_id': 'net1'},
{'project_id': 'project1', 'network_id': 'net2'},
]
result = checks.CoreChecks.duplicated_ha_network_per_project_check(
mock.ANY)
self.assertEqual(Code.WARNING, result.code)

View File

@ -0,0 +1,8 @@
---
other:
- |
Introduced a database constraint to limit the number of
``ha_router_networks`` registers per project to one only. This register is
used to bind projects and networks, defining the corresponding network
as high availability (HA) network. By definition, only one HA network per
project can exist.