Create Openstack CLI plugin for Barbican

This is the first implementation of the barbicanclient plugin for the
OpenStack CLI. Since we chose to use cliff in for the client, the
integration with the OCC is quite seamless. Only change that needed to
be done was that, since the OCC uses a ClientManager class to fetch the
specific libraries for the components, we needed to simulate that in the
barbicanclient.

Currently, the plugin can be used if the barbican server is configured
with keystone authentication. This is because currently there is no way
for us to set the X-Project-Id header manually from the client (if the
plugin is being used) but that functionality is out of the scope of this
first implementation.

Change-Id: I37fd158af24e785bc0b7125c6b4c1a9795927a10
This commit is contained in:
Juan Antonio Osorio Robles
2015-07-06 16:59:43 +03:00
committed by Juan Antonio Osorio Robles
parent d154ad90a8
commit 85f5ec262c
9 changed files with 96 additions and 42 deletions

View File

@@ -18,6 +18,7 @@ Command-line interface to the Barbican API.
"""
import sys
from collections import namedtuple
from cliff import app
from cliff import command
@@ -52,7 +53,8 @@ class Barbican(app.App):
super(Barbican, self).__init__(
description=__doc__.strip(),
version=version.__version__,
command_manager=commandmanager.CommandManager('barbican.client'),
command_manager=commandmanager.CommandManager(
'openstack.key_manager.v1'),
deferred_help=True,
**kwargs
)
@@ -309,8 +311,9 @@ class Barbican(app.App):
client interface.
This is inherited from the framework.
"""
self.client_manager = namedtuple('ClientManager', 'key_manager')
if cmd.auth_required:
self.client = self.create_client(self.options)
self.client_manager.key_manager = self.create_client(self.options)
def run(self, argv):
# If no arguments are provided, usage is displayed

View File

@@ -28,7 +28,7 @@ class GetCA(show.ShowOne):
return parser
def take_action(self, args):
entity = self.app.client.cas.get(ca_ref=args.URI)
entity = self.app.client_manager.key_manager.cas.get(ca_ref=args.URI)
return entity._get_formatted_entity()
@@ -52,5 +52,6 @@ class ListCA(lister.Lister):
return parser
def take_action(self, args):
obj_list = self.app.client.cas.list(args.limit, args.offset, args.name)
obj_list = self.app.client_manager.key_manager.cas.list(
args.limit, args.offset, args.name)
return cas.CA._list_objects(obj_list)

View File

