Browse Source
Added a new port extension: device profile (``port_device_profile``). This extension adds the "device_profile" parameter to the "port" API and specifies the device profile per port. This parameter is a string. This parameter is passed to Nova and Nova retrieves the requested device profile from Cyborg. Reference: https://docs.openstack.org/api-ref/accelerator/v2/index.html# device-profiles For backwards compatibility, this parameter will be "None" by default. Closes-Bug: #1906602 Depends-On: https://review.opendev.org/c/openstack/neutron-lib/+/767586 Change-Id: I1202a8388e64ae4270ef4ca118993504ae7c1731changes/22/767922/9
20 changed files with 318 additions and 9 deletions
@ -1 +1 @@
|
||||
26d1e9f5c766 |
||||
1e0744e4ffea |
||||
|
@ -0,0 +1,43 @@
|
||||
# Copyright 2020 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 |
||||
from neutron_lib.db import constants as db_const |
||||
import sqlalchemy as sa |
||||
|
||||
|
||||
"""port_device_profile |
||||
|
||||
Revision ID: 1e0744e4ffea |
||||
Revises: 26d1e9f5c766 |
||||
Create Date: 2020-12-18 10:12:14.865465 |
||||
|
||||
""" |
||||
|
||||
# revision identifiers, used by Alembic. |
||||
revision = '1e0744e4ffea' |
||||
down_revision = '26d1e9f5c766' |
||||
|
||||
|
||||
def upgrade(): |
||||
op.create_table('portdeviceprofiles', |
||||
sa.Column('port_id', |
||||
sa.String(length=db_const.UUID_FIELD_SIZE), |
||||
sa.ForeignKey('ports.id', ondelete='CASCADE'), |
||||
primary_key=True), |
||||
sa.Column('device_profile', |
||||
sa.String(255), |
||||
nullable=True) |
||||
) |
@ -0,0 +1,34 @@
|
||||
# Copyright 2020 Red Hat, 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.db import constants as db_const |
||||
from neutron_lib.db import model_base |
||||
import sqlalchemy as sa |
||||
|
||||
from neutron.db import models_v2 |
||||
|
||||
|
||||
class PortDeviceProfile(model_base.BASEV2): |
||||
__tablename__ = 'portdeviceprofiles' |
||||
port_id = sa.Column(sa.String(db_const.UUID_FIELD_SIZE), |
||||
sa.ForeignKey('ports.id', ondelete='CASCADE'), |
||||
primary_key=True) |
||||
device_profile = sa.Column('device_profile', sa.String(length=255)) |
||||
port = sa.orm.relationship( |
||||
models_v2.Port, load_on_pending=True, |
||||
backref=sa.orm.backref('device_profile', uselist=False, |
||||
cascade='delete', lazy='joined')) |
||||
|
||||
revises_on_change = ('port', ) |
@ -0,0 +1,38 @@
|
||||
# Copyright (c) 2020 Red Hat, Inc. |
||||
# |
||||
# 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.api.definitions import port_device_profile as pdp |
||||
|
||||
from neutron.objects.port.extensions import port_device_profile as pdp_obj |
||||
|
||||
|
||||
class PortDeviceProfileMixin(object): |
||||
"""Mixin class to add device profile (Cyborg) to a port""" |
||||
|
||||
def _process_create_port(self, context, data, result): |
||||
if not data.get(pdp.DEVICE_PROFILE): |
||||
result[pdp.DEVICE_PROFILE] = None |
||||
return |
||||
|
||||
obj = pdp_obj.PortDeviceProfile( |
||||
context, port_id=result['id'], |
||||
device_profile=data[pdp.DEVICE_PROFILE]) |
||||
obj.create() |
||||
result[pdp.DEVICE_PROFILE] = data[pdp.DEVICE_PROFILE] |
||||
|
||||
def _extend_port_dict(self, port_db, result): |
||||
if port_db.device_profile: |
||||
result[pdp.DEVICE_PROFILE] = port_db.device_profile.device_profile |
||||
else: |
||||
result[pdp.DEVICE_PROFILE] = None |
@ -0,0 +1,20 @@
|
||||
# Copyright (c) 2020 Red Hat, Inc. |
||||
# |
||||
# 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.api.definitions import port_device_profile |
||||
from neutron_lib.api import extensions as api_extensions |
||||
|
||||
|
||||
class Port_device_profile(api_extensions.APIExtensionDescriptor): |
||||
api_definition = port_device_profile |
@ -0,0 +1,36 @@
|
||||
# Copyright (c) 2020 Red Hat, Inc. |
||||
# |
||||
# 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.objects import common_types |
||||
from oslo_versionedobjects import fields as obj_fields |
||||
|
||||
from neutron.db.models import port_device_profile |
||||
from neutron.objects import base |
||||
|
||||
|
||||
@base.NeutronObjectRegistry.register |
||||
class PortDeviceProfile(base.NeutronDbObject): |
||||
# Version 1.0: Initial version |
||||
VERSION = '1.0' |
||||
|
||||
db_model = port_device_profile.PortDeviceProfile |
||||
|
||||
primary_keys = ['port_id'] |
||||
|
||||
fields = { |
||||
'port_id': common_types.UUIDField(), |
||||
'device_profile': obj_fields.StringField(nullable=True), |
||||
} |
||||
|
||||
foreign_keys = {'Port': {'port_id': 'id'}} |
@ -0,0 +1,42 @@
|
||||
# Copyright 2020 Red Hat, 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.api.definitions import port_device_profile as pdp |
||||
from neutron_lib.plugins.ml2 import api |
||||
from oslo_log import log as logging |
||||
|
||||
from neutron.db import port_device_profile_db |
||||
|
||||
|
||||
LOG = logging.getLogger(__name__) |
||||
|
||||
|
||||
class PortDeviceProfileExtensionDriver( |
||||
api.ExtensionDriver, port_device_profile_db.PortDeviceProfileMixin): |
||||
|
||||
_supported_extension_alias = pdp.ALIAS |
||||
|
||||
def initialize(self): |
||||
LOG.info('PortDeviceProfileExtensionDriver initialization complete') |
||||
|
||||
@property |
||||
def extension_alias(self): |
||||
return self._supported_extension_alias |
||||
|
||||
def process_create_port(self, context, data, result): |
||||
self._process_create_port(context, data, result) |
||||
|
||||
def extend_port_dict(self, session, port_db, result): |
||||
self._extend_port_dict(port_db, result) |
@ -0,0 +1,58 @@
|
||||
# Copyright (c) 2020 Red Hat, Inc. |
||||
# |
||||
# 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. |
||||
|
||||
import ddt |
||||
from neutron_lib.api.definitions import port_device_profile as apidef |
||||
from neutron_lib.db import api as db_api |
||||
|
||||
from neutron.db import db_base_plugin_v2 |
||||
from neutron.db import port_device_profile_db as pdp_db |
||||
from neutron.tests.unit.db import test_db_base_plugin_v2 |
||||
|
||||
|
||||
class PortDeviceProfileExtensionTestPlugin( |
||||
db_base_plugin_v2.NeutronDbPluginV2, |
||||
pdp_db.PortDeviceProfileMixin): |
||||
"""Test plugin to mixin the port device profile extension.""" |
||||
|
||||
supported_extension_aliases = [apidef.ALIAS] |
||||
|
||||
def create_port(self, context, port): |
||||
with db_api.CONTEXT_WRITER.using(context): |
||||
new_port = super(PortDeviceProfileExtensionTestPlugin, |
||||
self).create_port(context, port) |
||||
self._process_create_port(context, port['port'], new_port) |
||||
return new_port |
||||
|
||||
|
||||
@ddt.ddt |
||||
class PortDeviceProfileExtensionTestCase( |
||||
test_db_base_plugin_v2.NeutronDbPluginV2TestCase): |
||||
"""Test API extension numa_affinity_policy attributes.""" |
||||
|
||||
def setUp(self, *args): |
||||
plugin = ('neutron.tests.unit.extensions.test_port_device_profile.' |
||||
'PortDeviceProfileExtensionTestPlugin') |
||||
super(PortDeviceProfileExtensionTestCase, self).setUp(plugin=plugin) |
||||
|
||||
@ddt.data('device_profile_1', None) |
||||
def test_create_and_check_port_device_profile(self, device_profile): |
||||
keys = [('name', 'name_1'), |
||||
('admin_state_up', True), |
||||
('status', self.port_create_status), |
||||
('device_profile', device_profile)] |
||||
with self.port(name='name_1', device_profile=device_profile) as port: |
||||
for k, v in keys: |
||||
self.assertEqual(v, port['port'][k]) |
||||
return port |
@ -0,0 +1,13 @@
|
||||
--- |
||||
features: |
||||
- | |
||||
Introduce the attribute ``port_device_profile`` to ports that |
||||
specifies the device profile needed per port. This parameter is |
||||
a string. This parameter is passed to Nova and Nova retrieves |
||||
the requested profile from Cyborg: |
||||
`Device profiles <https://docs.openstack.org/api-ref/accelerator/v2/index.html#device-profiles>`_. |
||||
|
||||
Operators can turn on this feature via the configuration option:: |
||||
|
||||
[ml2] |
||||
extension_drivers = port_device_profile |
Loading…
Reference in new issue