placement: add nested resource providers
Adds initial support for storing the relationship between parent and child resource providers. Nested resource providers are essential for expressing certain types of resources -- in particular SR-IOV physical functions and certain SR-IOV fully-programmable gate arrays. The resources that these providers expose are of resource class SRIOV_NET_VF and we will need a way of indicating that the physical function providing these virtual function resources is tagged with certain traits (representing vendor_id, product_id or the physical network the PF is attached to). The compute host is a resource provider which has an SR-IOV-enabled physical function (NIC) as a child resource provider. The physical function has an inventory containing some total amount of SRIOV_NET_VF resources. These SRIOV_NET_VF resources are allocated to zero or more consumers (instances) on the compute host. compute host (parent resource provider) | | SR-IOV PF (child resource provider) : / \ / \ VF1 VF2 (inventory of child provider) The resource provider model gets two new fields: - root_provider_uuid: The "top" or "root" of the tree of nested providers - parent_provider_uuid: The immediate parent of the provider, or None if the provider is a root provider. The database schema adds two new columns to the resource_providers table that contain the internal integer IDs that correspond to the user-facing UUID values: - root_provider_id - parent_provider_id The root_provider_uuid field is non-nullable in the ResourceProvider object definition, and this code includes an online data migration to automatically populate the root_provider_id field with the value of the resource_providers.id field for any resource providers already in the DB. The root_provider_id field value is populated automatically when a provider is created. If the parent provider UUID is set, then the root_provider_id is set to the root_provider_id value of the parent. If parent is unset, root_provider_id is set to the value of the id attribute of the provider being created. The corresponding UUID values for root and parent provider are fetched in the queries that retrieves resource provider data using two self-referential joins. The root_provider_id column allows us to do extremely quick lookups of an entire tree of providers without needing to perform any recursive database queries. Logic in this patch ensures that no resource provider can be deleted if any of its children have any allocations active on them. We also check to ensure that when created or updated, a resource provider's parent provider UUID actually points to an existing provider. It's important to point out that qualitative trait information is only associated with a resource provider entity, not the resources that resource provider has in its inventory. This is the reason why nested resource providers are necessary. In the case of things like NUMA nodes or SRIOV physical functions, if a compute host had multiple SRIOV physical functions, each associated with a different network trait, there would be no way to differentiate between the SRIOV_NET_VF resources that those multiple SRIOV physical functions provided if the containing compute host had a single inventory item containing the total number of VFs exposed by both PFs. Change-Id: I2d8df57f77a03cde898d9ec792c5d59b75f61204 blueprint: nested-resource-providers Co-Authored-By: Moshe Levi <moshele@mellanox.com>
This commit is contained in:
parent
beb17c6b5c
commit
77ef172f65
nova/db/sqlalchemy
50
nova/db/sqlalchemy/api_migrations/migrate_repo/versions/051_nested_resource_providers.py
Normal file
50
nova/db/sqlalchemy/api_migrations/migrate_repo/versions/051_nested_resource_providers.py
Normal file
@ -0,0 +1,50 @@
|
||||
# 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 sqlalchemy import Column
|
||||
from sqlalchemy import ForeignKey
|
||||
from sqlalchemy import Index
|
||||
from sqlalchemy import Integer
|
||||
from sqlalchemy import MetaData
|
||||
from sqlalchemy import Table
|
||||
|
||||
|
||||
def upgrade(migrate_engine):
|
||||
meta = MetaData()
|
||||
meta.bind = migrate_engine
|
||||
|
||||
resource_providers = Table('resource_providers', meta, autoload=True)
|
||||
columns_to_add = [
|
||||
('root_provider_id',
|
||||
Column('root_provider_id', Integer,
|
||||
ForeignKey('resource_providers.id'))),
|
||||
('parent_provider_id',
|
||||
Column('parent_provider_id', Integer,
|
||||
ForeignKey('resource_providers.id'))),
|
||||
]
|
||||
for col_name, column in columns_to_add:
|
||||
if not hasattr(resource_providers.c, col_name):
|
||||
resource_providers.create_column(column)
|
||||
|
||||
indexed_columns = set()
|
||||
for idx in resource_providers.indexes:
|
||||
for c in idx.columns:
|
||||
indexed_columns.add(c.name)
|
||||
|
||||
if 'root_provider_id' not in indexed_columns:
|
||||
index = Index('resource_providers_root_provider_id_idx',
|
||||
resource_providers.c.root_provider_id)
|
||||
index.create()
|
||||
if 'parent_provider_id' not in indexed_columns:
|
||||
index = Index('resource_providers_parent_provider_id_idx',
|
||||
resource_providers.c.parent_provider_id)
|
||||
index.create()
|
@ -293,6 +293,10 @@ class ResourceProvider(API_BASE):
|
||||
schema.UniqueConstraint('uuid',
|
||||
name='uniq_resource_providers0uuid'),
|
||||
Index('resource_providers_name_idx', 'name'),
|
||||
Index('resource_providers_root_provider_id_idx',
|
||||
'root_provider_id'),
|
||||
Index('resource_providers_parent_provider_id_idx',
|
||||
'parent_provider_id'),
|
||||
schema.UniqueConstraint('name',
|
||||
name='uniq_resource_providers0name')
|
||||
)
|
||||
@ -301,6 +305,13 @@ class ResourceProvider(API_BASE):
|
||||
uuid = Column(String(36), nullable=False)
|
||||
name = Column(Unicode(200), nullable=True)
|
||||
generation = Column(Integer, default=0)
|
||||
# Represents the root of the "tree" that the provider belongs to
|
||||
root_provider_id = Column(Integer, ForeignKey('resource_providers.id'),
|
||||
nullable=True)
|
||||
# The immediate parent provider of this provider, or NULL if there is no
|
||||
# parent. If parent_provider_id == NULL then root_provider_id == id
|
||||
parent_provider_id = Column(Integer, ForeignKey('resource_providers.id'),
|
||||
nullable=True)
|
||||
|
||||
|
||||
class Inventory(API_BASE):
|
||||
|
Loading…
x
Reference in New Issue
Block a user