Merge "decouple neutron db models and ovo for neutron-lib"
This commit is contained in:
commit
9b7cd99a76
143
specs/rocky/neutronlib-decouple-models.rst
Normal file
143
specs/rocky/neutronlib-decouple-models.rst
Normal file
@ -0,0 +1,143 @@
|
||||
..
|
||||
This work is licensed under a Creative Commons Attribution 3.0 Unported
|
||||
License.
|
||||
|
||||
http://creativecommons.org/licenses/by/3.0/legalcode
|
||||
|
||||
==================================================
|
||||
Decoupling database imports/access for neutron-lib
|
||||
==================================================
|
||||
|
||||
This work is not related to an enhancement request and therefore doesn't have
|
||||
a RFE. Rather the intent herein is to discuss how we decouple ``neutron.db``
|
||||
and related database imports/access as part of the overall neutron-lib effort.
|
||||
|
||||
Current neutron database access can be broken into the following high-level
|
||||
categories:
|
||||
|
||||
- Database API & Utilities
|
||||
- Core & Extension Database Mixins
|
||||
- Database Resource Models
|
||||
- Database Migration
|
||||
|
||||
As the database access patterns span a wide range of logic/code, a set of specs
|
||||
will be proposed each focusing on a single access pattern.
|
||||
|
||||
This spec specifically address Database Resource Model access.
|
||||
|
||||
For current neutron-lib related blueprints, see [1]_ and [2]_.
|
||||
|
||||
|
||||
Problem Description
|
||||
===================
|
||||
|
||||
As part of our neutron-lib effort, we need to decouple out-of-tree networking
|
||||
projects that depend on (e.g. ``import``) neutron. However, today a large
|
||||
number of neutron consumers import database related neutron modules including
|
||||
models [3]_ [4]_.
|
||||
|
||||
Access to database models by consumers is typically used for:
|
||||
|
||||
- Defining relationships between neutron and other project models. Note that
|
||||
while string names can be used when defining a relationship, this is not
|
||||
a viable solution for all cases due to [8]_.
|
||||
- Building queries using models and/or their fields. With the introduction of
|
||||
versioned objects, consumers can effectively query using methods on objects.
|
||||
Therefore the deliverables of this spec enable such an approach by making
|
||||
versioned objects accessible via neutron-lib.
|
||||
- Importing models to have them available for database tools. This includes
|
||||
database migration tools, so while this spec doesn't directly solve
|
||||
the migration access, it needs to lay a foundation for it (covered in a
|
||||
separate spec).
|
||||
|
||||
The intent of this spec is to propose how we can provide access to database
|
||||
models without direct neutron imports by means of a bridge in neutron-lib
|
||||
thereby breaking consumer's dependencies on neutron's internal database
|
||||
models.
|
||||
|
||||
Proposed Change
|
||||
===============
|
||||
|
||||
While one foreseeable solution would be to publish models using
|
||||
discoverable entry points (stevedore) or register them using a factory,
|
||||
these models must be versioned to allow consumers to determine compatibility.
|
||||
Without versioning the underlying model can change without the consumers
|
||||
knowledge, thereby breaking them.
|
||||
|
||||
Implementing versioned models is simple enough with some new facility, however
|
||||
we already have such a versioning scheme; neutron versioned objects. Neutron
|
||||
objects already contain a reference to the underlying model as well as a
|
||||
version number that's incremented as the model changes [5]_. Therefore if we
|
||||
can provide a way for consumers to get at neutron objects, they have access to
|
||||
a version, corresponding model, etc..
|
||||
|
||||
This spec proposes we use a simple entry point scheme whereby all versioned
|
||||
objects are defined as entry points that can then be looked up and handed
|
||||
out by some bridging logic in neutron-lib. More specifically:
|
||||
|
||||
- Neutron versioned objects can be "published" via an entry point in
|
||||
``setup.cfg`` where each entry point is a versioned object class. This
|
||||
exposes the objects to neutron-lib that can be discovered and loaded with
|
||||
``stevedore``.
|
||||
- A simple API in neutron-lib allowing consumers to retrieve versioned objects
|
||||
at runtime. In it's basic form a consumer asks for an object of type ``X``,
|
||||
whereupon neutron-lib looks it up from the entry point and returns the
|
||||
concrete object class to the consumer (e.g. ``load_class('Port')`` looks up
|
||||
and returns the versioned object class for ``Port``).
|
||||
- If consumers need to create instances of the versioned object(s) returned
|
||||
from neutron-lib, they can invoke it's constructor directly to create a
|
||||
new instance. Since versioned object constructor's are based on the object's
|
||||
``fields`` and the ``fields`` are tied to the model, consumers can query
|
||||
the object's ``VERSION`` to determine compatibility with the constructor.
|
||||
|
||||
The snippet below illustrates the API from a consumers point of view::
|
||||
|
||||
from neutron_lib.objects import registry
|
||||
# .. other imports
|
||||
|
||||
# Loading the object from neutron-lib uses stevedore to find the requested
|
||||
# object. Also note that under the covers the model is imported since the
|
||||
# concrete versioned object must import the model to ref it.
|
||||
port_ovo = registry.load_class(constants.PORT)
|
||||
|
||||
if port_ovo.VERSION > '1.1':
|
||||
raise UnsupportedException("Can't use port objects greater than 1.1")
|
||||
|
||||
# It's just an OVO class, so we can use it's static/class methods directly
|
||||
a_port = port_ovo.get_object(...)
|
||||
|
||||
# Create a new versioned object; it's VERSION determines the constructor's
|
||||
# supported kwargs so consumers can detect compatibility
|
||||
new_port = port_ovo(context, project_id=...)
|
||||
|
||||
As mentioned earlier, while this solution doesn't completely solve database
|
||||
migration access, it paves the way as we now have a way to find and load
|
||||
versioned objects which must import the respective model.
|
||||
|
||||
Using this scheme, we should be able to eliminate consumers imports for:
|
||||
|
||||
- Existing ``neutron.objects`` imports [6]_. Consumers now get their object from
|
||||
the neutron-lib API provided herein.
|
||||
- Building queries; version objects have methods allowing consumers to
|
||||
effectively query and there should be no need to build direct queries in
|
||||
consumers otherwise.
|
||||
|
||||
In addition, the rollout of this functionality should have minimal impact to
|
||||
the main code paths; the only real change in neutron is to expose the objects
|
||||
via ``setup.cfg``. The neutron-lib logic can be implemented, tested and rolled
|
||||
out independently thereby reducing risk.
|
||||
|
||||
For a sample proof of concept, see the patches on [7]_ that use this approach
|
||||
to remove/use versioned objects in a few of the vmware-nsx modules.
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://blueprints.launchpad.net/neutron/+spec/neutron-lib-networking-ovn
|
||||
.. [2] https://blueprints.launchpad.net/neutron/+spec/neutron-lib-dynr
|
||||
.. [3] http://codesearch.openstack.org/?q=from%20neutron.db.model
|
||||
.. [4] http://codesearch.openstack.org/?q=from%20neutron.db%20import%20model
|
||||
.. [5] https://docs.openstack.org/neutron/latest/contributor/internals/objects_usage.html
|
||||
.. [6] http://codesearch.openstack.org/?q=from%20neutron.objects
|
||||
.. [7] https://review.openstack.org/#/q/topic:bp/neutronlib-decouple-db
|
||||
.. [8] https://stackoverflow.com/questions/45534903/python-sqlalchemy-attributeerror-mapper
|
Loading…
x
Reference in New Issue
Block a user