Implement quota defaults command for KB

kingbird quota defaults list the default global quotas for a tenant.
Add test-case for the same.
Added profile related things.

Change-Id: I1a6b04fdf3ef7f7fa9aa61c8da9311c7e4c4a5f2
This commit is contained in:
Goutham Pratapa 2016-11-23 17:40:57 +05:30
parent 516b739613
commit 450695bd30
11 changed files with 272 additions and 11 deletions

View File

@ -0,0 +1,55 @@
# Copyright (c) 2016 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 json
class Resource(object):
# This will be overridden by the actual resource
resource_name = 'Something'
def __init__(self, manager, data, values):
self.manager = manager
self._data = data
self._values = values
class ResourceManager(object):
resource_class = None
def __init__(self, http_client):
self.http_client = http_client
def _list(self, url, response_key=None):
resp = self.http_client.get(url)
if resp.status_code != 200:
self._raise_api_exception(resp)
json_response_key = get_json(resp)
json_objects = [json_response_key[item] for item in json_response_key]
resource = []
for json_object in json_objects:
for resource_data in json_object:
resource.append(self.resource_class(self, resource_data,
json_object[resource_data]))
return resource
def get_json(response):
"""Get JSON representation of response."""
json_field_or_function = getattr(response, 'json', None)
if callable(json_field_or_function):
return response.json()
else:
return json.loads(response.content)

View File

@ -19,6 +19,7 @@ import six
import osprofiler.profiler
from kingbirdclient.api import httpclient
from kingbirdclient.api.v1 import quota_manager as qm
_DEFAULT_KINGBIRD_URL = "http://localhost:8118/v1.0"
@ -73,6 +74,9 @@ class Client(object):
insecure=insecure
)
# Create all resource managers
self.quota_manager = qm.quota_manager(self.http_client)
def authenticate(kingbird_url=None, username=None,
api_key=None, project_name=None, auth_url=None,

View File

@ -0,0 +1,29 @@
# Copyright (c) 2016 Ericsson AB.
# 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
#
# 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 Quota(base.Resource):
resource_name = 'os-quota-sets'
class quota_manager(base.ResourceManager):
resource_class = Quota
def list_defaults(self):
tenant = self.http_client.project_id
url = '/%s/os-quota-sets/defaults' % tenant
return self._list(url)

View File

View File

@ -0,0 +1,51 @@
# Copyright (c) 2016 Ericsson AB
# 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
#
# 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 abc
from osc_lib.command import command
import six
@six.add_metaclass(abc.ABCMeta)
class KingbirdLister(command.Lister):
@abc.abstractmethod
def _get_format_function(self):
raise NotImplementedError
@abc.abstractmethod
def _get_resources(self, parsed_args):
"""Get a list of API resources (e.g. using client)."""
raise NotImplementedError
def _validate_parsed_args(self, parsed_args):
# No-op by default.
pass
def take_action(self, parsed_args):
self._validate_parsed_args(parsed_args)
f = self._get_format_function()
ret = self._get_resources(parsed_args)
if not isinstance(ret, list):
ret = [ret]
data = [f(r)[1] for r in ret]
if data:
return f()[0], data
else:
return f()

View File

@ -0,0 +1,44 @@
# Copyright (c) 2016 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.commands.v1 import base
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 ListDefaults(base.KingbirdLister):
"""List all default quotas."""
def _get_format_function(self):
return format
def _get_resources(self, parsed_args):
kingbird_client = self.app.client_manager.sync_engine
return kingbird_client.quota_manager.list_defaults()

View File

@ -29,7 +29,7 @@ from cliff import commandmanager
from osc_lib.command import command
import argparse
from kingbirdclient.commands.v1 import quota_manager as qm
LOG = logging.getLogger(__name__)
@ -290,6 +290,19 @@ class KingbirdShell(app.App):
'(Env: KINGBIRDCLIENT_INSECURE)'
)
parser.add_argument(
'--profile',
dest='profile',
metavar='HMAC_KEY',
help='HMAC key to use for encrypting context data for performance '
'profiling of operation. This key should be one of the '
'values configured for the osprofiler middleware in kingbird,'
'it is specified in the profiler section of the kingbird '
'configuration (i.e. /etc/kingbird/kingbird.conf). '
'Without the key, profiling will not be triggered even if '
'osprofiler is enabled on the server side.'
)
return parser
def initialize_app(self, argv):
@ -337,7 +350,8 @@ class KingbirdShell(app.App):
service_type=self.options.service_type,
auth_token=self.options.token,
cacert=self.options.cacert,
insecure=self.options.insecure
insecure=self.options.insecure,
profile=self.options.profile
)
if not self.options.auth_url and not skip_auth:
@ -348,6 +362,15 @@ class KingbirdShell(app.App):
" default url with --os-auth-system or env[OS_AUTH_SYSTEM]")
)
# Adding client_manager variable to make kingbird client work with
# unified OpenStack client.
ClientManager = type(
'ClientManager',
(object,),
dict(sync_engine=self.client)
)
self.client_manager = ClientManager()
def _set_shell_commands(self, cmds_dict):
for k, v in cmds_dict.items():
self.command_manager.add_command(k, v)
@ -370,6 +393,7 @@ class KingbirdShell(app.App):
def _get_commands_v1():
return {
'bash-completion': BashCompletionCommand,
'quota defaults': qm.ListDefaults,
}

