implementation of bp disable-enable-device
add disable and enable device api Change-Id: I3d2f7ac3b8de29bc0c3125b7340d9a90cffa7127
This commit is contained in:
parent
4d329240f9
commit
ef7ce3f2c3
@ -13,19 +13,25 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from http import HTTPStatus
|
||||||
import pecan
|
import pecan
|
||||||
import wsme
|
import wsme
|
||||||
from wsme import types as wtypes
|
from wsme import types as wtypes
|
||||||
|
|
||||||
from oslo_log import log
|
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 base
|
||||||
from cyborg.api.controllers import link
|
from cyborg.api.controllers import link
|
||||||
from cyborg.api.controllers import types
|
from cyborg.api.controllers import types
|
||||||
|
from cyborg.api.controllers.v2 import versions
|
||||||
from cyborg.api import expose
|
from cyborg.api import expose
|
||||||
from cyborg.common import authorize_wsgi
|
from cyborg.common import authorize_wsgi
|
||||||
|
from cyborg.common import placement_client
|
||||||
from cyborg import objects
|
from cyborg import objects
|
||||||
|
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ -56,6 +62,9 @@ class Device(base.APIBase):
|
|||||||
hostname = wtypes.text
|
hostname = wtypes.text
|
||||||
"""The hostname of the device"""
|
"""The hostname of the device"""
|
||||||
|
|
||||||
|
status = wtypes.text
|
||||||
|
"""The status of the device"""
|
||||||
|
|
||||||
links = wsme.wsattr([link.Link], readonly=True)
|
links = wsme.wsattr([link.Link], readonly=True)
|
||||||
"""A list containing a self link"""
|
"""A list containing a self link"""
|
||||||
|
|
||||||
@ -69,6 +78,9 @@ class Device(base.APIBase):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def convert_with_links(cls, obj_device):
|
def convert_with_links(cls, obj_device):
|
||||||
api_device = cls(**obj_device.as_dict())
|
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 = [
|
api_device.links = [
|
||||||
link.Link.make_link('self', pecan.request.public_url,
|
link.Link.make_link('self', pecan.request.public_url,
|
||||||
'devices', api_device.uuid)
|
'devices', api_device.uuid)
|
||||||
@ -93,6 +105,8 @@ class DeviceCollection(base.APIBase):
|
|||||||
class DevicesController(base.CyborgController):
|
class DevicesController(base.CyborgController):
|
||||||
"""REST controller for Devices."""
|
"""REST controller for Devices."""
|
||||||
|
|
||||||
|
_custom_actions = {'disable': ['POST'], 'enable': ['POST']}
|
||||||
|
|
||||||
@authorize_wsgi.authorize_wsgi("cyborg:device", "get_one")
|
@authorize_wsgi.authorize_wsgi("cyborg:device", "get_one")
|
||||||
@expose.expose(Device, wtypes.text)
|
@expose.expose(Device, wtypes.text)
|
||||||
def get_one(self, uuid):
|
def get_one(self, uuid):
|
||||||
@ -128,3 +142,51 @@ class DevicesController(base.CyborgController):
|
|||||||
obj_devices = objects.Device.list(context, filters=filters_dict)
|
obj_devices = objects.Device.list(context, filters=filters_dict)
|
||||||
LOG.info('[devices:get_all] Returned: %s', obj_devices)
|
LOG.info('[devices:get_all] Returned: %s', obj_devices)
|
||||||
return DeviceCollection.convert_with_links(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.0: Initial minor version.
|
||||||
# v2.1: Add project_id for arq patch
|
# v2.1: Add project_id for arq patch
|
||||||
# v2.2: Support getting device profile by name (newly introduced) and uuid.
|
# 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_0_INITIAL_VERSION = 0
|
||||||
MINOR_1_PROJECT_ID = 1
|
MINOR_1_PROJECT_ID = 1
|
||||||
MINOR_2_DP_BY_NAME = 2
|
MINOR_2_DP_BY_NAME = 2
|
||||||
|
MINOR_3_DEVICE_STATUS = 3
|
||||||
|
|
||||||
# When adding another version, update:
|
# When adding another version, update:
|
||||||
# - MINOR_MAX_VERSION
|
# - MINOR_MAX_VERSION
|
||||||
@ -36,7 +37,7 @@ MINOR_2_DP_BY_NAME = 2
|
|||||||
# explanation of what changed in the new version
|
# 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
|
# String representations of the minor and maximum versions
|
||||||
_MIN_VERSION_STRING = '{}.{}'.format(BASE_VERSION, MINOR_0_INITIAL_VERSION)
|
_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.
|
name (newly introduced) and uuid.
|
||||||
|
|
||||||
- GET /v2/device_profiles/{device_profile_name_or_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_SSD)
|
||||||
|
|
||||||
|
|
||||||
|
# Device type
|
||||||
|
DEVICE_STATUS = ("enabled", "maintaining")
|
||||||
|
|
||||||
|
|
||||||
# Attach handle type
|
# Attach handle type
|
||||||
# 'TEST_PCI': used by fake driver, ignored by Nova virt driver.
|
# 'TEST_PCI': used by fake driver, ignored by Nova virt driver.
|
||||||
ATTACH_HANDLE_TYPES = (AH_TYPE_PCI, AH_TYPE_MDEV, AH_TYPE_TEST_PCI) = (
|
ATTACH_HANDLE_TYPES = (AH_TYPE_PCI, AH_TYPE_MDEV, AH_TYPE_TEST_PCI) = (
|
||||||
|
@ -145,7 +145,7 @@ class PlacementClient(object):
|
|||||||
|
|
||||||
def update_inventory(
|
def update_inventory(
|
||||||
self, resource_provider_uuid, inventories,
|
self, resource_provider_uuid, inventories,
|
||||||
resource_provider_generation=None):
|
resource_provider_generation=None, version=None):
|
||||||
if resource_provider_generation is None:
|
if resource_provider_generation is None:
|
||||||
resource_provider_generation = self.get_resource_provider(
|
resource_provider_generation = self.get_resource_provider(
|
||||||
resource_provider_uuid=resource_provider_uuid)['generation']
|
resource_provider_uuid=resource_provider_uuid)['generation']
|
||||||
@ -155,7 +155,7 @@ class PlacementClient(object):
|
|||||||
'inventories': inventories
|
'inventories': inventories
|
||||||
}
|
}
|
||||||
try:
|
try:
|
||||||
return self.put(url, body).json()
|
return self.put(url, body, version=version).json()
|
||||||
except ks_exc.NotFound:
|
except ks_exc.NotFound:
|
||||||
raise exception.PlacementResourceProviderNotFound(
|
raise exception.PlacementResourceProviderNotFound(
|
||||||
resource_provider=resource_provider_uuid)
|
resource_provider=resource_provider_uuid)
|
||||||
@ -355,3 +355,7 @@ class PlacementClient(object):
|
|||||||
elif resp.status_code == 204:
|
elif resp.status_code == 204:
|
||||||
LOG.info("Successfully delete trait %(trait_name).", {
|
LOG.info("Successfully delete trait %(trait_name).", {
|
||||||
"trait_name", 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',
|
policy.RuleDefault('cyborg:device:get_all',
|
||||||
'rule:allow',
|
'rule:allow',
|
||||||
description='Retrieve all device records'),
|
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 = [
|
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)
|
std_board_info = Column(Text, nullable=True)
|
||||||
vendor_board_info = Column(Text, nullable=True)
|
vendor_board_info = Column(Text, nullable=True)
|
||||||
hostname = Column(String(255), nullable=False)
|
hostname = Column(String(255), nullable=False)
|
||||||
|
status = Column(Enum("enabled", "maintaining", name='device_status'),
|
||||||
|
default='enabled', nullable=False)
|
||||||
|
|
||||||
|
|
||||||
class Deployable(Base):
|
class Deployable(Base):
|
||||||
|
@ -29,7 +29,8 @@ LOG = logging.getLogger(__name__)
|
|||||||
class Device(base.CyborgObject, object_base.VersionedObjectDictCompat):
|
class Device(base.CyborgObject, object_base.VersionedObjectDictCompat):
|
||||||
# Version 1.0: Initial version
|
# Version 1.0: Initial version
|
||||||
# Version 1.1: Add AICHIP, GENERIC type
|
# Version 1.1: Add AICHIP, GENERIC type
|
||||||
VERSION = '1.1'
|
# Version 1.2: Add status field
|
||||||
|
VERSION = '1.2'
|
||||||
|
|
||||||
dbapi = dbapi.get_instance()
|
dbapi = dbapi.get_instance()
|
||||||
|
|
||||||
@ -43,6 +44,8 @@ class Device(base.CyborgObject, object_base.VersionedObjectDictCompat):
|
|||||||
'std_board_info': object_fields.StringField(nullable=True),
|
'std_board_info': object_fields.StringField(nullable=True),
|
||||||
'vendor_board_info': object_fields.StringField(nullable=True),
|
'vendor_board_info': object_fields.StringField(nullable=True),
|
||||||
'hostname': object_fields.StringField(nullable=False),
|
'hostname': object_fields.StringField(nullable=False),
|
||||||
|
'status': object_fields.EnumField(valid_values=constants.DEVICE_STATUS,
|
||||||
|
nullable=False, default="enabled"),
|
||||||
}
|
}
|
||||||
|
|
||||||
def create(self, context):
|
def create(self, context):
|
||||||
|
Loading…
Reference in New Issue
Block a user