Add entry points for kb client

Created initial directory structure for KB commands to work.
Modify setup.cfg to add entry point.
Refactored shell.py to display help, bash-completion and
exceptions for invalid credentials.
Add testcases for the same.

Change-Id: I8d31aef2722c73572074754f7a608b720ce2f678
This commit is contained in:
Goutham Pratapa 2016-11-15 15:54:47 +05:30
parent f6e549f9be
commit fda1462d75
7 changed files with 223 additions and 25 deletions

View File

@ -0,0 +1,5 @@
===============================
Commands
================================
This module helps in mapping kingbird commands to APIs.

View File

View File

@ -38,3 +38,12 @@ class IllegalArgumentException(KingbirdClientException):
def __init__(self, message=None):
if message:
self.message = message
class CommandError(KingbirdClientException):
message = "CommandErrorException occurred"
code = "COMMAND_ERROR_EXCEPTION"
def __init__(self, message=None):
if message:
self.message = message

View File

@ -21,6 +21,7 @@ import sys
from kingbirdclient import __version__ as kingbird_version
from kingbirdclient.api import client
from kingbirdclient import exceptions
from kingbirdclient.openstack.common import cliutils as c
from cliff import app
@ -289,19 +290,6 @@ 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 mistral, '
'it is specified in the profiler section of the mistral '
'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):
@ -311,19 +299,33 @@ class KingbirdShell(app.App):
self._set_shell_commands(self._get_commands(ver))
do_help = ('help' in argv) or ('-h' in argv) or not argv
# Set default for auth_url if not supplied. The default is not
# set at the parser to support use cases where auth is not enabled.
# An example use case would be a developer's environment.
if not self.options.auth_url:
if self.options.password or self.options.token:
self.options.auth_url = 'http://localhost:35357/v3'
do_help = ['help', '-h', 'bash-completion']
# bash-completion should not require authentication.
if do_help or ('bash-completion' in argv):
skip_auth = ''.join(argv) in do_help
if skip_auth:
self.options.auth_url = None
if self.options.auth_url and not self.options.token \
and not skip_auth:
if not self.options.tenant_name:
raise exceptions.CommandError(
("You must provide a tenant_name "
"via --os-tenantname env[OS_TENANT_NAME]")
)
if not self.options.username:
raise exceptions.CommandError(
("You must provide a username "
"via --os-username env[OS_USERNAME]")
)
if not self.options.password:
raise exceptions.CommandError(
("You must provide a password "
"via --os-password env[OS_PASSWORD]")
)
self.client = client.client(
kingbird_url=self.options.kingbird_url,
username=self.options.username,
@ -335,10 +337,17 @@ class KingbirdShell(app.App):
service_type=self.options.service_type,
auth_token=self.options.token,
cacert=self.options.cacert,
insecure=self.options.insecure,
profile=self.options.profile
insecure=self.options.insecure
)
if not self.options.auth_url and not skip_auth:
raise exceptions.CommandError(
("You must provide an auth url via either"
"--os-auth-url or env[OS_AUTH_URL] or "
"specify an auth_system which defines a"
" default url with --os-auth-system or env[OS_AUTH_SYSTEM]")
)
def _set_shell_commands(self, cmds_dict):
for k, v in cmds_dict.items():
self.command_manager.add_command(k, v)

View File

@ -0,0 +1,38 @@
# Copyright 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 re
from testtools import matchers
from kingbirdclient.tests import base_shell_test as base
class TestCLIBashCompletionV1(base.BaseShellTests):
def test_bash_completion(self):
bash_completion, stderr = self.shell('bash-completion')
self.assertIn('bash-completion', bash_completion)
self.assertFalse(stderr)
class TestCLIHelp(base.BaseShellTests):
def test_help(self):
required = [
'.*?^usage: ',
'.*?^\s+help\s+print detailed help for another command'
]
kb_help, stderr = self.shell('help')
for r in required:
self.assertThat((kb_help + stderr),
matchers.MatchesRegex(r, re.DOTALL | re.MULTILINE))

View File

