General cleanup; basic commands for CAs and Certificates.

This commit is contained in:
Pino de Candia 2018-01-25 14:34:12 -06:00
parent f51eb96394
commit 274e9667b0
9 changed files with 108 additions and 924 deletions

View File

@ -1,21 +0,0 @@
#!/usr/bin/env python
# Copyright 2012 Managed I.T.
#
# Author: Kiall Mac Innes <kiall@managedit.ie>
#
# 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 sys
from tatuclient.shell import TatuShell
shell = TatuShell()
sys.exit(shell.run(sys.argv[1:]))

View File

@ -42,18 +42,13 @@ openstack.ssh.v1 =
usercert_list = tatuclient.v1.cli.usercert:ListUserCertsCommand
usercert_show = tatuclient.v1.cli.usercert:ShowUserCertCommand
usercert_revoke = tatuclient.v1.cli.usercert:RevokeUserCertCommand
usercert_delete = tatuclient.v1.cli.usercert:DeleteUserCertCommand
hostcert_create = tatuclient.v1.cli.hostcert:CreateHostCertCommand
hostcert_list = tatuclient.v1.cli.hostcert:ListHostCertsCommand
hostcert_show = tatuclient.v1.cli.hostcert:ShowHostCertCommand
hostcert_revoke = tatuclient.v1.cli.hostcert:RevokeHostCertCommand
hostcert_delete = tatuclient.v1.cli.hostcert:DeleteHostCertCommand
sshca_create = tatuclient.v1.cli.ca:CreateCACommand
sshca_list = tatuclient.v1.cli.ca:ListCAsCommand
sshca_show = tatuclient.v1.cli.ca:ShowCACommand
sshca_delete = tatuclient.v1.cli.ca:DeleteCACommand
[build_sphinx]
builders = html,man

View File

@ -87,40 +87,6 @@ class Controller(object):
return body
@six.add_metaclass(abc.ABCMeta)
class CrudController(Controller):
@abc.abstractmethod
def list(self, *args, **kw):
"""
List a resource
"""
@abc.abstractmethod
def get(self, *args, **kw):
"""
Get a resource
"""
@abc.abstractmethod
def create(self, *args, **kw):
"""
Create a resource
"""
@abc.abstractmethod
def update(self, *args, **kw):
"""
Update a resource
"""
@abc.abstractmethod
def delete(self, *args, **kw):
"""
Delete a resource
"""
def get_versions():
mgr = extension.ExtensionManager('tatuclient.versions')
return dict([(ep.name, ep.plugin) for ep in mgr.extensions])

View File

