2015-01-05 13:09:32 +08:00
|
|
|
# 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
|
|
|
|
|
2015-01-16 15:53:16 +08:00
|
|
|
from oslo_serialization import jsonutils
|
2015-01-05 19:46:22 +08:00
|
|
|
|
|
|
|
from senlinclient.common import exc
|
2015-01-05 13:09:32 +08:00
|
|
|
from senlinclient.common.i18n import _
|
|
|
|
from senlinclient.common import utils
|
2015-01-16 15:53:16 +08:00
|
|
|
from senlinclient.v1 import models
|
2015-01-05 13:09:32 +08:00
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
2015-01-05 19:46:22 +08:00
|
|
|
def do_build_info(sc, args):
|
|
|
|
'''Retrieve build information.'''
|
2015-01-16 15:53:16 +08:00
|
|
|
result = sc.get(models.BuildInfo)
|
2015-01-05 19:46:22 +08:00
|
|
|
formatters = {
|
|
|
|
'api': utils.json_formatter,
|
|
|
|
'engine': utils.json_formatter,
|
|
|
|
}
|
|
|
|
utils.print_dict(result, formatters=formatters)
|
|
|
|
|
|
|
|
|
2015-03-21 07:54:57 +08:00
|
|
|
# PROFILE TYPES
|
2015-01-05 19:46:22 +08:00
|
|
|
|
|
|
|
|
|
|
|
def do_profile_type_list(sc, args):
|
|
|
|
'''List the available profile types.'''
|
2015-07-18 01:55:59 -04:00
|
|
|
types = sc.list(models.ProfileType, paginated=False)
|
2015-01-16 15:53:16 +08:00
|
|
|
utils.print_list(types, ['name'], sortby_index=0)
|
2015-01-05 19:46:22 +08:00
|
|
|
|
|
|
|
|
2015-02-15 19:52:22 +08:00
|
|
|
@utils.arg('profile_type', metavar='<PROFILE_TYPE>',
|
|
|
|
help=_('Profile type to generate a template for.'))
|
|
|
|
@utils.arg('-F', '--format', metavar='<FORMAT>',
|
|
|
|
help=_("The template output format, one of: %s.")
|
|
|
|
% ', '.join(utils.supported_formats.keys()))
|
|
|
|
def do_profile_type_schema(sc, args):
|
|
|
|
'''Get the spec of a profile type.'''
|
|
|
|
try:
|
|
|
|
params = {'profile_type': args.profile_type}
|
|
|
|
schema = sc.get(models.ProfileTypeSchema, params)
|
|
|
|
except exc.HTTPNotFound:
|
|
|
|
raise exc.CommandError(
|
|
|
|
_('Profile Type %s not found.') % args.profile_type)
|
|
|
|
|
|
|
|
schema = dict(schema)
|
|
|
|
|
|
|
|
if args.format:
|
|
|
|
print(utils.format_output(schema, format=args.format))
|
|
|
|
else:
|
|
|
|
print(utils.format_output(schema))
|
|
|
|
|
|
|
|
|
2015-03-21 07:54:57 +08:00
|
|
|
# PROFILES
|
2015-01-05 19:46:22 +08:00
|
|
|
|
|
|
|
|
2015-07-08 04:21:07 -04:00
|
|
|
@utils.arg('-D', '--show-deleted', default=False, action="store_true",
|
2015-01-19 21:37:50 +08:00
|
|
|
help=_('Include soft-deleted profiles if any.'))
|
|
|
|
@utils.arg('-l', '--limit', metavar='<LIMIT>',
|
2015-01-25 19:28:29 +08:00
|
|
|
help=_('Limit the number of profiles returned.'))
|
2015-01-19 21:37:50 +08:00
|
|
|
@utils.arg('-m', '--marker', metavar='<ID>',
|
|
|
|
help=_('Only return profiles that appear after the given ID.'))
|
2015-02-05 20:02:06 +08:00
|
|
|
@utils.arg('-F', '--full-id', default=False, action="store_true",
|
|
|
|
help=_('Print full IDs in list.'))
|
2015-01-19 21:37:50 +08:00
|
|
|
def do_profile_list(sc, args=None):
|
|
|
|
'''List profiles that meet the criteria.'''
|
2015-02-05 20:02:06 +08:00
|
|
|
def _short_id(obj):
|
2015-04-26 06:24:45 -04:00
|
|
|
return obj.id[:8]
|
2015-02-05 20:02:06 +08:00
|
|
|
|
2015-07-06 00:04:45 -04:00
|
|
|
fields = ['id', 'name', 'type', 'created_time']
|
2015-01-26 22:45:16 +08:00
|
|
|
queries = {
|
|
|
|
'show_deleted': args.show_deleted,
|
|
|
|
'limit': args.limit,
|
|
|
|
'marker': args.marker,
|
|
|
|
}
|
|
|
|
|
|
|
|
profiles = sc.list(models.Profile, **queries)
|
2015-02-05 20:02:06 +08:00
|
|
|
formatters = {}
|
|
|
|
if not args.full_id:
|
|
|
|
formatters = {
|
|
|
|
'id': _short_id,
|
|
|
|
}
|
|
|
|
utils.print_list(profiles, fields, formatters=formatters, sortby_index=1)
|
|
|
|
|
|
|
|
|
|
|
|
def _show_profile(sc, profile_id):
|
|
|
|
try:
|
|
|
|
params = {'id': profile_id}
|
|
|
|
profile = sc.get(models.Profile, params)
|
|
|
|
except exc.HTTPNotFound:
|
|
|
|
raise exc.CommandError(_('Profile not found: %s') % profile_id)
|
|
|
|
|
|
|
|
formatters = {
|
2015-05-06 23:01:00 -04:00
|
|
|
'metadata': utils.json_formatter,
|
2015-02-05 20:02:06 +08:00
|
|
|
}
|
2015-02-08 22:24:42 +08:00
|
|
|
|
2015-08-31 23:21:03 -04:00
|
|
|
formatters['spec'] = utils.nested_dict_formatter(
|
|
|
|
['type', 'version', 'properties'],
|
|
|
|
['property', 'value'])
|
2015-02-08 22:24:42 +08:00
|
|
|
|
2015-02-05 20:02:06 +08:00
|
|
|
utils.print_dict(profile.to_dict(), formatters=formatters)
|
2015-01-19 21:37:50 +08:00
|
|
|
|
|
|
|
|
2015-02-07 21:32:31 +08:00
|
|
|
@utils.arg('-s', '--spec-file', metavar='<SPEC FILE>', required=True,
|
2015-01-19 21:37:50 +08:00
|
|
|
help=_('The spec file used to create the profile.'))
|
|
|
|
@utils.arg('-p', '--permission', metavar='<PERMISSION>', default='',
|
|
|
|
help=_('A string format permission for this profile.'))
|
2015-07-08 17:37:31 +09:00
|
|
|
@utils.arg('-M', '--metadata', metavar='<KEY1=VALUE1;KEY2=VALUE2...>',
|
2015-05-06 23:01:00 -04:00
|
|
|
help=_('Metadata values to be attached to the profile. '
|
|
|
|
'This can be specified multiple times, or once with '
|
|
|
|
'key-value pairs separated by a semicolon.'),
|
2015-01-19 21:37:50 +08:00
|
|
|
action='append')
|
|
|
|
@utils.arg('name', metavar='<PROFILE_NAME>',
|
|
|
|
help=_('Name of the profile to create.'))
|
|
|
|
def do_profile_create(sc, args):
|
|
|
|
'''Create a profile.'''
|
|
|
|
spec = utils.get_spec_content(args.spec_file)
|
2015-08-31 23:21:03 -04:00
|
|
|
type_name = spec.get('type', None)
|
|
|
|
type_version = spec.get('version', None)
|
|
|
|
properties = spec.get('properties', None)
|
|
|
|
if type_name is None:
|
|
|
|
raise exc.CommandError(_("Missing 'type' key in spec file."))
|
|
|
|
if type_version is None:
|
|
|
|
raise exc.CommandError(_("Missing 'version' key in spec file."))
|
|
|
|
if properties is None:
|
|
|
|
raise exc.CommandError(_("Missing 'properties' key in spec file."))
|
|
|
|
|
|
|
|
if type_name == 'os.heat.stack':
|
|
|
|
stack_properties = utils.process_stack_spec(properties)
|
|
|
|
spec['properties'] = stack_properties
|
|
|
|
|
2015-01-19 21:37:50 +08:00
|
|
|
params = {
|
|
|
|
'name': args.name,
|
|
|
|
'spec': spec,
|
|
|
|
'permission': args.permission,
|
2015-05-06 23:01:00 -04:00
|
|
|
'metadata': utils.format_parameters(args.metadata),
|
2015-01-19 21:37:50 +08:00
|
|
|
}
|
|
|
|
|
2015-02-03 22:52:13 +08:00
|
|
|
profile = sc.create(models.Profile, params)
|
2015-02-05 20:02:06 +08:00
|
|
|
_show_profile(sc, profile.id)
|
2015-01-20 23:34:45 +08:00
|
|
|
|
|
|
|
|
2015-02-11 23:43:21 +08:00
|
|
|
@utils.arg('id', metavar='<PROFILE>',
|
2015-01-20 23:34:45 +08:00
|
|
|
help=_('Name or ID of profile to show.'))
|
|
|
|
def do_profile_show(sc, args):
|
|
|
|
'''Show the profile details.'''
|
2015-02-05 20:02:06 +08:00
|
|
|
_show_profile(sc, args.id)
|
2015-01-20 21:45:14 +08:00
|
|
|
|
|
|
|
|
2015-03-02 14:08:15 +08:00
|
|
|
@utils.arg('-n', '--name', metavar='<NAME>',
|
|
|
|
help=_('The new name for the profile.'))
|
|
|
|
@utils.arg('-s', '--spec-file', metavar='<SPEC FILE>',
|
|
|
|
help=_('The new spec file for the profile.'))
|
|
|
|
@utils.arg('-p', '--permission', metavar='<PERMISSION>', default='',
|
|
|
|
help=_('A string format permission for this profile.'))
|
2015-07-08 17:37:31 +09:00
|
|
|
@utils.arg('-M', '--metadata', metavar='<KEY1=VALUE1;KEY2=VALUE2...>',
|
2015-05-06 23:01:00 -04:00
|
|
|
help=_('Metadata values to be attached to the profile. '
|
|
|
|
'This can be specified multiple times, or once with '
|
|
|
|
'key-value pairs separated by a semicolon.'),
|
2015-03-02 14:08:15 +08:00
|
|
|
action='append')
|
|
|
|
@utils.arg('id', metavar='<PROFILE_ID>',
|
|
|
|
help=_('Name or ID of the profile to update.'))
|
|
|
|
def do_profile_update(sc, args):
|
|
|
|
'''Update a profile.'''
|
|
|
|
spec = None
|
|
|
|
if args.spec_file:
|
|
|
|
spec = utils.get_spec_content(args.spec_file)
|
2015-08-31 23:21:03 -04:00
|
|
|
type_name = spec['type']
|
|
|
|
if type_name == 'os.heat.stack':
|
|
|
|
spec['properties'] = utils.process_stack_spec(spec['properties'])
|
2015-03-02 14:08:15 +08:00
|
|
|
params = {
|
|
|
|
'name': args.name,
|
|
|
|
'spec': spec,
|
|
|
|
'permission': args.permission,
|
|
|
|
}
|
2015-08-20 22:50:58 -04:00
|
|
|
if args.metadata:
|
|
|
|
params['metadata'] = utils.format_parameters(args.metadata)
|
2015-03-02 14:08:15 +08:00
|
|
|
|
|
|
|
# Find the profile first, we need its id
|
|
|
|
try:
|
|
|
|
profile = sc.get(models.Profile, {'id': args.id})
|
|
|
|
except exc.HTTPNotFound:
|
|
|
|
raise exc.CommandError(_('Profile not found: %s') % args.id)
|
|
|
|
|
|
|
|
params['id'] = profile.id
|
|
|
|
sc.update(models.Profile, params)
|
2015-07-22 19:31:05 +09:00
|
|
|
_show_profile(sc, profile.id)
|
2015-03-02 14:08:15 +08:00
|
|
|
|
|
|
|
|
2015-02-03 22:17:52 +08:00
|
|
|
@utils.arg('-f', '--force', default=False, action="store_true",
|
|
|
|
help=_('Delete the profile completely from database.'))
|
2015-02-11 23:43:21 +08:00
|
|
|
@utils.arg('id', metavar='<PROFILE>', nargs='+',
|
2015-01-20 21:45:14 +08:00
|
|
|
help=_('Name or ID of profile(s) to delete.'))
|
|
|
|
def do_profile_delete(sc, args):
|
|
|
|
'''Delete profile(s).'''
|
|
|
|
failure_count = 0
|
|
|
|
|
|
|
|
for cid in args.id:
|
|
|
|
try:
|
2015-02-03 22:17:52 +08:00
|
|
|
query = {
|
|
|
|
'id': cid,
|
|
|
|
'force': args.force
|
|
|
|
}
|
2015-01-20 21:45:14 +08:00
|
|
|
sc.delete(models.Profile, query)
|
|
|
|
except exc.HTTPNotFound as ex:
|
|
|
|
failure_count += 1
|
|
|
|
print(ex)
|
|
|
|
if failure_count == len(args.id):
|
|
|
|
msg = _('Failed to delete any of the specified profile(s).')
|
|
|
|
raise exc.CommandError(msg)
|
|
|
|
print('Profile deleted: %s' % args.id)
|
2015-01-19 21:37:50 +08:00
|
|
|
|
|
|
|
|
2015-03-21 07:54:57 +08:00
|
|
|
# POLICY TYPES
|
2015-01-05 19:46:22 +08:00
|
|
|
|
|
|
|
|
|
|
|
def do_policy_type_list(sc, args):
|
|
|
|
'''List the available policy types.'''
|
2015-07-18 01:55:59 -04:00
|
|
|
types = sc.list(models.PolicyType, paginated=False)
|
2015-01-16 15:53:16 +08:00
|
|
|
utils.print_list(types, ['name'], sortby_index=0)
|
2015-01-05 19:46:22 +08:00
|
|
|
|
|
|
|
|
|
|
|
@utils.arg('policy_type', metavar='<POLICY_TYPE>',
|
|
|
|
help=_('Policy type to get the details for.'))
|
|
|
|
def do_policy_type_show(sc, args):
|
|
|
|
'''Show the policy type.'''
|
|
|
|
try:
|
2015-01-16 15:53:16 +08:00
|
|
|
params = {'policy_type': args.policy_type}
|
|
|
|
policy_type = sc.get(models.PolicyTypeSchema, params)
|
2015-01-05 19:46:22 +08:00
|
|
|
except exc.HTTPNotFound:
|
|
|
|
raise exc.CommandError(
|
|
|
|
_('Policy Type not found: %s') % args.policy_type)
|
|
|
|
else:
|
|
|
|
print(jsonutils.dumps(policy_type, indent=2))
|
|
|
|
|
|
|
|
|
2015-02-15 20:53:08 +08:00
|
|
|
@utils.arg('policy_type', metavar='<POLICY_TYPE>',
|
|
|
|
help=_('Policy type to generate a template for.'))
|
|
|
|
@utils.arg('-F', '--format', metavar='<FORMAT>',
|
|
|
|
help=_("The template output format, one of: %s.")
|
|
|
|
% ', '.join(utils.supported_formats.keys()))
|
|
|
|
def do_policy_type_schema(sc, args):
|
|
|
|
'''Get the spec of a policy type.'''
|
|
|
|
try:
|
|
|
|
params = {'policy_type': args.policy_type}
|
|
|
|
schema = sc.get(models.PolicyTypeSchema, params)
|
|
|
|
except exc.HTTPNotFound:
|
|
|
|
raise exc.CommandError(
|
|
|
|
_('Policy type %s not found.') % args.policy_type)
|
|
|
|
|
|
|
|
schema = dict(schema)
|
|
|
|
|
|
|
|
if args.format:
|
|
|
|
print(utils.format_output(schema, format=args.format))
|
|
|
|
else:
|
|
|
|
print(utils.format_output(schema))
|
|
|
|
|
|
|
|
|
2015-04-17 01:10:03 -04:00
|
|
|
# WEBHOOKS
|
|
|
|
|
|
|
|
|
2015-07-08 04:21:07 -04:00
|
|
|
@utils.arg('-D', '--show-deleted', default=False, action="store_true",
|
2015-04-17 01:10:03 -04:00
|
|
|
help=_('Include deleted webhooks if any.'))
|
|
|
|
@utils.arg('-l', '--limit', metavar='<LIMIT>',
|
|
|
|
help=_('Limit the number of webhooks returned.'))
|
|
|
|
@utils.arg('-m', '--marker', metavar='<ID>',
|
|
|
|
help=_('Only return webhooks that appear after the given ID.'))
|
|
|
|
@utils.arg('-F', '--full-id', default=False, action="store_true",
|
|
|
|
help=_('Print full IDs in list.'))
|
|
|
|
def do_webhook_list(sc, args=None):
|
|
|
|
'''List webhooks that meet the criteria.'''
|
|
|
|
def _short_id(obj):
|
2015-04-26 06:24:45 -04:00
|
|
|
return obj.id[:8]
|
2015-04-17 01:10:03 -04:00
|
|
|
|
2015-08-25 15:32:36 +09:00
|
|
|
fields = ['id', 'name', 'obj_id', 'obj_type', 'action', 'created_time',
|
|
|
|
'deleted_time']
|
2015-04-17 01:10:03 -04:00
|
|
|
queries = {
|
|
|
|
'show_deleted': args.show_deleted,
|
|
|
|
'limit': args.limit,
|
|
|
|
'marker': args.marker,
|
|
|
|
}
|
|
|
|
|
|
|
|
webhooks = sc.list(models.Webhook, **queries)
|
|
|
|
formatters = {}
|
|
|
|
if not args.full_id:
|
|
|
|
formatters = {
|
|
|
|
'id': _short_id,
|
|
|
|
}
|
|
|
|
utils.print_list(webhooks, fields, formatters=formatters, sortby_index=1)
|
|
|
|
|
|
|
|
|
|
|
|
def _show_webhook(sc, webhook_id=None, webhook=None):
|
|
|
|
if webhook is None:
|
|
|
|
try:
|
|
|
|
params = {'id': webhook_id}
|
|
|
|
webhook = sc.get(models.Webhook, params)
|
|
|
|
except exc.HTTPNotFound:
|
|
|
|
raise exc.CommandError(_('Webhook not found: %s') % webhook_id)
|
|
|
|
|
|
|
|
formatters = {}
|
|
|
|
utils.print_dict(webhook.to_dict(), formatters=formatters)
|
|
|
|
|
|
|
|
|
|
|
|
@utils.arg('id', metavar='<WEBHOOK>',
|
2015-05-14 23:35:40 -04:00
|
|
|
help=_('Name or ID of the webhook to show.'))
|
2015-04-17 01:10:03 -04:00
|
|
|
def do_webhook_show(sc, args):
|
|
|
|
'''Show the webhook details.'''
|
|
|
|
_show_webhook(sc, webhook_id=args.id)
|
|
|
|
|
|
|
|
|
2015-06-08 04:48:26 -04:00
|
|
|
@utils.arg('-c', '--cluster', metavar='<CLUSTER>',
|
|
|
|
help=_('Targeted cluster for this webhook.'))
|
|
|
|
@utils.arg('-n', '--node', metavar='<NODE>',
|
|
|
|
help=_('Targeted node for this webhook.'))
|
|
|
|
@utils.arg('-p', '--policy', metavar='<POLICY>',
|
|
|
|
help=_('Targeted policy for this webhook.'))
|
2015-04-17 01:10:03 -04:00
|
|
|
@utils.arg('-a', '--action', metavar='<ACTION>', required=True,
|
2015-06-08 04:48:26 -04:00
|
|
|
help=_('Name of action to be triggered for this webhook.'))
|
|
|
|
@utils.arg('-C', '--credential', metavar='<KEY1=VALUE1;KEY2=VALUE2...>',
|
|
|
|
help=_('The credential to be used when the webhook is triggered.'),
|
2015-04-17 01:10:03 -04:00
|
|
|
action='append')
|
2015-06-08 04:48:26 -04:00
|
|
|
@utils.arg('-P', '--params', metavar='<KEY1=VALUE1;KEY2=VALUE2...>',
|
|
|
|
help=_('A dictionary of parameters that will be passed to target '
|
|
|
|
'action when the webhook is triggered.'),
|
2015-04-17 01:10:03 -04:00
|
|
|
action='append')
|
|
|
|
@utils.arg('name', metavar='<NAME>',
|
|
|
|
help=_('Name of the webhook to create.'))
|
|
|
|
def do_webhook_create(sc, args):
|
|
|
|
'''Create a webhook.'''
|
2015-06-08 04:48:26 -04:00
|
|
|
|
|
|
|
c = sum(x is not None for x in [args.cluster, args.node, args.policy])
|
|
|
|
if c > 1:
|
|
|
|
msg = _("Only one of 'cluster', 'node' or 'policy' can be specified.")
|
|
|
|
raise exc.CommandError(msg)
|
|
|
|
elif c == 0:
|
|
|
|
msg = _("One of 'cluster', 'node' or 'policy' must be specified.")
|
|
|
|
raise exc.CommandError(msg)
|
|
|
|
|
|
|
|
if args.cluster:
|
|
|
|
obj_type = 'cluster'
|
|
|
|
obj_id = args.cluster
|
|
|
|
elif args.node:
|
|
|
|
obj_type = 'node'
|
|
|
|
obj_id = args.node
|
|
|
|
else:
|
|
|
|
obj_type = 'policy'
|
|
|
|
obj_id = args.policy
|
|
|
|
|
2015-04-17 01:10:03 -04:00
|
|
|
params = {
|
|
|
|
'name': args.name,
|
2015-06-08 04:48:26 -04:00
|
|
|
'obj_id': obj_id,
|
|
|
|
'obj_type': obj_type,
|
2015-04-17 01:10:03 -04:00
|
|
|
'action': args.action,
|
|
|
|
'credential': utils.format_parameters(args.credential),
|
|
|
|
'params': utils.format_parameters(args.params)
|
|
|
|
}
|
|
|
|
|
|
|
|
webhook = sc.create(models.Webhook, params, True)
|
|
|
|
_show_webhook(sc, webhook=webhook)
|
|
|
|
|
|
|
|
|
|
|
|
@utils.arg('id', metavar='<WEBHOOK>', nargs='+',
|
|
|
|
help=_('Name or ID of webhook(s) to delete.'))
|
|
|
|
def do_webhook_delete(sc, args):
|
|
|
|
'''Delete webhook(s).'''
|
|
|
|
failure_count = 0
|
|
|
|
|
|
|
|
for cid in args.id:
|
|
|
|
try:
|
|
|
|
query = {
|
|
|
|
'id': cid,
|
|
|
|
}
|
|
|
|
sc.delete(models.Webhook, query)
|
|
|
|
except exc.HTTPNotFound as ex:
|
|
|
|
failure_count += 1
|
|
|
|
print(ex)
|
|
|
|
if failure_count == len(args.id):
|
|
|
|
msg = _('Failed to delete any of the specified webhook(s).')
|
|
|
|
raise exc.CommandError(msg)
|
|
|
|
print('Webhook deleted: %s' % args.id)
|
|
|
|
|
|
|
|
|
2015-03-21 07:54:57 +08:00
|
|
|
# POLICIES
|
2015-01-05 19:46:22 +08:00
|
|
|
|
|
|
|
|
2015-07-08 04:21:07 -04:00
|
|
|
@utils.arg('-D', '--show-deleted', default=False, action="store_true",
|
2015-02-08 22:24:42 +08:00
|
|
|
help=_('Include soft-deleted policies if any.'))
|
|
|
|
@utils.arg('-l', '--limit', metavar='<LIMIT>',
|
|
|
|
help=_('Limit the number of policies returned.'))
|
|
|
|
@utils.arg('-m', '--marker', metavar='<ID>',
|
|
|
|
help=_('Only return policies that appear after the given ID.'))
|
|
|
|
@utils.arg('-F', '--full-id', default=False, action="store_true",
|
|
|
|
help=_('Print full IDs in list.'))
|
|
|
|
def do_policy_list(sc, args=None):
|
|
|
|
'''List policies that meet the criteria.'''
|
|
|
|
def _short_id(obj):
|
2015-04-26 06:24:45 -04:00
|
|
|
return obj.id[:8]
|
2015-02-08 22:24:42 +08:00
|
|
|
|
|
|
|
fields = ['id', 'name', 'type', 'level', 'cooldown', 'created_time']
|
|
|
|
queries = {
|
|
|
|
'show_deleted': args.show_deleted,
|
|
|
|
'limit': args.limit,
|
|
|
|
'marker': args.marker,
|
|
|
|
}
|
|
|
|
|
|
|
|
policies = sc.list(models.Policy, **queries)
|
|
|
|
formatters = {}
|
|
|
|
if not args.full_id:
|
|
|
|
formatters = {
|
|
|
|
'id': _short_id,
|
|
|
|
}
|
|
|
|
utils.print_list(policies, fields, formatters=formatters, sortby_index=1)
|
|
|
|
|
|
|
|
|
2015-03-03 13:17:53 +08:00
|
|
|
def _show_policy(sc, policy_id=None, policy=None):
|
|
|
|
if policy is None:
|
|
|
|
try:
|
|
|
|
params = {'id': policy_id}
|
|
|
|
policy = sc.get(models.Policy, params)
|
|
|
|
except exc.HTTPNotFound:
|
|
|
|
raise exc.CommandError(_('Policy not found: %s') % policy_id)
|
2015-02-08 22:24:42 +08:00
|
|
|
|
|
|
|
formatters = {
|
2015-05-06 23:01:00 -04:00
|
|
|
'metadata': utils.json_formatter,
|
2015-02-08 22:24:42 +08:00
|
|
|
'spec': utils.json_formatter,
|
|
|
|
}
|
|
|
|
utils.print_dict(policy.to_dict(), formatters=formatters)
|
|
|
|
|
|
|
|
|
|
|
|
@utils.arg('-s', '--spec-file', metavar='<SPEC_FILE>', required=True,
|
|
|
|
help=_('The spec file used to create the policy.'))
|
|
|
|
@utils.arg('-c', '--cooldown', metavar='<SECONDS>', default=0,
|
|
|
|
help=_('An integer indicating the cooldown seconds once the '
|
|
|
|
'policy is effected. Default to 0.'))
|
|
|
|
@utils.arg('-l', '--enforcement-level', metavar='<LEVEL>', default=0,
|
|
|
|
help=_('An integer beteen 0 and 100 representing the enforcement '
|
|
|
|
'level. Default to 0.'))
|
|
|
|
@utils.arg('name', metavar='<NAME>',
|
|
|
|
help=_('Name of the policy to create.'))
|
|
|
|
def do_policy_create(sc, args):
|
|
|
|
'''Create a policy.'''
|
|
|
|
spec = utils.get_spec_content(args.spec_file)
|
|
|
|
params = {
|
|
|
|
'name': args.name,
|
|
|
|
'spec': spec,
|
|
|
|
'cooldown': args.cooldown,
|
|
|
|
'level': args.enforcement_level,
|
|
|
|
}
|
|
|
|
|
|
|
|
policy = sc.create(models.Policy, params)
|
2015-03-03 13:17:53 +08:00
|
|
|
_show_policy(sc, policy=policy)
|
2015-02-08 22:24:42 +08:00
|
|
|
|
|
|
|
|
2015-02-11 23:43:21 +08:00
|
|
|
@utils.arg('id', metavar='<POLICY>',
|
2015-03-03 13:17:53 +08:00
|
|
|
help=_('Name of the policy to be updated.'))
|
2015-02-08 22:24:42 +08:00
|
|
|
def do_policy_show(sc, args):
|
|
|
|
'''Show the policy details.'''
|
2015-03-03 13:17:53 +08:00
|
|
|
_show_policy(sc, policy_id=args.id)
|
|
|
|
|
|
|
|
|
2015-03-03 17:25:30 +08:00
|
|
|
@utils.arg('-c', '--cooldown', metavar='<SECONDS>',
|
2015-03-03 13:17:53 +08:00
|
|
|
help=_('An integer indicating the cooldown seconds once the '
|
|
|
|
'policy is effected. Default to 0.'))
|
2015-03-03 17:25:30 +08:00
|
|
|
@utils.arg('-l', '--enforcement-level', metavar='<LEVEL>',
|
2015-03-03 13:17:53 +08:00
|
|
|
help=_('An integer beteen 0 and 100 representing the enforcement '
|
|
|
|
'level. Default to 0.'))
|
|
|
|
@utils.arg('-n', '--name', metavar='<NAME>',
|
|
|
|
help=_('New name of the policy to be updated.'))
|
|
|
|
@utils.arg('id', metavar='<POLICY>',
|
|
|
|
help=_('Name of the policy to be updated.'))
|
|
|
|
def do_policy_update(sc, args):
|
|
|
|
'''Update a policy.'''
|
|
|
|
params = {
|
|
|
|
'name': args.name,
|
|
|
|
'cooldown': args.cooldown,
|
|
|
|
'level': args.enforcement_level,
|
|
|
|
}
|
|
|
|
|
|
|
|
policy = sc.get(models.Policy, {'id': args.id})
|
|
|
|
if policy is not None:
|
|
|
|
params['id'] = policy.id
|
|
|
|
sc.update(models.Policy, params)
|
|
|
|
_show_policy(sc, policy_id=policy.id)
|
2015-02-08 22:24:42 +08:00
|
|
|
|
|
|
|
|
|
|
|
@utils.arg('-f', '--force', default=False, action="store_true",
|
|
|
|
help=_('Delete the policy completely from database.'))
|
2015-02-11 23:43:21 +08:00
|
|
|
@utils.arg('id', metavar='<POLICY>', nargs='+',
|
2015-02-08 22:24:42 +08:00
|
|
|
help=_('Name or ID of policy(s) to delete.'))
|
|
|
|
def do_policy_delete(sc, args):
|
|
|
|
'''Delete policy(s).'''
|
|
|
|
failure_count = 0
|
|
|
|
|
|
|
|
for cid in args.id:
|
|
|
|
try:
|
|
|
|
query = {
|
|
|
|
'id': cid,
|
|
|
|
'force': args.force
|
|
|
|
}
|
|
|
|
sc.delete(models.Policy, query)
|
|
|
|
except exc.HTTPNotFound as ex:
|
|
|
|
failure_count += 1
|
|
|
|
print(ex)
|
|
|
|
if failure_count == len(args.id):
|
|
|
|
msg = _('Failed to delete any of the specified policy(s).')
|
|
|
|
raise exc.CommandError(msg)
|
|
|
|
print('Policy deleted: %s' % args.id)
|
|
|
|
|
|
|
|
|
2015-03-21 07:54:57 +08:00
|
|
|
# CLUSTERS
|
2015-01-05 19:46:22 +08:00
|
|
|
|
|
|
|
|
2015-07-08 04:21:07 -04:00
|
|
|
@utils.arg('-D', '--show-deleted', default=False, action="store_true",
|
2015-01-07 13:04:22 +08:00
|
|
|
help=_('Include soft-deleted clusters if any.'))
|
|
|
|
@utils.arg('-n', '--show-nested', default=False, action="store_true",
|
|
|
|
help=_('Include nested clusters if any.'))
|
|
|
|
@utils.arg('-f', '--filters', metavar='<KEY1=VALUE1;KEY2=VALUE2...>',
|
2015-08-27 03:11:18 -04:00
|
|
|
help=_('Filter parameters to apply on returned triggers. '
|
2015-01-07 13:04:22 +08:00
|
|
|
'This can be specified multiple times, or once with '
|
|
|
|
'parameters separated by a semicolon.'),
|
|
|
|
action='append')
|
2015-01-23 16:38:10 +08:00
|
|
|
@utils.arg('-k', '--sort-keys', metavar='<KEYS>',
|
|
|
|
help=_('Name of keys used for sorting the returned events.'))
|
2015-07-08 04:21:07 -04:00
|
|
|
@utils.arg('-s', '--sort-dir', metavar='<DIR>',
|
2015-01-23 16:38:10 +08:00
|
|
|
help=_('Direction for sorting, where DIR can be "asc" or "desc".'))
|
2015-01-07 13:04:22 +08:00
|
|
|
@utils.arg('-l', '--limit', metavar='<LIMIT>',
|
|
|
|
help=_('Limit the number of clusters returned.'))
|
|
|
|
@utils.arg('-m', '--marker', metavar='<ID>',
|
|
|
|
help=_('Only return clusters that appear after the given cluster '
|
|
|
|
'ID.'))
|
2015-02-05 20:02:06 +08:00
|
|
|
@utils.arg('-F', '--full-id', default=False, action="store_true",
|
|
|
|
help=_('Print full IDs in list.'))
|
2015-01-07 13:04:22 +08:00
|
|
|
def do_cluster_list(sc, args=None):
|
|
|
|
'''List the user's clusters.'''
|
2015-02-05 20:02:06 +08:00
|
|
|
def _short_id(obj):
|
2015-04-26 06:24:45 -04:00
|
|
|
return obj.id[:8]
|
2015-02-05 20:02:06 +08:00
|
|
|
|
2015-07-06 10:29:22 -04:00
|
|
|
fields = ['id', 'name', 'status', 'created_time', 'updated_time']
|
|
|
|
sort_keys = ['name', 'status', 'created_time', 'updated_time']
|
2015-01-26 22:45:16 +08:00
|
|
|
queries = {
|
|
|
|
'limit': args.limit,
|
|
|
|
'marker': args.marker,
|
2015-07-06 10:29:22 -04:00
|
|
|
'sort_keys': args.sort_keys,
|
|
|
|
'sort_dir': args.sort_dir,
|
2015-01-26 22:45:16 +08:00
|
|
|
'show_deleted': args.show_deleted,
|
|
|
|
'show_nested': args.show_nested
|
|
|
|
}
|
2015-08-05 04:44:02 -04:00
|
|
|
if args.filters:
|
|
|
|
queries.update(utils.format_parameters(args.filters))
|
|
|
|
|
2015-01-26 22:45:16 +08:00
|
|
|
if args.show_nested:
|
|
|
|
fields.append('parent')
|
2015-01-07 13:04:22 +08:00
|
|
|
|
2015-07-06 10:29:22 -04:00
|
|
|
# we only validate the sort keys
|
|
|
|
# - if all keys are valid, we won't enforce sorting in the resulting list
|
|
|
|
# - if any keys are invalid, we abort the command execution;
|
|
|
|
# - if no sort key is specified, we use created_time column for sorting
|
|
|
|
if args.sort_keys:
|
|
|
|
for key in args.sort_keys.split(';'):
|
|
|
|
if len(key) > 0 and key not in sort_keys:
|
|
|
|
raise exc.CommandError(_('Invalid sorting key: %s') % key)
|
|
|
|
sortby_index = None
|
|
|
|
else:
|
|
|
|
sortby_index = 3
|
|
|
|
|
2015-01-26 22:45:16 +08:00
|
|
|
clusters = sc.list(models.Cluster, **queries)
|
2015-02-05 20:02:06 +08:00
|
|
|
formatters = {}
|
|
|
|
if not args.full_id:
|
|
|
|
formatters = {
|
|
|
|
'id': _short_id,
|
|
|
|
}
|
2015-07-06 10:29:22 -04:00
|
|
|
utils.print_list(clusters, fields, formatters=formatters,
|
|
|
|
sortby_index=sortby_index)
|
2015-01-07 13:04:22 +08:00
|
|
|
|
|
|
|
|
2015-02-04 10:35:08 +08:00
|
|
|
def _show_cluster(sc, cluster_id):
|
|
|
|
try:
|
|
|
|
query = {'id': cluster_id}
|
|
|
|
cluster = sc.get(models.Cluster, query)
|
|
|
|
except exc.HTTPNotFound:
|
2015-02-05 20:02:06 +08:00
|
|
|
raise exc.CommandError(_('Cluster %s is not found') % cluster_id)
|
2015-02-04 10:35:08 +08:00
|
|
|
|
|
|
|
formatters = {
|
2015-05-06 23:01:00 -04:00
|
|
|
'metadata': utils.json_formatter,
|
2015-02-04 10:35:08 +08:00
|
|
|
'nodes': utils.list_formatter,
|
|
|
|
}
|
|
|
|
utils.print_dict(cluster.to_dict(), formatters=formatters)
|
|
|
|
|
|
|
|
|
2015-02-07 21:32:31 +08:00
|
|
|
@utils.arg('-p', '--profile', metavar='<PROFILE>', required=True,
|
|
|
|
help=_('Profile Id used for this cluster.'))
|
2015-05-15 03:22:02 -04:00
|
|
|
@utils.arg('-n', '--min-size', metavar='<MIN-SIZE>', default=0,
|
2015-04-30 04:41:13 -04:00
|
|
|
help=_('Min size of the cluster. Default to 0.'))
|
2015-06-12 13:45:51 +09:00
|
|
|
@utils.arg('-m', '--max-size', metavar='<MAX-SIZE>', default=-1,
|
2015-09-21 22:17:52 -04:00
|
|
|
help=_('Max size of the cluster. Default to -1, means unlimited.'))
|
2015-04-28 22:37:25 -04:00
|
|
|
@utils.arg('-c', '--desired-capacity', metavar='<DESIRED-CAPACITY>', default=0,
|
|
|
|
help=_('Desired capacity of the cluster. Default to 0.'))
|
2015-01-26 13:33:55 +08:00
|
|
|
@utils.arg('-o', '--parent', metavar='<PARENT_ID>',
|
|
|
|
help=_('ID of the parent cluster, if exists.'))
|
|
|
|
@utils.arg('-t', '--timeout', metavar='<TIMEOUT>', type=int,
|
2015-01-05 19:46:22 +08:00
|
|
|
help=_('Cluster creation timeout in minutes.'))
|
2015-07-08 17:37:31 +09:00
|
|
|
@utils.arg('-M', '--metadata', metavar='<KEY1=VALUE1;KEY2=VALUE2...>',
|
2015-05-06 23:01:00 -04:00
|
|
|
help=_('Metadata values to be attached to the cluster. '
|
|
|
|
'This can be specified multiple times, or once with '
|
|
|
|
'key-value pairs separated by a semicolon.'),
|
2015-02-07 21:32:31 +08:00
|
|
|
action='append')
|
2015-01-05 19:46:22 +08:00
|
|
|
@utils.arg('name', metavar='<CLUSTER_NAME>',
|
|
|
|
help=_('Name of the cluster to create.'))
|
|
|
|
def do_cluster_create(sc, args):
|
|
|
|
'''Create the cluster.'''
|
2015-01-16 15:53:16 +08:00
|
|
|
params = {
|
2015-01-05 19:46:22 +08:00
|
|
|
'name': args.name,
|
|
|
|
'profile_id': args.profile,
|
2015-04-30 04:41:13 -04:00
|
|
|
'min_size': args.min_size,
|
|
|
|
'max_size': args.max_size,
|
2015-04-28 22:37:25 -04:00
|
|
|
'desired_capacity': args.desired_capacity,
|
2015-01-26 13:33:55 +08:00
|
|
|
'parent': args.parent,
|
2015-05-06 23:01:00 -04:00
|
|
|
'metadata': utils.format_parameters(args.metadata),
|
2015-01-05 19:46:22 +08:00
|
|
|
'timeout': args.timeout
|
|
|
|
}
|
|
|
|
|
2015-02-04 10:35:08 +08:00
|
|
|
cluster = sc.create(models.Cluster, params)
|
|
|
|
_show_cluster(sc, cluster.id)
|
2015-01-05 19:46:22 +08:00
|
|
|
|
|
|
|
|
2015-02-11 23:43:21 +08:00
|
|
|
@utils.arg('id', metavar='<CLUSTER>', nargs='+',
|
2015-01-05 19:46:22 +08:00
|
|
|
help=_('Name or ID of cluster(s) to delete.'))
|
|
|
|
def do_cluster_delete(sc, args):
|
|
|
|
'''Delete the cluster(s).'''
|
|
|
|
failure_count = 0
|
|
|
|
|
|
|
|
for cid in args.id:
|
|
|
|
try:
|
2015-01-16 15:53:16 +08:00
|
|
|
query = {'id': cid}
|
|
|
|
sc.delete(models.Cluster, query)
|
2015-01-05 19:46:22 +08:00
|
|
|
except exc.HTTPNotFound as ex:
|
|
|
|
failure_count += 1
|
|
|
|
print(ex)
|
|
|
|
if failure_count == len(args.id):
|
|
|
|
msg = _('Failed to delete any of the specified clusters.')
|
|
|
|
raise exc.CommandError(msg)
|
2015-01-28 23:06:51 +08:00
|
|
|
|
|
|
|
print('Request accepted')
|
2015-01-05 19:46:22 +08:00
|
|
|
|
|
|
|
|
2015-02-07 21:32:31 +08:00
|
|
|
@utils.arg('-p', '--profile', metavar='<PROFILE>',
|
2015-01-05 19:46:22 +08:00
|
|
|
help=_('ID of new profile to use.'))
|
|
|
|
@utils.arg('-t', '--timeout', metavar='<TIMEOUT>',
|
2015-03-03 17:25:30 +08:00
|
|
|
help=_('New timeout (in minutes) value for the cluster.'))
|
|
|
|
@utils.arg('-r', '--parent', metavar='<PARENT>',
|
|
|
|
help=_('ID of parent cluster for the cluster.'))
|
2015-07-08 17:37:31 +09:00
|
|
|
@utils.arg('-M', '--metadata', metavar='<KEY1=VALUE1;KEY2=VALUE2...>',
|
2015-05-06 23:01:00 -04:00
|
|
|
help=_('Metadata values to be attached to the cluster. '
|
|
|
|
'This can be specified multiple times, or once with '
|
|
|
|
'key-value pairs separated by a semicolon.'),
|
2015-01-05 19:46:22 +08:00
|
|
|
action='append')
|
2015-03-03 17:25:30 +08:00
|
|
|
@utils.arg('-n', '--name', metavar='<NAME>',
|
|
|
|
help=_('New name for the cluster to update.'))
|
2015-02-11 23:43:21 +08:00
|
|
|
@utils.arg('id', metavar='<CLUSTER>',
|
2015-03-03 17:25:30 +08:00
|
|
|
help=_('Name or ID of cluster to be updated.'))
|
2015-01-05 19:46:22 +08:00
|
|
|
def do_cluster_update(sc, args):
|
|
|
|
'''Update the cluster.'''
|
2015-03-03 18:01:19 +08:00
|
|
|
cluster = sc.get(models.Cluster, {'id': args.id})
|
2015-01-16 15:53:16 +08:00
|
|
|
params = {
|
2015-03-03 18:01:19 +08:00
|
|
|
'id': cluster.id,
|
2015-03-03 17:25:30 +08:00
|
|
|
'name': args.name,
|
2015-01-05 19:46:22 +08:00
|
|
|
'profile_id': args.profile,
|
2015-03-03 17:25:30 +08:00
|
|
|
'parent': args.parent,
|
2015-05-06 23:01:00 -04:00
|
|
|
'metadata': utils.format_parameters(args.metadata),
|
2015-03-03 17:25:30 +08:00
|
|
|
'timeout': args.timeout,
|
2015-01-05 19:46:22 +08:00
|
|
|
}
|
|
|
|
|
2015-01-16 15:53:16 +08:00
|
|
|
sc.update(models.Cluster, params)
|
2015-03-03 18:01:19 +08:00
|
|
|
_show_cluster(sc, cluster.id)
|
2015-01-05 19:46:22 +08:00
|
|
|
|
|
|
|
|
2015-02-11 23:43:21 +08:00
|
|
|
@utils.arg('id', metavar='<CLUSTER>',
|
2015-01-07 13:04:22 +08:00
|
|
|
help=_('Name or ID of cluster to show.'))
|
|
|
|
def do_cluster_show(sc, args):
|
|
|
|
'''Show details of the cluster.'''
|
2015-02-04 10:35:08 +08:00
|
|
|
_show_cluster(sc, args.id)
|
2015-01-07 13:04:22 +08:00
|
|
|
|
2015-01-07 14:43:23 +08:00
|
|
|
|
2015-07-08 04:21:07 -04:00
|
|
|
@utils.arg('-D', '--show-deleted', default=False, action="store_true",
|
2015-01-07 14:38:32 +08:00
|
|
|
help=_('Include soft-deleted nodes if any.'))
|
|
|
|
@utils.arg('-f', '--filters', metavar='<KEY1=VALUE1;KEY2=VALUE2...>',
|
|
|
|
help=_('Filter parameters to apply on returned nodes. '
|
|
|
|
'This can be specified multiple times, or once with '
|
|
|
|
'parameters separated by a semicolon.'),
|
|
|
|
action='append')
|
|
|
|
@utils.arg('-l', '--limit', metavar='<LIMIT>',
|
|
|
|
help=_('Limit the number of nodes returned.'))
|
|
|
|
@utils.arg('-m', '--marker', metavar='<ID>',
|
|
|
|
help=_('Only return nodes that appear after the given node ID.'))
|
2015-02-01 22:33:20 +08:00
|
|
|
@utils.arg('-F', '--full-id', default=False, action="store_true",
|
|
|
|
help=_('Print full IDs in list.'))
|
2015-02-11 23:43:21 +08:00
|
|
|
@utils.arg('id', metavar='<CLUSTER>',
|
2015-01-07 13:04:22 +08:00
|
|
|
help=_('Name or ID of cluster to nodes from.'))
|
|
|
|
def do_cluster_node_list(sc, args):
|
|
|
|
'''List nodes from cluster.'''
|
2015-02-01 22:33:20 +08:00
|
|
|
def _short_id(obj):
|
2015-04-26 06:24:45 -04:00
|
|
|
return obj.id[:8]
|
2015-02-01 22:33:20 +08:00
|
|
|
|
|
|
|
def _short_physical_id(obj):
|
2015-09-18 13:49:31 +08:00
|
|
|
return obj.physical_id[:8] if obj.physical_id else ''
|
2015-02-01 22:33:20 +08:00
|
|
|
|
2015-08-05 04:44:02 -04:00
|
|
|
queries = {
|
2015-01-07 14:38:32 +08:00
|
|
|
'cluster_id': args.id,
|
|
|
|
'show_deleted': args.show_deleted,
|
|
|
|
'limit': args.limit,
|
|
|
|
'marker': args.marker,
|
|
|
|
}
|
2015-08-05 04:44:02 -04:00
|
|
|
if args.filters:
|
|
|
|
queries.update(utils.format_parameters(args.filters))
|
2015-01-07 14:38:32 +08:00
|
|
|
|
|
|
|
try:
|
2015-08-05 04:44:02 -04:00
|
|
|
nodes = sc.list(models.Node, **queries)
|
2015-01-07 14:38:32 +08:00
|
|
|
except exc.HTTPNotFound:
|
|
|
|
msg = _('No node matching criteria is found')
|
|
|
|
raise exc.CommandError(msg)
|
|
|
|
|
2015-02-01 22:33:20 +08:00
|
|
|
if not args.full_id:
|
|
|
|
formatters = {
|
|
|
|
'id': _short_id,
|
|
|
|
'physical_id': _short_physical_id,
|
|
|
|
}
|
|
|
|
else:
|
|
|
|
formatters = {}
|
|
|
|
|
2015-02-12 16:37:01 +08:00
|
|
|
fields = ['id', 'name', 'index', 'status', 'physical_id', 'created_time']
|
2015-02-01 22:33:20 +08:00
|
|
|
utils.print_list(nodes, fields, formatters=formatters, sortby_index=5)
|
2015-01-07 13:04:22 +08:00
|
|
|
|
|
|
|
|
2015-02-07 21:32:31 +08:00
|
|
|
@utils.arg('-n', '--nodes', metavar='<NODES>', required=True,
|
2015-02-06 20:29:36 +08:00
|
|
|
help=_('ID of nodes to be added; multiple nodes can be separated '
|
|
|
|
'with ","'))
|
|
|
|
@utils.arg('id', metavar='<CLUSTER>',
|
2015-01-05 19:46:22 +08:00
|
|
|
help=_('Name or ID of cluster to operate on.'))
|
|
|
|
def do_cluster_node_add(sc, args):
|
|
|
|
'''Add specified nodes to cluster.'''
|
2015-02-06 20:29:36 +08:00
|
|
|
node_ids = args.nodes.split(',')
|
|
|
|
params = {
|
|
|
|
'id': args.id,
|
|
|
|
'action': 'add_nodes',
|
|
|
|
'action_args': {
|
|
|
|
'nodes': node_ids,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
resp = sc.action(models.Cluster, params)
|
2015-02-07 21:32:31 +08:00
|
|
|
print('Request accepted by action %s' % resp['action'])
|
2015-01-05 19:46:22 +08:00
|
|
|
|
|
|
|
|
2015-02-07 21:32:31 +08:00
|
|
|
@utils.arg('-n', '--nodes', metavar='<NODES>', required=True,
|
|
|
|
help=_('ID of nodes to be deleted; multiple nodes can be separated'
|
|
|
|
'with ",".'))
|
2015-02-11 23:43:21 +08:00
|
|
|
@utils.arg('id', metavar='<CLUSTER>',
|
2015-01-05 19:46:22 +08:00
|
|
|
help=_('Name or ID of cluster to operate on.'))
|
|
|
|
def do_cluster_node_del(sc, args):
|
|
|
|
'''Delete specified nodes from cluster.'''
|
2015-02-07 21:32:31 +08:00
|
|
|
node_ids = args.nodes.split(',')
|
|
|
|
params = {
|
|
|
|
'id': args.id,
|
|
|
|
'action': 'del_nodes',
|
|
|
|
'action_args': {
|
|
|
|
'nodes': node_ids,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
resp = sc.action(models.Cluster, params)
|
|
|
|
print('Request accepted by action %s' % resp['action'])
|
2015-01-05 19:46:22 +08:00
|
|
|
|
|
|
|
|
2015-05-15 03:22:02 -04:00
|
|
|
@utils.arg('-c', '--capacity', metavar='<CAPACITY>', type=int,
|
|
|
|
help=_('The desired number of nodes of the cluster.'))
|
|
|
|
@utils.arg('-a', '--adjustment', metavar='<ADJUSTMENT>', type=int,
|
|
|
|
help=_('A positive integer meaning the number of nodes to add, '
|
|
|
|
'or a negative integer indicating the number of nodes to '
|
|
|
|
'remove.'))
|
|
|
|
@utils.arg('-p', '--percentage', metavar='<PERCENTAGE>', type=float,
|
|
|
|
help=_('A value that is interpreted as the percentage of size '
|
|
|
|
'adjustment. This value can be positive or negative.'))
|
|
|
|
@utils.arg('-t', '--min-step', metavar='<MIN_STEP>', type=int,
|
|
|
|
help=_('An integer specifying the number of nodes for adjustment '
|
|
|
|
'when <PERCENTAGE> is specified.'))
|
|
|
|
@utils.arg('-s', '--strict', action='store_true', default=False,
|
|
|
|
help=_('A boolean specifying whether the resize should be '
|
|
|
|
'performed on a best-effort basis when the new capacity '
|
|
|
|
'may go beyond size constraints.'))
|
|
|
|
@utils.arg('-n', '--min-size', metavar='MIN', type=int,
|
|
|
|
help=_('New lower bound of cluster size.'))
|
|
|
|
@utils.arg('-m', '--max-size', metavar='MAX', type=int,
|
|
|
|
help=_('New upper bound of cluster size. A value of -1 indicates '
|
|
|
|
'no upper limit on cluster size.'))
|
|
|
|
@utils.arg('id', metavar='<CLUSTER>',
|
|
|
|
help=_('Name or ID of cluster to operate on.'))
|
|
|
|
def do_cluster_resize(sc, args):
|
|
|
|
'''Resize a cluster.'''
|
|
|
|
# validate parameters
|
|
|
|
# NOTE: this will be much simpler if cliutils supports exclusive groups
|
|
|
|
|
|
|
|
action_args = {}
|
|
|
|
|
|
|
|
capacity = args.capacity
|
|
|
|
adjustment = args.adjustment
|
|
|
|
percentage = args.percentage
|
|
|
|
min_size = args.min_size
|
|
|
|
max_size = args.max_size
|
|
|
|
min_step = args.min_step
|
|
|
|
|
|
|
|
if sum(v is not None for v in (capacity, adjustment, percentage)) > 1:
|
|
|
|
raise exc.CommandError(_("Only one of 'capacity', 'adjustment' and "
|
|
|
|
"'percentage' can be specified."))
|
|
|
|
|
2015-07-29 05:15:56 -04:00
|
|
|
action_args['adjustment_type'] = None
|
|
|
|
action_args['number'] = None
|
|
|
|
|
2015-05-15 03:22:02 -04:00
|
|
|
if capacity is not None:
|
|
|
|
if capacity < 0:
|
|
|
|
raise exc.CommandError(_('Cluster capacity must be larger than '
|
|
|
|
' or equal to zero.'))
|
|
|
|
action_args['adjustment_type'] = 'EXACT_CAPACITY'
|
|
|
|
action_args['number'] = capacity
|
|
|
|
|
|
|
|
if adjustment is not None:
|
|
|
|
if adjustment == 0:
|
|
|
|
raise exc.CommandError(_('Adjustment cannot be zero.'))
|
|
|
|
action_args['adjustment_type'] = 'CHANGE_IN_CAPACITY'
|
|
|
|
action_args['number'] = adjustment
|
|
|
|
|
|
|
|
if percentage is not None:
|
|
|
|
if (percentage == 0 or percentage == 0.0):
|
|
|
|
raise exc.CommandError(_('Percentage cannot be zero.'))
|
|
|
|
action_args['adjustment_type'] = 'CHANGE_IN_PERCENTAGE'
|
|
|
|
action_args['number'] = percentage
|
|
|
|
|
|
|
|
if min_step is not None:
|
|
|
|
if percentage is None:
|
|
|
|
raise exc.CommandError(_('Min step is only used with percentage.'))
|
|
|
|
|
|
|
|
if min_size is not None:
|
|
|
|
if min_size < 0:
|
|
|
|
raise exc.CommandError(_('Min size cannot be less than zero.'))
|
|
|
|
if max_size is not None and max_size >= 0 and min_size > max_size:
|
|
|
|
raise exc.CommandError(_('Min size cannot be larger than '
|
|
|
|
'max size.'))
|
|
|
|
if capacity is not None and min_size > capacity:
|
|
|
|
raise exc.CommandError(_('Min size cannot be larger than the '
|
|
|
|
'specified capacity'))
|
|
|
|
|
|
|
|
if max_size is not None:
|
|
|
|
if capacity is not None and max_size > 0 and max_size < capacity:
|
|
|
|
raise exc.CommandError(_('Max size cannot be less than the '
|
|
|
|
'specified capacity.'))
|
|
|
|
# do a normalization
|
|
|
|
if max_size < 0:
|
|
|
|
max_size = -1
|
|
|
|
|
|
|
|
action_args['min_size'] = min_size
|
|
|
|
action_args['max_size'] = max_size
|
|
|
|
action_args['min_step'] = min_step
|
|
|
|
action_args['strict'] = args.strict
|
|
|
|
|
|
|
|
params = {
|
|
|
|
'id': args.id,
|
|
|
|
'action': 'resize',
|
|
|
|
'action_args': action_args,
|
|
|
|
}
|
|
|
|
|
|
|
|
resp = sc.action(models.Cluster, params)
|
|
|
|
print('Request accepted by action %s' % resp['action'])
|
|
|
|
|
|
|
|
|
2015-02-15 19:52:22 +08:00
|
|
|
@utils.arg('-c', '--count', metavar='<COUNT>',
|
2015-02-11 23:43:21 +08:00
|
|
|
help=_('Number of nodes to be added.'))
|
|
|
|
@utils.arg('id', metavar='<CLUSTER>',
|
|
|
|
help=_('Name or ID of cluster to operate on.'))
|
|
|
|
def do_cluster_scale_out(sc, args):
|
|
|
|
'''Scale out a cluster by the specified number of nodes.'''
|
|
|
|
params = {
|
|
|
|
'id': args.id,
|
|
|
|
'action': 'scale_out',
|
|
|
|
'action_args': {
|
2015-02-15 19:52:22 +08:00
|
|
|
'count': args.count
|
2015-02-11 23:43:21 +08:00
|
|
|
}
|
|
|
|
}
|
2015-02-15 19:52:22 +08:00
|
|
|
|
2015-02-11 23:43:21 +08:00
|
|
|
resp = sc.action(models.Cluster, params)
|
|
|
|
print('Request accepted by action %s' % resp['action'])
|
|
|
|
|
|
|
|
|
2015-02-15 19:52:22 +08:00
|
|
|
@utils.arg('-c', '--count', metavar='<COUNT>',
|
2015-02-11 23:43:21 +08:00
|
|
|
help=_('Number of nodes to be added.'))
|
|
|
|
@utils.arg('id', metavar='<CLUSTER>',
|
2015-01-07 13:04:22 +08:00
|
|
|
help=_('Name or ID of cluster to operate on.'))
|
2015-02-11 23:43:21 +08:00
|
|
|
def do_cluster_scale_in(sc, args):
|
|
|
|
'''Scale in a cluster by the specified number of nodes.'''
|
2015-02-15 19:52:22 +08:00
|
|
|
if args.count is not None:
|
|
|
|
action_args = {'count': args.count}
|
|
|
|
else:
|
|
|
|
action_args = {}
|
|
|
|
|
2015-02-11 23:43:21 +08:00
|
|
|
params = {
|
|
|
|
'id': args.id,
|
|
|
|
'action': 'scale_in',
|
2015-02-15 19:52:22 +08:00
|
|
|
'action_args': action_args,
|
2015-02-11 23:43:21 +08:00
|
|
|
}
|
|
|
|
resp = sc.action(models.Cluster, params)
|
|
|
|
print('Request accepted by action %s' % resp['action'])
|
|
|
|
|
|
|
|
|
|
|
|
@utils.arg('-f', '--filters', metavar='<KEY1=VALUE1;KEY2=VALUE2...>',
|
|
|
|
help=_('Filter parameters to apply on returned results. '
|
|
|
|
'This can be specified multiple times, or once with '
|
|
|
|
'parameters separated by a semicolon.'),
|
|
|
|
action='append')
|
2015-03-04 17:34:27 +08:00
|
|
|
@utils.arg('-k', '--sort-keys', metavar='<KEYS>',
|
|
|
|
help=_('Name of keys used for sorting the returned events.'))
|
2015-07-12 03:50:34 -04:00
|
|
|
@utils.arg('-s', '--sort-dir', metavar='<DIR>',
|
2015-03-04 17:34:27 +08:00
|
|
|
help=_('Direction for sorting, where DIR can be "asc" or "desc".'))
|
2015-02-11 23:43:21 +08:00
|
|
|
@utils.arg('id', metavar='<CLUSTER>',
|
|
|
|
help=_('Name or ID of cluster to query on.'))
|
2015-01-07 13:04:22 +08:00
|
|
|
def do_cluster_policy_list(sc, args):
|
|
|
|
'''List policies from cluster.'''
|
2015-01-16 15:53:16 +08:00
|
|
|
query = {'id': args.id}
|
2015-02-11 23:43:21 +08:00
|
|
|
cluster = sc.get(models.Cluster, query)
|
|
|
|
|
2015-07-08 06:34:14 -04:00
|
|
|
fields = ['policy_id', 'policy', 'type', 'priority', 'level',
|
|
|
|
'cooldown', 'enabled']
|
|
|
|
sort_keys = ['priority', 'level', 'cooldown', 'enabled']
|
|
|
|
|
2015-02-11 23:43:21 +08:00
|
|
|
queries = {
|
2015-03-04 17:34:27 +08:00
|
|
|
'sort_keys': args.sort_keys,
|
|
|
|
'sort_dir': args.sort_dir,
|
2015-02-11 23:43:21 +08:00
|
|
|
}
|
2015-07-08 06:34:14 -04:00
|
|
|
|
2015-08-05 04:44:02 -04:00
|
|
|
if args.filters:
|
|
|
|
queries.update(utils.format_parameters(args.filters))
|
|
|
|
|
2015-07-08 06:34:14 -04:00
|
|
|
sortby_index = None
|
|
|
|
if args.sort_keys:
|
|
|
|
for key in args.sort_keys.split(';'):
|
|
|
|
if len(key) > 0 and key not in sort_keys:
|
|
|
|
raise exc.CommandError(_('Invalid sorting key: %s') % key)
|
|
|
|
else:
|
|
|
|
sortby_index = 3
|
|
|
|
|
2015-02-11 23:43:21 +08:00
|
|
|
policies = sc.list(models.ClusterPolicy,
|
|
|
|
path_args={'cluster_id': cluster.id},
|
|
|
|
**queries)
|
2015-07-08 06:34:14 -04:00
|
|
|
utils.print_list(policies, fields, sortby_index=sortby_index)
|
2015-01-05 19:46:22 +08:00
|
|
|
|
|
|
|
|
2015-03-05 10:16:02 +08:00
|
|
|
@utils.arg('-p', '--policy', metavar='<POLICY>', required=True,
|
|
|
|
help=_('ID or name of the policy to query on.'))
|
|
|
|
@utils.arg('id', metavar='<CLUSTER>',
|
|
|
|
help=_('ID or name of the cluster to query on.'))
|
|
|
|
def do_cluster_policy_show(sc, args):
|
|
|
|
'''Show a specific policy that is bound to the specified cluster.'''
|
|
|
|
queries = {
|
|
|
|
'cluster_id': args.id,
|
|
|
|
'policy_id': args.policy
|
|
|
|
}
|
|
|
|
binding = sc.get(models.ClusterPolicy, queries)
|
|
|
|
utils.print_dict(binding.to_dict())
|
|
|
|
|
|
|
|
|
2015-02-11 23:43:21 +08:00
|
|
|
@utils.arg('-p', '--policy', metavar='<POLICY>', required=True,
|
|
|
|
help=_('ID or name of policy to be attached.'))
|
2015-02-12 15:21:22 +08:00
|
|
|
@utils.arg('-r', '--priority', metavar='<PRIORITY>', default=50,
|
2015-02-11 23:43:21 +08:00
|
|
|
help=_('An integer specifying the relative priority among '
|
|
|
|
'all policies attached to a cluster. The lower the '
|
|
|
|
'value, the higher the priority. Default is 50.'))
|
2015-09-25 14:48:16 +09:00
|
|
|
@utils.arg('-l', '--enforcement-level', metavar='<LEVEL>',
|
2015-02-11 23:43:21 +08:00
|
|
|
help=_('An integer beteen 0 and 100 representing the enforcement '
|
|
|
|
'level. Default to enforcement level of policy.'))
|
2015-09-25 14:48:16 +09:00
|
|
|
@utils.arg('-c', '--cooldown', metavar='<SECONDS>',
|
2015-02-11 23:43:21 +08:00
|
|
|
help=_('An integer indicating the cooldown seconds once the '
|
|
|
|
'policy is effected. Default to cooldown of policy.'))
|
|
|
|
@utils.arg('-e', '--enabled', default=True, action="store_true",
|
|
|
|
help=_('Whether the policy should be enabled once attached. '
|
|
|
|
'Default to enabled.'))
|
2015-01-05 19:46:22 +08:00
|
|
|
@utils.arg('id', metavar='<NAME or ID>',
|
|
|
|
help=_('Name or ID of cluster to operate on.'))
|
|
|
|
def do_cluster_policy_attach(sc, args):
|
|
|
|
'''Attach policy to cluster.'''
|
2015-02-11 23:43:21 +08:00
|
|
|
params = {
|
|
|
|
'id': args.id,
|
2015-02-12 15:21:22 +08:00
|
|
|
'action': 'policy_attach',
|
2015-02-11 23:43:21 +08:00
|
|
|
'action_args': {
|
|
|
|
'policy_id': args.policy,
|
|
|
|
'priority': args.priority,
|
|
|
|
'level': args.enforcement_level,
|
|
|
|
'cooldown': args.cooldown,
|
2015-02-12 15:21:22 +08:00
|
|
|
'enabled': args.enabled,
|
2015-02-11 23:43:21 +08:00
|
|
|
}
|
|
|
|
}
|
2015-02-12 15:21:22 +08:00
|
|
|
|
2015-02-11 23:43:21 +08:00
|
|
|
resp = sc.action(models.Cluster, params)
|
|
|
|
print('Request accepted by action %s' % resp['action'])
|
2015-01-05 19:46:22 +08:00
|
|
|
|
|
|
|
|
2015-02-11 23:43:21 +08:00
|
|
|
@utils.arg('-p', '--policy', metavar='<POLICY>', required=True,
|
|
|
|
help=_('ID or name of policy to be detached.'))
|
2015-01-07 14:43:23 +08:00
|
|
|
@utils.arg('id', metavar='<NAME or ID>',
|
|
|
|
help=_('Name or ID of cluster to operate on.'))
|
|
|
|
def do_cluster_policy_detach(sc, args):
|
|
|
|
'''Detach policy from cluster.'''
|
2015-02-11 23:43:21 +08:00
|
|
|
params = {
|
|
|
|
'id': args.id,
|
2015-02-12 15:21:22 +08:00
|
|
|
'action': 'policy_detach',
|
2015-02-11 23:43:21 +08:00
|
|
|
'action_args': {
|
|
|
|
'policy_id': args.policy,
|
|
|
|
}
|
|
|
|
}
|
2015-02-12 15:21:22 +08:00
|
|
|
|
2015-02-11 23:43:21 +08:00
|
|
|
resp = sc.action(models.Cluster, params)
|
|
|
|
print('Request accepted by action %s' % resp['action'])
|
2015-01-07 14:43:23 +08:00
|
|
|
|
|
|
|
|
2015-02-11 23:43:21 +08:00
|
|
|
@utils.arg('-p', '--policy', metavar='<POLICY>', required=True,
|
2015-02-12 15:21:22 +08:00
|
|
|
help=_('ID or name of policy to be updated.'))
|
2015-02-11 23:43:21 +08:00
|
|
|
@utils.arg('-r', '--priority', metavar='<PRIORITY>',
|
|
|
|
help=_('An integer specifying the relative priority among '
|
|
|
|
'all policies attached to a cluster. The lower the '
|
|
|
|
'value, the higher the priority. Default is 50.'))
|
2015-02-12 15:21:22 +08:00
|
|
|
@utils.arg('-l', '--enforcement-level', metavar='<LEVEL>',
|
2015-02-11 23:43:21 +08:00
|
|
|
help=_('New enforcement level.'))
|
2015-01-07 13:04:22 +08:00
|
|
|
@utils.arg('-c', '--cooldown', metavar='<COOLDOWN>',
|
|
|
|
help=_('Cooldown interval in seconds.'))
|
2015-02-12 15:21:22 +08:00
|
|
|
@utils.arg('-e', '--enabled', metavar='<BOOLEAN>',
|
|
|
|
help=_('Whether the policy should be enabled.'))
|
2015-01-05 19:46:22 +08:00
|
|
|
@utils.arg('id', metavar='<NAME or ID>',
|
|
|
|
help=_('Name or ID of cluster to operate on.'))
|
2015-02-12 15:21:22 +08:00
|
|
|
def do_cluster_policy_update(sc, args):
|
|
|
|
'''Update a policy on cluster.'''
|
2015-01-16 15:53:16 +08:00
|
|
|
params = {
|
2015-02-11 23:43:21 +08:00
|
|
|
'id': args.id,
|
2015-02-12 15:21:22 +08:00
|
|
|
'action': 'policy_update',
|
2015-02-11 23:43:21 +08:00
|
|
|
'action_args': {
|
|
|
|
'policy_id': args.policy,
|
|
|
|
'priority': args.priority,
|
|
|
|
'level': args.enforcement_level,
|
|
|
|
'cooldown': args.cooldown,
|
2015-02-12 15:21:22 +08:00
|
|
|
'enabled': args.enabled,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
resp = sc.action(models.Cluster, params)
|
|
|
|
print('Request accepted by action %s' % resp['action'])
|
|
|
|
|
|
|
|
|
|
|
|
@utils.arg('-p', '--policy', metavar='<POLICY>', required=True,
|
|
|
|
help=_('ID or name of policy to be enabled.'))
|
|
|
|
@utils.arg('id', metavar='<NAME or ID>',
|
|
|
|
help=_('Name or ID of cluster to operate on.'))
|
|
|
|
def do_cluster_policy_enable(sc, args):
|
|
|
|
'''Enable a policy on cluster.'''
|
|
|
|
params = {
|
|
|
|
'id': args.id,
|
|
|
|
'action': 'policy_enable',
|
|
|
|
'action_args': {
|
|
|
|
'policy_id': args.policy,
|
2015-02-11 23:43:21 +08:00
|
|
|
}
|
2015-01-07 13:04:22 +08:00
|
|
|
}
|
2015-02-11 23:43:21 +08:00
|
|
|
resp = sc.action(models.Cluster, params)
|
|
|
|
print('Request accepted by action %s' % resp['action'])
|
|
|
|
|
|
|
|
|
|
|
|
@utils.arg('-p', '--policy', metavar='<POLICY>', required=True,
|
|
|
|
help=_('ID or name of policy to be disabled.'))
|
|
|
|
@utils.arg('id', metavar='<NAME or ID>',
|
|
|
|
help=_('Name or ID of cluster to operate on.'))
|
|
|
|
def do_cluster_policy_disable(sc, args):
|
|
|
|
'''Disable a policy on a cluster.'''
|
|
|
|
params = {
|
|
|
|
'id': args.id,
|
2015-02-12 15:21:22 +08:00
|
|
|
'action': 'policy_disable',
|
2015-02-11 23:43:21 +08:00
|
|
|
'action_args': {
|
|
|
|
'policy_id': args.policy,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
resp = sc.action(models.Cluster, params)
|
|
|
|
print('Request accepted by action %s' % resp['action'])
|
2015-01-05 19:46:22 +08:00
|
|
|
|
|
|
|
|
2015-03-21 07:54:57 +08:00
|
|
|
# NODES
|
2015-01-05 19:46:22 +08:00
|
|
|
|
|
|
|
|
2015-07-08 02:40:49 -04:00
|
|
|
@utils.arg('-c', '--cluster', metavar='<CLUSTER>',
|
|
|
|
help=_('ID or name of cluster from which nodes are to be listed.'))
|
|
|
|
@utils.arg('-D', '--show-deleted', default=False, action="store_true",
|
2015-01-23 16:38:10 +08:00
|
|
|
help=_('Include soft-deleted nodes if any.'))
|
|
|
|
@utils.arg('-f', '--filters', metavar='<KEY1=VALUE1;KEY2=VALUE2...>',
|
|
|
|
help=_('Filter parameters to apply on returned nodes. '
|
|
|
|
'This can be specified multiple times, or once with '
|
|
|
|
'parameters separated by a semicolon.'),
|
|
|
|
action='append')
|
|
|
|
@utils.arg('-k', '--sort-keys', metavar='<KEYS>',
|
2015-08-27 03:11:18 -04:00
|
|
|
help=_('Name of keys used for sorting the returned nodes.'))
|
2015-07-08 02:40:49 -04:00
|
|
|
@utils.arg('-s', '--sort-dir', metavar='<DIR>',
|
2015-01-23 16:38:10 +08:00
|
|
|
help=_('Direction for sorting, where DIR can be "asc" or "desc".'))
|
|
|
|
@utils.arg('-l', '--limit', metavar='<LIMIT>',
|
|
|
|
help=_('Limit the number of nodes returned.'))
|
|
|
|
@utils.arg('-m', '--marker', metavar='<ID>',
|
|
|
|
help=_('Only return nodes that appear after the given node ID.'))
|
2015-08-27 03:11:18 -04:00
|
|
|
@utils.arg('-g', '--global-project', default=False, action="store_true",
|
2015-03-05 14:08:22 +08:00
|
|
|
help=_('Indicate that this node list should include nodes from '
|
2015-08-27 03:11:18 -04:00
|
|
|
'all projects. This option is subject to access policy '
|
2015-03-05 14:08:22 +08:00
|
|
|
'checking. Default is False.'))
|
2015-02-01 22:33:20 +08:00
|
|
|
@utils.arg('-F', '--full-id', default=False, action="store_true",
|
|
|
|
help=_('Print full IDs in list.'))
|
2015-01-23 16:38:10 +08:00
|
|
|
def do_node_list(sc, args):
|
|
|
|
'''Show list of nodes.'''
|
2015-02-01 22:33:20 +08:00
|
|
|
def _short_id(obj):
|
2015-04-26 06:24:45 -04:00
|
|
|
return obj.id[:8]
|
2015-02-01 22:33:20 +08:00
|
|
|
|
|
|
|
def _short_cluster_id(obj):
|
2015-04-26 06:24:45 -04:00
|
|
|
return obj.cluster_id[:8] if obj.cluster_id else ''
|
2015-02-01 22:33:20 +08:00
|
|
|
|
|
|
|
def _short_physical_id(obj):
|
2015-04-26 06:24:45 -04:00
|
|
|
return obj.physical_id[:8] if obj.physical_id else ''
|
2015-01-23 16:38:10 +08:00
|
|
|
|
|
|
|
fields = ['id', 'name', 'status', 'cluster_id', 'physical_id',
|
2015-01-30 15:07:50 +08:00
|
|
|
'profile_name', 'created_time', 'updated_time']
|
2015-07-08 06:34:14 -04:00
|
|
|
sort_keys = ['index', 'name', 'created_time', 'updated_time',
|
|
|
|
'deleted_time', 'status']
|
2015-01-26 22:45:16 +08:00
|
|
|
|
|
|
|
queries = {
|
|
|
|
'show_deleted': args.show_deleted,
|
|
|
|
'cluster_id': args.cluster,
|
|
|
|
'sort_keys': args.sort_keys,
|
|
|
|
'sort_dir': args.sort_dir,
|
|
|
|
'limit': args.limit,
|
|
|
|
'marker': args.marker,
|
2015-08-27 03:11:18 -04:00
|
|
|
'global_project': args.global_project,
|
2015-01-26 22:45:16 +08:00
|
|
|
}
|
|
|
|
|
2015-08-05 04:44:02 -04:00
|
|
|
if args.filters:
|
|
|
|
queries.update(utils.format_parameters(args.filters))
|
|
|
|
|
2015-08-27 03:11:18 -04:00
|
|
|
if args.show_deleted is not None:
|
2015-01-30 15:07:50 +08:00
|
|
|
fields.append('deleted_time')
|
|
|
|
|
2015-07-08 06:34:14 -04:00
|
|
|
sortby_index = None
|
|
|
|
if args.sort_keys:
|
|
|
|
for key in args.sort_keys.split(';'):
|
|
|
|
if len(key) > 0 and key not in sort_keys:
|
|
|
|
raise exc.CommandError(_('Invalid sorting key: %s') % key)
|
|
|
|
else:
|
|
|
|
sortby_index = 6
|
|
|
|
|
2015-01-26 22:45:16 +08:00
|
|
|
nodes = sc.list(models.Node, **queries)
|
2015-02-01 22:33:20 +08:00
|
|
|
|
|
|
|
if not args.full_id:
|
|
|
|
formatters = {
|
|
|
|
'id': _short_id,
|
|
|
|
'cluster_id': _short_cluster_id,
|
|
|
|
'physical_id': _short_physical_id,
|
|
|
|
}
|
|
|
|
else:
|
|
|
|
formatters = {}
|
|
|
|
|
2015-07-08 06:34:14 -04:00
|
|
|
utils.print_list(nodes, fields, formatters=formatters,
|
|
|
|
sortby_index=sortby_index)
|
2015-01-23 16:38:10 +08:00
|
|
|
|
|
|
|
|
2015-04-21 09:53:31 -04:00
|
|
|
def _show_node(sc, node_id, show_details=False):
|
2015-02-04 13:46:41 +08:00
|
|
|
'''Show detailed info about the specified node.'''
|
|
|
|
try:
|
2015-04-21 09:53:31 -04:00
|
|
|
query = {
|
|
|
|
'id': node_id,
|
|
|
|
'show_details': show_details,
|
|
|
|
}
|
|
|
|
node = sc.get_with_args(models.Node, query)
|
2015-02-04 13:46:41 +08:00
|
|
|
except exc.HTTPNotFound:
|
2015-02-05 20:02:06 +08:00
|
|
|
msg = _('Node %s is not found') % node_id
|
2015-02-04 13:46:41 +08:00
|
|
|
raise exc.CommandError(msg)
|
|
|
|
|
|
|
|
formatters = {
|
2015-05-06 23:01:00 -04:00
|
|
|
'metadata': utils.json_formatter,
|
2015-02-04 13:46:41 +08:00
|
|
|
'data': utils.json_formatter,
|
|
|
|
}
|
2015-04-21 09:53:31 -04:00
|
|
|
data = node.to_dict()
|
|
|
|
if show_details:
|
|
|
|
formatters['details'] = utils.nested_dict_formatter(
|
|
|
|
list(node['details'].keys()), ['property', 'value'])
|
2015-02-04 13:46:41 +08:00
|
|
|
|
2015-04-21 09:53:31 -04:00
|
|
|
utils.print_dict(data, formatters=formatters)
|
2015-02-04 13:46:41 +08:00
|
|
|
|
|
|
|
|
2015-02-07 21:32:31 +08:00
|
|
|
@utils.arg('-p', '--profile', metavar='<PROFILE>', required=True,
|
2015-01-05 19:46:22 +08:00
|
|
|
help=_('Profile Id used for this node.'))
|
2015-02-07 21:32:31 +08:00
|
|
|
@utils.arg('-c', '--cluster', metavar='<CLUSTER>',
|
|
|
|
help=_('Cluster Id for this node.'))
|
2015-01-05 19:46:22 +08:00
|
|
|
@utils.arg('-r', '--role', metavar='<ROLE>',
|
|
|
|
help=_('Role for this node in the specific cluster.'))
|
2015-07-08 17:37:31 +09:00
|
|
|
@utils.arg('-M', '--metadata', metavar='<KEY1=VALUE1;KEY2=VALUE2...>',
|
2015-05-06 23:01:00 -04:00
|
|
|
help=_('Metadata values to be attached to the cluster. '
|
|
|
|
'This can be specified multiple times, or once with '
|
|
|
|
'key-value pairs separated by a semicolon.'),
|
2015-01-05 19:46:22 +08:00
|
|
|
action='append')
|
|
|
|
@utils.arg('name', metavar='<NODE_NAME>',
|
|
|
|
help=_('Name of the node to create.'))
|
|
|
|
def do_node_create(sc, args):
|
|
|
|
'''Create the node.'''
|
2015-01-16 15:53:16 +08:00
|
|
|
params = {
|
2015-01-05 19:46:22 +08:00
|
|
|
'name': args.name,
|
|
|
|
'cluster_id': args.cluster,
|
|
|
|
'profile_id': args.profile,
|
|
|
|
'role': args.role,
|
2015-05-06 23:01:00 -04:00
|
|
|
'metadata': utils.format_parameters(args.metadata),
|
2015-01-05 19:46:22 +08:00
|
|
|
}
|
|
|
|
|
2015-02-04 13:46:41 +08:00
|
|
|
node = sc.create(models.Node, params)
|
|
|
|
_show_node(sc, node.id)
|
2015-01-05 19:46:22 +08:00
|
|
|
|
|
|
|
|
2015-04-21 09:53:31 -04:00
|
|
|
@utils.arg('-D', '--details', default=False, action="store_true",
|
|
|
|
help=_('Include physical object details.'))
|
2015-02-11 23:43:21 +08:00
|
|
|
@utils.arg('id', metavar='<NODE>',
|
2015-01-23 16:58:41 +08:00
|
|
|
help=_('Name or ID of the node to show the details for.'))
|
|
|
|
def do_node_show(sc, args):
|
|
|
|
'''Show detailed info about the specified node.'''
|
2015-04-21 09:53:31 -04:00
|
|
|
_show_node(sc, args.id, args.details)
|
2015-01-23 16:58:41 +08:00
|
|
|
|
|
|
|
|
2015-02-11 23:43:21 +08:00
|
|
|
@utils.arg('id', metavar='<NODE>', nargs='+',
|
2015-01-05 19:46:22 +08:00
|
|
|
help=_('Name or ID of node(s) to delete.'))
|
|
|
|
def do_node_delete(sc, args):
|
|
|
|
'''Delete the node(s).'''
|
|
|
|
failure_count = 0
|
|
|
|
|
|
|
|
for nid in args.id:
|
|
|
|
try:
|
2015-01-16 15:53:16 +08:00
|
|
|
query = {'id': nid}
|
|
|
|
sc.delete(models.Node, query)
|
2015-01-25 19:50:02 +08:00
|
|
|
except exc.HTTPNotFound:
|
2015-01-05 19:46:22 +08:00
|
|
|
failure_count += 1
|
2015-01-25 19:28:29 +08:00
|
|
|
print('Node id "%s" not found' % nid)
|
2015-01-05 19:46:22 +08:00
|
|
|
if failure_count == len(args.id):
|
|
|
|
msg = _('Failed to delete any of the specified nodes.')
|
|
|
|
raise exc.CommandError(msg)
|
2015-01-23 16:38:10 +08:00
|
|
|
print('Request accepted')
|
2015-01-05 19:46:22 +08:00
|
|
|
|
|
|
|
|
2015-01-07 15:13:51 +08:00
|
|
|
@utils.arg('-n', '--name', metavar='<NAME>',
|
|
|
|
help=_('New name for the node.'))
|
2015-01-05 19:46:22 +08:00
|
|
|
@utils.arg('-p', '--profile', metavar='<PROFILE ID>',
|
|
|
|
help=_('ID of new profile to use.'))
|
2015-01-07 15:13:51 +08:00
|
|
|
@utils.arg('-r', '--role', metavar='<ROLE>',
|
|
|
|
help=_('Role for this node in the specific cluster.'))
|
2015-07-08 17:37:31 +09:00
|
|
|
@utils.arg('-M', '--metadata', metavar='<KEY1=VALUE1;KEY2=VALUE2...>',
|
2015-05-06 23:01:00 -04:00
|
|
|
help=_('Metadata values to be attached to the node. '
|
|
|
|
'Metadata can be specified multiple times, or once with '
|
|
|
|
'key-value pairs separated by a semicolon.'),
|
2015-01-05 19:46:22 +08:00
|
|
|
action='append')
|
2015-02-11 23:43:21 +08:00
|
|
|
@utils.arg('id', metavar='<NODE>',
|
|
|
|
help=_('Name or ID of node to update.'))
|
2015-01-05 19:46:22 +08:00
|
|
|
def do_node_update(sc, args):
|
|
|
|
'''Update the node.'''
|
2015-03-21 07:54:57 +08:00
|
|
|
# Find the node first, we need its UUID
|
2015-03-05 17:57:10 +08:00
|
|
|
try:
|
|
|
|
node = sc.get(models.Node, {'id': args.id})
|
|
|
|
except exc.HTTPNotFound:
|
|
|
|
raise exc.CommandError(_('Node not found: %s') % args.id)
|
|
|
|
|
2015-01-16 15:53:16 +08:00
|
|
|
params = {
|
2015-03-05 17:57:10 +08:00
|
|
|
'id': node.id,
|
2015-01-07 15:13:51 +08:00
|
|
|
'name': args.name,
|
|
|
|
'role': args.role,
|
2015-09-10 04:42:16 -04:00
|
|
|
'profile_id': args.profile,
|
2015-05-06 23:01:00 -04:00
|
|
|
'metadata': utils.format_parameters(args.metadata),
|
2015-01-05 19:46:22 +08:00
|
|
|
}
|
|
|
|
|
2015-01-16 15:53:16 +08:00
|
|
|
sc.update(models.Node, params)
|
2015-03-05 17:57:10 +08:00
|
|
|
_show_node(sc, node.id)
|
2015-01-05 19:46:22 +08:00
|
|
|
|
|
|
|
|
2015-02-08 11:56:33 +08:00
|
|
|
@utils.arg('-c', '--cluster', required=True,
|
|
|
|
help=_('ID or name of cluster for node to join.'))
|
2015-02-11 23:43:21 +08:00
|
|
|
@utils.arg('id', metavar='<NODE>',
|
2015-01-05 19:46:22 +08:00
|
|
|
help=_('Name or ID of node to operate on.'))
|
2015-02-08 11:56:33 +08:00
|
|
|
def do_node_join(sc, args):
|
|
|
|
'''Make node join the specified cluster.'''
|
2015-01-16 15:53:16 +08:00
|
|
|
params = {
|
|
|
|
'id': args.id,
|
2015-02-08 11:56:33 +08:00
|
|
|
'action': 'join',
|
|
|
|
'action_args': {
|
|
|
|
'cluster_id': args.cluster,
|
|
|
|
}
|
2015-01-07 15:13:51 +08:00
|
|
|
}
|
2015-02-08 11:56:33 +08:00
|
|
|
resp = sc.action(models.Node, params)
|
|
|
|
print('Request accepted by action %s' % resp['action'])
|
2015-02-05 20:02:06 +08:00
|
|
|
_show_node(sc, args.id)
|
2015-01-05 19:46:22 +08:00
|
|
|
|
|
|
|
|
2015-02-11 23:43:21 +08:00
|
|
|
@utils.arg('id', metavar='<NODE>',
|
2015-01-05 19:46:22 +08:00
|
|
|
help=_('Name or ID of node to operate on.'))
|
2015-02-08 11:56:33 +08:00
|
|
|
def do_node_leave(sc, args):
|
|
|
|
'''Make node leave its current cluster.'''
|
2015-01-16 15:53:16 +08:00
|
|
|
params = {
|
|
|
|
'id': args.id,
|
2015-02-08 11:56:33 +08:00
|
|
|
'action': 'leave',
|
2015-01-07 15:13:51 +08:00
|
|
|
}
|
2015-02-08 11:56:33 +08:00
|
|
|
resp = sc.action(models.Node, params)
|
|
|
|
print('Request accepted by action %s' % resp['action'])
|
2015-02-05 20:02:06 +08:00
|
|
|
_show_node(sc, args.id)
|
2015-01-05 19:46:22 +08:00
|
|
|
|
|
|
|
|
2015-08-27 03:11:18 -04:00
|
|
|
# TRIGGERS
|
|
|
|
|
|
|
|
|
|
|
|
@utils.arg('-D', '--show-deleted', default=False, action="store_true",
|
|
|
|
help=_('Include soft-deleted triggers if any.'))
|
|
|
|
@utils.arg('-l', '--limit', metavar='<LIMIT>',
|
|
|
|
help=_('Limit the number of triggers returned.'))
|
|
|
|
@utils.arg('-m', '--marker', metavar='<ID>',
|
|
|
|
help=_('Only return triggers that appear after the given ID.'))
|
|
|
|
@utils.arg('-k', '--sort-keys', metavar='<KEYS>',
|
|
|
|
help=_('Name of keys used for sorting the returned triggers.'))
|
|
|
|
@utils.arg('-s', '--sort-dir', metavar='<DIR>',
|
|
|
|
help=_('Direction for sorting, where DIR can be "asc" or "desc".'))
|
|
|
|
@utils.arg('-f', '--filters', metavar='<KEY1=VALUE1;KEY2=VALUE2...>',
|
|
|
|
help=_('Filter parameters to apply on returned clusters. '
|
|
|
|
'This can be specified multiple times, or once with '
|
|
|
|
'parameters separated by a semicolon.'),
|
|
|
|
action='append')
|
|
|
|
@utils.arg('-g', '--global-project', default=False, action="store_true",
|
|
|
|
help=_('Indicate that the list should include triggers from '
|
|
|
|
'all projects. This option is subject to access policy '
|
|
|
|
'checking. Default is False.'))
|
|
|
|
@utils.arg('-F', '--full-id', default=False, action="store_true",
|
|
|
|
help=_('Print full IDs in list.'))
|
|
|
|
def do_trigger_list(sc, args=None):
|
|
|
|
'''List triggers that meet the criteria.'''
|
|
|
|
def _short_id(obj):
|
|
|
|
return obj.id[:8]
|
|
|
|
|
|
|
|
fields = ['id', 'name', 'type', 'state', 'enabled', 'severity',
|
|
|
|
'created_time']
|
|
|
|
sort_keys = ['name', 'type', 'state', 'severity', 'created_time',
|
|
|
|
'enabled', 'updated_time']
|
|
|
|
queries = {
|
|
|
|
'limit': args.limit,
|
|
|
|
'marker': args.marker,
|
|
|
|
'sort_keys': args.sort_keys,
|
|
|
|
'sort_dir': args.sort_dir,
|
|
|
|
'global_project': args.global_project,
|
|
|
|
}
|
|
|
|
|
|
|
|
if args.show_deleted is not None:
|
|
|
|
fields.append('deleted_time')
|
|
|
|
|
|
|
|
if args.filters:
|
|
|
|
queries.update(utils.format_parameters(args.filters))
|
|
|
|
|
|
|
|
sortby_index = None
|
|
|
|
if args.sort_keys:
|
|
|
|
for key in args.sort_keys.split(';'):
|
|
|
|
if len(key) > 0 and key not in sort_keys:
|
|
|
|
raise exc.CommandError(_('Invalid sorting key: %s') % key)
|
|
|
|
else:
|
|
|
|
sortby_index = 1
|
|
|
|
|
|
|
|
triggers = sc.list(models.Trigger, **queries)
|
|
|
|
formatters = {}
|
|
|
|
if not args.full_id:
|
|
|
|
formatters = {
|
|
|
|
'id': _short_id,
|
|
|
|
}
|
|
|
|
utils.print_list(triggers, fields, formatters=formatters,
|
|
|
|
sortby_index=sortby_index)
|
|
|
|
|
|
|
|
|
|
|
|
def _show_trigger(sc, trigger_id):
|
|
|
|
try:
|
|
|
|
params = {'id': trigger_id}
|
|
|
|
trigger = sc.get(models.Trigger, params)
|
|
|
|
except exc.HTTPNotFound:
|
|
|
|
raise exc.CommandError(_('Trigger not found: %s') % trigger_id)
|
|
|
|
|
|
|
|
formatters = {
|
|
|
|
'spec': utils.json_formatter,
|
|
|
|
}
|
|
|
|
|
|
|
|
utils.print_dict(trigger.to_dict(), formatters=formatters)
|
|
|
|
|
|
|
|
|
|
|
|
@utils.arg('-s', '--spec-file', metavar='<SPEC FILE>', required=True,
|
|
|
|
help=_('The spec file used to create the trigger.'))
|
|
|
|
@utils.arg('--desc', metavar='<DESCRIPTION>',
|
|
|
|
help=_('A string for describing of the trigger to be created.'))
|
|
|
|
@utils.arg('-e', '--enabled', default=True, action='store_true',
|
|
|
|
help=_('Whether the trigger should be enabled when created.'))
|
|
|
|
@utils.arg('-v', '--severity',
|
|
|
|
help=_('Severity level of the target trigger to be created.'))
|
|
|
|
@utils.arg('--state',
|
|
|
|
help=_('Initial state of the target trigger.'))
|
|
|
|
@utils.arg('name', metavar='<TRIGGER_NAME>',
|
|
|
|
help=_('Name of the trigger to create.'))
|
|
|
|
def do_trigger_create(sc, args):
|
|
|
|
'''Create a trigger.'''
|
|
|
|
|
|
|
|
spec = utils.get_spec_content(args.spec_file)
|
|
|
|
params = {
|
|
|
|
'name': args.name,
|
|
|
|
'spec': spec,
|
|
|
|
'enabled': args.enabled,
|
|
|
|
'severity': args.severity,
|
|
|
|
'state': args.state,
|
|
|
|
'description': args.desc,
|
|
|
|
}
|
|
|
|
|
|
|
|
trigger = sc.create(models.Trigger, params)
|
|
|
|
_show_trigger(sc, trigger.id)
|
|
|
|
|
|
|
|
|
|
|
|
@utils.arg('id', metavar='<TRIGGER>',
|
|
|
|
help=_('Name or ID of trigger to show.'))
|
|
|
|
def do_trigger_show(sc, args):
|
|
|
|
'''Show the trigger details.'''
|
|
|
|
_show_trigger(sc, args.id)
|
|
|
|
|
|
|
|
|
|
|
|
@utils.arg('id', metavar='<TRIGGER>', nargs='+',
|
|
|
|
help=_('Name or ID of trigger(s) to delete.'))
|
|
|
|
def do_trigger_delete(sc, args):
|
|
|
|
'''Delete trigger(s).'''
|
|
|
|
failure_count = 0
|
|
|
|
|
|
|
|
for cid in args.id:
|
|
|
|
try:
|
|
|
|
query = {
|
|
|
|
'id': cid,
|
|
|
|
}
|
|
|
|
sc.delete(models.Trigger, query)
|
|
|
|
except exc.HTTPNotFound as ex:
|
|
|
|
failure_count += 1
|
|
|
|
print(ex)
|
|
|
|
if failure_count == len(args.id):
|
|
|
|
msg = _('Failed to delete any of the specified trigger(s).')
|
|
|
|
raise exc.CommandError(msg)
|
|
|
|
print('Triggers deleted: %s' % args.id)
|
|
|
|
|
|
|
|
|
2015-03-21 07:54:57 +08:00
|
|
|
# EVENTS
|
2015-01-05 19:46:22 +08:00
|
|
|
|
|
|
|
|
|
|
|
@utils.arg('-f', '--filters', metavar='<KEY1=VALUE1;KEY2=VALUE2...>',
|
|
|
|
help=_('Filter parameters to apply on returned events. '
|
|
|
|
'This can be specified multiple times, or once with '
|
|
|
|
'parameters separated by a semicolon.'),
|
|
|
|
action='append')
|
|
|
|
@utils.arg('-l', '--limit', metavar='<LIMIT>',
|
|
|
|
help=_('Limit the number of events returned.'))
|
|
|
|
@utils.arg('-m', '--marker', metavar='<ID>',
|
|
|
|
help=_('Only return events that appear after the given event ID.'))
|
2015-01-13 15:21:25 +08:00
|
|
|
@utils.arg('-k', '--sort-keys', metavar='<KEYS>',
|
|
|
|
help=_('Name of keys used for sorting the returned events.'))
|
2015-07-08 04:21:07 -04:00
|
|
|
@utils.arg('-s', '--sort-dir', metavar='<DIR>',
|
2015-01-13 15:21:25 +08:00
|
|
|
help=_('Direction for sorting, where DIR can be "asc" or "desc".'))
|
2015-08-27 03:11:18 -04:00
|
|
|
@utils.arg('-g', '--global-project', default=False, action="store_true",
|
|
|
|
help=_('Whether events from all projects should be listed. '
|
|
|
|
' Default to False. Setting this to True may demand '
|
2015-02-27 13:59:37 +08:00
|
|
|
'for an admin privilege.'))
|
|
|
|
@utils.arg('-D', '--show-deleted', default=False, action="store_true",
|
|
|
|
help=_('Whether deleted events should be listed as well. '
|
|
|
|
'Default to False.'))
|
2015-08-30 08:31:49 -04:00
|
|
|
@utils.arg('-F', '--full-id', default=False, action="store_true",
|
|
|
|
help=_('Print full IDs in list.'))
|
2015-01-05 19:46:22 +08:00
|
|
|
def do_event_list(sc, args):
|
|
|
|
'''List events.'''
|
2015-08-30 08:31:49 -04:00
|
|
|
def _short_id(obj):
|
|
|
|
return obj.id[:8]
|
|
|
|
|
|
|
|
def _short_obj_id(obj):
|
2015-09-18 13:49:31 +08:00
|
|
|
return obj.obj_id[:8] if obj.obj_id else ''
|
2015-08-30 08:31:49 -04:00
|
|
|
|
2015-07-08 06:34:14 -04:00
|
|
|
fields = ['id', 'timestamp', 'obj_type', 'obj_id', 'action', 'status',
|
|
|
|
'status_reason']
|
|
|
|
sort_keys = ['timestamp', 'obj_type', 'obj_name', 'user', 'action']
|
|
|
|
|
2015-01-16 15:53:16 +08:00
|
|
|
queries = {
|
2015-01-13 15:21:25 +08:00
|
|
|
'sort_keys': args.sort_keys,
|
|
|
|
'sort_dir': args.sort_dir,
|
|
|
|
'limit': args.limit,
|
|
|
|
'marker': args.marker,
|
2015-08-27 03:11:18 -04:00
|
|
|
'global_project': args.global_project,
|
2015-02-27 13:59:37 +08:00
|
|
|
'show_deleted': args.show_deleted,
|
2015-01-13 15:21:25 +08:00
|
|
|
}
|
|
|
|
|
2015-08-05 04:44:02 -04:00
|
|
|
if args.filters:
|
|
|
|
queries.update(utils.format_parameters(args.filters))
|
|
|
|
|
2015-07-08 06:34:14 -04:00
|
|
|
sortby_index = None
|
|
|
|
if args.sort_keys:
|
|
|
|
for key in args.sort_keys.split(';'):
|
|
|
|
if len(key) > 0 and key not in sort_keys:
|
|
|
|
raise exc.CommandError(_('Invalid sorting key: %s') % key)
|
|
|
|
else:
|
|
|
|
sortby_index = 0
|
2015-01-05 19:46:22 +08:00
|
|
|
|
2015-08-30 08:31:49 -04:00
|
|
|
formatters = {}
|
|
|
|
if not args.full_id:
|
|
|
|
formatters['id'] = _short_id
|
|
|
|
formatters['obj_id'] = _short_obj_id
|
|
|
|
|
2015-07-08 06:34:14 -04:00
|
|
|
events = sc.list(models.Event, **queries)
|
2015-08-30 08:31:49 -04:00
|
|
|
utils.print_list(events, fields, formatters=formatters,
|
|
|
|
sortby_index=sortby_index)
|
2015-01-05 19:46:22 +08:00
|
|
|
|
|
|
|
|
|
|
|
@utils.arg('event', metavar='<EVENT>',
|
|
|
|
help=_('ID of event to display details for.'))
|
|
|
|
def do_event_show(sc, args):
|
|
|
|
'''Describe the event.'''
|
|
|
|
try:
|
2015-01-16 15:53:16 +08:00
|
|
|
query = {'id': args.event}
|
|
|
|
event = sc.get(models.Event, query)
|
2015-01-05 19:46:22 +08:00
|
|
|
except exc.HTTPNotFound as ex:
|
|
|
|
raise exc.CommandError(str(ex))
|
|
|
|
|
|
|
|
utils.print_dict(event.to_dict())
|
|
|
|
|
|
|
|
|
2015-03-21 07:54:57 +08:00
|
|
|
# ACTIONS
|
2015-01-05 19:46:22 +08:00
|
|
|
|
|
|
|
|
|
|
|
@utils.arg('-f', '--filters', metavar='<KEY1=VALUE1;KEY2=VALUE2...>',
|
|
|
|
help=_('Filter parameters to apply on returned actions. '
|
|
|
|
'This can be specified multiple times, or once with '
|
|
|
|
'parameters separated by a semicolon.'),
|
|
|
|
action='append')
|
2015-01-23 21:50:00 +08:00
|
|
|
@utils.arg('-k', '--sort-keys', metavar='<KEYS>',
|
|
|
|
help=_('Name of keys used for sorting the returned events.'))
|
2015-07-08 04:21:07 -04:00
|
|
|
@utils.arg('-s', '--sort-dir', metavar='<DIR>',
|
2015-01-23 21:50:00 +08:00
|
|
|
help=_('Direction for sorting, where DIR can be "asc" or "desc".'))
|
2015-01-05 19:46:22 +08:00
|
|
|
@utils.arg('-l', '--limit', metavar='<LIMIT>',
|
2015-01-23 21:50:00 +08:00
|
|
|
help=_('Limit the number of nodes returned.'))
|
2015-01-05 19:46:22 +08:00
|
|
|
@utils.arg('-m', '--marker', metavar='<ID>',
|
2015-01-23 21:50:00 +08:00
|
|
|
help=_('Only return nodes that appear after the given node ID.'))
|
2015-07-08 04:21:07 -04:00
|
|
|
@utils.arg('-D', '--show-deleted', default=False, action="store_true",
|
2015-01-23 21:50:00 +08:00
|
|
|
help=_('Include soft-deleted nodes if any.'))
|
2015-01-26 14:07:14 +08:00
|
|
|
@utils.arg('-F', '--full-id', default=False, action="store_true",
|
|
|
|
help=_('Print full IDs in list.'))
|
2015-01-05 19:46:22 +08:00
|
|
|
def do_action_list(sc, args):
|
|
|
|
'''List actions.'''
|
2015-01-26 14:07:14 +08:00
|
|
|
def _short_id(obj):
|
2015-04-26 06:24:45 -04:00
|
|
|
return obj.id[:8]
|
2015-01-26 22:55:00 +08:00
|
|
|
|
2015-01-26 14:07:14 +08:00
|
|
|
def _short_target(obj):
|
2015-09-18 13:49:31 +08:00
|
|
|
return obj.target[:8] if obj.target else ''
|
2015-01-26 14:07:14 +08:00
|
|
|
|
2015-07-08 06:34:14 -04:00
|
|
|
fields = ['id', 'name', 'action', 'status', 'target', 'depends_on',
|
|
|
|
'depended_by']
|
2015-07-08 22:08:21 -04:00
|
|
|
sort_keys = ['name', 'target', 'action', 'created_time', 'status']
|
2015-07-08 06:34:14 -04:00
|
|
|
|
2015-01-26 22:45:16 +08:00
|
|
|
queries = {
|
|
|
|
'show_deleted': args.show_deleted,
|
|
|
|
'sort_keys': args.sort_keys,
|
|
|
|
'sort_dir': args.sort_dir,
|
|
|
|
'limit': args.limit,
|
|
|
|
'marker': args.marker,
|
|
|
|
}
|
2015-01-05 19:46:22 +08:00
|
|
|
|
2015-08-05 04:44:02 -04:00
|
|
|
if args.filters:
|
|
|
|
queries.update(utils.format_parameters(args.filters))
|
|
|
|
|
2015-07-08 06:34:14 -04:00
|
|
|
sortby_index = None
|
|
|
|
if args.sort_keys:
|
|
|
|
for key in args.sort_keys.split(';'):
|
|
|
|
if len(key) > 0 and key not in sort_keys:
|
|
|
|
raise exc.CommandError(_('Invalid sorting key: %s') % key)
|
|
|
|
else:
|
|
|
|
sortby_index = 0
|
2015-01-05 19:46:22 +08:00
|
|
|
|
2015-07-08 06:34:14 -04:00
|
|
|
actions = sc.list(models.Action, **queries)
|
2015-01-05 19:46:22 +08:00
|
|
|
|
2015-01-26 14:07:14 +08:00
|
|
|
if not args.full_id:
|
|
|
|
formatters = {
|
|
|
|
'id': _short_id,
|
|
|
|
'target': _short_target,
|
|
|
|
}
|
|
|
|
else:
|
|
|
|
formatters = {}
|
|
|
|
|
2015-07-08 06:34:14 -04:00
|
|
|
utils.print_list(actions, fields, formatters=formatters,
|
|
|
|
sortby_index=sortby_index)
|
2015-01-23 21:50:00 +08:00
|
|
|
|
|
|
|
|
2015-02-11 23:43:21 +08:00
|
|
|
@utils.arg('id', metavar='<ACTION>',
|
2015-01-23 21:50:00 +08:00
|
|
|
help=_('Name or ID of the action to show the details for.'))
|
|
|
|
def do_action_show(sc, args):
|
|
|
|
'''Show detailed info about the specified action.'''
|
|
|
|
try:
|
|
|
|
query = {'id': args.id}
|
|
|
|
action = sc.get(models.Action, query)
|
|
|
|
except exc.HTTPNotFound:
|
2015-09-15 02:07:04 -04:00
|
|
|
msg = _('Action %(id)s is not found') % {'id': args.id}
|
2015-01-23 21:50:00 +08:00
|
|
|
raise exc.CommandError(msg)
|
|
|
|
|
|
|
|
formatters = {
|
|
|
|
'inputs': utils.json_formatter,
|
|
|
|
'outputs': utils.json_formatter,
|
2015-05-06 23:01:00 -04:00
|
|
|
'metadata': utils.json_formatter,
|
2015-01-23 21:50:00 +08:00
|
|
|
'data': utils.json_formatter,
|
|
|
|
}
|
|
|
|
|
|
|
|
utils.print_dict(action.to_dict(), formatters=formatters)
|