@ -0,0 +1,133 @@
# Copyright 2016 EricssonAB.
#
# 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.tests import base_shell_test as base
class TestShell(base.BaseShellTests):
@mock.patch('kingbirdclient.api.client.determine_client_version')
def test_kingbird_version(self, mock):
self.shell(
'--os-kingbird-version=v1 quota-defaults'
)
self.assertTrue(mock.called)
kingbird_version = mock.call_args
self.assertEqual('v1', kingbird_version[0][0])
@mock.patch('kingbirdclient.api.client.determine_client_version')
def test_default_kingbird_version(self, mock):
default_version = 'v1.0'
self.shell('quota-defaults')
self.assertTrue(mock.called)
kingbird_version = mock.call_args
self.assertEqual(default_version, kingbird_version[0][0])
@mock.patch('kingbirdclient.api.client.client')
def test_env_variables(self, mock):
self.shell(
'--os-auth-url=https://127.0.0.1:35357/v3 '
'--os-username=admin '
'--os-password=1234 '
'--os-tenant-name=admin '
'quota-defaults'
)
self.assertTrue(mock.called)
params = mock.call_args
self.assertEqual('https://127.0.0.1:35357/v3', params[1]['auth_url'])
self.assertEqual('admin', params[1]['username'])
self.assertEqual('admin', params[1]['project_name'])
@mock.patch('kingbirdclient.api.client.client')
def test_env_without_auth_url(self, mock):
self.shell(
'--os-username=admin '
'--os-password=1234 '
'--os-tenant-name=admin '
'quota-defaults'
)
self.assertTrue(mock.called)
params = mock.call_args
self.assertEqual('', params[1]['auth_url'])
self.assertEqual('admin', params[1]['username'])
self.assertEqual('admin', params[1]['project_name'])
@mock.patch('kingbirdclient.api.client.client')
def test_kb_service_type(self, mock):
self.shell('--os-service-type=synchronization')
self.assertTrue(mock.called)
parameters = mock.call_args
self.assertEqual('synchronization', parameters[1]['service_type'])
@mock.patch('kingbirdclient.api.client.client')
def test_kb_default_service_type(self, mock):
self.shell('quota-defaults')
self.assertTrue(mock.called)
params = mock.call_args
# Default service type is synchronization
self.assertEqual('synchronization', params[1]['service_type'])
@mock.patch('kingbirdclient.api.client.client')
def test_kb_endpoint_type(self, mock):
self.shell('--os-kingbird-endpoint-type=adminURL quota-defaults')
self.assertTrue(mock.called)
params = mock.call_args
self.assertEqual('adminURL', params[1]['endpoint_type'])
@mock.patch('kingbirdclient.api.client.client')
def test_kb_default_endpoint_type(self, mock):
self.shell('quota-defaults')
self.assertTrue(mock.called)
params = mock.call_args
self.assertEqual('publicURL', params[1]['endpoint_type'])
@mock.patch('kingbirdclient.api.client.client')
def test_os_auth_token(self, mock):
self.shell(
'--os-auth-token=abcd1234 '
'quota-defaults'
)
self.assertTrue(mock.called)
params = mock.call_args
self.assertEqual('abcd1234', params[1]['auth_token'])
@mock.patch('kingbirdclient.api.client.client')
def test_command_without_kingbird_url(self, mock):
self.shell(
'quota-defaults'
)
self.assertTrue(mock.called)
params = mock.call_args
self.assertEqual('', params[1]['kingbird_url'])
@mock.patch('kingbirdclient.api.client.client')
def test_command_with_kingbird_url(self, mock):
self.shell(
'--os-kingbird-url=http://localhost:8118/v1 quota-defaults'
)
self.assertTrue(mock.called)
params = mock.call_args
self.assertEqual('http://localhost:8118/v1',
params[1]['kingbird_url'])
@mock.patch('kingbirdclient.api.client.client')
def test_command_without_project_name(self, mock):
self.shell(
'quota-defaults'
)
self.assertTrue(mock.called)
params = mock.call_args
self.assertEqual('', params[1]['project_name'])

View File

@ -23,6 +23,10 @@ classifier =
packages =
kingbirdclient
[entry_points]
console_scripts =
kingbird = kingbirdclient.shell:main
[build_sphinx]
source-dir = doc/source
build-dir = doc/build
@ -48,4 +52,4 @@ output_file = kingbirdclient/locale/kingbirdclient.pot
[build_releasenotes]
all_files = 1
build-dir = releasenotes/build
source-dir = releasenotes/source
source-dir = releasenotes/source