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<Entity> and not List<Entities>; 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
This commit is contained in:
@@ -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='<action>',
|
||||
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='<entity>',
|
||||
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='<auth-url>',
|
||||
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='<auth-url>',
|
||||
default=client.env('OS_AUTH_URL'),
|
||||
help='Defaults to env[OS_AUTH_URL].')
|
||||
parser.add_argument('--os-username', '-U',
|
||||
metavar='<auth-user-name>',
|
||||
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:]))
|
||||
|
||||
0
barbicanclient/barbican_cli/__init__.py
Normal file
0
barbicanclient/barbican_cli/__init__.py
Normal file
23
barbicanclient/barbican_cli/formatter.py
Normal file
23
barbicanclient/barbican_cli/formatter.py
Normal file
@@ -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))
|
||||
121
barbicanclient/barbican_cli/orders.py
Normal file
121
barbicanclient/barbican_cli/orders.py
Normal file
@@ -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)
|
||||
169
barbicanclient/barbican_cli/secrets.py
Normal file
169
barbicanclient/barbican_cli/secrets.py
Normal file
@@ -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,))
|
||||
@@ -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)
|
||||
|
||||
@@ -3,3 +3,4 @@ argparse
|
||||
requests>=1.2.3
|
||||
six>=1.5.2
|
||||
python-keystoneclient>=0.9.0
|
||||
cliff==1.6.1
|
||||
|
||||
12
setup.cfg
12
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
|
||||
|
||||
Reference in New Issue
Block a user