v2 API Support(using openstack-sdk)
Modifying cyborgclient to supporting v2 API, and using openstack sdk. This patch depends openstacksdk patch[1]. command usage: $openstack accelerator *commands below* deployable ( list | show | program ) device list device profile ( list | create | delete | show ) arq ( list | create | delete | show | bind | unbind ) [1] https://review.opendev.org/#/c/679914/ Change-Id: If6bb52b453c1aa7fb328fd08ebbb79312fa7d299 Story: 2006930
This commit is contained in:
@@ -14,9 +14,12 @@
|
||||
#
|
||||
import logging
|
||||
|
||||
from cyborgclient import exceptions as exc
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
from oslo_serialization import jsonutils
|
||||
|
||||
|
||||
def common_filters(marker=None, limit=None, sort_key=None, sort_dir=None):
|
||||
"""Generate common filters for any list request.
|
||||
@@ -110,3 +113,47 @@ def clean_listing_columns(headers, columns, data_sample):
|
||||
col_headers.append(header)
|
||||
cols.append(col)
|
||||
return tuple(col_headers), tuple(cols)
|
||||
|
||||
|
||||
def json_formatter(js):
|
||||
return jsonutils.dumps(js, indent=2, ensure_ascii=False)
|
||||
|
||||
|
||||
def split_and_deserialize(string):
|
||||
"""Split and try to JSON deserialize a string.
|
||||
|
||||
Gets a string with the KEY=VALUE format, split it (using '=' as the
|
||||
separator) and try to JSON deserialize the VALUE.
|
||||
:returns: A tuple of (key, value).
|
||||
"""
|
||||
|
||||
try:
|
||||
key, value = string.split("=", 1)
|
||||
except ValueError:
|
||||
raise exc.CommandError(_('Attributes must be a list of '
|
||||
'PATH=VALUE not "%s"') % string)
|
||||
try:
|
||||
value = jsonutils.loads(value)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
return (key, value)
|
||||
|
||||
|
||||
def args_array_to_patch(op, attributes):
|
||||
patch = []
|
||||
for attr in attributes:
|
||||
# Sanitize
|
||||
if not attr.startswith('/'):
|
||||
attr = '/' + attr
|
||||
|
||||
if op in ['add', 'replace']:
|
||||
path, value = split_and_deserialize(attr)
|
||||
patch.append({'op': op, 'path': path, 'value': value})
|
||||
|
||||
elif op == "remove":
|
||||
# For remove only the key is needed
|
||||
patch.append({'op': op, 'path': attr})
|
||||
else:
|
||||
raise exc.CommandError(_('Unknown PATCH operation: %s') % op)
|
||||
return patch
|
||||
|
@@ -1,5 +1,3 @@
|
||||
# Copyright 2016 Huawei, 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
|
||||
@@ -13,49 +11,94 @@
|
||||
# under the License.
|
||||
#
|
||||
|
||||
"""OpenStackClient plugin for Accelerator management service."""
|
||||
|
||||
import logging
|
||||
|
||||
from openstack.config import cloud_region
|
||||
from openstack.config import defaults as config_defaults
|
||||
from openstack import connection
|
||||
from osc_lib import utils
|
||||
|
||||
from cyborgclient.i18n import _
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_ACCELERATOR_API_VERSION = '1'
|
||||
DEFAULT_ACCELERATOR_API_VERSION = '2'
|
||||
API_VERSION_OPTION = 'os_accelerator_api_version'
|
||||
API_NAME = 'accelerator'
|
||||
API_VERSIONS = {
|
||||
'1': 'cyborgclient.v1.client.Client',
|
||||
}
|
||||
CURRENT_API_VERSION = '2'
|
||||
|
||||
|
||||
def _make_key(service_type, key):
|
||||
if not service_type:
|
||||
return key
|
||||
else:
|
||||
service_type = service_type.lower().replace('-', '_')
|
||||
return "_".join([service_type, key])
|
||||
|
||||
|
||||
def _get_config_from_profile(profile, **kwargs):
|
||||
# Deal with clients still trying to use legacy profile objects
|
||||
region_name = None
|
||||
for service in profile.get_services():
|
||||
if service.region:
|
||||
region_name = service.region
|
||||
service_type = service.service_type
|
||||
if service.interface:
|
||||
key = _make_key(service_type, 'interface')
|
||||
kwargs[key] = service.interface
|
||||
if service.version:
|
||||
version = service.version
|
||||
if version.startswith('v'):
|
||||
version = version[2:]
|
||||
key = _make_key(service_type, 'api_version')
|
||||
kwargs[key] = version
|
||||
if service.api_version:
|
||||
version = service.api_version
|
||||
key = _make_key(service_type, 'default_microversion')
|
||||
kwargs[key] = version
|
||||
|
||||
config_kwargs = config_defaults.get_defaults()
|
||||
config_kwargs.update(kwargs)
|
||||
config = cloud_region.CloudRegion(
|
||||
region_name=region_name, config=config_kwargs)
|
||||
return config
|
||||
|
||||
|
||||
def create_connection(prof=None, cloud_region=None, **kwargs):
|
||||
version_key = _make_key(API_NAME, 'api_version')
|
||||
kwargs[version_key] = CURRENT_API_VERSION
|
||||
|
||||
if not cloud_region:
|
||||
if prof:
|
||||
cloud_region = _get_config_from_profile(prof, **kwargs)
|
||||
else:
|
||||
# If we got the CloudRegion from python-openstackclient and it doesn't
|
||||
# already have a default microversion set, set it here.
|
||||
microversion_key = _make_key(API_NAME, 'default_microversion')
|
||||
cloud_region.config.setdefault(microversion_key, CURRENT_API_VERSION)
|
||||
|
||||
user_agent = kwargs.pop('user_agent', None)
|
||||
app_name = kwargs.pop('app_name', None)
|
||||
app_version = kwargs.pop('app_version', None)
|
||||
if user_agent is not None and (not app_name and not app_version):
|
||||
app_name, app_version = user_agent.split('/', 1)
|
||||
|
||||
return connection.Connection(
|
||||
config=cloud_region,
|
||||
app_name=app_name,
|
||||
app_version=app_version, **kwargs)
|
||||
|
||||
|
||||
def make_client(instance):
|
||||
"""Returns an accelerators service client"""
|
||||
cyborg_client = utils.get_client_class(
|
||||
API_NAME,
|
||||
instance._api_version[API_NAME],
|
||||
API_VERSIONS)
|
||||
LOG.debug('Instantiating accelerators client: %s', cyborg_client)
|
||||
|
||||
endpoint = instance.get_endpoint_for_service_type(
|
||||
API_NAME,
|
||||
region_name=instance.region_name,
|
||||
interface=instance.interface,
|
||||
"""Returns a accelerator proxy"""
|
||||
conn = create_connection(
|
||||
cloud_region=instance._cli_options,
|
||||
)
|
||||
|
||||
kwargs = {'endpoint': endpoint,
|
||||
'auth_url': instance.auth.auth_url,
|
||||
'region_name': instance.region_name,
|
||||
'username': instance.auth_ref.username}
|
||||
|
||||
if instance.session:
|
||||
kwargs.update(session=instance.session)
|
||||
else:
|
||||
kwargs.update(token=instance.auth_ref.auth_token)
|
||||
|
||||
client = cyborg_client(**kwargs)
|
||||
|
||||
return client
|
||||
LOG.debug('Connection: %s', conn)
|
||||
LOG.debug('Accelerator client initialized using OpenStackSDK: %s',
|
||||
conn.accelerator)
|
||||
return conn.accelerator
|
||||
|
||||
|
||||
def build_option_parser(parser):
|
||||
@@ -66,8 +109,7 @@ def build_option_parser(parser):
|
||||
default=utils.env(
|
||||
'OS_ACCELERATOR_API_VERSION',
|
||||
default=DEFAULT_ACCELERATOR_API_VERSION),
|
||||
help=(_('Accelerations compute API version, default=%s '
|
||||
'(Env: OS_ACCELERATOR_API_VERSION)') %
|
||||
DEFAULT_ACCELERATOR_API_VERSION)
|
||||
)
|
||||
help='Accelerator API version, default=' +
|
||||
DEFAULT_ACCELERATOR_API_VERSION +
|
||||
' (Env: OS_ACCELERATOR_API_VERSION)')
|
||||
return parser
|
||||
|
0
cyborgclient/osc/v2/__init__.py
Normal file
0
cyborgclient/osc/v2/__init__.py
Normal file
305
cyborgclient/osc/v2/accelerator_request.py
Normal file
305
cyborgclient/osc/v2/accelerator_request.py
Normal file
@@ -0,0 +1,305 @@
|
||||
# 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.
|
||||
#
|
||||
|
||||
|
||||
"""Cyborg v2 Acceleration accelerator action implementations"""
|
||||
|
||||
import logging
|
||||
|
||||
from openstack import exceptions as sdk_exc
|
||||
from osc_lib.command import command
|
||||
from osc_lib import utils as oscutils
|
||||
|
||||
from cyborgclient.common import utils
|
||||
from cyborgclient import exceptions as exc
|
||||
from cyborgclient.i18n import _
|
||||
|
||||
|
||||
class ListAcceleratorRequest(command.Lister):
|
||||
"""List all accelerator requests"""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListAcceleratorRequest, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'--long',
|
||||
dest='detail',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_("List additional fields in output")
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
acc_client = self.app.client_manager.accelerator
|
||||
|
||||
if parsed_args.detail:
|
||||
column_headers = (
|
||||
"uuid",
|
||||
"state",
|
||||
"device_profile_name",
|
||||
"hostname",
|
||||
"device_rp_uuid",
|
||||
"instance_uuid",
|
||||
"attach_handle_type",
|
||||
"attach_handle_info",
|
||||
)
|
||||
columns = (
|
||||
"uuid",
|
||||
"state",
|
||||
"device_profile_name",
|
||||
"hostname",
|
||||
"device_rp_uuid",
|
||||
"instance_uuid",
|
||||
"attach_handle_type",
|
||||
"attach_handle_info",
|
||||
)
|
||||
else:
|
||||
column_headers = (
|
||||
"uuid",
|
||||
"state",
|
||||
"device_profile_name",
|
||||
"instance_uuid",
|
||||
"attach_handle_type",
|
||||
"attach_handle_info",
|
||||
)
|
||||
columns = (
|
||||
"uuid",
|
||||
"state",
|
||||
"device_profile_name",
|
||||
"instance_uuid",
|
||||
"attach_handle_type",
|
||||
"attach_handle_info",
|
||||
)
|
||||
|
||||
data = acc_client.accelerator_requests()
|
||||
if not data:
|
||||
return (), ()
|
||||
formatters = {}
|
||||
return (column_headers,
|
||||
(oscutils.get_item_properties(
|
||||
s, columns, formatters=formatters) for s in data))
|
||||
|
||||
|
||||
class CreateAcceleratorRequest(command.ShowOne):
|
||||
"""Register a new accelerator_request with the accelerator service"""
|
||||
|
||||
log = logging.getLogger(__name__ + ".CreateAcceleratorRequest")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CreateAcceleratorRequest, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'device_profile_name',
|
||||
metavar='<device_profile_name>',
|
||||
help=_("The name of device_profile for accelerator_request."))
|
||||
parser.add_argument(
|
||||
'device_profile_group_id',
|
||||
metavar='<device_profile_group_id>',
|
||||
help=_("The group id of device_profile \
|
||||
for the accelerator_request."))
|
||||
parser.add_argument(
|
||||
'--image-uuid',
|
||||
metavar='<glance_image_uuid>',
|
||||
dest='img_uuid',
|
||||
help=_("The uuid of image saved in glance."))
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)", parsed_args)
|
||||
|
||||
acc_client = self.app.client_manager.accelerator
|
||||
|
||||
attrs = {
|
||||
'device_profile_name': parsed_args.device_profile_name,
|
||||
'device_profile_group_id': parsed_args.device_profile_group_id,
|
||||
'image_uuid': parsed_args.img_uuid,
|
||||
}
|
||||
|
||||
accelerator_request = acc_client.create_accelerator_request(**attrs)
|
||||
|
||||
return _show_accelerator_request(acc_client,
|
||||
accelerator_request.uuid)
|
||||
|
||||
|
||||
class DeleteAcceleratorRequest(command.Command):
|
||||
"""Delete accelerator request(s)."""
|
||||
|
||||
log = logging.getLogger(__name__ + ".DeleteAcceleratorRequest")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(DeleteAcceleratorRequest, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
"accelerator_requests",
|
||||
metavar="<uuid>",
|
||||
nargs="+",
|
||||
help=_("UUID(s) of the accelerator_request(s) to delete.")
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)", parsed_args)
|
||||
|
||||
acc_client = self.app.client_manager.accelerator
|
||||
|
||||
failures = []
|
||||
for uuid in parsed_args.accelerator_requests:
|
||||
try:
|
||||
acc_client.delete_accelerator_request(uuid, False)
|
||||
print(_('Deleted accelerator_request %s') % uuid)
|
||||
except exc.ClientException as e:
|
||||
failures.append(_("Failed to delete accelerator_request\
|
||||
%(accelerator_request)s: %(error)s")
|
||||
% {'uuid': uuid, 'error': e})
|
||||
|
||||
if failures:
|
||||
raise exc.ClientException("\n".join(failures))
|
||||
|
||||
|
||||
class ShowAcceleratorRequest(command.ShowOne):
|
||||
"""Show accelerator_request details."""
|
||||
|
||||
log = logging.getLogger(__name__ + ".ShowAcceleratorRequest")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowAcceleratorRequest, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
"accelerator_request",
|
||||
metavar="<uuid>",
|
||||
help=_("UUID of the accelerator_request.")
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)", parsed_args)
|
||||
|
||||
acc_client = self.app.client_manager.accelerator
|
||||
|
||||
return _show_accelerator_request(acc_client,
|
||||
parsed_args.accelerator_request)
|
||||
|
||||
|
||||
def _show_accelerator_request(acc_client, uuid):
|
||||
"""Show detailed info about accelerator_request."""
|
||||
|
||||
columns = (
|
||||
"uuid",
|
||||
"state",
|
||||
"device_profile_name",
|
||||
"hostname",
|
||||
"device_rp_uuid",
|
||||
"instance_uuid",
|
||||
"attach_handle_type",
|
||||
"attach_handle_info",
|
||||
)
|
||||
|
||||
try:
|
||||
accelerator_request = acc_client.get_accelerator_request(uuid)
|
||||
except sdk_exc.ResourceNotFound:
|
||||
raise exc.CommandError(_('accelerator_request not found: %s') % uuid)
|
||||
|
||||
formatters = {
|
||||
'data': utils.json_formatter,
|
||||
}
|
||||
data = accelerator_request.to_dict()
|
||||
return columns, oscutils.get_dict_properties(data, columns,
|
||||
formatters=formatters)
|
||||
|
||||
|
||||
class BindAcceleratorRequest(command.ShowOne):
|
||||
"""Bind accelerator to instance."""
|
||||
|
||||
log = logging.getLogger(__name__ + ".BindAcceleratorRequest")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(BindAcceleratorRequest, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'accelerator_request',
|
||||
metavar='<accelerator_request>',
|
||||
help=_("UUID of the accelerator request")
|
||||
)
|
||||
parser.add_argument(
|
||||
'hostname',
|
||||
metavar='<hostname>',
|
||||
help=_("Bind hostname of the accelerator request")
|
||||
)
|
||||
parser.add_argument(
|
||||
"instance_uuid",
|
||||
metavar="<instance_uuid>",
|
||||
help=_("Bind instance_uuid of the accelerator request")
|
||||
)
|
||||
parser.add_argument(
|
||||
"device_rp_uuid",
|
||||
metavar="<device_rp_uuid>",
|
||||
help=_("Bind device_rp_uuid of the accelerator request")
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)", parsed_args)
|
||||
|
||||
acc_client = self.app.client_manager.accelerator
|
||||
|
||||
properties = []
|
||||
if parsed_args.hostname:
|
||||
hostname = ["hostname=%s" % parsed_args.hostname]
|
||||
properties.extend(utils.args_array_to_patch('add', hostname))
|
||||
if parsed_args.instance_uuid:
|
||||
instance_uuid = ["instance_uuid=%s" % parsed_args.instance_uuid]
|
||||
properties.extend(utils.args_array_to_patch('add', instance_uuid))
|
||||
if parsed_args.device_rp_uuid:
|
||||
device_rp_uuid = ["device_rp_uuid=%s" % parsed_args.device_rp_uuid]
|
||||
properties.extend(utils.args_array_to_patch('add', device_rp_uuid))
|
||||
|
||||
if properties:
|
||||
acc_client.update_accelerator_request(
|
||||
parsed_args.accelerator_request, properties)
|
||||
return _show_accelerator_request(acc_client,
|
||||
parsed_args.accelerator_request)
|
||||
else:
|
||||
self.log.warning("Please specify what to set.")
|
||||
|
||||
|
||||
class UnbindAcceleratorRequest(command.ShowOne):
|
||||
"""Unbind accelerator from instance."""
|
||||
|
||||
log = logging.getLogger(__name__ + ".UnbindAcceleratorRequest")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(UnbindAcceleratorRequest, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'accelerator_request',
|
||||
metavar='<accelerator_request>',
|
||||
help=_("UUID of the accelerator request")
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)", parsed_args)
|
||||
|
||||
acc_client = self.app.client_manager.accelerator
|
||||
|
||||
properties = [{'path': '/hostname', 'op': 'remove'},
|
||||
{'path': '/instance_uuid', 'op': 'remove'},
|
||||
{'path': '/device_rp_uuid', 'op': 'remove'}]
|
||||
|
||||
acc_client.update_accelerator_request(parsed_args.accelerator_request,
|
||||
properties)
|
||||
|
||||
return _show_accelerator_request(acc_client,
|
||||
parsed_args.accelerator_request)
|
167
cyborgclient/osc/v2/deployable.py
Normal file
167
cyborgclient/osc/v2/deployable.py
Normal file
@@ -0,0 +1,167 @@
|
||||
# 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.
|
||||
#
|
||||
|
||||
|
||||
"""Cyborg v2 Acceleration accelerator action implementations"""
|
||||
import logging
|
||||
|
||||
from openstack import exceptions as sdk_exc
|
||||
from osc_lib.command import command
|
||||
from osc_lib import utils as oscutils
|
||||
|
||||
from cyborgclient.common import utils
|
||||
from cyborgclient import exceptions as exc
|
||||
from cyborgclient.i18n import _
|
||||
|
||||
|
||||
class ListDeployable(command.Lister):
|
||||
"""List all deployables"""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListDeployable, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'--long',
|
||||
dest='detail',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_("List additional fields in output")
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
acc_client = self.app.client_manager.accelerator
|
||||
|
||||
if parsed_args.detail:
|
||||
column_headers = (
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"uuid",
|
||||
"parent_id",
|
||||
"root_id",
|
||||
"name",
|
||||
"num_accelerators",
|
||||
"device_id"
|
||||
)
|
||||
|
||||
columns = (
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"id",
|
||||
"parent_id",
|
||||
"root_id",
|
||||
"name",
|
||||
"num_accelerators",
|
||||
"device_id"
|
||||
)
|
||||
else:
|
||||
column_headers = (
|
||||
"uuid",
|
||||
"name",
|
||||
"device_id",
|
||||
)
|
||||
columns = (
|
||||
"id",
|
||||
"name",
|
||||
"device_id",
|
||||
)
|
||||
data = acc_client.deployables()
|
||||
if not data:
|
||||
return (), ()
|
||||
formatters = {}
|
||||
return (column_headers,
|
||||
(oscutils.get_item_properties(
|
||||
s, columns, formatters=formatters) for s in data))
|
||||
|
||||
|
||||
class ShowDeployable(command.ShowOne):
|
||||
"""Show deployable details."""
|
||||
log = logging.getLogger(__name__ + ".ShowDeployable")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowDeployable, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
"deployable",
|
||||
metavar="<uuid>",
|
||||
help=_("UUID of the deployable.")
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)", parsed_args)
|
||||
acc_client = self.app.client_manager.accelerator
|
||||
return _show_deployable(acc_client,
|
||||
parsed_args.deployable)
|
||||
|
||||
|
||||
def _show_deployable(acc_client, uuid):
|
||||
"""Show detailed info about deployable."""
|
||||
columns = (
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"uuid",
|
||||
"name",
|
||||
)
|
||||
try:
|
||||
deployable = acc_client.get_deployable(uuid)
|
||||
except sdk_exc.ResourceNotFound:
|
||||
raise exc.CommandError(_('deployable not found: %s') % uuid)
|
||||
formatters = {
|
||||
'data': utils.json_formatter,
|
||||
}
|
||||
data = deployable.to_dict()
|
||||
data['uuid'] = data.pop('id', uuid)
|
||||
return columns, oscutils.get_dict_properties(data, columns,
|
||||
formatters=formatters)
|
||||
|
||||
|
||||
class ProgramDeployable(command.ShowOne):
|
||||
"""Reconfigure deployable."""
|
||||
log = logging.getLogger(__name__ + ".ProgramDeployable")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ProgramDeployable, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'deployable_uuid',
|
||||
metavar='<deployable_uuid>',
|
||||
default=False,
|
||||
help=_("Deployable UUID for reconfigure.")
|
||||
)
|
||||
parser.add_argument(
|
||||
'image_uuid',
|
||||
metavar='<image_uuid>',
|
||||
default=False,
|
||||
help=_("Image UUID for reconfigure.")
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)", parsed_args)
|
||||
acc_client = self.app.client_manager.accelerator
|
||||
dep_uuid = parsed_args.deployable_uuid
|
||||
try:
|
||||
acc_client.get_deployable(dep_uuid)
|
||||
except sdk_exc.ResourceNotFound:
|
||||
raise exc.CommandError(_('deployable not found: %s') % dep_uuid)
|
||||
|
||||
image_uuid = parsed_args.image_uuid
|
||||
image_client = self.app.client_manager.image.images
|
||||
try:
|
||||
image_client.get(image_uuid)
|
||||
except sdk_exc.ResourceNotFound:
|
||||
raise exc.CommandError(_('image not found: %s') % image_uuid)
|
||||
|
||||
program_info = [{'path': '/program',
|
||||
'value': [{'image_uuid': image_uuid}],
|
||||
'op': 'replace'}]
|
||||
acc_client.update_deployable(dep_uuid, program_info)
|
||||
return _show_deployable(acc_client, dep_uuid)
|
135
cyborgclient/osc/v2/device.py
Normal file
135
cyborgclient/osc/v2/device.py
Normal file
@@ -0,0 +1,135 @@
|
||||
# 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.
|
||||
#
|
||||
|
||||
|
||||
"""Cyborg v2 Acceleration accelerator action implementations"""
|
||||
import logging
|
||||
|
||||
from openstack import exceptions as sdk_exc
|
||||
from osc_lib.command import command
|
||||
from osc_lib import utils as oscutils
|
||||
|
||||
from cyborgclient.common import utils
|
||||
from cyborgclient import exceptions as exc
|
||||
from cyborgclient.i18n import _
|
||||
|
||||
|
||||
class ListDevice(command.Lister):
|
||||
"""List all devices"""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListDevice, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'--long',
|
||||
dest='detail',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_("List additional fields in output")
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
acc_client = self.app.client_manager.accelerator
|
||||
|
||||
if parsed_args.detail:
|
||||
column_headers = (
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"uuid",
|
||||
"type",
|
||||
"vendor",
|
||||
"model",
|
||||
"hostname",
|
||||
"std_board_info",
|
||||
"vendor_board_info"
|
||||
)
|
||||
|
||||
columns = (
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"uuid",
|
||||
"type",
|
||||
"vendor",
|
||||
"model",
|
||||
"hostname",
|
||||
"std_board_info",
|
||||
"vendor_board_info"
|
||||
)
|
||||
else:
|
||||
column_headers = (
|
||||
"uuid",
|
||||
"type",
|
||||
"vendor",
|
||||
"hostname",
|
||||
"std_board_info",
|
||||
)
|
||||
columns = (
|
||||
"uuid",
|
||||
"type",
|
||||
"vendor",
|
||||
"hostname",
|
||||
"std_board_info",
|
||||
)
|
||||
|
||||
data = acc_client.devices()
|
||||
if not data:
|
||||
return (), ()
|
||||
formatters = {}
|
||||
return (column_headers,
|
||||
(oscutils.get_item_properties(
|
||||
s, columns, formatters=formatters) for s in data))
|
||||
|
||||
|
||||
class ShowDevice(command.ShowOne):
|
||||
"""Show device details."""
|
||||
log = logging.getLogger(__name__ + ".ShowDevice")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowDevice, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
"device",
|
||||
metavar="<uuid>",
|
||||
help=_("UUID of the device.")
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)", parsed_args)
|
||||
acc_client = self.app.client_manager.accelerator
|
||||
return _show_device(acc_client,
|
||||
parsed_args.device)
|
||||
|
||||
|
||||
def _show_device(acc_client, uuid):
|
||||
"""Show detailed info about device."""
|
||||
columns = (
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"uuid",
|
||||
"type",
|
||||
"vendor",
|
||||
"model",
|
||||
"hostname",
|
||||
"std_board_info",
|
||||
"vendor_board_info"
|
||||
)
|
||||
try:
|
||||
device = acc_client.get_device(uuid)
|
||||
except sdk_exc.ResourceNotFound:
|
||||
raise exc.CommandError(_('device not found: %s') % uuid)
|
||||
formatters = {
|
||||
'data': utils.json_formatter,
|
||||
}
|
||||
data = device.to_dict()
|
||||
return columns, oscutils.get_dict_properties(data, columns,
|
||||
formatters=formatters)
|
182
cyborgclient/osc/v2/device_profile.py
Normal file
182
cyborgclient/osc/v2/device_profile.py
Normal file
@@ -0,0 +1,182 @@
|
||||
# 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.
|
||||
#
|
||||
|
||||
|
||||
"""Cyborg v2 Acceleration accelerator action implementations"""
|
||||
|
||||
import logging
|
||||
|
||||
from openstack import exceptions as sdk_exc
|
||||
from osc_lib.command import command
|
||||
from osc_lib import utils as oscutils
|
||||
from oslo_serialization import jsonutils
|
||||
|
||||
from cyborgclient.common import utils
|
||||
from cyborgclient import exceptions as exc
|
||||
from cyborgclient.i18n import _
|
||||
|
||||
|
||||
class ListDeviceProfile(command.Lister):
|
||||
"""List all device profiles"""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListDeviceProfile, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'--long',
|
||||
dest='detail',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_("List additional fields in output")
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
acc_client = self.app.client_manager.accelerator
|
||||
|
||||
if parsed_args.detail:
|
||||
column_headers = (
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"uuid",
|
||||
"name",
|
||||
"groups"
|
||||
)
|
||||
columns = (
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"uuid",
|
||||
"name",
|
||||
"groups"
|
||||
)
|
||||
else:
|
||||
column_headers = (
|
||||
"uuid",
|
||||
"name",
|
||||
"groups",
|
||||
)
|
||||
columns = (
|
||||
"uuid",
|
||||
"name",
|
||||
"groups",
|
||||
)
|
||||
|
||||
data = acc_client.device_profiles()
|
||||
if not data:
|
||||
return (), ()
|
||||
formatters = {}
|
||||
return (column_headers,
|
||||
(oscutils.get_item_properties(
|
||||
s, columns, formatters=formatters) for s in data))
|
||||
|
||||
|
||||
class CreateDeviceProfile(command.ShowOne):
|
||||
"""Register a new device_profile with the accelerator service"""
|
||||
log = logging.getLogger(__name__ + ".CreateDeviceProfile")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CreateDeviceProfile, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'name',
|
||||
metavar='<name>',
|
||||
help=_("Unique name for the device_profile."))
|
||||
parser.add_argument(
|
||||
'groups',
|
||||
metavar='<groups>',
|
||||
help=_("groups for the device_profile."))
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)", parsed_args)
|
||||
acc_client = self.app.client_manager.accelerator
|
||||
|
||||
attrs = {
|
||||
'name': parsed_args.name,
|
||||
'groups': list(jsonutils.loads(parsed_args.groups)),
|
||||
}
|
||||
device_profile = acc_client.create_device_profile(**attrs)
|
||||
return _show_device_profile(acc_client, device_profile.uuid)
|
||||
|
||||
|
||||
class DeleteDeviceProfile(command.Command):
|
||||
"""Delete deviceProfile(s)."""
|
||||
|
||||
log = logging.getLogger(__name__ + ".DeleteDeviceProfile")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(DeleteDeviceProfile, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
"device_profiles",
|
||||
metavar="<uuid>",
|
||||
nargs="+",
|
||||
help=_("UUID(s) of the device_profile(s) to delete.")
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)", parsed_args)
|
||||
|
||||
acc_client = self.app.client_manager.accelerator
|
||||
|
||||
failures = []
|
||||
for uuid in parsed_args.device_profiles:
|
||||
try:
|
||||
acc_client.delete_device_profile(uuid, False)
|
||||
print(_('Deleted device_profile %s') % uuid)
|
||||
except exc.ClientException as e:
|
||||
failures.append(_("Failed to delete device_profile \
|
||||
%(device_profile)s: %(error)s")
|
||||
% {'uuid': uuid, 'error': e})
|
||||
if failures:
|
||||
raise exc.ClientException("\n".join(failures))
|
||||
|
||||
|
||||
class ShowDeviceProfile(command.ShowOne):
|
||||
"""Show device_profile details."""
|
||||
log = logging.getLogger(__name__ + ".ShowDeviceProfile")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowDeviceProfile, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
"device_profile",
|
||||
metavar="<uuid>",
|
||||
help=_("UUID of the device_profile.")
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)", parsed_args)
|
||||
acc_client = self.app.client_manager.accelerator
|
||||
return _show_device_profile(acc_client,
|
||||
parsed_args.device_profile)
|
||||
|
||||
|
||||
def _show_device_profile(acc_client, uuid):
|
||||
"""Show detailed info about device_profile."""
|
||||
columns = (
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"uuid",
|
||||
"name",
|
||||
"groups",
|
||||
)
|
||||
try:
|
||||
device_profile = acc_client.get_device_profile(uuid)
|
||||
except sdk_exc.ResourceNotFound:
|
||||
raise exc.CommandError(_('device_profile not found: %s') % uuid)
|
||||
formatters = {
|
||||
'data': utils.json_formatter,
|
||||
}
|
||||
data = device_profile.to_dict()
|
||||
return columns, oscutils.get_dict_properties(data, columns,
|
||||
formatters=formatters)
|
58
cyborgclient/tests/unit/osc/fakes.py
Normal file
58
cyborgclient/tests/unit/osc/fakes.py
Normal file
@@ -0,0 +1,58 @@
|
||||
# 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 sys
|
||||
|
||||
|
||||
AUTH_TOKEN = "foobar"
|
||||
AUTH_URL = "http://0.0.0.0"
|
||||
API_VERSION = '2'
|
||||
|
||||
|
||||
class FakeApp(object):
|
||||
def __init__(self):
|
||||
_stdout = None
|
||||
self.client_manager = None
|
||||
self.stdin = sys.stdin
|
||||
self.stdout = _stdout or sys.stdout
|
||||
self.stderr = sys.stderr
|
||||
self.restapi = None
|
||||
|
||||
|
||||
class FakeClientManager(object):
|
||||
def __init__(self):
|
||||
self.identity = None
|
||||
self.auth_ref = None
|
||||
self.interface = 'public'
|
||||
self._region_name = 'RegionOne'
|
||||
self.session = 'fake session'
|
||||
self._api_version = {'accelerator': API_VERSION}
|
||||
|
||||
|
||||
class FakeResource(object):
|
||||
def __init__(self, manager, info, loaded=False):
|
||||
self.__name__ = type(self).__name__
|
||||
self.manager = manager
|
||||
self._info = info
|
||||
self._add_details(info)
|
||||
self._loaded = loaded
|
||||
|
||||
def _add_details(self, info):
|
||||
for (k, v) in info.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
def __repr__(self):
|
||||
reprkeys = sorted(k for k in self.__dict__.keys() if k[0] != '_' and
|
||||
k != 'manager')
|
||||
info = ", ".join("%s=%s" % (k, getattr(self, k)) for k in reprkeys)
|
||||
return "<%s %s>" % (self.__class__.__name__, info)
|
72
cyborgclient/tests/unit/osc/test_plugin.py
Normal file
72
cyborgclient/tests/unit/osc/test_plugin.py
Normal file
@@ -0,0 +1,72 @@
|
||||
# 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 mock
|
||||
from openstack import connection as sdk_connection
|
||||
import testtools
|
||||
|
||||
from cyborgclient.osc import plugin
|
||||
|
||||
|
||||
class TestPlugin(testtools.TestCase):
|
||||
|
||||
@mock.patch.object(sdk_connection, 'Connection')
|
||||
def test_create_connection_with_profile(self, mock_connection):
|
||||
class FakeService(object):
|
||||
interface = 'public'
|
||||
region = 'a_region'
|
||||
version = '2'
|
||||
api_version = None
|
||||
service_type = 'accelerator'
|
||||
|
||||
mock_prof = mock.Mock()
|
||||
mock_prof.get_services.return_value = [FakeService()]
|
||||
mock_conn = mock.Mock()
|
||||
mock_connection.return_value = mock_conn
|
||||
kwargs = {
|
||||
'user_id': '123',
|
||||
'password': 'abc',
|
||||
'auth_url': 'test_url'
|
||||
}
|
||||
res = plugin.create_connection(mock_prof, **kwargs)
|
||||
mock_connection.assert_called_once_with(
|
||||
app_name=None, app_version=None,
|
||||
config=mock.ANY,
|
||||
accelerator_api_version=plugin.CURRENT_API_VERSION,
|
||||
**kwargs
|
||||
)
|
||||
self.assertEqual(mock_conn, res)
|
||||
|
||||
@mock.patch.object(sdk_connection, 'Connection')
|
||||
def test_create_connection_without_profile(self, mock_connection):
|
||||
mock_conn = mock.Mock()
|
||||
mock_connection.return_value = mock_conn
|
||||
kwargs = {
|
||||
'interface': 'public',
|
||||
'region_name': 'RegionOne',
|
||||
'user_id': '123',
|
||||
'password': 'abc',
|
||||
'auth_url': 'test_url'
|
||||
}
|
||||
res = plugin.create_connection(**kwargs)
|
||||
|
||||
mock_connection.assert_called_once_with(
|
||||
app_name=None, app_version=None,
|
||||
auth_url='test_url',
|
||||
accelerator_api_version=plugin.CURRENT_API_VERSION,
|
||||
config=None,
|
||||
interface='public',
|
||||
password='abc',
|
||||
region_name='RegionOne',
|
||||
user_id='123'
|
||||
)
|
||||
self.assertEqual(mock_conn, res)
|
0
cyborgclient/tests/unit/osc/v2/__init__.py
Normal file
0
cyborgclient/tests/unit/osc/v2/__init__.py
Normal file
122
cyborgclient/tests/unit/osc/v2/fakes.py
Normal file
122
cyborgclient/tests/unit/osc/v2/fakes.py
Normal file
@@ -0,0 +1,122 @@
|
||||
# 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 cyborgclient.tests.unit.osc import fakes
|
||||
import mock
|
||||
from osc_lib.tests import utils
|
||||
import uuid
|
||||
|
||||
deployable_created_at = '2019-06-24T00:00:00.000000+00:00'
|
||||
deployable_updated_at = '2019-06-24T11:11:11.111111+11:11'
|
||||
deployable_uuid = uuid.uuid4().hex
|
||||
deployable_name = 'fake_dep_name'
|
||||
deployable_parent_id = None
|
||||
deployable_root_id = 1
|
||||
deployable_num_accelerators = 4
|
||||
deployable_device_id = 0
|
||||
|
||||
DEPLOYABLE = {
|
||||
'created_at': deployable_created_at,
|
||||
'updated_at': deployable_updated_at,
|
||||
'id': deployable_uuid,
|
||||
'name': deployable_name,
|
||||
'parent_id': deployable_parent_id,
|
||||
'root_id': deployable_root_id,
|
||||
'num_accelerators': deployable_num_accelerators,
|
||||
'device_id': deployable_device_id,
|
||||
}
|
||||
|
||||
device_created_at = '2019-06-24T00:00:00.000000+00:00'
|
||||
device_updated_at = '2019-06-24T22:22:22.222222+22:22'
|
||||
device_id = 1
|
||||
device_uuid = uuid.uuid4().hex
|
||||
device_name = 'fake_dev_name'
|
||||
device_type = 'fake_dev_type'
|
||||
device_vendor = '0x8086'
|
||||
device_model = 'fake_dev_model'
|
||||
device_hostname = 'fake_host'
|
||||
device_std_board_info = '{"product_id": "0x09c4"}'
|
||||
device_vendor_board_info = 'fake_vb_info'
|
||||
|
||||
DEVICE = {
|
||||
'created_at': device_created_at,
|
||||
'updated_at': device_updated_at,
|
||||
'id': device_id,
|
||||
'uuid': device_uuid,
|
||||
'type': device_type,
|
||||
'vendor': device_vendor,
|
||||
'model': device_model,
|
||||
'hostname': device_hostname,
|
||||
'std_board_info': device_std_board_info,
|
||||
'vendor_board_info': device_vendor_board_info
|
||||
}
|
||||
|
||||
device_profile_created_at = '2019-06-24T00:00:00.000000+00:00'
|
||||
device_profile_updated_at = '2019-06-24T11:11:11.111111+11:11'
|
||||
device_profile_id = 1
|
||||
device_profile_uuid = uuid.uuid4().hex
|
||||
device_profile_name = 'fake_devprof_name'
|
||||
device_profile_groups = [
|
||||
{"resources:ACCELERATOR_FPGA": "1",
|
||||
"trait:CUSTOM_FPGA_INTEL_PAC_ARRIA10": "required",
|
||||
"trait:CUSTOM_FUNCTION_ID_3AFB": "required",
|
||||
},
|
||||
{"resources:CUSTOM_ACCELERATOR_FOO": "2",
|
||||
"resources:CUSTOM_MEMORY": "200",
|
||||
"trait:CUSTOM_TRAIT_ALWAYS": "required",
|
||||
}
|
||||
]
|
||||
|
||||
DEVICE_PROFILE = {
|
||||
'created_at': device_profile_created_at,
|
||||
'updated_at': device_profile_updated_at,
|
||||
'id': device_profile_id,
|
||||
'uuid': device_profile_uuid,
|
||||
'name': device_profile_name,
|
||||
'groups': device_profile_groups,
|
||||
}
|
||||
|
||||
accelerator_request_uuid = uuid.uuid4().hex
|
||||
accelerator_request_state = 'fake_state'
|
||||
accelerator_request_device_profile_name = 'fake_arq_devprof_name'
|
||||
accelerator_request_hostname = 'fake_arq_hostname'
|
||||
accelerator_request_device_rp_uuid = 1
|
||||
accelerator_request_instance_uuid = 2
|
||||
accelerator_request_attach_handle_type = 3
|
||||
accelerator_request_attach_handle_info = 4
|
||||
|
||||
ACCELERATOR_REQUEST = {
|
||||
'uuid': accelerator_request_uuid,
|
||||
'state': accelerator_request_state,
|
||||
'device_profile_name': accelerator_request_device_profile_name,
|
||||
'hostname': accelerator_request_hostname,
|
||||
'device_rp_uuid': accelerator_request_device_rp_uuid,
|
||||
'instance_uuid': accelerator_request_instance_uuid,
|
||||
'attach_handle_type': accelerator_request_attach_handle_type,
|
||||
'attach_handle_info': accelerator_request_attach_handle_info,
|
||||
}
|
||||
|
||||
|
||||
class TestAccelerator(utils.TestCommand):
|
||||
|
||||
def setUp(self):
|
||||
super(TestAccelerator, self).setUp()
|
||||
|
||||
self.app.client_manager.auth_ref = mock.MagicMock(auth_token="TOKEN")
|
||||
self.app.client_manager.accelerator = mock.MagicMock()
|
||||
|
||||
|
||||
class FakeAcceleratorResource(fakes.FakeResource):
|
||||
|
||||
def get_keys(self):
|
||||
return {'property': 'value'}
|
104
cyborgclient/tests/unit/osc/v2/test_accelerator_request.py
Normal file
104
cyborgclient/tests/unit/osc/v2/test_accelerator_request.py
Normal file
@@ -0,0 +1,104 @@
|
||||
# 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 copy
|
||||
|
||||
from cyborgclient.osc.v2 import accelerator_request as osc_accelerator_request
|
||||
from cyborgclient.tests.unit.osc.v2 import fakes as acc_fakes
|
||||
|
||||
|
||||
class TestAcceleratorRequest(acc_fakes.TestAccelerator):
|
||||
|
||||
def setUp(self):
|
||||
super(TestAcceleratorRequest, self).setUp()
|
||||
|
||||
self.mock_acc_client = self.app.client_manager.accelerator
|
||||
self.mock_acc_client.reset_mock()
|
||||
|
||||
|
||||
class TestAcceleratorRequestList(TestAcceleratorRequest):
|
||||
|
||||
def setUp(self):
|
||||
super(TestAcceleratorRequestList, self).setUp()
|
||||
|
||||
self.mock_acc_client.accelerator_requests.return_value = [
|
||||
acc_fakes.FakeAcceleratorResource(
|
||||
None,
|
||||
copy.deepcopy(acc_fakes.ACCELERATOR_REQUEST),
|
||||
loaded=True)
|
||||
]
|
||||
|
||||
self.cmd = osc_accelerator_request.ListAcceleratorRequest(
|
||||
self.app, None
|
||||
)
|
||||
|
||||
def test_accelerator_request_list(self):
|
||||
arglist = []
|
||||
verifylist = []
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
kwargs = {}
|
||||
|
||||
self.mock_acc_client.accelerator_requests.assert_called_with(**kwargs)
|
||||
|
||||
collist = (
|
||||
'uuid',
|
||||
'state',
|
||||
'device_profile_name',
|
||||
'instance_uuid',
|
||||
'attach_handle_type',
|
||||
'attach_handle_info',
|
||||
)
|
||||
self.assertEqual(collist, columns)
|
||||
|
||||
datalist = [(
|
||||
acc_fakes.accelerator_request_uuid,
|
||||
acc_fakes.accelerator_request_state,
|
||||
acc_fakes.accelerator_request_device_profile_name,
|
||||
acc_fakes.accelerator_request_instance_uuid,
|
||||
acc_fakes.accelerator_request_attach_handle_type,
|
||||
acc_fakes.accelerator_request_attach_handle_info,
|
||||
), ]
|
||||
self.assertEqual(datalist, list(data))
|
||||
|
||||
def test_accelerator_request_list_long(self):
|
||||
arglist = ['--long']
|
||||
verifylist = []
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
kwargs = {}
|
||||
|
||||
self.mock_acc_client.accelerator_requests.assert_called_with(**kwargs)
|
||||
|
||||
collist = (
|
||||
'uuid',
|
||||
'state',
|
||||
'device_profile_name',
|
||||
'hostname',
|
||||
'device_rp_uuid',
|
||||
'instance_uuid',
|
||||
'attach_handle_type',
|
||||
'attach_handle_info',
|
||||
)
|
||||
self.assertEqual(collist, columns)
|
||||
|
||||
datalist = [(
|
||||
acc_fakes.accelerator_request_uuid,
|
||||
acc_fakes.accelerator_request_state,
|
||||
acc_fakes.accelerator_request_device_profile_name,
|
||||
acc_fakes.accelerator_request_hostname,
|
||||
acc_fakes.accelerator_request_device_rp_uuid,
|
||||
acc_fakes.accelerator_request_instance_uuid,
|
||||
acc_fakes.accelerator_request_attach_handle_type,
|
||||
acc_fakes.accelerator_request_attach_handle_info,
|
||||
), ]
|
||||
self.assertEqual(datalist, list(data))
|
96
cyborgclient/tests/unit/osc/v2/test_deployable.py
Normal file
96
cyborgclient/tests/unit/osc/v2/test_deployable.py
Normal file
@@ -0,0 +1,96 @@
|
||||
# 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 copy
|
||||
|
||||
from cyborgclient.osc.v2 import deployable as osc_deployable
|
||||
from cyborgclient.tests.unit.osc.v2 import fakes as acc_fakes
|
||||
|
||||
|
||||
class TestDeployable(acc_fakes.TestAccelerator):
|
||||
|
||||
def setUp(self):
|
||||
super(TestDeployable, self).setUp()
|
||||
|
||||
self.mock_acc_client = self.app.client_manager.accelerator
|
||||
self.mock_acc_client.reset_mock()
|
||||
|
||||
|
||||
class TestDeployableList(TestDeployable):
|
||||
|
||||
def setUp(self):
|
||||
super(TestDeployableList, self).setUp()
|
||||
|
||||
self.mock_acc_client.deployables.return_value = [
|
||||
acc_fakes.FakeAcceleratorResource(
|
||||
None,
|
||||
copy.deepcopy(acc_fakes.DEPLOYABLE),
|
||||
loaded=True)
|
||||
]
|
||||
|
||||
self.cmd = osc_deployable.ListDeployable(self.app, None)
|
||||
|
||||
def test_deployable_list(self):
|
||||
arglist = []
|
||||
verifylist = []
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
kwargs = {}
|
||||
|
||||
self.mock_acc_client.deployables.assert_called_with(**kwargs)
|
||||
|
||||
collist = (
|
||||
'uuid',
|
||||
'name',
|
||||
'device_id'
|
||||
)
|
||||
self.assertEqual(collist, columns)
|
||||
|
||||
datalist = [(
|
||||
acc_fakes.deployable_uuid,
|
||||
acc_fakes.deployable_name,
|
||||
acc_fakes.deployable_device_id,
|
||||
), ]
|
||||
self.assertEqual(datalist, list(data))
|
||||
|
||||
def test_deployable_list_long(self):
|
||||
arglist = ['--long']
|
||||
verifylist = []
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
kwargs = {}
|
||||
|
||||
self.mock_acc_client.deployables.assert_called_with(**kwargs)
|
||||
|
||||
collist = (
|
||||
'created_at',
|
||||
'updated_at',
|
||||
'uuid',
|
||||
'parent_id',
|
||||
'root_id',
|
||||
'name',
|
||||
'num_accelerators',
|
||||
'device_id'
|
||||
)
|
||||
self.assertEqual(collist, columns)
|
||||
|
||||
datalist = [(
|
||||
acc_fakes.deployable_created_at,
|
||||
acc_fakes.deployable_updated_at,
|
||||
acc_fakes.deployable_uuid,
|
||||
acc_fakes.deployable_parent_id,
|
||||
acc_fakes.deployable_root_id,
|
||||
acc_fakes.deployable_name,
|
||||
acc_fakes.deployable_num_accelerators,
|
||||
acc_fakes.deployable_device_id,
|
||||
), ]
|
||||
self.assertEqual(datalist, list(data))
|
102
cyborgclient/tests/unit/osc/v2/test_device.py
Normal file
102
cyborgclient/tests/unit/osc/v2/test_device.py
Normal file
@@ -0,0 +1,102 @@
|
||||
# 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 copy
|
||||
|
||||
from cyborgclient.osc.v2 import device as osc_device
|
||||
from cyborgclient.tests.unit.osc.v2 import fakes as acc_fakes
|
||||
|
||||
|
||||
class TestDevice(acc_fakes.TestAccelerator):
|
||||
|
||||
def setUp(self):
|
||||
super(TestDevice, self).setUp()
|
||||
|
||||
self.mock_acc_client = self.app.client_manager.accelerator
|
||||
self.mock_acc_client.reset_mock()
|
||||
|
||||
|
||||
class TestDeviceList(TestDevice):
|
||||
|
||||
def setUp(self):
|
||||
super(TestDeviceList, self).setUp()
|
||||
|
||||
self.mock_acc_client.devices.return_value = [
|
||||
acc_fakes.FakeAcceleratorResource(
|
||||
None,
|
||||
copy.deepcopy(acc_fakes.DEVICE),
|
||||
loaded=True)
|
||||
]
|
||||
|
||||
self.cmd = osc_device.ListDevice(self.app, None)
|
||||
|
||||
def test_device_list(self):
|
||||
arglist = []
|
||||
verifylist = []
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
kwargs = {}
|
||||
|
||||
self.mock_acc_client.devices.assert_called_with(**kwargs)
|
||||
|
||||
collist = (
|
||||
'uuid',
|
||||
'type',
|
||||
'vendor',
|
||||
'hostname',
|
||||
'std_board_info'
|
||||
)
|
||||
self.assertEqual(collist, columns)
|
||||
|
||||
datalist = [(
|
||||
acc_fakes.device_uuid,
|
||||
acc_fakes.device_type,
|
||||
acc_fakes.device_vendor,
|
||||
acc_fakes.device_hostname,
|
||||
acc_fakes.device_std_board_info,
|
||||
), ]
|
||||
self.assertEqual(datalist, list(data))
|
||||
|
||||
def test_device_list_long(self):
|
||||
arglist = ['--long']
|
||||
verifylist = []
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
kwargs = {}
|
||||
|
||||
self.mock_acc_client.devices.assert_called_with(**kwargs)
|
||||
|
||||
collist = (
|
||||
'created_at',
|
||||
'updated_at',
|
||||
'uuid',
|
||||
'type',
|
||||
'vendor',
|
||||
'model',
|
||||
'hostname',
|
||||
'std_board_info',
|
||||
'vendor_board_info',
|
||||
)
|
||||
self.assertEqual(collist, columns)
|
||||
|
||||
datalist = [(
|
||||
acc_fakes.device_created_at,
|
||||
acc_fakes.device_updated_at,
|
||||
acc_fakes.device_uuid,
|
||||
acc_fakes.device_type,
|
||||
acc_fakes.device_vendor,
|
||||
acc_fakes.device_model,
|
||||
acc_fakes.device_hostname,
|
||||
acc_fakes.device_std_board_info,
|
||||
acc_fakes.device_vendor_board_info,
|
||||
), ]
|
||||
self.assertEqual(datalist, list(data))
|
90
cyborgclient/tests/unit/osc/v2/test_device_profile.py
Normal file
90
cyborgclient/tests/unit/osc/v2/test_device_profile.py
Normal file
@@ -0,0 +1,90 @@
|
||||
# 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 copy
|
||||
|
||||
from cyborgclient.osc.v2 import device_profile as osc_device_profile
|
||||
from cyborgclient.tests.unit.osc.v2 import fakes as acc_fakes
|
||||
|
||||
|
||||
class TestDeviceProfile(acc_fakes.TestAccelerator):
|
||||
|
||||
def setUp(self):
|
||||
super(TestDeviceProfile, self).setUp()
|
||||
|
||||
self.mock_acc_client = self.app.client_manager.accelerator
|
||||
self.mock_acc_client.reset_mock()
|
||||
|
||||
|
||||
class TestDeviceProfileList(TestDeviceProfile):
|
||||
|
||||
def setUp(self):
|
||||
super(TestDeviceProfileList, self).setUp()
|
||||
|
||||
self.mock_acc_client.device_profiles.return_value = [
|
||||
acc_fakes.FakeAcceleratorResource(
|
||||
None,
|
||||
copy.deepcopy(acc_fakes.DEVICE_PROFILE),
|
||||
loaded=True)
|
||||
]
|
||||
|
||||
self.cmd = osc_device_profile.ListDeviceProfile(self.app, None)
|
||||
|
||||
def test_device_profile_list(self):
|
||||
arglist = []
|
||||
verifylist = []
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
kwargs = {}
|
||||
|
||||
self.mock_acc_client.device_profiles.assert_called_with(**kwargs)
|
||||
|
||||
collist = (
|
||||
'uuid',
|
||||
'name',
|
||||
'groups',
|
||||
)
|
||||
self.assertEqual(collist, columns)
|
||||
|
||||
datalist = [(
|
||||
acc_fakes.device_profile_uuid,
|
||||
acc_fakes.device_profile_name,
|
||||
acc_fakes.device_profile_groups,
|
||||
), ]
|
||||
self.assertEqual(datalist, list(data))
|
||||
|
||||
def test_device_profile_list_long(self):
|
||||
arglist = ['--long']
|
||||
verifylist = []
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
kwargs = {}
|
||||
|
||||
self.mock_acc_client.device_profiles.assert_called_with(**kwargs)
|
||||
|
||||
collist = (
|
||||
'created_at',
|
||||
'updated_at',
|
||||
'uuid',
|
||||
'name',
|
||||
'groups',
|
||||
)
|
||||
self.assertEqual(collist, columns)
|
||||
|
||||
datalist = [(
|
||||
acc_fakes.device_profile_created_at,
|
||||
acc_fakes.device_profile_updated_at,
|
||||
acc_fakes.device_profile_uuid,
|
||||
acc_fakes.device_profile_name,
|
||||
acc_fakes.device_profile_groups,
|
||||
), ]
|
||||
self.assertEqual(datalist, list(data))
|
17
setup.cfg
17
setup.cfg
@@ -31,6 +31,23 @@ openstack.cli.extension =
|
||||
openstack.accelerator.v1 =
|
||||
accelerator_list = cyborgclient.osc.v1.accelerator:ListAccelerator
|
||||
|
||||
openstack.accelerator.v2 =
|
||||
accelerator_deployable_list = cyborgclient.osc.v2.deployable:ListDeployable
|
||||
accelerator_deployable_program = cyborgclient.osc.v2.deployable:ProgramDeployable
|
||||
accelerator_deployable_show = cyborgclient.osc.v2.deployable:ShowDeployable
|
||||
accelerator_device_list = cyborgclient.osc.v2.device:ListDevice
|
||||
accelerator_device_show = cyborgclient.osc.v2.device.ShowDevice
|
||||
accelerator_device_profile_list = cyborgclient.osc.v2.device_profile:ListDeviceProfile
|
||||
accelerator_device_profile_create = cyborgclient.osc.v2.device_profile:CreateDeviceProfile
|
||||
accelerator_device_profile_delete = cyborgclient.osc.v2.device_profile:DeleteDeviceProfile
|
||||
accelerator_device_profile_show = cyborgclient.osc.v2.device_profile:ShowDeviceProfile
|
||||
accelerator_arq_list = cyborgclient.osc.v2.accelerator_request:ListAcceleratorRequest
|
||||
accelerator_arq_create = cyborgclient.osc.v2.accelerator_request:CreateAcceleratorRequest
|
||||
accelerator_arq_delete = cyborgclient.osc.v2.accelerator_request:DeleteAcceleratorRequest
|
||||
accelerator_arq_show = cyborgclient.osc.v2.accelerator_request:ShowAcceleratorRequest
|
||||
accelerator_arq_bind = cyborgclient.osc.v2.accelerator_request:BindAcceleratorRequest
|
||||
accelerator_arq_unbind = cyborgclient.osc.v2.accelerator_request:UnbindAcceleratorRequest
|
||||
|
||||
[build_sphinx]
|
||||
all-files = 1
|
||||
warning-is-error = 1
|
||||
|
@@ -12,5 +12,6 @@ oslotest>=1.10.0 # Apache-2.0
|
||||
stestr>=1.0.0 # Apache-2.0
|
||||
testtools>=1.4.0 # MIT
|
||||
openstackdocstheme>=1.20.0 # Apache-2.0
|
||||
requests-mock>=0.6.0 # Apache-2.0
|
||||
# releasenotes
|
||||
reno>=1.8.0 # Apache-2.0
|
||||
|
14
tox.ini
14
tox.ini
@@ -45,6 +45,20 @@ commands =
|
||||
[testenv:debug]
|
||||
commands = oslo_debug_helper {posargs}
|
||||
|
||||
[testenv:osc_plugins]
|
||||
deps =
|
||||
-c{env:UPPER_CONSTRAINTS_FILE:https://opendev.org/openstack/requirements/raw/branch/master/upper-constraints.txt}
|
||||
-r{toxinidir}/requirements.txt
|
||||
../../x/pbrx
|
||||
whitelist_externals =
|
||||
bash
|
||||
commands =
|
||||
# bash wrapper is required to handle a subshell of find.
|
||||
bash ./tests/install-siblings.sh
|
||||
pbr freeze
|
||||
openstack --version
|
||||
python tests/check_osc_commands.py
|
||||
|
||||
[flake8]
|
||||
# E123, E125 skipped as they are invalid PEP-8.
|
||||
|
||||
|
Reference in New Issue
Block a user