neutron/neutron/objects/trunk.py
Ihar Hrachyshka 6f83466307 Allow objects to opt in new engine facade
New facade is enabled by setting new_facade = True for the object of
interest. With new_facade on, all OVO actions will use the new reader /
writer decorator to activate sessions.

There are two new facade decorators added to OVO: db_context_reader and
db_context_write that should be used instead of explicit
autonested_transaction / reader.using / writer.using in OVO context.

All neutron.objects.db.api helpers now receive OVO classes / objects
instead of model classes, since they need to know which type of engine
facade to use for which object. While it means we change signatures for
those helper functions, they are not used anywhere outside neutron tree
except vmware-nsx unit tests, and the latter pass anyway because the
tests completely mock out them disregarding their signatures.

This patch also adds several new OVO objects to be able to continue
using neutron.objects.db.api helpers to persist models that previously
didn't have corresponding OVO classes.

Finally, the patch adds registration for missing options in
neutron/tests/unit/extensions/test_qos_fip.py to be able to debug
failures in those unit tests. Strictly speaking, this change doesn't
belong to the patch, but I include it nevertheless to speed up merge in
time close to release.

There are several non-obvious changes included, specifically:

- in neutron.objects.base, decorator() that refreshes / expunges models
from the active session now opens a subtransaction for the whole span of
call / refresh / expunge, so that we can safely refresh model regardless
of whether caller opened another parent subtransaction (it was not the
case for create_subnetpool in base db plugin code).

- in neutron.db.l3_fip_qos, removed code that updates obj.db_model
relationship directly after corresponding insertions for child policy
binding model. This code is not needed because the only caller to the
_process_extra_fip_qos_update method refetches latest state of floating
ip OVO object anyway, and this code triggers several unit test failures.

- unit tests checking that a single commit happens for get_object and
get_objects are no longer valid for new facade objects that use reader
decorator that doesn't commit but close. This change is as intended, so
unit tests were tweaked to check close for new facade objects.

Change-Id: I15ec238c18a464f977f7d1079605b82965052311
Related-Bug: #1746996
2018-02-09 04:07:34 +00:00

143 lines
5.2 KiB
Python

# Copyright (c) 2016 Mirantis, Inc.
# All Rights Reserved.
#
# 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 neutron_lib import exceptions as n_exc
from neutron_lib.objects import exceptions as o_exc
from oslo_db import exception as o_db_exc
from oslo_utils import versionutils
from oslo_versionedobjects import fields as obj_fields
from neutron.objects import base
from neutron.objects import common_types
from neutron.services.trunk import exceptions as t_exc
from neutron.services.trunk import models
@base.NeutronObjectRegistry.register
class SubPort(base.NeutronDbObject):
# Version 1.0: Initial version
VERSION = '1.0'
db_model = models.SubPort
primary_keys = ['port_id']
foreign_keys = {'Trunk': {'trunk_id': 'id'}}
fields = {
'port_id': common_types.UUIDField(),
'trunk_id': common_types.UUIDField(),
'segmentation_type': obj_fields.StringField(),
'segmentation_id': obj_fields.IntegerField(),
}
fields_no_update = ['segmentation_type', 'segmentation_id', 'trunk_id']
def to_dict(self):
_dict = super(SubPort, self).to_dict()
# trunk_id is redundant in the subport dict.
_dict.pop('trunk_id')
return _dict
def create(self):
with self.db_context_writer(self.obj_context):
try:
super(SubPort, self).create()
except o_db_exc.DBReferenceError as ex:
if ex.key_table is None:
# NOTE(ivc): 'key_table' is provided by 'oslo.db' [1]
# only for a limited set of database backends (i.e.
# MySQL and PostgreSQL). Other database backends
# (including SQLite) would have 'key_table' set to None.
# We emulate the 'key_table' support for such database
# backends.
#
# [1] https://github.com/openstack/oslo.db/blob/3fadd5a
# /oslo_db/sqlalchemy/exc_filters.py#L190-L203
if not Trunk.get_object(self.obj_context,
id=self.trunk_id):
ex.key_table = Trunk.db_model.__tablename__
if ex.key_table == Trunk.db_model.__tablename__:
raise t_exc.TrunkNotFound(trunk_id=self.trunk_id)
raise n_exc.PortNotFound(port_id=self.port_id)
except o_exc.NeutronDbObjectDuplicateEntry:
raise t_exc.DuplicateSubPort(
segmentation_type=self.segmentation_type,
segmentation_id=self.segmentation_id,
trunk_id=self.trunk_id)
@base.NeutronObjectRegistry.register
class Trunk(base.NeutronDbObject):
# Version 1.0: Initial version
# Version 1.1: Changed tenant_id to project_id
VERSION = '1.1'
db_model = models.Trunk
fields = {
'admin_state_up': obj_fields.BooleanField(),
'id': common_types.UUIDField(),
'project_id': obj_fields.StringField(),
'name': obj_fields.StringField(),
'port_id': common_types.UUIDField(),
'status': obj_fields.StringField(),
'sub_ports': obj_fields.ListOfObjectsField(SubPort.__name__),
}
fields_no_update = ['project_id', 'port_id']
synthetic_fields = ['sub_ports']
def create(self):
with self.db_context_writer(self.obj_context):
sub_ports = []
if self.obj_attr_is_set('sub_ports'):
sub_ports = self.sub_ports
try:
super(Trunk, self).create()
except o_db_exc.DBReferenceError:
raise n_exc.PortNotFound(port_id=self.port_id)
if sub_ports:
for sub_port in sub_ports:
sub_port.trunk_id = self.id
sub_port.create()
self.sub_ports.append(sub_port)
self.obj_reset_changes(['sub_ports'])
def update(self, **kwargs):
self.update_fields(kwargs)
super(Trunk, self).update()
# TODO(hichihara): For tag mechanism. This will be removed in bug/1704137
def to_dict(self):
_dict = super(Trunk, self).to_dict()
try:
_dict['tags'] = [t.tag for t in self.db_obj.standard_attr.tags]
except AttributeError:
# AttrtibuteError can be raised when accessing self.db_obj
# or self.db_obj.standard_attr
pass
return _dict
def obj_make_compatible(self, primitive, target_version):
_target_version = versionutils.convert_version_to_tuple(target_version)
if _target_version < (1, 1):
primitive['tenant_id'] = primitive.pop('project_id')