Merge "implementation of bp disable-enable-device"
This commit is contained in:
commit
ab8b851424
@ -13,19 +13,25 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from http import HTTPStatus
|
||||
import pecan
|
||||
import wsme
|
||||
from wsme import types as wtypes
|
||||
|
||||
from oslo_log import log
|
||||
|
||||
from cyborg.accelerator.common import exception
|
||||
from cyborg import api
|
||||
from cyborg.api.controllers import base
|
||||
from cyborg.api.controllers import link
|
||||
from cyborg.api.controllers import types
|
||||
from cyborg.api.controllers.v2 import versions
|
||||
from cyborg.api import expose
|
||||
from cyborg.common import authorize_wsgi
|
||||
from cyborg.common import placement_client
|
||||
from cyborg import objects
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
@ -56,6 +62,9 @@ class Device(base.APIBase):
|
||||
hostname = wtypes.text
|
||||
"""The hostname of the device"""
|
||||
|
||||
status = wtypes.text
|
||||
"""The status of the device"""
|
||||
|
||||
links = wsme.wsattr([link.Link], readonly=True)
|
||||
"""A list containing a self link"""
|
||||
|
||||
@ -69,6 +78,9 @@ class Device(base.APIBase):
|
||||
@classmethod
|
||||
def convert_with_links(cls, obj_device):
|
||||
api_device = cls(**obj_device.as_dict())
|
||||
# return status filed from microversion of 2.3
|
||||
if not api.request.version.minor >= versions.MINOR_3_DEVICE_STATUS:
|
||||
delattr(api_device, 'status')
|
||||
api_device.links = [
|
||||
link.Link.make_link('self', pecan.request.public_url,
|
||||
'devices', api_device.uuid)
|
||||
@ -93,6 +105,8 @@ class DeviceCollection(base.APIBase):
|
||||
class DevicesController(base.CyborgController):
|
||||
"""REST controller for Devices."""
|
||||
|
||||
_custom_actions = {'disable': ['POST'], 'enable': ['POST']}
|
||||
|
||||
@authorize_wsgi.authorize_wsgi("cyborg:device", "get_one")
|
||||
@expose.expose(Device, wtypes.text)
|
||||
def get_one(self, uuid):
|
||||
@ -128,3 +142,51 @@ class DevicesController(base.CyborgController):
|
||||
obj_devices = objects.Device.list(context, filters=filters_dict)
|
||||
LOG.info('[devices:get_all] Returned: %s', obj_devices)
|
||||
return DeviceCollection.convert_with_links(obj_devices)
|
||||
|
||||
@authorize_wsgi.authorize_wsgi("cyborg:device", "disable")
|
||||
@expose.expose(None, wtypes.text, types.uuid,
|
||||
status_code=HTTPStatus.OK)
|
||||
def disable(self, uuid):
|
||||
context = pecan.request.context
|
||||
device = objects.Device.get(context, uuid)
|
||||
device.status = 'maintaining'
|
||||
device.save(context)
|
||||
# update resource provider inventories
|
||||
client = placement_client.PlacementClient()
|
||||
deployable = objects.Deployable.get_by_id(context, device.id)
|
||||
filters = {'deployable_id': deployable.id, 'key': 'rc'}
|
||||
attributes = objects.Attribute.get_by_filter(context, filters)
|
||||
if attributes:
|
||||
att_type = attributes[0].value
|
||||
else:
|
||||
raise exception.ResourceNotFound(
|
||||
resource='Attribute',
|
||||
msg='with deployable_id=%s,key=%s' % (deployable.id, 'rc'))
|
||||
client.update_rp_inventory_reserved(
|
||||
deployable.rp_uuid, att_type,
|
||||
deployable.num_accelerators,
|
||||
deployable.num_accelerators)
|
||||
|
||||
@authorize_wsgi.authorize_wsgi("cyborg:device", "enable")
|
||||
@expose.expose(None, wtypes.text, types.uuid,
|
||||
status_code=HTTPStatus.OK)
|
||||
def enable(self, uuid):
|
||||
context = pecan.request.context
|
||||
device = objects.Device.get(context, uuid)
|
||||
device.status = 'enabled'
|
||||
device.save(context)
|
||||
# update resource provider inventories
|
||||
client = placement_client.PlacementClient()
|
||||
deployable = objects.Deployable.get_by_id(context, device.id)
|
||||
filters = {'deployable_id': deployable.id, 'key': 'rc'}
|
||||
attributes = objects.Attribute.get_by_filter(context, filters)
|
||||
if attributes:
|
||||
att_type = attributes[0].value
|
||||
else:
|
||||
raise exception.ResourceNotFound(
|
||||
resource='Attribute',
|
||||
msg='with deployable_id=%s,key=%s' % (deployable.id, 'rc'))
|
||||
client.update_rp_inventory_reserved(
|
||||
deployable.rp_uuid, att_type,
|
||||
deployable.num_accelerators,
|
||||
0)
|
||||
|
@ -25,10 +25,11 @@ BASE_VERSION = 2
|
||||
# v2.0: Initial minor version.
|
||||
# v2.1: Add project_id for arq patch
|
||||
# v2.2: Support getting device profile by name (newly introduced) and uuid.
|
||||
# v2.3: Add status info for device API.
|
||||
MINOR_0_INITIAL_VERSION = 0
|
||||
MINOR_1_PROJECT_ID = 1
|
||||
MINOR_2_DP_BY_NAME = 2
|
||||
|
||||
MINOR_3_DEVICE_STATUS = 3
|
||||
|
||||
# When adding another version, update:
|
||||
# - MINOR_MAX_VERSION
|
||||
@ -36,7 +37,7 @@ MINOR_2_DP_BY_NAME = 2
|
||||
# explanation of what changed in the new version
|
||||
|
||||
|
||||
MINOR_MAX_VERSION = MINOR_2_DP_BY_NAME
|
||||
MINOR_MAX_VERSION = MINOR_3_DEVICE_STATUS
|
||||
|
||||
# String representations of the minor and maximum versions
|
||||
_MIN_VERSION_STRING = '{}.{}'.format(BASE_VERSION, MINOR_0_INITIAL_VERSION)
|
||||
|
@ -37,3 +37,11 @@ Changed ``device_profile_uuid`` to ``device_profile_name_or_uuid`` in
|
||||
name (newly introduced) and uuid.
|
||||
|
||||
- GET /v2/device_profiles/{device_profile_name_or_uuid}
|
||||
|
||||
2.3
|
||||
---
|
||||
|
||||
Add new status info for list Device and get device API.
|
||||
|
||||
- GET: /devices
|
||||
- GET: /devices/{uuid}
|
||||
|
@ -66,6 +66,10 @@ DEVICE_TYPE = (DEVICE_GPU, DEVICE_FPGA, DEVICE_AICHIP, DEVICE_QAT, DEVICE_NIC,
|
||||
DEVICE_SSD)
|
||||
|
||||
|
||||
# Device type
|
||||
DEVICE_STATUS = ("enabled", "maintaining")
|
||||
|
||||
|
||||
# Attach handle type
|
||||
# 'TEST_PCI': used by fake driver, ignored by Nova virt driver.
|
||||
ATTACH_HANDLE_TYPES = (AH_TYPE_PCI, AH_TYPE_MDEV, AH_TYPE_TEST_PCI) = (
|
||||
|
@ -148,7 +148,7 @@ class PlacementClient(object):
|
||||
|
||||
def update_inventory(
|
||||
self, resource_provider_uuid, inventories,
|
||||
resource_provider_generation=None):
|
||||
resource_provider_generation=None, version=None):
|
||||
if resource_provider_generation is None:
|
||||
resource_provider_generation = self.get_resource_provider(
|
||||
resource_provider_uuid=resource_provider_uuid)['generation']
|
||||
@ -158,7 +158,7 @@ class PlacementClient(object):
|
||||
'inventories': inventories
|
||||
}
|
||||
try:
|
||||
return self.put(url, body).json()
|
||||
return self.put(url, body, version=version).json()
|
||||
except ks_exc.NotFound:
|
||||
raise exception.PlacementResourceProviderNotFound(
|
||||
resource_provider=resource_provider_uuid)
|
||||
@ -358,3 +358,7 @@ class PlacementClient(object):
|
||||
elif resp.status_code == 204:
|
||||
LOG.info("Successfully delete trait %(trait_name).", {
|
||||
"trait_name", name})
|
||||
|
||||
def update_rp_inventory_reserved(self, rp_uuid, resource, total, reserved):
|
||||
update_inventory = {resource: {"total": total, "reserved": reserved}}
|
||||
self.update_inventory(rp_uuid, update_inventory, version='1.26')
|
||||
|
@ -48,6 +48,12 @@ device_policies = [
|
||||
policy.RuleDefault('cyborg:device:get_all',
|
||||
'rule:allow',
|
||||
description='Retrieve all device records'),
|
||||
policy.RuleDefault('cyborg:device:disable',
|
||||
'rule:admin_api',
|
||||
description='Disable a device'),
|
||||
policy.RuleDefault('cyborg:device:enable',
|
||||
'rule:admin_api',
|
||||
description='Enable a device'),
|
||||
]
|
||||
|
||||
deployable_policies = [
|
||||
|
@ -0,0 +1,21 @@
|
||||
"""add-device-status
|
||||
|
||||
Revision ID: 6c77bd6afea5
|
||||
Revises: 4cc1d79978fc
|
||||
Create Date: 2023-08-15 23:05:31.918963
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '6c77bd6afea5'
|
||||
down_revision = '4cc1d79978fc'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
|
||||
def upgrade():
|
||||
new_column = sa.Column('status', sa.Enum('enabled', 'maintaining'),
|
||||
nullable=False, default='enabled')
|
||||
op.add_column('devices', new_column)
|
@ -88,6 +88,8 @@ class Device(Base):
|
||||
std_board_info = Column(Text, nullable=True)
|
||||
vendor_board_info = Column(Text, nullable=True)
|
||||
hostname = Column(String(255), nullable=False)
|
||||
status = Column(Enum("enabled", "maintaining", name='device_status'),
|
||||
default='enabled', nullable=False)
|
||||
|
||||
|
||||
class Deployable(Base):
|
||||
|
@ -29,7 +29,8 @@ LOG = logging.getLogger(__name__)
|
||||
class Device(base.CyborgObject, object_base.VersionedObjectDictCompat):
|
||||
# Version 1.0: Initial version
|
||||
# Version 1.1: Add AICHIP, GENERIC type
|
||||
VERSION = '1.1'
|
||||
# Version 1.2: Add status field
|
||||
VERSION = '1.2'
|
||||
|
||||
dbapi = dbapi.get_instance()
|
||||
|
||||
@ -43,6 +44,8 @@ class Device(base.CyborgObject, object_base.VersionedObjectDictCompat):
|
||||
'std_board_info': object_fields.StringField(nullable=True),
|
||||
'vendor_board_info': object_fields.StringField(nullable=True),
|
||||
'hostname': object_fields.StringField(nullable=False),
|
||||
'status': object_fields.EnumField(valid_values=constants.DEVICE_STATUS,
|
||||
nullable=False, default="enabled"),
|
||||
}
|
||||
|
||||
def create(self, context):
|
||||
|
Loading…
Reference in New Issue
Block a user