Implement quota-class management commands for KB.
"quota-class show" List the quotas for a quota class. "quota-class update" Update quotas for a quota class. "quota-class delete" Delete quotas for a quota-class. Add test-cases for the same. Depends-on: I7c3f809afcf65077701e320fc97135a3c21c7786 Change-Id: I182ef0d84d5fbcca2b443b14d8f4bd6d42735659
This commit is contained in:
parent
f57144cfcb
commit
3333a3c6be
@ -50,6 +50,20 @@ class ResourceManager(object):
|
||||
resource = self._generate_resource(json_response_key)
|
||||
return resource
|
||||
|
||||
def _update(self, url, data):
|
||||
data = json.dumps(data)
|
||||
resp = self.http_client.put(url, data)
|
||||
if resp.status_code != 200:
|
||||
self._raise_api_exception(resp)
|
||||
json_response_key = get_json(resp)
|
||||
result = self._generate_resource(json_response_key)
|
||||
return result
|
||||
|
||||
def _delete(self, url):
|
||||
resp = self.http_client.delete(url)
|
||||
if resp.status_code != 200:
|
||||
self._raise_api_exception(resp)
|
||||
|
||||
def _raise_api_exception(self, resp):
|
||||
error_data = resp.content
|
||||
raise exceptions.APIException(error_code=resp.status_code,
|
||||
|
@ -19,6 +19,7 @@ import six
|
||||
import osprofiler.profiler
|
||||
|
||||
from kingbirdclient.api import httpclient
|
||||
from kingbirdclient.api.v1 import quota_class_manager as qcm
|
||||
from kingbirdclient.api.v1 import quota_manager as qm
|
||||
|
||||
_DEFAULT_KINGBIRD_URL = "http://localhost:8118/v1.0"
|
||||
@ -76,6 +77,7 @@ class Client(object):
|
||||
|
||||
# Create all resource managers
|
||||
self.quota_manager = qm.quota_manager(self.http_client)
|
||||
self.quota_class_manager = qcm.quota_class_manager(self.http_client)
|
||||
|
||||
|
||||
def authenticate(kingbird_url=None, username=None,
|
||||
|
42
kingbirdclient/api/v1/quota_class_manager.py
Normal file
42
kingbirdclient/api/v1/quota_class_manager.py
Normal file
@ -0,0 +1,42 @@
|
||||
# Copyright (c) 2017 Ericsson AB.
|
||||
#
|
||||
# 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 kingbirdclient.api import base
|
||||
|
||||
|
||||
class QuotaClass(base.Resource):
|
||||
resource_name = 'os-quota-class-sets'
|
||||
|
||||
|
||||
class quota_class_manager(base.ResourceManager):
|
||||
resource_class = QuotaClass
|
||||
|
||||
def list_quota_class(self, quota_class):
|
||||
tenant = self.http_client.project_id
|
||||
url = '/%s/os-quota-class-sets/%s' % (tenant, quota_class)
|
||||
return self._list(url)
|
||||
|
||||
def quota_class_update(self, quota_class, **kwargs):
|
||||
if kwargs:
|
||||
data = dict()
|
||||
data['quota_class_set'] = {
|
||||
k: int(v) for k, v in kwargs.items() if v is not None}
|
||||
tenant = self.http_client.project_id
|
||||
url = '/%s/os-quota-class-sets/%s' % (tenant, quota_class)
|
||||
return self._update(url, data)
|
||||
|
||||
def delete_quota_class(self, quota_class):
|
||||
tenant = self.http_client.project_id
|
||||
url = '/%s/os-quota-class-sets/%s' % (tenant, quota_class)
|
||||
return self._delete(url)
|
229
kingbirdclient/commands/v1/quota_class_manager.py
Normal file
229
kingbirdclient/commands/v1/quota_class_manager.py
Normal file
@ -0,0 +1,229 @@
|
||||
# Copyright (c) 2017 Ericsson AB.
|
||||
#
|
||||
# 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 kingbirdclient.commands.v1 import base
|
||||
from kingbirdclient import exceptions
|
||||
|
||||
|
||||
def format(quotas=None):
|
||||
columns = (
|
||||
'Quota',
|
||||
'Limit'
|
||||
)
|
||||
|
||||
if quotas:
|
||||
data = (
|
||||
quotas._data,
|
||||
quotas._values,
|
||||
)
|
||||
|
||||
else:
|
||||
data = (tuple('<none>' for _ in range(len(columns))),)
|
||||
|
||||
return columns, data
|
||||
|
||||
|
||||
class ListQuotaClass(base.KingbirdLister):
|
||||
"""List the quotas for a quota class."""
|
||||
|
||||
def _get_format_function(self):
|
||||
return format
|
||||
|
||||
def get_parser(self, parsed_args):
|
||||
parser = super(ListQuotaClass, self).get_parser(parsed_args)
|
||||
parser.add_argument(
|
||||
'quota_class',
|
||||
help='Name of quota class to list the quotas.'
|
||||
)
|
||||
return parser
|
||||
|
||||
def _get_resources(self, parsed_args):
|
||||
kingbird_client = self.app.client_manager.sync_engine
|
||||
quota_class = parsed_args.quota_class
|
||||
return kingbird_client.quota_class_manager.\
|
||||
list_quota_class(quota_class)
|
||||
|
||||
|
||||
class UpdateQuotaClass(base.KingbirdLister):
|
||||
"""Update quotas for a quota class."""
|
||||
|
||||
def _get_format_function(self):
|
||||
return format
|
||||
|
||||
def get_parser(self, parsed_args):
|
||||
parser = super(UpdateQuotaClass, self).get_parser(parsed_args)
|
||||
|
||||
parser.add_argument(
|
||||
'quota_class',
|
||||
help='Name of quota class to update the quotas.'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--metadata_items',
|
||||
help='New value for the "metadata-items" quota'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--subnet',
|
||||
help='New value for the "subnet" quota'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--network',
|
||||
help='New value for the "network" quota'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--floatingip',
|
||||
help='New value for the "floatingip" quota'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--gigabytes',
|
||||
help='New value for the "gigabytes" quota'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--backup_gigabytes',
|
||||
help='New value for the "backup_gigabytes" quota'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--ram',
|
||||
help='New value for the "ram" quota'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--floating_ips',
|
||||
help='New value for the "floating_ips" quota'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--snapshots',
|
||||
help='New value for the "snapshots" quota'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--security_group_rule',
|
||||
help='New value for the "security_group_rule" quota'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--instances',
|
||||
help='New value for the "instances" quota'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--key_pairs',
|
||||
help='New value for the "key_pairs" quota'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--volumes',
|
||||
help='New value for the "volumes" quota'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--router',
|
||||
help='New value for the "router" quota'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--security_group',
|
||||
help='New value for the "security_group" quota'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--cores',
|
||||
help='New value for the "cores" quota'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--backups',
|
||||
help='New value for the "backups" quota'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--fixed_ips',
|
||||
help='New value for the "fixed_ips" quota'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--port',
|
||||
help='New value for the "port" quota'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--security_groups',
|
||||
help='New value for the "security_groups" quota'
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
def _get_resources(self, parsed_args):
|
||||
quota_class = parsed_args.quota_class
|
||||
kingbird_client = self.app.client_manager.sync_engine
|
||||
kwargs = {
|
||||
"metadata_items": parsed_args.metadata_items,
|
||||
"subnet": parsed_args.subnet,
|
||||
"network": parsed_args.network,
|
||||
"floatingip": parsed_args.floatingip,
|
||||
"gigabytes": parsed_args.gigabytes,
|
||||
"backup_gigabytes": parsed_args.backup_gigabytes,
|
||||
"ram": parsed_args.ram,
|
||||
"floating_ips": parsed_args.floating_ips,
|
||||
"snapshots": parsed_args.snapshots,
|
||||
"security_group_rule": parsed_args.security_group_rule,
|
||||
"instances": parsed_args.instances,
|
||||
"key_pairs": parsed_args.key_pairs,
|
||||
"volumes": parsed_args.volumes,
|
||||
"router": parsed_args.router,
|
||||
"security_group": parsed_args.security_group,
|
||||
"cores": parsed_args.cores,
|
||||
"backups": parsed_args.backups,
|
||||
"fixed_ips": parsed_args.fixed_ips,
|
||||
"port": parsed_args.port,
|
||||
"security_groups": parsed_args.security_groups
|
||||
}
|
||||
return kingbird_client.quota_class_manager.\
|
||||
quota_class_update(quota_class, **kwargs)
|
||||
|
||||
|
||||
class DeleteQuotaClass(command.Command):
|
||||
"""Delete quotas for a quota-class."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(DeleteQuotaClass, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'quota_class',
|
||||
help='Name of quota class to delete quotas.'
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
kingbird_client = self.app.client_manager.sync_engine
|
||||
quota_class = parsed_args.quota_class
|
||||
try:
|
||||
kingbird_client.quota_class_manager.\
|
||||
delete_quota_class(quota_class)
|
||||
print("Request to delete %s quota_class has been accepted." %
|
||||
(parsed_args.quota_class))
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
error_msg = "Unable to delete the specified quota_class."
|
||||
raise exceptions.KingbirdClientException(error_msg)
|
@ -29,6 +29,7 @@ from cliff import commandmanager
|
||||
from osc_lib.command import command
|
||||
|
||||
import argparse
|
||||
from kingbirdclient.commands.v1 import quota_class_manager as qcm
|
||||
from kingbirdclient.commands.v1 import quota_manager as qm
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -395,6 +396,9 @@ class KingbirdShell(app.App):
|
||||
'bash-completion': BashCompletionCommand,
|
||||
'quota defaults': qm.ListDefaults,
|
||||
'quota show': qm.GlobalLimits,
|
||||
'quota-class show': qcm.ListQuotaClass,
|
||||
'quota-class update': qcm.UpdateQuotaClass,
|
||||
'quota-class delete': qcm.DeleteQuotaClass,
|
||||
}
|
||||
|
||||
|
||||
|
66
kingbirdclient/tests/v1/test_quota_class_manager.py
Normal file
66
kingbirdclient/tests/v1/test_quota_class_manager.py
Normal file
@ -0,0 +1,66 @@
|
||||
# Copyright (c) 2017 Ericsson AB.
|
||||
#
|
||||
# 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 kingbirdclient.api.v1 import quota_class_manager as qcm
|
||||
from kingbirdclient.commands.v1 import quota_class_manager as quota_class_cmd
|
||||
from kingbirdclient.tests import base
|
||||
|
||||
QUOTAS_DICT = {
|
||||
'Quota': 'fake_item',
|
||||
'Limit': '123'
|
||||
}
|
||||
|
||||
CLASS_NAME = 'default'
|
||||
|
||||
QUOTACLASSMANAGER = qcm.QuotaClass(mock, QUOTAS_DICT['Quota'],
|
||||
QUOTAS_DICT['Limit'])
|
||||
|
||||
|
||||
class TestCLIQuotaClassManagerV1(base.BaseCommandTest):
|
||||
|
||||
def test_list_quota_class(self):
|
||||
self.client.quota_class_manager.\
|
||||
list_quota_class.return_value = [QUOTACLASSMANAGER]
|
||||
actual_quota = self.call(quota_class_cmd.ListQuotaClass,
|
||||
app_args=[CLASS_NAME])
|
||||
self.assertEqual([('fake_item', '123')], actual_quota[1])
|
||||
|
||||
def test_negative_list_quota_class(self):
|
||||
self.client.quota_class_manager.\
|
||||
list_quota_class.return_value = []
|
||||
actual_quota = self.call(quota_class_cmd.ListQuotaClass,
|
||||
app_args=[CLASS_NAME])
|
||||
self.assertEqual((('<none>', '<none>'),), actual_quota[1])
|
||||
|
||||
def test_update_quota_class(self):
|
||||
self.client.quota_class_manager.\
|
||||
quota_class_update.return_value = [QUOTACLASSMANAGER]
|
||||
actual_quota = self.call(quota_class_cmd.UpdateQuotaClass,
|
||||
app_args=[CLASS_NAME, '--ram', '51200'])
|
||||
self.assertEqual([('fake_item', '123')], actual_quota[1])
|
||||
|
||||
def test_negative_update_quota_class(self):
|
||||
self.client.quota_class_manager.\
|
||||
quota_class_update.return_value = []
|
||||
actual_quota = self.call(quota_class_cmd.UpdateQuotaClass,
|
||||
app_args=[CLASS_NAME, '--ram', '51200'])
|
||||
self.assertEqual((('<none>', '<none>'),), actual_quota[1])
|
||||
|
||||
def test_delete_quota_class(self):
|
||||
self.call(quota_class_cmd.DeleteQuotaClass,
|
||||
app_args=[CLASS_NAME])
|
||||
self.client.quota_class_manager.delete_quota_class.\
|
||||
assert_called_once_with(CLASS_NAME)
|
Loading…
x
Reference in New Issue
Block a user