From 9f0452fdc0f7e62dcf7e9fa4829ff82409f84cca Mon Sep 17 00:00:00 2001 From: Juan Antonio Osorio Date: Wed, 16 Jul 2014 16:29:37 +0300 Subject: [PATCH] Introduce cliff for cli framework This patch introduces the cliff framework from oslo. The same functionality from the old command line interface was replicated, and a few orthographic errors where corrected from the command help. The application structure was made so that it resembles the way python-openstackclient was done, this will enable the code to be integrated to that client in a more straight forward way. Same with the naming of classes within the sub-commands. For example, the list commands are List and not List; this was done in such way because it is done that way in python-openstack client; and the aim of this commit is to produce functional code, and at the same time, follow their standards to be able to integrate this there without much hassle. NOTE: Only secrets and orders were added, since verifications are no longer in use Implements: blueprint cliff-for-python-barbicanclient Change-Id: Ice2dddf418dfb76a616b65f22dc8dfd7ef4df36f --- barbicanclient/barbican.py | 318 ++++------------------- barbicanclient/barbican_cli/__init__.py | 0 barbicanclient/barbican_cli/formatter.py | 23 ++ barbicanclient/barbican_cli/orders.py | 121 +++++++++ barbicanclient/barbican_cli/secrets.py | 169 ++++++++++++ barbicanclient/test/test_barbican.py | 36 +-- requirements.txt | 1 + setup.cfg | 12 + 8 files changed, 388 insertions(+), 292 deletions(-) create mode 100644 barbicanclient/barbican_cli/__init__.py create mode 100644 barbicanclient/barbican_cli/formatter.py create mode 100644 barbicanclient/barbican_cli/orders.py create mode 100644 barbicanclient/barbican_cli/secrets.py diff --git a/barbicanclient/barbican.py b/barbicanclient/barbican.py index 8561d2af..e2406468 100644 --- a/barbicanclient/barbican.py +++ b/barbicanclient/barbican.py @@ -19,43 +19,39 @@ Command-line interface to the Barbican API. import argparse import logging +import sys + +from cliff import app +from cliff import commandmanager from barbicanclient.common import auth from barbicanclient import client +from barbicanclient import version -class Barbican: +class Barbican(app.App): + """Barbican comand line interface.""" - def __init__(self): - self.parser = self._get_main_parser() - self.subparsers = self.parser.add_subparsers( - title='subcommands', - metavar='', - description='Action to perform' + def __init__(self, **kwargs): + super(Barbican, self).__init__( + description=__doc__.strip(), + version=version.__version__, + command_manager=commandmanager.CommandManager('barbican.client'), + **kwargs ) - self._add_create_args() - self._add_store_args() - self._add_get_args() - self._add_list_args() - self._add_verify_args() - self._add_delete_args() - def _get_main_parser(self): - parser = argparse.ArgumentParser( - description=__doc__.strip() - ) - parser.add_argument('command', - metavar='', - choices=['order', 'secret', 'verification'], - help='Entity used for command, e.g.,' - ' order, secret, verification.') - auth_group = parser.add_mutually_exclusive_group() - auth_group.add_argument('--no-auth', '-N', action='store_true', - help='Do not use authentication.') - auth_group.add_argument('--os-auth-url', '-A', - metavar='', - default=client.env('OS_AUTH_URL'), - help='Defaults to env[OS_AUTH_URL].') + def build_option_parser(self, description, version, argparse_kwargs=None): + """Introduces global arguments for the application. + This is inherited from the framework. + """ + parser = super(Barbican, self).build_option_parser( + description, version, argparse_kwargs) + parser.add_argument('--no-auth', '-N', action='store_true', + help='Do not use authentication.') + parser.add_argument('--os-auth-url', '-A', + metavar='', + default=client.env('OS_AUTH_URL'), + help='Defaults to env[OS_AUTH_URL].') parser.add_argument('--os-username', '-U', metavar='', default=client.env('OS_USERNAME'), @@ -120,242 +116,27 @@ class Barbican: 'option should be used with caution.') return parser - def _add_verify_args(self): - verify_parser = self.subparsers.add_parser('verify', - help='Create a new ' - 'verification.') - verify_parser.add_argument('--type', '-t', default='image', - help='resource type to verify, ' - 'such as "image".') + def _assert_no_auth_and_auth_url_mutually_exclusive(self, no_auth, + auth_url): + if no_auth and auth_url: + raise Exception("ERROR: argument --os-auth-url/-A: not allowed " + "with argument --no-auth/-N") - verify_parser.add_argument('--ref', '-r', - help='reference URI to ' - 'resource to verify.') - - verify_parser.add_argument('--action', '-a', default='vm_attach', - help='action to perform on ' - 'resource, such as "vm_attach".') - - verify_parser.add_argument('--impersonation', '-i', default=True, - help='is impersonation allowed ' - 'for the resource.') - verify_parser.set_defaults(func=self.verify) - - def _add_create_args(self): - create_parser = self.subparsers.add_parser('create', - help='Create a new order.') - create_parser.add_argument('--name', '-n', - help='a human-friendly name.') - create_parser.add_argument('--algorithm', '-a', default='aes', - help='the algorithm to be used with the ' - 'requested key (default: ' - '%(default)s).') - create_parser.add_argument('--bit-length', '-b', default=256, - help='the bit length of the requested' - ' secret key (default: %(default)s).', - type=int) - create_parser.add_argument('--mode', '-m', default='cbc', - help='the algorithmm mode to be used with ' - 'the rquested key (default: %(default)s).') - create_parser.add_argument('--payload-content-type', '-t', - default='application/octet-stream', - help='the type/format of the secret to be' - ' generated (default: %(default)s).') - create_parser.add_argument('--expiration', '-x', - help='the expiration ' - 'time for the secret in ISO 8601 format.') - create_parser.set_defaults(func=self.create) - - def _add_store_args(self): - store_parser = self.subparsers.add_parser( - 'store', - help='Store a secret in barbican.' - ) - store_parser.add_argument('--name', '-n', - help='a human-friendly name.') - store_parser.add_argument('--payload', '-p', help='the unencrypted' - ' secret; if provided, ' - 'you must also provide' - ' a payload_content_type') - store_parser.add_argument('--payload-content-type', '-t', - help='the type/format of the provided ' - 'secret data; "text/plain" is assumed to be' - ' UTF-8; required when --payload is' - ' supplied.') - store_parser.add_argument('--payload-content-encoding', '-e', - help='required if --payload-content-type is' - ' "application/octet-stream".') - store_parser.add_argument('--algorithm', '-a', default='aes', - help='the algorithm (default: ' - '%(default)s).') - store_parser.add_argument('--bit-length', '-b', default=256, - help='the bit length ' - '(default: %(default)s).', - type=int) - store_parser.add_argument('--mode', '-m', default='cbc', - help='the algorithmm mode; used only for ' - 'reference (default: %(default)s)') - store_parser.add_argument('--expiration', '-x', help='the expiration ' - 'time for the secret in ISO 8601 format.') - store_parser.set_defaults(func=self.store) - - def _add_delete_args(self): - delete_parser = self.subparsers.add_parser( - 'delete', - help='Delete a secret, order or ' - 'verification by providing its href.' - ) - delete_parser.add_argument('URI', help='The URI reference for the' - ' secret, order ' - 'or verification') - delete_parser.set_defaults(func=self.delete) - - def _add_get_args(self): - get_parser = self.subparsers.add_parser( - 'get', - help='Retrieve a secret, order or ' - 'verification by providing its URI.' - ) - get_parser.add_argument('URI', help='The URI reference ' - 'for the secret, ' - 'order or verification.') - get_parser.add_argument('--decrypt', '-d', help='if specified, keep' - ' will retrieve the unencrypted secret data;' - ' the data type can be specified with' - ' --payload-content-type (only used for' - ' secrets).', - action='store_true') - get_parser.add_argument('--payload_content_type', '-t', - default='text/plain', - help='the content type of the decrypted' - ' secret (default: %(default)s; only used for' - ' secrets)') - get_parser.set_defaults(func=self.get) - - def _add_list_args(self): - list_parser = self.subparsers.add_parser('list', - help='List secrets, ' - 'orders or ' - 'verifications') - list_parser.add_argument('--limit', '-l', default=10, help='specify ' - 'the limit to the number of items to list per' - ' page (default: %(default)s; maximum: 100)', - type=int) - list_parser.add_argument('--offset', '-o', default=0, help='specify t' - 'he page offset (default: %(default)s)', - type=int) - list_parser.add_argument('--name', '-n', default=None, help='specify t' - 'he secret name (default: %(default)s)') - list_parser.add_argument('--algorithm', '-a', default=None, - help='the algorithm filter for the list' - '(default: %(default)s).') - list_parser.add_argument('--bit-length', '-b', default=0, - help='the bit length filter for the list' - ' (default: %(default)s).', - type=int) - list_parser.add_argument('--mode', '-m', default=None, - help='the algorithmm mode filter for the' - ' list (default: %(default)s).') - list_parser.set_defaults(func=self.list) - - def store(self, args): - if args.command == 'secret': - secret = self.client.secrets.store(args.name, - args.payload, - args.payload_content_type, - args.payload_content_encoding, - args.algorithm, - args.bit_length, - args.mode, - args.expiration) - print(secret) - else: - self.parser.exit(status=1, message='ERROR: store is only supported' - ' for secrets\n') - - def create(self, args): - if args.command == 'order': - order = self.client.orders.create(args.name, - args.payload_content_type, - args.algorithm, - args.bit_length, - args.mode, - args.expiration) - print(order) - else: - self.parser.exit(status=1, message='ERROR: create is only ' - 'supported for orders\n') - - def delete(self, args): - if args.command == 'secret': - self.client.secrets.delete(args.URI) - elif args.command == 'verification': - self.client.verifications.delete(args.URI) - elif args.command == 'order': - self.client.orders.delete(args.URI) - else: - self.parser.exit(status=1, message='ERROR: delete is only ' - 'supported for secrets, ' - 'orders or verifications\n') - - def get(self, args): - if args.command == 'secret': - if args.decrypt: - print(self.client.secrets.decrypt(args.URI, - args.payload_content_type)) - else: - print(self.client.secrets.get(args.URI)) - elif args.command == 'verification': - print(self.client.verifications.get(args.URI)) - elif args.command == 'order': - print(self.client.orders.get(args.URI)) - else: - self.parser.exit(status=1, message='ERROR: get is only ' - 'supported for secrets, ' - 'orders or verifications\n') - - def list(self, args): - if args.command == 'secret': - ls = self.client.secrets.list(limit=args.limit, - offset=args.offset, - name=args.name, - mode=args.mode, - algorithm=args.algorithm, - bits=args.bit_length) - elif args.command == 'verification': - ls = self.client.verifications.list(args.limit, args.offset) - elif args.command == 'order': - ls = self.client.orders.list(args.limit, args.offset) - else: - self.parser.exit(status=1, message='ERROR: get list is only ' - 'supported for secrets, ' - 'orders or verifications\n') - for obj in ls: - print(obj) - print('{0}s displayed: {1} - offset: {2}'.format(args.command, len(ls), - args.offset)) - - def verify(self, args): - if args.command == 'verification': - verify = self.client.verifications\ - .create(resource_type=args.type, - resource_ref=args.ref, - resource_action=args.action, - impersonation_allowed=args.impersonation) - print(verify) - else: - self.parser.exit(status=1, message='ERROR: verify is only ' - 'supported for verifications\n') - - def execute(self, **kwargs): - args = self.parser.parse_args(kwargs.get('argv')) + def initialize_app(self, argv): + """Initializes the application. + Checks if the minimal parameters are provided and creates the client + interface. + This is inherited from the framework. + """ + args = self.options + self._assert_no_auth_and_auth_url_mutually_exclusive(args.no_auth, + args.os_auth_url) if args.no_auth: if not all([args.endpoint, args.os_tenant_id or args.os_project_id]): - self.parser.exit( - status=1, - message='ERROR: please specify --endpoint and ' - '--os-project-id(or --os-tenant-id)\n') + raise Exception( + 'ERROR: please specify --endpoint and ' + '--os-project-id(or --os-tenant-id)') self.client = client.Client(endpoint=args.endpoint, tenant_id=args.os_tenant_id or args.os_project_id, @@ -370,17 +151,14 @@ class Barbican: args.os_project_id, insecure=args.insecure) else: - self.parser.exit( - status=1, - message='ERROR: please specify authentication credentials\n' - ) - args.func(args) + self.stderr.write(self.parser.format_usage()) + raise Exception('ERROR: please specify authentication credentials') -def main(): - k = Barbican() - k.execute() +def main(argv=sys.argv[1:]): + barbican_app = Barbican() + return barbican_app.run(argv) if __name__ == '__main__': - main() + sys.exit(main(sys.argv[1:])) diff --git a/barbicanclient/barbican_cli/__init__.py b/barbicanclient/barbican_cli/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/barbicanclient/barbican_cli/formatter.py b/barbicanclient/barbican_cli/formatter.py new file mode 100644 index 00000000..a345a302 --- /dev/null +++ b/barbicanclient/barbican_cli/formatter.py @@ -0,0 +1,23 @@ +# 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. + + +class EntityFormatter(object): + """ Helper class with the purpose of formatting entities for display.""" + + def _list_objects(self, obj_list): + data = (self._get_formatted_data(obj) for obj in obj_list) + return (self.columns, data) + + def _get_formatted_entity(self, entity): + return (self.columns, self._get_formatted_data(entity)) diff --git a/barbicanclient/barbican_cli/orders.py b/barbicanclient/barbican_cli/orders.py new file mode 100644 index 00000000..3f265ee0 --- /dev/null +++ b/barbicanclient/barbican_cli/orders.py @@ -0,0 +1,121 @@ +# 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. +""" +Command-line interface sub-commands related to orders. +""" + +from cliff import command +from cliff import lister +from cliff import show + +from barbicanclient.barbican_cli.formatter import EntityFormatter + + +class OrderFormatter(EntityFormatter): + + columns = ("Order href", + "Secret href", + "Created", + "Status", + ) + + def _get_formatted_data(self, entity): + data = (entity.order_ref, + entity.secret_ref, + entity.created, + entity.status, + ) + return data + + +class CreateOrder(show.ShowOne, OrderFormatter): + """Create a new order.""" + + def get_parser(self, prog_name): + parser = super(CreateOrder, self).get_parser(prog_name) + parser.add_argument('--name', '-n', + help='a human-friendly name.') + parser.add_argument('--algorithm', '-a', default='aes', + help='the algorithm to be used with the ' + 'requested key (default: ' + '%(default)s).') + parser.add_argument('--bit-length', '-b', default=256, + help='the bit length of the requested' + ' secret key (default: %(default)s).', + type=int) + parser.add_argument('--mode', '-m', default='cbc', + help='the algorithm mode to be used with ' + 'the requested key (default: %(default)s).') + parser.add_argument('--payload-content-type', '-t', + default='application/octet-stream', + help='the type/format of the secret to be' + ' generated (default: %(default)s).') + parser.add_argument('--expiration', '-x', + help='the expiration ' + 'time for the secret in ISO 8601 format.') + return parser + + def take_action(self, args): + entity = self.app.client.orders.create(args.name, + args.payload_content_type, + args.algorithm, + args.bit_length, + args.mode, + args.expiration) + return self._get_formatted_entity(entity) + + +class DeleteOrder(command.Command): + """Delete an order by providing its href.""" + + def get_parser(self, prog_name): + parser = super(DeleteOrder, self).get_parser(prog_name) + parser.add_argument('URI', help='The URI reference for the order') + return parser + + def take_action(self, args): + self.app.client.orders.delete(args.URI) + + +class GetOrder(show.ShowOne, OrderFormatter): + """Retrieve an order by providing its URI.""" + + def get_parser(self, prog_name): + parser = super(GetOrder, self).get_parser(prog_name) + parser.add_argument('URI', help='The URI reference order.') + return parser + + def take_action(self, args): + entity = self.app.client.orders.get(args.URI) + return self._get_formatted_entity(entity) + + +class ListOrder(lister.Lister, OrderFormatter): + """List orders.""" + + def get_parser(self, prog_name): + parser = super(ListOrder, self).get_parser(prog_name) + parser.add_argument('--limit', '-l', default=10, + help='specify the limit to the number of items ' + 'to list per page (default: %(default)s; ' + 'maximum: 100)', + type=int) + parser.add_argument('--offset', '-o', default=0, + help='specify the page offset ' + '(default: %(default)s)', + type=int) + return parser + + def take_action(self, args): + obj_list = self.app.client.orders.list(args.limit, args.offset) + return self._list_objects(obj_list) diff --git a/barbicanclient/barbican_cli/secrets.py b/barbicanclient/barbican_cli/secrets.py new file mode 100644 index 00000000..4cd6352a --- /dev/null +++ b/barbicanclient/barbican_cli/secrets.py @@ -0,0 +1,169 @@ +# 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. +""" +Command-line interface sub-commands related to secrets. +""" + +from cliff import command +from cliff import lister +from cliff import show + +from barbicanclient.barbican_cli.formatter import EntityFormatter + + +class SecretFormatter(EntityFormatter): + + columns = ("Secret href", + "Name", + "Created", + "Status", + "Content types", + "Algorithm", + "Bit length", + "Mode", + "Expiration", + ) + + def _get_formatted_data(self, entity): + data = (entity.secret_ref, + entity.name, + entity.created, + entity.status, + entity.content_types, + entity.algorithm, + entity.bit_length, + entity.mode, + entity.expiration, + ) + return data + + +class DeleteSecret(command.Command): + """Delete an secret by providing its href.""" + + def get_parser(self, prog_name): + parser = super(DeleteSecret, self).get_parser(prog_name) + parser.add_argument('URI', help='The URI reference for the secret') + return parser + + def take_action(self, args): + self.app.client.secrets.delete(args.URI) + + +class GetSecret(show.ShowOne, SecretFormatter): + """Retrieve a secret by providing its URI.""" + + def get_parser(self, prog_name): + parser = super(GetSecret, self).get_parser(prog_name) + parser.add_argument('URI', help='The URI reference for the secret.') + parser.add_argument('--decrypt', '-d', + help='if specified, retrieve the ' + 'unencrypted secret data; ' + 'the data type can be specified with ' + '--payload-content-type.', + action='store_true') + parser.add_argument('--payload_content_type', '-t', + default='text/plain', + help='the content type of the decrypted' + ' secret (default: %(default)s.') + return parser + + def take_action(self, args): + if args.decrypt: + entity = self.app.client.secrets.decrypt(args.URI, + args.payload_content_type) + return (('Secret',), + (entity,)) + else: + entity = self.app.client.secrets.get(args.URI) + return self._get_formatted_entity(entity) + + +class ListSecret(lister.Lister, SecretFormatter): + """List secrets.""" + + def get_parser(self, prog_name): + parser = super(ListSecret, self).get_parser(prog_name) + parser.add_argument('--limit', '-l', default=10, + help='specify the limit to the number of items ' + 'to list per page (default: %(default)s; ' + 'maximum: 100)', + type=int) + parser.add_argument('--offset', '-o', default=0, + help='specify the page offset ' + '(default: %(default)s)', + type=int) + parser.add_argument('--name', '-n', default=None, + help='specify the secret name ' + '(default: %(default)s)') + parser.add_argument('--algorithm', '-a', default=None, + help='the algorithm filter for the list' + '(default: %(default)s).') + parser.add_argument('--bit-length', '-b', default=0, + help='the bit length filter for the list' + ' (default: %(default)s).', + type=int) + parser.add_argument('--mode', '-m', default=None, + help='the algorithm mode filter for the' + ' list (default: %(default)s).') + return parser + + def take_action(self, args): + obj_list = self.app.client.secrets.list(args.limit, args.offset, + args.name, args.mode, + args.algorithm, + args.bit_length) + return self._list_objects(obj_list) + + +class StoreSecret(show.ShowOne, SecretFormatter): + """Store a secret in Barbican.""" + + def get_parser(self, prog_name): + parser = super(StoreSecret, self).get_parser(prog_name) + parser.add_argument('--name', '-n', + help='a human-friendly name.') + parser.add_argument('--payload', '-p', + help='the unencrypted secret; if provided, ' + 'you must also provide a ' + 'payload_content_type') + parser.add_argument('--payload-content-type', '-t', + help='the type/format of the provided ' + 'secret data; "text/plain" is assumed to be ' + 'UTF-8; required when --payload is ' + 'supplied.') + parser.add_argument('--payload-content-encoding', '-e', + help='required if --payload-content-type is ' + '"application/octet-stream".') + parser.add_argument('--algorithm', '-a', default='aes', + help='the algorithm (default: ' + '%(default)s).') + parser.add_argument('--bit-length', '-b', default=256, + help='the bit length ' + '(default: %(default)s).', + type=int) + parser.add_argument('--mode', '-m', default='cbc', + help='the algorithm mode; used only for ' + 'reference (default: %(default)s)') + parser.add_argument('--expiration', '-x', + help='the expiration time for the secret in ' + 'ISO 8601 format.') + return parser + + def take_action(self, args): + entity = self.app.client.secrets.store( + args.name, args.payload, args.payload_content_type, + args.payload_content_encoding, args.algorithm, + args.bit_length, args.mode, args.expiration) + return (('Secret',), + (entity,)) diff --git a/barbicanclient/test/test_barbican.py b/barbicanclient/test/test_barbican.py index 46f0c212..336448b1 100644 --- a/barbicanclient/test/test_barbican.py +++ b/barbicanclient/test/test_barbican.py @@ -31,37 +31,29 @@ class WhenTestingBarbicanCLI(test_client.BaseEntityResource): def setUp(self): self._setUp('barbican') + self.global_file = six.StringIO() def barbican(self, argstr): """Source: Keystone client's shell method in test_shell.py""" - orig = sys.stdout - orig_err = sys.stderr clean_env = {} _old_env, os.environ = os.environ, clean_env.copy() - exit_code = 0 + exit_code = 1 try: - sys.stdout = six.StringIO() - sys.stderr = sys.stdout - _barbican = barbicanclient.barbican.Barbican() - _barbican.execute(argv=argstr.split()) - except SystemExit: - exc_type, exc_value, exc_traceback = sys.exc_info() - exit_code = exc_value.code + stdout = self.global_file + _barbican = barbicanclient.barbican.Barbican(stdout=stdout, + stderr=stdout) + exit_code = _barbican.run(argv=argstr.split()) + except Exception as exception: + exit_message = exception.message finally: - if exit_code == 0: - out = sys.stdout.getvalue() - else: - out = sys.stderr.getvalue() - sys.stdout.close() - sys.stdout = orig - sys.stderr = orig_err + out = stdout.getvalue() os.environ = _old_env return exit_code, out def test_should_show_usage_error_with_no_args(self): args = "" exit_code, out = self.barbican(args) - self.assertEqual(2, exit_code) + self.assertEqual(1, exit_code) self.assertIn('usage:', out) def test_should_show_usage_with_help_flag(self): @@ -73,9 +65,9 @@ class WhenTestingBarbicanCLI(test_client.BaseEntityResource): def test_should_error_if_noauth_and_authurl_both_specified(self): args = "--no-auth --os-auth-url http://localhost:5000/v3" exit_code, out = self.barbican(args) - self.assertEqual(2, exit_code) + self.assertEqual(1, exit_code) self.assertIn( - 'error: argument --os-auth-url/-A: not allowed with ' + 'ERROR: argument --os-auth-url/-A: not allowed with ' 'argument --no-auth/-N', out) def _expect_error_with_invalid_noauth_args(self, args): @@ -175,7 +167,7 @@ class TestBarbicanWithKeystoneClient(testtools.TestCase): barbican_url, v2_token['access']['token']['tenant']['id']), status=200) - self.barbican.execute(argv=argv) + self.barbican.run(argv=argv) @httpretty.activate def test_v3_auth(self): @@ -202,4 +194,4 @@ class TestBarbicanWithKeystoneClient(testtools.TestCase): barbican_url, v3_token['token']['project']['id']), status=200) - self.barbican.execute(argv=argv) + self.barbican.run(argv=argv) diff --git a/requirements.txt b/requirements.txt index 927084d1..18459a90 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,4 @@ argparse requests>=1.2.3 six>=1.5.2 python-keystoneclient>=0.9.0 +cliff==1.6.1 diff --git a/setup.cfg b/setup.cfg index bda4d214..0b2bd4fb 100644 --- a/setup.cfg +++ b/setup.cfg @@ -26,6 +26,18 @@ packages = console_scripts = barbican = barbicanclient.barbican:main +barbican.client = + + order_create = barbicanclient.barbican_cli.orders:CreateOrder + order_delete = barbicanclient.barbican_cli.orders:DeleteOrder + order_get = barbicanclient.barbican_cli.orders:GetOrder + order_list = barbicanclient.barbican_cli.orders:ListOrder + + secret_delete = barbicanclient.barbican_cli.secrets:DeleteSecret + secret_get = barbicanclient.barbican_cli.secrets:GetSecret + secret_list = barbicanclient.barbican_cli.secrets:ListSecret + secret_store = barbicanclient.barbican_cli.secrets:StoreSecret + [build_sphinx] source-dir = doc/source build-dir = doc/build