View File

@ -71,7 +71,7 @@ class BaseClientTest(unittest2.TestCase):
class BaseCommandTest(unittest2.TestCase):
def setUp(self):
self.app = mock.Mock()
self.client = self.app.client_manager.workflow_engine
self.client = self.app.client_manager.sync_engine
def call(self, command, app_args=[], prog_name=''):
cmd = command(self.app, app_args)

View File

@ -31,7 +31,7 @@ class TestShell(base.BaseShellTests):
@mock.patch('kingbirdclient.api.client.determine_client_version')
def test_default_kingbird_version(self, mock):
default_version = 'v1.0'
self.shell('quota-defaults')
self.shell('quota defaults')
self.assertTrue(mock.called)
kingbird_version = mock.call_args
self.assertEqual(default_version, kingbird_version[0][0])
@ -43,7 +43,7 @@ class TestShell(base.BaseShellTests):
'--os-username=admin '
'--os-password=1234 '
'--os-tenant-name=admin '
'quota-defaults'
'quota defaults'
)
self.assertTrue(mock.called)
params = mock.call_args
@ -57,7 +57,7 @@ class TestShell(base.BaseShellTests):
'--os-username=admin '
'--os-password=1234 '
'--os-tenant-name=admin '
'quota-defaults'
'quota defaults'
)
self.assertTrue(mock.called)
params = mock.call_args
@ -74,7 +74,7 @@ class TestShell(base.BaseShellTests):
@mock.patch('kingbirdclient.api.client.client')
def test_kb_default_service_type(self, mock):
self.shell('quota-defaults')
self.shell('quota defaults')
self.assertTrue(mock.called)
params = mock.call_args
# Default service type is synchronization
@ -89,7 +89,7 @@ class TestShell(base.BaseShellTests):
@mock.patch('kingbirdclient.api.client.client')
def test_kb_default_endpoint_type(self, mock):
self.shell('quota-defaults')
self.shell('quota defaults')
self.assertTrue(mock.called)
params = mock.call_args
self.assertEqual('publicURL', params[1]['endpoint_type'])
@ -98,7 +98,7 @@ class TestShell(base.BaseShellTests):
def test_os_auth_token(self, mock):
self.shell(
'--os-auth-token=abcd1234 '
'quota-defaults'
'quota defaults'
)
self.assertTrue(mock.called)
params = mock.call_args
@ -107,7 +107,7 @@ class TestShell(base.BaseShellTests):
@mock.patch('kingbirdclient.api.client.client')
def test_command_without_kingbird_url(self, mock):
self.shell(
'quota-defaults'
'quota defaults'
)
self.assertTrue(mock.called)
params = mock.call_args
@ -126,8 +126,22 @@ class TestShell(base.BaseShellTests):
@mock.patch('kingbirdclient.api.client.client')
def test_command_without_project_name(self, mock):
self.shell(
'quota-defaults'
'quota defaults'
)
self.assertTrue(mock.called)
params = mock.call_args
self.assertEqual('', params[1]['project_name'])
@mock.patch('kingbirdclient.api.client.client')
def test_kingbird_profile(self, mock):
self.shell('--profile=SECRET_HMAC_KEY quota defaults')
self.assertTrue(mock.called)
params = mock.call_args
self.assertEqual('SECRET_HMAC_KEY', params[1]['profile'])
@mock.patch('kingbirdclient.api.client.client')
def test_kingbird_without_profile(self, mock):
self.shell('quota defaults')
self.assertTrue(mock.called)
params = mock.call_args
self.assertEqual(None, params[1]['profile'])

View File

View File

@ -0,0 +1,40 @@
# Copyright (c) 2016 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_manager as qm
from kingbirdclient.commands.v1 import quota_manager as quota_cmd
from kingbirdclient.tests import base
QUOTAS_DICT = {
'Quota': 'fake_item',
'Limit': '123'
}
QUOTAMANAGER = qm.Quota(mock, QUOTAS_DICT['Quota'],
QUOTAS_DICT['Limit'])
class TestCLIQuotaManagerV1(base.BaseCommandTest):
def test_list_defaults(self):
self.client.quota_manager.list_defaults.return_value = [QUOTAMANAGER]
actual_quota = self.call(quota_cmd.ListDefaults)
self.assertEqual([('fake_item', '123')], actual_quota[1])
def test_negative_list_defaults(self):
self.client.quota_manager.list_defaults.return_value = []
actual_quota = self.call(quota_cmd.ListDefaults)
self.assertEqual((('<none>', '<none>'),), actual_quota[1])