@ -36,213 +36,4 @@ def env(*vars, **kwargs):
value = os.environ.get(v)
if value:
return value
return kwargs.get('default', '')
class TatuShell(App):
CONSOLE_MESSAGE_FORMAT = '%(levelname)s: %(message)s'
DEFAULT_VERBOSE_LEVEL = 0
def __init__(self):
super(TatuShell, self).__init__(
description='Tatu Client',
version=version.version_string(),
command_manager=CommandManager('tatuclient.cli'),
)
self.log = logging.getLogger(__name__)
def build_option_parser(self, description, version):
parser = super(TatuShell, self).build_option_parser(
description, version)
parser.add_argument('--os-username',
default=env('OS_USERNAME'),
help='Name used for authentication with the '
'OpenStack Identity service. '
'Defaults to env[OS_USERNAME].')
parser.add_argument('--os-user-id',
default=env('OS_USER_ID'),
help='User ID used for authentication with the '
'OpenStack Identity service. '
'Defaults to env[OS_USER_ID].')
parser.add_argument('--os-user-domain-id',
default=env('OS_USER_DOMAIN_ID'),
help='Defaults to env[OS_USER_DOMAIN_ID].')
parser.add_argument('--os-user-domain-name',
default=env('OS_USER_DOMAIN_NAME'),
help='Defaults to env[OS_USER_DOMAIN_NAME].')
parser.add_argument('--os-password',
default=env('OS_PASSWORD'),
help='Password used for authentication with the '
'OpenStack Identity service. '
'Defaults to env[OS_PASSWORD].')
parser.add_argument('--os-tenant-name',
default=env('OS_TENANT_NAME'),
help='Tenant to request authorization on. '
'Defaults to env[OS_TENANT_NAME].')
parser.add_argument('--os-tenant-id',
default=env('OS_TENANT_ID'),
help='Tenant to request authorization on. '
'Defaults to env[OS_TENANT_ID].')
parser.add_argument('--os-project-name',
default=env('OS_PROJECT_NAME'),
help='Project to request authorization on. '
'Defaults to env[OS_PROJECT_NAME].')
parser.add_argument('--os-domain-name',
default=env('OS_DOMAIN_NAME'),
help='Project to request authorization on. '
'Defaults to env[OS_DOMAIN_NAME].')
parser.add_argument('--os-domain-id',
default=env('OS_DOMAIN_ID'),
help='Defaults to env[OS_DOMAIN_ID].')
parser.add_argument('--os-project-id',
default=env('OS_PROJECT_ID'),
help='Project to request authorization on. '
'Defaults to env[OS_PROJECT_ID].')
parser.add_argument('--os-project-domain-id',
default=env('OS_PROJECT_DOMAIN_ID'),
help='Defaults to env[OS_PROJECT_DOMAIN_ID].')
parser.add_argument('--os-project-domain-name',
default=env('OS_PROJECT_DOMAIN_NAME'),
help='Defaults to env[OS_PROJECT_DOMAIN_NAME].')
parser.add_argument('--os-auth-url',
default=env('OS_AUTH_URL'),
help='Specify the Identity endpoint to use for '
'authentication. '
'Defaults to env[OS_AUTH_URL].')
parser.add_argument('--os-region-name',
default=env('OS_REGION_NAME'),
help='Specify the region to use. '
'Defaults to env[OS_REGION_NAME].')
parser.add_argument('--os-token',
default=env('OS_SERVICE_TOKEN'),
help='Specify an existing token to use instead of '
'retrieving one via authentication (e.g. '
'with username & password). '
'Defaults to env[OS_SERVICE_TOKEN].')
parser.add_argument('--os-endpoint',
default=env('OS_SSH_ENDPOINT',
'OS_SERVICE_ENDPOINT'),
help='Specify an endpoint to use instead of '
'retrieving one from the service catalog '
'(via authentication). '
'Defaults to env[OS_SSH_ENDPOINT].')
parser.add_argument('--os-endpoint-type',
default=env('OS_ENDPOINT_TYPE',
default='publicURL'),
help='Defaults to env[OS_ENDPOINT_TYPE].')
parser.add_argument('--os-service-type',
default=env('OS_SSH_SERVICE_TYPE', default='ssh'),
help=("Defaults to env[OS_SSH_SERVICE_TYPE], or "
"'ssh'."))
parser.add_argument('--os-cacert',
default=env('OS_CACERT'),
help=('CA certificate bundle file. Defaults to '
'env[OS_CACERT].'))
parser.add_argument('--insecure', action='store_true',
help="Explicitly allow 'insecure' SSL requests.")
parser.add_argument('--all-tenants', action='store_true',
help="Allows to list all domains from all "
"tenants.")
return parser
def configure_logging(self):
"""Configure logging for the app
Cliff sets some defaults we don't want so re-work it a bit
"""
if self.options.debug:
# --debug forces verbose_level 3
# Set this here so cliff.app.configure_logging() can work
self.options.verbose_level = 3
super(TatuShell, self).configure_logging()
root_logger = logging.getLogger('')
# Requests logs some stuff at INFO that we don't want
# unless we have DEBUG
requests_log = logging.getLogger("requests")
requests_log.setLevel(logging.ERROR)
# Other modules we don't want DEBUG output for so
# don't reset them below
iso8601_log = logging.getLogger("iso8601")
iso8601_log.setLevel(logging.ERROR)
# Set logging to the requested level
self.dump_stack_trace = False
if self.options.verbose_level == 0:
# --quiet
root_logger.setLevel(logging.ERROR)
elif self.options.verbose_level == 1:
# This is the default case, no --debug, --verbose or --quiet
root_logger.setLevel(logging.WARNING)
elif self.options.verbose_level == 2:
# One --verbose
root_logger.setLevel(logging.INFO)
elif self.options.verbose_level >= 3:
# Two or more --verbose
root_logger.setLevel(logging.DEBUG)
requests_log.setLevel(logging.DEBUG)
if self.options.debug:
# --debug forces traceback
self.dump_stack_trace = True
def initialize_app(self, argv):
super(TatuShell, self).initialize_app(argv)
self.session = utils.get_session(
auth_url=self.options.os_auth_url,
endpoint=self.options.os_endpoint,
domain_id=self.options.os_domain_id,
domain_name=self.options.os_domain_name,
project_id=self.options.os_project_id or self.options.os_tenant_id,
project_name=(self.options.os_project_name or
self.options.os_tenant_name),
project_domain_name=self.options.os_project_domain_name,
project_domain_id=self.options.os_project_domain_id,
username=self.options.os_username,
user_id=self.options.os_user_id,
password=self.options.os_password,
user_domain_id=self.options.os_user_domain_id,
user_domain_name=self.options.os_user_domain_name,
token=self.options.os_token,
insecure=self.options.insecure,
cacert=self.options.os_cacert
)
def run(self, argv):
try:
return super(TatuShell, self).run(argv)
except Exception as e:
if not logging.getLogger('').handlers:
logging.basicConfig()
if self.dump_stack_trace:
self.log.error(traceback.format_exc(e))
else:
self.log.error('Exception raised: ' + str(e))
return 1
return kwargs.get('default', '')