@@ -31,7 +31,7 @@ class DeleteContainer(command.Command):
return parser
def take_action(self, args):
self.app.client.containers.delete(args.URI)
self.app.client_manager.key_manager.containers.delete(args.URI)
class GetContainer(show.ShowOne):
@@ -43,7 +43,8 @@ class GetContainer(show.ShowOne):
return parser
def take_action(self, args):
entity = self.app.client.containers.get(args.URI)
entity = self.app.client_manager.key_manager.containers.get(
args.URI)
return entity._get_formatted_entity()
@@ -70,8 +71,8 @@ class ListContainer(lister.Lister):
return parser
def take_action(self, args):
obj_list = self.app.client.containers.list(args.limit, args.offset,
args.name, args.type)
obj_list = self.app.client_manager.key_manager.containers.list(
args.limit, args.offset, args.name, args.type)
return Container._list_objects(obj_list)
@@ -93,8 +94,8 @@ class CreateContainer(show.ShowOne):
return parser
def take_action(self, args):
container_type = self.app.client.containers._container_map.get(
args.type)
client = self.app.client_manager.key_manager
container_type = client.containers._container_map.get(args.type)
if not container_type:
raise ValueError('Invalid container type specified.')
secret_refs = CreateContainer._parse_secrets(args.secret)
@@ -103,7 +104,7 @@ class CreateContainer(show.ShowOne):
private_key_ref = secret_refs.get('private_key')
private_key_pass_ref = secret_refs.get('private_key_passphrase')
entity = RSAContainer(
api=self.app.client.containers._api,
api=client.containers._api,
name=args.name,
public_key_ref=public_key_ref,
private_key_ref=private_key_ref,
@@ -115,7 +116,7 @@ class CreateContainer(show.ShowOne):
private_key_ref = secret_refs.get('private_key')
private_key_pass_ref = secret_refs.get('private_key_passphrase')
entity = CertificateContainer(
api=self.app.client.containers._api,
api=client.containers._api,
name=args.name,
certificate_ref=certificate_ref,
intermediates_ref=intermediates_ref,
@@ -123,7 +124,7 @@ class CreateContainer(show.ShowOne):
private_key_passphrase_ref=private_key_pass_ref,
)
else:
entity = container_type(api=self.app.client.containers._api,
entity = container_type(api=client.containers._api,
name=args.name, secret_refs=secret_refs)
entity.store()
return entity._get_formatted_entity()

View File

@@ -73,14 +73,14 @@ class CreateOrder(show.ShowOne):
raise ValueError(
'Couldn\'t read request file %s.' % args.request_file)
entity = self.app.client.orders.create(
entity = self.app.client_manager.key_manager.orders.create(
name=args.name, type=args.type, subject_dn=args.subject_dn,
request_type=args.request_type,
source_container_ref=args.source_container_ref,
ca_id=args.ca_id, profile=args.profile,
request_data=request_data)
else:
entity = self.app.client.orders.create(
entity = self.app.client_manager.key_manager.orders.create(
name=args.name, type=args.type,
payload_content_type=args.payload_content_type,
algorithm=args.algorithm, bit_length=args.bit_length,
@@ -98,7 +98,7 @@ class DeleteOrder(command.Command):
return parser
def take_action(self, args):
self.app.client.orders.delete(args.URI)
self.app.client_manager.key_manager.orders.delete(args.URI)
class GetOrder(show.ShowOne):
@@ -110,7 +110,8 @@ class GetOrder(show.ShowOne):
return parser
def take_action(self, args):
entity = self.app.client.orders.get(order_ref=args.URI)
entity = self.app.client_manager.key_manager.orders.get(
order_ref=args.URI)
return entity._get_formatted_entity()
@@ -131,7 +132,8 @@ class ListOrder(lister.Lister):
return parser
def take_action(self, args):
obj_list = self.app.client.orders.list(args.limit, args.offset)
obj_list = self.app.client_manager.key_manager.orders.list(
args.limit, args.offset)
if not obj_list:
return [], []
columns = obj_list[0]._get_generic_columns()

View File

@@ -29,7 +29,7 @@ class DeleteSecret(command.Command):
return parser
def take_action(self, args):
self.app.client.secrets.delete(args.URI)
self.app.client_manager.key_manager.secrets.delete(args.URI)
class GetSecret(show.ShowOne):
@@ -62,12 +62,13 @@ class GetSecret(show.ShowOne):
def take_action(self, args):
if args.decrypt or args.payload:
entity = self.app.client.secrets.get(args.URI,
args.payload_content_type)
entity = self.app.client_manager.key_manager.secrets.get(
args.URI, args.payload_content_type)
return (('Payload',),
(entity.payload,))
else:
entity = self.app.client.secrets.get(secret_ref=args.URI)
entity = self.app.client_manager.key_manager.secrets.get(
secret_ref=args.URI)
return entity._get_formatted_entity()
@@ -82,8 +83,8 @@ class UpdateSecret(show.ShowOne):
return parser
def take_action(self, args):
self.app.client.secrets.update(args.URI,
args.payload)
self.app.client_manager.key_manager.secrets.update(args.URI,
args.payload)
class ListSecret(lister.Lister):
@@ -116,10 +117,9 @@ class ListSecret(lister.Lister):
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)
obj_list = self.app.client_manager.key_manager.secrets.list(
args.limit, args.offset, args.name, args.mode, args.algorithm,
args.bit_length)
return secrets.Secret._list_objects(obj_list)
@@ -162,7 +162,7 @@ class StoreSecret(show.ShowOne):
return parser
def take_action(self, args):
entity = self.app.client.secrets.create(
entity = self.app.client_manager.key_manager.secrets.create(
name=args.name, payload=args.payload,
payload_content_type=args.payload_content_type,
payload_content_encoding=args.payload_content_encoding,

View File

@@ -0,0 +1,43 @@
# 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 logging
from barbicanclient import client
LOG = logging.getLogger(__name__)
DEFAULT_API_VERSION = '1'
API_VERSION_OPTION = 'os_key_manager_api_version'
API_NAME = 'key_manager'
API_VERSIONS = {
'1': 'barbicanclient.client.Client',
}
def make_client(instance):
"""Returns a Barbican service client."""
return client.Client(session=instance.session,
region_name=instance._region_name)
def build_option_parser(parser):
"""Hook to add global options."""
parser.add_argument('--os-key-manager-api-version',
metavar='<key-manager-api-version>',
default=client.env(
'OS_KEY_MANAGER_API_VERSION',
default=DEFAULT_API_VERSION),
help=('Barbican API version, default=' +
DEFAULT_API_VERSION +
' (Env: OS_KEY_MANAGER_API_VERSION)'))
return parser

View File

@@ -30,7 +30,7 @@ class ContainerBehaviors(base_behaviors.BaseBehaviors):
:param container_href the href to the container to delete
"""
argv = ['container', 'delete']
argv = ['secret', 'container', 'delete']
self.add_auth_and_endpoint(argv)
argv.extend([container_href])
@@ -44,7 +44,7 @@ class ContainerBehaviors(base_behaviors.BaseBehaviors):
:return: the href to the newly created container
"""
argv = ['container', 'create']
argv = ['secret', 'container', 'create']
self.add_auth_and_endpoint(argv)
for secret_href in secret_hrefs:
argv.extend(['--secret', secret_href])
@@ -64,7 +64,7 @@ class ContainerBehaviors(base_behaviors.BaseBehaviors):
:return dict of container values, or an empty dict if the container
is not found.
"""
argv = ['container', 'get']
argv = ['secret', 'container', 'get']
self.add_auth_and_endpoint(argv)
argv.extend([container_href])
@@ -81,7 +81,7 @@ class ContainerBehaviors(base_behaviors.BaseBehaviors):
:return: a list of containers
"""
argv = ['container', 'list']
argv = ['secret', 'container', 'list']
self.add_auth_and_endpoint(argv)
stdout, stderr = self.issue_barbican_command(argv)

View File

@@ -27,12 +27,15 @@ packages =
console_scripts =
barbican = barbicanclient.barbican:main
barbican.client =
openstack.cli.extension =
key_manager = barbicanclient.osc_plugin
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
openstack.key_manager.v1 =
secret_order_create = barbicanclient.barbican_cli.orders:CreateOrder
secret_order_delete = barbicanclient.barbican_cli.orders:DeleteOrder
secret_order_get = barbicanclient.barbican_cli.orders:GetOrder
secret_order_list = barbicanclient.barbican_cli.orders:ListOrder
secret_delete = barbicanclient.barbican_cli.secrets:DeleteSecret
secret_get = barbicanclient.barbican_cli.secrets:GetSecret
@@ -40,10 +43,10 @@ barbican.client =
secret_store = barbicanclient.barbican_cli.secrets:StoreSecret
secret_update = barbicanclient.barbican_cli.secrets:UpdateSecret
container_delete = barbicanclient.barbican_cli.containers:DeleteContainer
container_get = barbicanclient.barbican_cli.containers:GetContainer
container_list = barbicanclient.barbican_cli.containers:ListContainer
container_create = barbicanclient.barbican_cli.containers:CreateContainer
secret_container_delete = barbicanclient.barbican_cli.containers:DeleteContainer
secret_container_get = barbicanclient.barbican_cli.containers:GetContainer
secret_container_list = barbicanclient.barbican_cli.containers:ListContainer
secret_container_create = barbicanclient.barbican_cli.containers:CreateContainer
ca_get = barbicanclient.barbican_cli.cas:GetCA
ca_list = barbicanclient.barbican_cli.cas:ListCA

View File

@@ -11,6 +11,7 @@ testrepository>=0.0.18
testtools>=1.4.0
oslotest>=1.10.0 # Apache-2.0
nose
python-openstackclient>=1.5.0
# Documentation build requirements
sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2