CLI for resource classes (v1.2)

Set method was skipped due to two reason that from version 1.7 it is
not allowed to rename resource classes.

Change-Id: Id18aab2a95849bc60769f2f81c363c17d049b21f
This commit is contained in:
Andrey Volkov 2017-10-11 11:38:16 +03:00 committed by Matt Riedemann
parent 4a0aa464fd
commit 73aaab7a02
5 changed files with 198 additions and 1 deletions

View File

@ -23,7 +23,8 @@ API_NAME = 'placement'
API_VERSION_OPTION = 'os_placement_api_version'
SUPPORTED_VERSIONS = [
'1.0',
'1.1'
'1.1',
'1.2'
]
API_VERSIONS = {v: 'osc_placement.http.SessionClient'
for v in SUPPORTED_VERSIONS}

View File

@ -0,0 +1,124 @@
# 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 osc_lib.command import command
from osc_lib import utils
from osc_placement import version
BASE_URL = '/resource_classes'
PER_CLASS_URL = BASE_URL + '/{name}'
FIELDS = ('name',)
class ListResourceClass(command.Lister):
"""Return a list of all resource classes.
This command requires at least --os-placement-api-version 1.2.
"""
def get_parser(self, prog_name):
parser = super(ListResourceClass, self).get_parser(prog_name)
return parser
@version.check(version.ge('1.2'))
def take_action(self, parsed_args):
http = self.app.client_manager.placement
resource_classes = http.request(
'GET', BASE_URL).json()['resource_classes']
rows = (utils.get_dict_properties(i, FIELDS) for i in resource_classes)
return FIELDS, rows
class CreateResourceClass(command.Command):
"""Create a new resource class.
This command requires at least --os-placement-api-version 1.2.
"""
def get_parser(self, prog_name):
parser = super(CreateResourceClass, self).get_parser(prog_name)
parser.add_argument(
'name',
metavar='<name>',
help='Name of the resource class'
)
return parser
@version.check(version.ge('1.2'))
def take_action(self, parsed_args):
http = self.app.client_manager.placement
http.request('POST', BASE_URL, json={'name': parsed_args.name})
class ShowResourceClass(command.ShowOne):
"""Return a representation of the resource class identified by {name}.
This command requires at least --os-placement-api-version 1.2.
"""
def get_parser(self, prog_name):
parser = super(ShowResourceClass, self).get_parser(prog_name)
parser.add_argument(
'name',
metavar='<name>',
help='Name of the resource class'
)
return parser
@version.check(version.ge('1.2'))
def take_action(self, parsed_args):
http = self.app.client_manager.placement
url = PER_CLASS_URL.format(name=parsed_args.name)
resource = http.request('GET', url).json()
return FIELDS, utils.get_dict_properties(resource, FIELDS)
class DeleteResourceClass(command.Command):
"""Delete the resource class identified by {name}.
Only custom resource classes can be deleted.
This command requires at least --os-placement-api-version 1.2.
"""
def get_parser(self, prog_name):
parser = super(DeleteResourceClass, self).get_parser(prog_name)
parser.add_argument(
'name',
metavar='<name>',
help='Name of the resource class'
)
return parser
@version.check(version.ge('1.2'))
def take_action(self, parsed_args):
http = self.app.client_manager.placement
url = PER_CLASS_URL.format(name=parsed_args.name)
http.request('DELETE', url)

View File

@ -171,3 +171,15 @@ class BaseTestCase(base.BaseTestCase):
cmd += ' '.join('--aggregate %s' % aggregate
for aggregate in aggregates)
return self.openstack(cmd, use_json=True)
def resource_class_list(self):
return self.openstack('resource class list', use_json=True)
def resource_class_show(self, name):
return self.openstack('resource class show ' + name, use_json=True)
def resource_class_create(self, name):
return self.openstack('resource class create ' + name)
def resource_class_delete(self, name):
return self.openstack('resource class delete ' + name)

View File

@ -0,0 +1,56 @@
# 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 osc_placement.tests.functional import base
class TestResourceClass(base.BaseTestCase):
VERSION = '1.2'
def test_list(self):
rcs = self.resource_class_list()
names = [rc['name'] for rc in rcs]
self.assertIn('VCPU', names)
self.assertIn('MEMORY_MB', names)
self.assertIn('DISK_GB', names)
def test_fail_create_if_incorrect_class(self):
self.assertCommandFailed('JSON does not validate',
self.resource_class_create, 'fake_class')
self.assertCommandFailed('JSON does not validate',
self.resource_class_create, 'CUSTOM_lower')
self.assertCommandFailed('JSON does not validate',
self.resource_class_create,
'CUSTOM_GPU.INTEL')
def test_create(self):
self.resource_class_create('CUSTOM_GPU_DEVICE')
rcs = self.resource_class_list()
names = [rc['name'] for rc in rcs]
self.assertIn('CUSTOM_GPU_DEVICE', names)
self.resource_class_delete('CUSTOM_GPU_DEVICE')
def test_fail_show_if_unknown_class(self):
self.assertCommandFailed('No such resource class',
self.resource_class_show, 'UNKNOWN')
def test_show(self):
rc = self.resource_class_show('VCPU')
self.assertEqual('VCPU', rc['name'])
def test_fail_delete_unknown_class(self):
self.assertCommandFailed('No such resource class',
self.resource_class_delete, 'UNKNOWN')
def test_fail_delete_standard_class(self):
self.assertCommandFailed('Cannot delete standard resource class',
self.resource_class_delete, 'VCPU')

View File

@ -43,6 +43,10 @@ openstack.placement.v1 =
resource_provider_inventory_delete = osc_placement.resources.inventory:DeleteInventory
resource_provider_aggregate_list = osc_placement.resources.aggregate:ListAggregate
resource_provider_aggregate_set = osc_placement.resources.aggregate:SetAggregate
resource_class_list = osc_placement.resources.resource_class:ListResourceClass
resource_class_create = osc_placement.resources.resource_class:CreateResourceClass
resource_class_show = osc_placement.resources.resource_class:ShowResourceClass
resource_class_delete = osc_placement.resources.resource_class:DeleteResourceClass
[build_sphinx]
source-dir = doc/source