View File

@ -101,15 +101,10 @@ def get_columns(data):
return list(columns)
@removals.removed_kwarg('all_tenants', removal_version='1.3.0')
@removals.removed_kwarg('edit_managed', removal_version='1.3.0')
def get_session(auth_url, endpoint, domain_id, domain_name, project_id,
project_name, project_domain_name, project_domain_id, username,
user_id, password, user_domain_id, user_domain_name, token,
insecure, cacert, all_tenants=False, edit_managed=False):
# NOTE: all_tenants and edit_managed are here for backwards compat
# reasons, do not add additional modifiers here.
insecure, cacert):
session = ks_session.Session()
# Build + Attach Authentication Plugin
@ -148,11 +143,6 @@ def get_session(auth_url, endpoint, domain_id, domain_name, project_id,
else:
session.verify = cacert
# NOTE: all_tenants and edit_managed are here for backwards compat
# reasons, do not add additional modifiers here.
session.all_tenants = all_tenants
session.edit_managed = edit_managed
return session

View File

@ -1,24 +1,21 @@
# Copyright 2014 Hewlett-Packard Development Company, L.P.
# Copyright 2017 Huawei, Inc. All rights reserved.
#
# Author: Endre Karlson <endre.karlson@hp.com>
# 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
#
# 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
#
# 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.
# 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 argparse
import logging
from osc_lib.command import command
import six
from tatuclient import utils
from tatuclient.v1.cli import common
@ -28,233 +25,52 @@ from tatuclient.v1.utils import get_all
LOG = logging.getLogger(__name__)
def _format_recordset(recordset):
# Remove unneeded fields for display output formatting
recordset['records'] = "\n".join(recordset['records'])
recordset.pop('links', None)
return recordset
def _has_project_id(data):
if len(data) < 1:
return False
if 'project_id' in data[0]:
return True
return False
_columns = ['auth_id', 'user_pub_key', 'host_pub_key']
_names = ['Project/CA ID', 'User Public Key', 'Host Public Key']
class ListCACommand(command.Lister):
"""List recordsets"""
columns = ['id', 'name', 'type', 'records', 'status', 'action']
"""List CAs"""
def get_parser(self, prog_name):
parser = super(ListRecordSetsCommand, self).get_parser(prog_name)
parser.add_argument('--name', help="RecordSet Name", required=False)
parser.add_argument('--type', help="RecordSet Type", required=False)
parser.add_argument('--data', help="RecordSet Record Data",
required=False)
parser.add_argument('--ttl', help="Time To Live (Seconds)",
required=False)
parser.add_argument('--description', help="Description",
required=False)
parser.add_argument('--status', help="RecordSet Status",
required=False)
parser.add_argument('--action', help="RecordSet Action",
required=False)
parser.add_argument('zone_id', help="Zone ID. To list all"
" recordsets specify 'all'")
parser = super(ListCACommand, self).get_parser(prog_name)
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.ssh
common.set_all_common_headers(client, parsed_args)
criterion = {}
if parsed_args.type is not None:
criterion["type"] = parsed_args.type
if parsed_args.name is not None:
criterion["name"] = parsed_args.name
if parsed_args.data is not None:
criterion["data"] = parsed_args.data
if parsed_args.ttl is not None:
criterion["ttl"] = parsed_args.ttl
if parsed_args.description is not None:
criterion["description"] = parsed_args.description
if parsed_args.status is not None:
criterion["status"] = parsed_args.status
if parsed_args.action is not None:
criterion["action"] = parsed_args.action
cols = self.columns
if parsed_args.zone_id == 'all':
data = get_all(client.recordsets.list_all_zones,
criterion=criterion)
cols.insert(2, 'zone_name')
else:
data = get_all(client.recordsets.list, args=[parsed_args.zone_id],
criterion=criterion)
if client.session.all_projects and _has_project_id(data):
cols.insert(1, 'project_id')
for i, rs in enumerate(data):
data[i] = _format_recordset(rs)
return cols, (utils.get_item_properties(s, cols) for s in data)
data = get_all(client.ca.list)
return _names, (utils.get_item_properties(s, _columns) for s in data)
class ShowRecordSetCommand(command.ShowOne):
"""Show recordset details"""
class ShowCACommand(command.ShowOne):
"""Show CA details"""
def get_parser(self, prog_name):
parser = super(ShowRecordSetCommand, self).get_parser(prog_name)
parser.add_argument('zone_id', help="Zone ID")
parser.add_argument('id', help="RecordSet ID")
parser = super(ShowCACommand, self).get_parser(prog_name)
parser.add_argument('auth_id', help="Project/CA ID")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.ssh
common.set_all_common_headers(client, parsed_args)
data = client.recordsets.get(parsed_args.zone_id, parsed_args.id)
_format_recordset(data)
return six.moves.zip(*sorted(six.iteritems(data)))
data = client.ca.get(parsed_args.auth_id)
return _names, utils.get_item_properties(data, _columns)
class CreateRecordSetCommand(command.ShowOne):
"""Create new recordset"""
log = logging.getLogger('deprecated')
class CreateCACommand(command.ShowOne):
"""Create new CA"""
def get_parser(self, prog_name):
parser = super(CreateRecordSetCommand, self).get_parser(prog_name)
parser.add_argument('zone_id', help="Zone ID")
parser.add_argument('name', help="RecordSet Name")
req_group = parser.add_mutually_exclusive_group(required=True)
req_group.add_argument(
'--records',
help=argparse.SUPPRESS,
nargs='+')
req_group.add_argument(
'--record',
help="RecordSet Record, repeat if necessary",
action='append')
parser.add_argument('--type', help="RecordSet Type", required=True)
parser.add_argument('--ttl', type=int, help="Time To Live (Seconds)")
parser.add_argument('--description', help="Description")
parser = super(CreateCACommand, self).get_parser(prog_name)
parser.add_argument('auth_id', help="Project/CA ID")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.ssh
common.set_all_common_headers(client, parsed_args)
all_records = parsed_args.record or parsed_args.records
if parsed_args.records:
self.log.warning(
"Option --records is deprecated, use --record instead.")
data = client.recordsets.create(
parsed_args.zone_id,
parsed_args.name,
parsed_args.type,
all_records,
description=parsed_args.description,
ttl=parsed_args.ttl)
_format_recordset(data)
return six.moves.zip(*sorted(six.iteritems(data)))
class SetRecordSetCommand(command.ShowOne):
"""Set recordset properties"""
def get_parser(self, prog_name):
parser = super(SetRecordSetCommand, self).get_parser(prog_name)
parser.add_argument('zone_id', help="Zone ID")
parser.add_argument('id', help="RecordSet ID")
parser.add_argument('--records', help="Records", nargs='+')
description_group = parser.add_mutually_exclusive_group()
description_group.add_argument('--description', help="Description")
description_group.add_argument('--no-description', action='store_true')
ttl_group = parser.add_mutually_exclusive_group()
ttl_group.add_argument('--ttl', type=int, help="TTL")
ttl_group.add_argument('--no-ttl', action='store_true')
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
data = {}
if parsed_args.no_description:
data['description'] = None
elif parsed_args.description:
data['description'] = parsed_args.description
if parsed_args.no_ttl:
data['ttl'] = None
elif parsed_args.ttl:
data['ttl'] = parsed_args.ttl
if parsed_args.records:
data['records'] = parsed_args.records
client = self.app.client_manager.ssh
common.set_all_common_headers(client, parsed_args)
updated = client.recordsets.update(
parsed_args.zone_id,
parsed_args.id,
data)
_format_recordset(updated)
return six.moves.zip(*sorted(six.iteritems(updated)))
class DeleteRecordSetCommand(command.ShowOne):
"""Delete recordset"""
def get_parser(self, prog_name):
parser = super(DeleteRecordSetCommand, self).get_parser(prog_name)
parser.add_argument('zone_id', help="Zone ID")
parser.add_argument('id', help="RecordSet ID")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.ssh
common.set_all_common_headers(client, parsed_args)
data = client.recordsets.delete(parsed_args.zone_id, parsed_args.id)
LOG.info('RecordSet %s was deleted', parsed_args.id)
_format_recordset(data)
return six.moves.zip(*sorted(six.iteritems(data)))
data = client.ca.create(parsed_args.auth_id)
return _names, utils.get_item_properties(data, _columns)

View File

@ -1,24 +1,21 @@
# Copyright 2014 Hewlett-Packard Development Company, L.P.
# Copyright 2017 Huawei, Inc. All rights reserved.
#
# Author: Endre Karlson <endre.karlson@hp.com>
# 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
#
# 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
#
# 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.
# 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 argparse
import logging
from osc_lib.command import command
import six
from tatuclient import utils
from tatuclient.v1.cli import common
@ -26,235 +23,53 @@ from tatuclient.v1.utils import get_all
LOG = logging.getLogger(__name__)
'host_id': host.host_id,
'fingerprint': host.fingerprint,
'auth_id': host.auth_id,
'cert': host.cert,
item = {
'host_id': host.host_id,
'fingerprint': host.fingerprint,
'auth_id': host.auth_id,
'cert': host.cert,
'hostname': host.hostname,
}
if CONF.tatu.use_pat_bastions:
item['pat_bastions'] = ','.join(
'{}:{}'.format(t[1], t[0]) for t in
get_port_ip_tuples(host.host_id, 22))
item['srv_url'] = get_srv_url(host.hostname, host.auth_id)
_columns = ['host_id', 'srv_url', 'pat_bastions', 'fingerprint', 'cert']
_names = ['Instance ID', 'SRV URL', 'PAT Bastions', 'Fingerprint', 'SSH Certificate']
def _format_recordset(recordset):
# Remove unneeded fields for display output formatting
recordset['records'] = "\n".join(recordset['records'])
recordset.pop('links', None)
return recordset
def _has_project_id(data):
if len(data) < 1:
return False
if 'project_id' in data[0]:
return True
return False
class ListRecordSetsCommand(command.Lister):
"""List recordsets"""
columns = ['id', 'name', 'type', 'records', 'status', 'action']
class ListHostCertCommand(command.Lister):
"""List HostCerts"""
def get_parser(self, prog_name):
parser = super(ListRecordSetsCommand, self).get_parser(prog_name)
parser.add_argument('--name', help="RecordSet Name", required=False)
parser.add_argument('--type', help="RecordSet Type", required=False)
parser.add_argument('--data', help="RecordSet Record Data",
required=False)
parser.add_argument('--ttl', help="Time To Live (Seconds)",
required=False)
parser.add_argument('--description', help="Description",
required=False)
parser.add_argument('--status', help="RecordSet Status",
required=False)
parser.add_argument('--action', help="RecordSet Action",
required=False)
parser.add_argument('zone_id', help="Zone ID. To list all"
" recordsets specify 'all'")
parser = super(ListHostCertCommand, self).get_parser(prog_name)
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.ssh
common.set_all_common_headers(client, parsed_args)
criterion = {}
if parsed_args.type is not None:
criterion["type"] = parsed_args.type
if parsed_args.name is not None:
criterion["name"] = parsed_args.name
if parsed_args.data is not None:
criterion["data"] = parsed_args.data
if parsed_args.ttl is not None:
criterion["ttl"] = parsed_args.ttl
if parsed_args.description is not None:
criterion["description"] = parsed_args.description
if parsed_args.status is not None:
criterion["status"] = parsed_args.status
if parsed_args.action is not None:
criterion["action"] = parsed_args.action
cols = self.columns
if parsed_args.zone_id == 'all':
data = get_all(client.recordsets.list_all_zones,
criterion=criterion)
cols.insert(2, 'zone_name')
else:
data = get_all(client.recordsets.list, args=[parsed_args.zone_id],
criterion=criterion)
if client.session.all_projects and _has_project_id(data):
cols.insert(1, 'project_id')
for i, rs in enumerate(data):
data[i] = _format_recordset(rs)
return cols, (utils.get_item_properties(s, cols) for s in data)
data = get_all(client.hostcert.list)
return _names, (utils.get_item_properties(s, _columns) for s in data)
class ShowRecordSetCommand(command.ShowOne):
"""Show recordset details"""
class ShowHostCertCommand(command.ShowOne):
"""Show HostCert details"""
def get_parser(self, prog_name):
parser = super(ShowRecordSetCommand, self).get_parser(prog_name)
parser.add_argument('zone_id', help="Zone ID")
parser.add_argument('id', help="RecordSet ID")
parser = super(ShowHostCertCommand, self).get_parser(prog_name)
parser.add_argument('serial', help="Serial Number")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.ssh
common.set_all_common_headers(client, parsed_args)
data = client.recordsets.get(parsed_args.zone_id, parsed_args.id)
_format_recordset(data)
return six.moves.zip(*sorted(six.iteritems(data)))
class CreateRecordSetCommand(command.ShowOne):
"""Create new recordset"""
log = logging.getLogger('deprecated')
def get_parser(self, prog_name):
parser = super(CreateRecordSetCommand, self).get_parser(prog_name)
parser.add_argument('zone_id', help="Zone ID")
parser.add_argument('name', help="RecordSet Name")
req_group = parser.add_mutually_exclusive_group(required=True)
req_group.add_argument(
'--records',
help=argparse.SUPPRESS,
nargs='+')
req_group.add_argument(
'--record',
help="RecordSet Record, repeat if necessary",
action='append')
parser.add_argument('--type', help="RecordSet Type", required=True)
parser.add_argument('--ttl', type=int, help="Time To Live (Seconds)")
parser.add_argument('--description', help="Description")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.ssh
common.set_all_common_headers(client, parsed_args)
all_records = parsed_args.record or parsed_args.records
if parsed_args.records:
self.log.warning(
"Option --records is deprecated, use --record instead.")
data = client.recordsets.create(
parsed_args.zone_id,
parsed_args.name,
parsed_args.type,
all_records,
description=parsed_args.description,
ttl=parsed_args.ttl)
_format_recordset(data)
return six.moves.zip(*sorted(six.iteritems(data)))
class SetRecordSetCommand(command.ShowOne):
"""Set recordset properties"""
def get_parser(self, prog_name):
parser = super(SetRecordSetCommand, self).get_parser(prog_name)
parser.add_argument('zone_id', help="Zone ID")
parser.add_argument('id', help="RecordSet ID")
parser.add_argument('--records', help="Records", nargs='+')
description_group = parser.add_mutually_exclusive_group()
description_group.add_argument('--description', help="Description")
description_group.add_argument('--no-description', action='store_true')
ttl_group = parser.add_mutually_exclusive_group()
ttl_group.add_argument('--ttl', type=int, help="TTL")
ttl_group.add_argument('--no-ttl', action='store_true')
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
data = {}
if parsed_args.no_description:
data['description'] = None
elif parsed_args.description:
data['description'] = parsed_args.description
if parsed_args.no_ttl:
data['ttl'] = None
elif parsed_args.ttl:
data['ttl'] = parsed_args.ttl
if parsed_args.records:
data['records'] = parsed_args.records
client = self.app.client_manager.ssh
common.set_all_common_headers(client, parsed_args)
updated = client.recordsets.update(
parsed_args.zone_id,
parsed_args.id,
data)
_format_recordset(updated)
return six.moves.zip(*sorted(six.iteritems(updated)))
class DeleteRecordSetCommand(command.ShowOne):
"""Delete recordset"""
def get_parser(self, prog_name):
parser = super(DeleteRecordSetCommand, self).get_parser(prog_name)
parser.add_argument('zone_id', help="Zone ID")
parser.add_argument('id', help="RecordSet ID")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.ssh
common.set_all_common_headers(client, parsed_args)
data = client.recordsets.delete(parsed_args.zone_id, parsed_args.id)
LOG.info('RecordSet %s was deleted', parsed_args.id)
_format_recordset(data)
return six.moves.zip(*sorted(six.iteritems(data)))
data = client.hostcert.get(parsed_args.serial)
return _names, utils.get_item_properties(data, _columns)

View File

@ -1,24 +1,21 @@
# Copyright 2014 Hewlett-Packard Development Company, L.P.
# Copyright 2017 Huawei, Inc. All rights reserved.
#
# Author: Endre Karlson <endre.karlson@hp.com>
# 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
#
# 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
#
# 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.
# 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 argparse
import logging
from osc_lib.command import command
import six
from tatuclient import utils
from tatuclient.v1.cli import common
@ -27,234 +24,70 @@ from tatuclient.v1.utils import get_all
LOG = logging.getLogger(__name__)
def _format_recordset(recordset):
# Remove unneeded fields for display output formatting
recordset['records'] = "\n".join(recordset['records'])
recordset.pop('links', None)
return recordset
_columns = ['serial', 'revoked', 'user_id', 'auth_id', 'fingerprint', 'cert']
_names = ['Serial Number', 'Revoked', 'User ID', 'Project/CA ID', 'Fingerprint', 'SSH Certificate']
def _has_project_id(data):
if len(data) < 1:
return False
if 'project_id' in data[0]:
return True
return False
class ListRecordSetsCommand(command.Lister):
"""List recordsets"""
columns = ['id', 'name', 'type', 'records', 'status', 'action']
class ListUserCertCommand(command.Lister):
"""List UserCerts"""
def get_parser(self, prog_name):
parser = super(ListRecordSetsCommand, self).get_parser(prog_name)
parser.add_argument('--name', help="RecordSet Name", required=False)
parser.add_argument('--type', help="RecordSet Type", required=False)
parser.add_argument('--data', help="RecordSet Record Data",
required=False)
parser.add_argument('--ttl', help="Time To Live (Seconds)",
required=False)
parser.add_argument('--description', help="Description",
required=False)
parser.add_argument('--status', help="RecordSet Status",
required=False)
parser.add_argument('--action', help="RecordSet Action",
required=False)
parser.add_argument('zone_id', help="Zone ID. To list all"
" recordsets specify 'all'")
parser = super(ListUserCertCommand, self).get_parser(prog_name)
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.ssh
common.set_all_common_headers(client, parsed_args)
criterion = {}
if parsed_args.type is not None:
criterion["type"] = parsed_args.type
if parsed_args.name is not None:
criterion["name"] = parsed_args.name
if parsed_args.data is not None:
criterion["data"] = parsed_args.data
if parsed_args.ttl is not None:
criterion["ttl"] = parsed_args.ttl
if parsed_args.description is not None:
criterion["description"] = parsed_args.description
if parsed_args.status is not None:
criterion["status"] = parsed_args.status
if parsed_args.action is not None:
criterion["action"] = parsed_args.action
cols = self.columns
if parsed_args.zone_id == 'all':
data = get_all(client.recordsets.list_all_zones,
criterion=criterion)
cols.insert(2, 'zone_name')
else:
data = get_all(client.recordsets.list, args=[parsed_args.zone_id],
criterion=criterion)
if client.session.all_projects and _has_project_id(data):
cols.insert(1, 'project_id')
for i, rs in enumerate(data):
data[i] = _format_recordset(rs)
return cols, (utils.get_item_properties(s, cols) for s in data)
data = get_all(client.usercert.list)
return _names, (utils.get_item_properties(s, _columns) for s in data)
class ShowRecordSetCommand(command.ShowOne):
"""Show recordset details"""
class ShowUserCertCommand(command.ShowOne):
"""Show UserCert details"""
def get_parser(self, prog_name):
parser = super(ShowRecordSetCommand, self).get_parser(prog_name)
parser.add_argument('zone_id', help="Zone ID")
parser.add_argument('id', help="RecordSet ID")
parser = super(ShowUserCertCommand, self).get_parser(prog_name)
parser.add_argument('serial', help="Serial Number")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.ssh
common.set_all_common_headers(client, parsed_args)
data = client.recordsets.get(parsed_args.zone_id, parsed_args.id)
_format_recordset(data)
return six.moves.zip(*sorted(six.iteritems(data)))
data = client.usercert.get(parsed_args.serial)
return _names, utils.get_item_properties(data, _columns)
class CreateRecordSetCommand(command.ShowOne):
"""Create new recordset"""
log = logging.getLogger('deprecated')
class CreateUserCertCommand(command.ShowOne):
"""Create new UserCert"""
def get_parser(self, prog_name):
parser = super(CreateRecordSetCommand, self).get_parser(prog_name)
parser.add_argument('zone_id', help="Zone ID")
parser.add_argument('name', help="RecordSet Name")
req_group = parser.add_mutually_exclusive_group(required=True)
req_group.add_argument(
'--records',
help=argparse.SUPPRESS,
nargs='+')
req_group.add_argument(
'--record',
help="RecordSet Record, repeat if necessary",
action='append')
parser.add_argument('--type', help="RecordSet Type", required=True)
parser.add_argument('--ttl', type=int, help="Time To Live (Seconds)")
parser.add_argument('--description', help="Description")
parser = super(CreateUserCertCommand, self).get_parser(prog_name)
parser.add_argument('user_id', help="User ID")
parser.add_argument('auth_id', help="Project/CA ID")
parser.add_argument('pub_key', help="Public Key")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.ssh
common.set_all_common_headers(client, parsed_args)
all_records = parsed_args.record or parsed_args.records
if parsed_args.records:
self.log.warning(
"Option --records is deprecated, use --record instead.")
data = client.recordsets.create(
parsed_args.zone_id,
parsed_args.name,
parsed_args.type,
all_records,
description=parsed_args.description,
ttl=parsed_args.ttl)
_format_recordset(data)
return six.moves.zip(*sorted(six.iteritems(data)))
data = client.usercert.create(parsed_args)
return _names, utils.get_item_properties(data, _columns)
class SetRecordSetCommand(command.ShowOne):
"""Set recordset properties"""
class RevokeUserCertCommand(command.ShowOne):
"""Create new UserCert"""
def get_parser(self, prog_name):
parser = super(SetRecordSetCommand, self).get_parser(prog_name)
parser.add_argument('zone_id', help="Zone ID")
parser.add_argument('id', help="RecordSet ID")
parser.add_argument('--records', help="Records", nargs='+')
description_group = parser.add_mutually_exclusive_group()
description_group.add_argument('--description', help="Description")
description_group.add_argument('--no-description', action='store_true')
ttl_group = parser.add_mutually_exclusive_group()
ttl_group.add_argument('--ttl', type=int, help="TTL")
ttl_group.add_argument('--no-ttl', action='store_true')
parser = super(RevokeUserCertCommand, self).get_parser(prog_name)
parser.add_argument('serial', help="Serial Number")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
data = {}
if parsed_args.no_description:
data['description'] = None
elif parsed_args.description:
data['description'] = parsed_args.description
if parsed_args.no_ttl:
data['ttl'] = None
elif parsed_args.ttl:
data['ttl'] = parsed_args.ttl
if parsed_args.records:
data['records'] = parsed_args.records
client = self.app.client_manager.ssh
common.set_all_common_headers(client, parsed_args)
updated = client.recordsets.update(
parsed_args.zone_id,
parsed_args.id,
data)
_format_recordset(updated)
return six.moves.zip(*sorted(six.iteritems(updated)))
class DeleteRecordSetCommand(command.ShowOne):
"""Delete recordset"""
def get_parser(self, prog_name):
parser = super(DeleteRecordSetCommand, self).get_parser(prog_name)
parser.add_argument('zone_id', help="Zone ID")
parser.add_argument('id', help="RecordSet ID")
common.add_all_common_options(parser)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.ssh
common.set_all_common_headers(client, parsed_args)
data = client.recordsets.delete(parsed_args.zone_id, parsed_args.id)
LOG.info('RecordSet %s was deleted', parsed_args.id)
_format_recordset(data)
return six.moves.zip(*sorted(six.iteritems(data)))
data = client.usercert.create(parsed_args.serial)
return _names, utils.get_item_properties(data, _columns)

View File

@ -34,7 +34,6 @@ class TatuAdapter(adapter.LegacyJsonAdapter):
def __init__(self, *args, **kwargs):
self.timeout = kwargs.pop('timeout', None)
self.all_projects = kwargs.pop('all_projects', False)
self.edit_managed = kwargs.pop('edit_managed', False)
self.sudo_project_id = kwargs.pop('sudo_project_id', None)
super(self.__class__, self).__init__(*args, **kwargs)
@ -109,5 +108,5 @@ class Client(object):
)
self.ca = CAController(self)
self.hostcert = HostCeretController(self)
self.hostcert = HostCertController(self)
self.usercert = UserCertController(self)