summaryrefslogtreecommitdiff
path: root/openstackclient
diff options
context:
space:
mode:
Diffstat (limited to 'openstackclient')
-rw-r--r--openstackclient/api/api.py3
-rw-r--r--openstackclient/common/quota.py34
-rw-r--r--openstackclient/compute/client.py1
-rw-r--r--openstackclient/compute/v2/availability_zone.py102
-rw-r--r--openstackclient/compute/v2/flavor.py31
-rw-r--r--openstackclient/compute/v2/security_group.py2
-rw-r--r--openstackclient/compute/v2/server.py14
-rw-r--r--openstackclient/compute/v2/usage.py83
-rw-r--r--openstackclient/identity/v2_0/project.py21
-rw-r--r--openstackclient/identity/v2_0/role.py21
-rw-r--r--openstackclient/identity/v2_0/user.py21
-rw-r--r--openstackclient/identity/v3/domain.py50
-rw-r--r--openstackclient/identity/v3/group.py63
-rw-r--r--openstackclient/identity/v3/project.py27
-rw-r--r--openstackclient/identity/v3/region.py38
-rw-r--r--openstackclient/identity/v3/role.py21
-rw-r--r--openstackclient/identity/v3/role_assignment.py12
-rw-r--r--openstackclient/identity/v3/service.py14
-rw-r--r--openstackclient/identity/v3/user.py27
-rw-r--r--openstackclient/image/v1/image.py18
-rw-r--r--openstackclient/image/v2/image.py18
-rw-r--r--openstackclient/network/v2/network.py13
-rw-r--r--openstackclient/object/v1/container.py18
-rw-r--r--openstackclient/object/v1/object.py32
-rw-r--r--openstackclient/tests/compute/v2/test_server.py2
-rw-r--r--openstackclient/tests/identity/v2_0/test_project.py4
-rw-r--r--openstackclient/tests/identity/v2_0/test_role.py4
-rw-r--r--openstackclient/tests/identity/v2_0/test_user.py4
-rw-r--r--openstackclient/tests/identity/v3/fakes.py2
-rw-r--r--openstackclient/tests/identity/v3/test_domain.py10
-rw-r--r--openstackclient/tests/identity/v3/test_project.py2
-rw-r--r--openstackclient/tests/identity/v3/test_role.py2
-rw-r--r--openstackclient/tests/identity/v3/test_service.py87
-rw-r--r--openstackclient/tests/identity/v3/test_user.py2
-rw-r--r--openstackclient/tests/image/v1/test_image.py2
-rw-r--r--openstackclient/tests/image/v2/test_image.py2
-rw-r--r--openstackclient/tests/network/v2/test_network.py2
-rw-r--r--openstackclient/volume/v1/backup.py14
-rw-r--r--openstackclient/volume/v1/snapshot.py14
-rw-r--r--openstackclient/volume/v1/volume.py63
40 files changed, 620 insertions, 280 deletions
diff --git a/openstackclient/api/api.py b/openstackclient/api/api.py
index 67386aaf..90b4e9c3 100644
--- a/openstackclient/api/api.py
+++ b/openstackclient/api/api.py
@@ -15,8 +15,7 @@
import simplejson as json
-from keystoneclient.openstack.common.apiclient \
- import exceptions as ksc_exceptions
+from keystoneclient import exceptions as ksc_exceptions
from keystoneclient import session as ksc_session
from openstackclient.common import exceptions
diff --git a/openstackclient/common/quota.py b/openstackclient/common/quota.py
index edf4ffdb..6d04b5c9 100644
--- a/openstackclient/common/quota.py
+++ b/openstackclient/common/quota.py
@@ -147,6 +147,21 @@ class ShowQuota(show.ShowOne):
)
return parser
+ def get_quota(self, client, parsed_args):
+ try:
+ if parsed_args.quota_class:
+ quota = client.quota_classes.get(parsed_args.project)
+ elif parsed_args.default:
+ quota = client.quotas.defaults(parsed_args.project)
+ else:
+ quota = client.quotas.get(parsed_args.project)
+ except Exception as e:
+ if type(e).__name__ == 'EndpointNotFound':
+ return {}
+ else:
+ raise e
+ return quota._info
+
def take_action(self, parsed_args):
self.log.debug('take_action(%s)', parsed_args)
@@ -159,23 +174,12 @@ class ShowQuota(show.ShowOne):
# does not exist. If this is determined to be the
# intended behaviour of the API we will validate
# the argument with Identity ourselves later.
- if parsed_args.quota_class:
- compute_quota = compute_client.quota_classes.get(
- parsed_args.project)
- volume_quota = volume_client.quota_classes.get(
- parsed_args.project)
- elif parsed_args.default:
- compute_quota = compute_client.quotas.defaults(
- parsed_args.project)
- volume_quota = volume_client.quotas.defaults(
- parsed_args.project)
- else:
- compute_quota = compute_client.quotas.get(parsed_args.project)
- volume_quota = volume_client.quotas.get(parsed_args.project)
+ compute_quota_info = self.get_quota(compute_client, parsed_args)
+ volume_quota_info = self.get_quota(volume_client, parsed_args)
info = {}
- info.update(compute_quota._info)
- info.update(volume_quota._info)
+ info.update(compute_quota_info)
+ info.update(volume_quota_info)
# Map the internal quota names to the external ones
for k, v in itertools.chain(
diff --git a/openstackclient/compute/client.py b/openstackclient/compute/client.py
index 3725350a..166747d5 100644
--- a/openstackclient/compute/client.py
+++ b/openstackclient/compute/client.py
@@ -50,6 +50,7 @@ def make_client(instance):
extensions=extensions,
http_log_debug=http_log_debug,
timings=instance.timing,
+ region_name=instance._region_name,
)
return client
diff --git a/openstackclient/compute/v2/availability_zone.py b/openstackclient/compute/v2/availability_zone.py
new file mode 100644
index 00000000..648c0ee4
--- /dev/null
+++ b/openstackclient/compute/v2/availability_zone.py
@@ -0,0 +1,102 @@
+# 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.
+#
+
+"""Compute v2 Availability Zone action implementations"""
+
+import copy
+import logging
+
+from cliff import lister
+from novaclient import exceptions as nova_exceptions
+import six
+
+from openstackclient.common import utils
+from openstackclient.i18n import _ # noqa
+
+
+def _xform_availability_zone(az, include_extra):
+ result = []
+ zone_info = {}
+ if hasattr(az, 'zoneState'):
+ zone_info['zone_status'] = ('available' if az.zoneState['available']
+ else 'not available')
+ if hasattr(az, 'zoneName'):
+ zone_info['zone_name'] = az.zoneName
+
+ if not include_extra:
+ result.append(zone_info)
+ return result
+
+ if hasattr(az, 'hosts') and az.hosts:
+ for host, services in six.iteritems(az.hosts):
+ host_info = copy.deepcopy(zone_info)
+ host_info['host_name'] = host
+
+ for svc, state in six.iteritems(services):
+ info = copy.deepcopy(host_info)
+ info['service_name'] = svc
+ info['service_status'] = '%s %s %s' % (
+ 'enabled' if state['active'] else 'disabled',
+ ':-)' if state['available'] else 'XXX',
+ state['updated_at'])
+ result.append(info)
+ else:
+ zone_info['host_name'] = ''
+ zone_info['service_name'] = ''
+ zone_info['service_status'] = ''
+ result.append(zone_info)
+ return result
+
+
+class ListAvailabilityZone(lister.Lister):
+ """List availability zones and their status"""
+
+ log = logging.getLogger(__name__ + '.ListAvailabilityZone')
+
+ def get_parser(self, prog_name):
+ parser = super(ListAvailabilityZone, self).get_parser(prog_name)
+ parser.add_argument(
+ '--long',
+ action='store_true',
+ default=False,
+ help=_('List additional fields in output'),
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ self.log.debug('take_action(%s)', parsed_args)
+
+ if parsed_args.long:
+ columns = ('Zone Name', 'Zone Status',
+ 'Host Name', 'Service Name', 'Service Status')
+ else:
+ columns = ('Zone Name', 'Zone Status')
+
+ compute_client = self.app.client_manager.compute
+ try:
+ data = compute_client.availability_zones.list()
+ except nova_exceptions.Forbidden as e: # policy doesn't allow
+ try:
+ data = compute_client.availability_zones.list(detailed=False)
+ except Exception:
+ raise e
+
+ # Argh, the availability zones are not iterable...
+ result = []
+ for zone in data:
+ result += _xform_availability_zone(zone, parsed_args.long)
+
+ return (columns,
+ (utils.get_dict_properties(
+ s, columns
+ ) for s in result))
diff --git a/openstackclient/compute/v2/flavor.py b/openstackclient/compute/v2/flavor.py
index 6dd00b1b..6f3788a0 100644
--- a/openstackclient/compute/v2/flavor.py
+++ b/openstackclient/compute/v2/flavor.py
@@ -34,64 +34,71 @@ class CreateFlavor(show.ShowOne):
parser = super(CreateFlavor, self).get_parser(prog_name)
parser.add_argument(
"name",
- metavar="<name>",
+ metavar="<flavor-name>",
help="New flavor name",
)
parser.add_argument(
"--id",
metavar="<id>",
default='auto',
- help="Unique flavor ID; 'auto' will create a UUID "
- "(default: auto)")
+ help="Unique flavor ID; 'auto' creates a UUID "
+ "(default: auto)",
+ )
parser.add_argument(
"--ram",
type=int,
metavar="<size-mb>",
default=256,
- help="Memory size in MB (default 256M)")
+ help="Memory size in MB (default 256M)",
+ )
parser.add_argument(
"--disk",
type=int,
metavar="<size-gb>",
default=0,
- help="Disk size in GB (default 0G)")
+ help="Disk size in GB (default 0G)",
+ )
parser.add_argument(
"--ephemeral",
type=int,
metavar="<size-gb>",
+ default=0,
help="Ephemeral disk size in GB (default 0G)",
- default=0)
+ )
parser.add_argument(
"--swap",
type=int,
metavar="<size-gb>",
+ default=0,
help="Swap space size in GB (default 0G)",
- default=0)
+ )
parser.add_argument(
"--vcpus",
type=int,
metavar="<vcpus>",
default=1,
- help="Number of vcpus (default 1)")
+ help="Number of vcpus (default 1)",
+ )
parser.add_argument(
"--rxtx-factor",
type=int,
metavar="<factor>",
+ default=1,
help="RX/TX factor (default 1)",
- default=1)
+ )
public_group = parser.add_mutually_exclusive_group()
public_group.add_argument(
"--public",
dest="public",
action="store_true",
default=True,
- help="Flavor is accessible to other projects (default)",
+ help="Flavor is available to other projects (default)",
)
public_group.add_argument(
"--private",
dest="public",
action="store_false",
- help="Flavor is inaccessible to other projects",
+ help="Flavor is not available to other projects",
)
return parser
@@ -168,7 +175,7 @@ class ListFlavor(lister.Lister):
class ShowFlavor(show.ShowOne):
- """Show flavor details"""
+ """Display flavor details"""
log = logging.getLogger(__name__ + ".ShowFlavor")
diff --git a/openstackclient/compute/v2/security_group.py b/openstackclient/compute/v2/security_group.py
index cd330857..f7ffb1d1 100644
--- a/openstackclient/compute/v2/security_group.py
+++ b/openstackclient/compute/v2/security_group.py
@@ -23,7 +23,7 @@ from cliff import command
from cliff import lister
from cliff import show
-from keystoneclient.openstack.common.apiclient import exceptions as ksc_exc
+from keystoneclient import exceptions as ksc_exc
from novaclient.v1_1 import security_group_rules
from openstackclient.common import parseractions
from openstackclient.common import utils
diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py
index 5ab1d5f3..a5d8b0c3 100644
--- a/openstackclient/compute/v2/server.py
+++ b/openstackclient/compute/v2/server.py
@@ -511,25 +511,27 @@ class CreateServerImage(show.ShowOne):
class DeleteServer(command.Command):
- """Delete server command"""
+ """Delete server(s)"""
log = logging.getLogger(__name__ + '.DeleteServer')
def get_parser(self, prog_name):
parser = super(DeleteServer, self).get_parser(prog_name)
parser.add_argument(
- 'server',
+ 'servers',
metavar='<server>',
- help=_('Server (name or ID)'),
+ nargs="+",
+ help=_('Server(s) to delete (name or ID)'),
)
return parser
def take_action(self, parsed_args):
self.log.debug('take_action(%s)', parsed_args)
compute_client = self.app.client_manager.compute
- server = utils.find_resource(
- compute_client.servers, parsed_args.server)
- compute_client.servers.delete(server.id)
+ for server in parsed_args.servers:
+ server_obj = utils.find_resource(
+ compute_client.servers, server)
+ compute_client.servers.delete(server_obj.id)
return
diff --git a/openstackclient/compute/v2/usage.py b/openstackclient/compute/v2/usage.py
index ed98af26..308241cf 100644
--- a/openstackclient/compute/v2/usage.py
+++ b/openstackclient/compute/v2/usage.py
@@ -20,6 +20,8 @@ import logging
import sys
from cliff import lister
+from cliff import show
+import six
from openstackclient.common import utils
@@ -60,12 +62,14 @@ class ListUsage(lister.Lister):
compute_client = self.app.client_manager.compute
columns = (
"tenant_id",
+ "server_usages",
"total_memory_mb_usage",
"total_vcpus_usage",
"total_local_gb_usage"
)
column_headers = (
"Project",
+ "Servers",
"RAM MB-Hours",
"CPU Hours",
"Disk GB-Hours"
@@ -84,7 +88,7 @@ class ListUsage(lister.Lister):
else:
end = now + datetime.timedelta(days=1)
- usage_list = compute_client.usage.list(start, end)
+ usage_list = compute_client.usage.list(start, end, detailed=True)
# Cache the project list
project_cache = {}
@@ -95,8 +99,8 @@ class ListUsage(lister.Lister):
# Just forget it if there's any trouble
pass
- if len(usage_list) > 0:
- sys.stdout.write("Usage from %s to %s:" % (
+ if parsed_args.formatter == 'table' and len(usage_list) > 0:
+ sys.stdout.write("Usage from %s to %s: \n" % (
start.strftime(dateformat),
end.strftime(dateformat),
))
@@ -106,8 +110,81 @@ class ListUsage(lister.Lister):
s, columns,
formatters={
'tenant_id': _format_project,
+ 'server_usages': lambda x: len(x),
'total_memory_mb_usage': lambda x: float("%.2f" % x),
'total_vcpus_usage': lambda x: float("%.2f" % x),
'total_local_gb_usage': lambda x: float("%.2f" % x),
},
) for s in usage_list))
+
+
+class ShowUsage(show.ShowOne):
+ """Show resource usage for a single project. """
+
+ log = logging.getLogger(__name__ + ".ShowUsage")
+
+ def get_parser(self, prog_name):
+ parser = super(ShowUsage, self).get_parser(prog_name)
+ parser.add_argument(
+ "--project",
+ metavar="<project>",
+ default=None,
+ help="Name or ID of project to show usage for."
+ )
+ parser.add_argument(
+ "--start",
+ metavar="<start>",
+ default=None,
+ help="Usage range start date, ex 2012-01-20"
+ " (default: 4 weeks ago)."
+ )
+ parser.add_argument(
+ "--end",
+ metavar="<end>",
+ default=None,
+ help="Usage range end date, ex 2012-01-20 (default: tomorrow)."
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ self.log.debug("take_action(%s)", parsed_args)
+
+ identity_client = self.app.client_manager.identity
+ compute_client = self.app.client_manager.compute
+ dateformat = "%Y-%m-%d"
+ now = datetime.datetime.utcnow()
+
+ if parsed_args.start:
+ start = datetime.datetime.strptime(parsed_args.start, dateformat)
+ else:
+ start = now - datetime.timedelta(weeks=4)
+
+ if parsed_args.end:
+ end = datetime.datetime.strptime(parsed_args.end, dateformat)
+ else:
+ end = now + datetime.timedelta(days=1)
+
+ if parsed_args.project:
+ project = utils.find_resource(
+ identity_client.projects,
+ parsed_args.project,
+ ).id
+ else:
+ # Get the project from the current auth
+ project = self.app.client_manager.auth_ref.project_id
+
+ usage = compute_client.usage.get(project, start, end)
+
+ if parsed_args.formatter == 'table':
+ sys.stdout.write("Usage from %s to %s on project %s: \n" % (
+ start.strftime(dateformat),
+ end.strftime(dateformat),
+ project
+ ))
+
+ info = {}
+ info['Servers'] = len(usage.server_usages)
+ info['RAM MB-Hours'] = float("%.2f" % usage.total_memory_mb_usage)
+ info['CPU Hours'] = float("%.2f" % usage.total_vcpus_usage)
+ info['Disk GB-Hours'] = float("%.2f" % usage.total_local_gb_usage)
+ return zip(*sorted(six.iteritems(info)))
diff --git a/openstackclient/identity/v2_0/project.py b/openstackclient/identity/v2_0/project.py
index b2f99425..9b195600 100644
--- a/openstackclient/identity/v2_0/project.py
+++ b/openstackclient/identity/v2_0/project.py
@@ -21,7 +21,7 @@ import six
from cliff import command
from cliff import lister
from cliff import show
-from keystoneclient.openstack.common.apiclient import exceptions as ksc_exc
+from keystoneclient import exceptions as ksc_exc
from openstackclient.common import parseractions
from openstackclient.common import utils
@@ -104,16 +104,17 @@ class CreateProject(show.ShowOne):
class DeleteProject(command.Command):
- """Delete an existing project"""
+ """Delete project(s)"""
log = logging.getLogger(__name__ + '.DeleteProject')
def get_parser(self, prog_name):
parser = super(DeleteProject, self).get_parser(prog_name)
parser.add_argument(
- 'project',
+ 'projects',
metavar='<project>',
- help=_('Project to delete (name or ID)'),
+ nargs="+",
+ help=_('Project(s) to delete (name or ID)'),
)
return parser
@@ -121,12 +122,12 @@ class DeleteProject(command.Command):
self.log.debug('take_action(%s)', parsed_args)
identity_client = self.app.client_manager.identity
- project = utils.find_resource(
- identity_client.tenants,
- parsed_args.project,
- )
-
- identity_client.tenants.delete(project.id)
+ for project in parsed_args.projects:
+ project_obj = utils.find_resource(
+ identity_client.tenants,
+ project,
+ )
+ identity_client.tenants.delete(project_obj.id)
return
diff --git a/openstackclient/identity/v2_0/role.py b/openstackclient/identity/v2_0/role.py
index cec95095..d03664e0 100644
--- a/openstackclient/identity/v2_0/role.py
+++ b/openstackclient/identity/v2_0/role.py
@@ -21,7 +21,7 @@ import six
from cliff import command
from cliff import lister
from cliff import show
-from keystoneclient.openstack.common.apiclient import exceptions as ksc_exc
+from keystoneclient import exceptions as ksc_exc
from openstackclient.common import exceptions
from openstackclient.common import utils
@@ -114,16 +114,17 @@ class CreateRole(show.ShowOne):
class DeleteRole(command.Command):
- """Delete an existing role"""
+ """Delete role(s)"""
log = logging.getLogger(__name__ + '.DeleteRole')
def get_parser(self, prog_name):
parser = super(DeleteRole, self).get_parser(prog_name)
parser.add_argument(
- 'role',
+ 'roles',
metavar='<role>',
- help=_('Role to delete (name or ID)'),
+ nargs="+",
+ help=_('Role(s) to delete (name or ID)'),
)
return parser
@@ -131,12 +132,12 @@ class DeleteRole(command.Command):
self.log.debug('take_action(%s)', parsed_args)
identity_client = self.app.client_manager.identity
- role = utils.find_resource(
- identity_client.roles,
- parsed_args.role,
- )
-
- identity_client.roles.delete(role.id)
+ for role in parsed_args.roles:
+ role_obj = utils.find_resource(
+ identity_client.roles,
+ role,
+ )
+ identity_client.roles.delete(role_obj.id)
return
diff --git a/openstackclient/identity/v2_0/user.py b/openstackclient/identity/v2_0/user.py
index 955e19e7..b5bbce3b 100644
--- a/openstackclient/identity/v2_0/user.py
+++ b/openstackclient/identity/v2_0/user.py
@@ -21,7 +21,7 @@ import six
from cliff import command
from cliff import lister
from cliff import show
-from keystoneclient.openstack.common.apiclient import exceptions as ksc_exc
+from keystoneclient import exceptions as ksc_exc
from openstackclient.common import utils
from openstackclient.i18n import _ # noqa
@@ -128,16 +128,17 @@ class CreateUser(show.ShowOne):
class DeleteUser(command.Command):
- """Delete user"""
+ """Delete user(s)"""
log = logging.getLogger(__name__ + '.DeleteUser')
def get_parser(self, prog_name):
parser = super(DeleteUser, self).get_parser(prog_name)
parser.add_argument(
- 'user',
+ 'users',
metavar='<user>',
- help=_('User to delete (name or ID)'),
+ nargs="+",
+ help=_('User(s) to delete (name or ID)'),
)
return parser
@@ -145,12 +146,12 @@ class DeleteUser(command.Command):
self.log.debug('take_action(%s)', parsed_args)
identity_client = self.app.client_manager.identity
- user = utils.find_resource(
- identity_client.users,
- parsed_args.user,
- )
-
- identity_client.users.delete(user.id)
+ for user in parsed_args.users:
+ user_obj = utils.find_resource(
+ identity_client.users,
+ user,
+ )
+ identity_client.users.delete(user_obj.id)
return
diff --git a/openstackclient/identity/v3/domain.py b/openstackclient/identity/v3/domain.py
index 1233fea5..189f0970 100644
--- a/openstackclient/identity/v3/domain.py
+++ b/openstackclient/identity/v3/domain.py
@@ -22,14 +22,14 @@ import sys
from cliff import command
from cliff import lister
from cliff import show
-from keystoneclient.openstack.common.apiclient import exceptions as ksc_exc
+from keystoneclient import exceptions as ksc_exc
from openstackclient.common import utils
from openstackclient.i18n import _ # noqa
class CreateDomain(show.ShowOne):
- """Create domain command"""
+ """Create new domain"""
log = logging.getLogger(__name__ + '.CreateDomain')
@@ -42,21 +42,20 @@ class CreateDomain(show.ShowOne):
)
parser.add_argument(
'--description',
- metavar='<domain-description>',
+ metavar='<description>',
help='New domain description',
)
enable_group = parser.add_mutually_exclusive_group()
enable_group.add_argument(
'--enable',
- dest='enabled',
action='store_true',
- default=True,
- help='Enable domain')
+ help='Enable domain (default)',
+ )
enable_group.add_argument(
'--disable',
- dest='enabled',
- action='store_false',
- help='Disable domain')
+ action='store_true',
+ help='Disable domain',
+ )
parser.add_argument(
'--or-show',
action='store_true',
@@ -68,11 +67,15 @@ class CreateDomain(show.ShowOne):
self.log.debug('take_action(%s)', parsed_args)
identity_client = self.app.client_manager.identity
+ enabled = True
+ if parsed_args.disable:
+ enabled = False
+
try:
domain = identity_client.domains.create(
name=parsed_args.name,
description=parsed_args.description,
- enabled=parsed_args.enabled,
+ enabled=enabled,
)
except ksc_exc.Conflict as e:
if parsed_args.or_show:
@@ -87,7 +90,7 @@ class CreateDomain(show.ShowOne):
class DeleteDomain(command.Command):
- """Delete domain command"""
+ """Delete domain"""
log = logging.getLogger(__name__ + '.DeleteDomain')
@@ -96,7 +99,7 @@ class DeleteDomain(command.Command):
parser.add_argument(
'domain',
metavar='<domain>',
- help='Name or ID of domain to delete',
+ help='Domain to delete (name or ID)',
)
return parser
@@ -110,7 +113,7 @@ class DeleteDomain(command.Command):
class ListDomain(lister.Lister):
- """List domain command"""
+ """List domains"""
log = logging.getLogger(__name__ + '.ListDomain')
@@ -126,7 +129,7 @@ class ListDomain(lister.Lister):
class SetDomain(command.Command):
- """Set domain command"""
+ """Set domain properties"""
log = logging.getLogger(__name__ + '.SetDomain')
@@ -135,28 +138,26 @@ class SetDomain(command.Command):
parser.add_argument(
'domain',
metavar='<domain>',
- help='Name or ID of domain to change',
+ help='Domain to modify (name or ID)',
)
parser.add_argument(
'--name',
- metavar='<new-domain-name>',
+ metavar='<name>',
help='New domain name',
)
parser.add_argument(
'--description',
- metavar='<domain-description>',
+ metavar='<description>',
help='New domain description',
)
enable_group = parser.add_mutually_exclusive_group()
enable_group.add_argument(
'--enable',
- dest='enabled',
action='store_true',
- help='Enable domain (default)',
+ help='Enable domain',
)
enable_group.add_argument(
'--disable',
- dest='disabled',
action='store_true',
help='Disable domain',
)
@@ -172,9 +173,10 @@ class SetDomain(command.Command):
kwargs['name'] = parsed_args.name
if parsed_args.description:
kwargs['description'] = parsed_args.description
- if parsed_args.enabled:
+
+ if parsed_args.enable:
kwargs['enabled'] = True
- if parsed_args.disabled:
+ if parsed_args.disable:
kwargs['enabled'] = False
if not kwargs:
@@ -185,7 +187,7 @@ class SetDomain(command.Command):
class ShowDomain(show.ShowOne):
- """Show domain command"""
+ """Show domain details"""
log = logging.getLogger(__name__ + '.ShowDomain')
@@ -194,7 +196,7 @@ class ShowDomain(show.ShowOne):
parser.add_argument(
'domain',
metavar='<domain>',
- help='Name or ID of domain to display',
+ help='Domain to display (name or ID)',
)
return parser
diff --git a/openstackclient/identity/v3/group.py b/openstackclient/identity/v3/group.py
index 5d3cf642..fbd8dd72 100644
--- a/openstackclient/identity/v3/group.py
+++ b/openstackclient/identity/v3/group.py
@@ -22,7 +22,7 @@ import sys
from cliff import command
from cliff import lister
from cliff import show
-from keystoneclient.openstack.common.apiclient import exceptions as ksc_exc
+from keystoneclient import exceptions as ksc_exc
from openstackclient.common import utils
from openstackclient.i18n import _ # noqa
@@ -39,12 +39,12 @@ class AddUserToGroup(command.Command):
parser.add_argument(
'group',
metavar='<group>',
- help='Group name or ID that user will be added to',
+ help='Group that user will be added to (name or ID)',
)
parser.add_argument(
'user',
metavar='<user>',
- help='User name or ID to add to group',
+ help='User to add to group (name or ID)',
)
return parser
@@ -68,7 +68,7 @@ class AddUserToGroup(command.Command):
class CheckUserInGroup(command.Command):
- """Checks that user is in a specific group"""
+ """Check user in group"""
log = logging.getLogger(__name__ + '.CheckUserInGroup')
@@ -77,12 +77,12 @@ class CheckUserInGroup(command.Command):
parser.add_argument(
'group',
metavar='<group>',
- help='Group name or ID that user will be added to',
+ help='Group to check if user belongs to (name or ID)',
)
parser.add_argument(
'user',
metavar='<user>',
- help='User name or ID to add to group',
+ help='User to check (name or ID)',
)
return parser
@@ -106,7 +106,7 @@ class CheckUserInGroup(command.Command):
class CreateGroup(show.ShowOne):
- """Create group command"""
+ """Create new group"""
log = logging.getLogger(__name__ + '.CreateGroup')
@@ -118,11 +118,11 @@ class CreateGroup(show.ShowOne):
help='New group name')
parser.add_argument(
'--description',
- metavar='<group-description>',
+ metavar='<description>',
help='New group description')
parser.add_argument(
'--domain',
- metavar='<group-domain>',
+ metavar='<domain>',
help='References the domain ID or name which owns the group')
parser.add_argument(
'--or-show',
@@ -159,16 +159,17 @@ class CreateGroup(show.ShowOne):
class DeleteGroup(command.Command):
- """Delete group command"""
+ """Delete group(s)"""
log = logging.getLogger(__name__ + '.DeleteGroup')
def get_parser(self, prog_name):
parser = super(DeleteGroup, self).get_parser(prog_name)
parser.add_argument(
- 'group',
+ 'groups',
metavar='<group>',
- help='Name or ID of group to delete')
+ nargs="+",
+ help='Group(s) to delete (name or ID)')
parser.add_argument(
'--domain',
metavar='<domain>',
@@ -180,16 +181,18 @@ class DeleteGroup(command.Command):
self.log.debug('take_action(%s)', parsed_args)
identity_client = self.app.client_manager.identity
+ domain = None
if parsed_args.domain:
domain = common.find_domain(identity_client, parsed_args.domain)
- group = utils.find_resource(identity_client.groups,
- parsed_args.group,
- domain_id=domain.id)
- else:
- group = utils.find_resource(identity_client.groups,
- parsed_args.group)
-
- identity_client.groups.delete(group.id)
+ for group in parsed_args.groups:
+ if domain is not None:
+ group_obj = utils.find_resource(identity_client.groups,
+ group,
+ domain_id=domain.id)
+ else:
+ group_obj = utils.find_resource(identity_client.groups,
+ group)
+ identity_client.groups.delete(group_obj.id)
return
@@ -265,12 +268,12 @@ class RemoveUserFromGroup(command.Command):
parser.add_argument(
'group',
metavar='<group>',
- help='Group name or ID that user will be removed from',
+ help='Group that user will be removed from (name or ID)',
)
parser.add_argument(
'user',
metavar='<user>',
- help='User name or ID to remove from group',
+ help='User to remove from group (name or ID)',
)
return parser
@@ -294,7 +297,7 @@ class RemoveUserFromGroup(command.Command):
class SetGroup(command.Command):
- """Set group command"""
+ """Set group properties"""
log = logging.getLogger(__name__ + '.SetGroup')
@@ -303,18 +306,18 @@ class SetGroup(command.Command):
parser.add_argument(
'group',
metavar='<group>',
- help='Name or ID of group to change')
+ help='Group to modify (name or ID)')
parser.add_argument(
'--name',
- metavar='<new-group-name>',
+ metavar='<name>',
help='New group name')
parser.add_argument(
'--domain',
- metavar='<group-domain>',
- help='New domain name or ID that will now own the group')
+ metavar='<domain>',
+ help='New domain that will now own the group (name or ID)')
parser.add_argument(
'--description',
- metavar='<group-description>',
+ metavar='<description>',
help='New group description')
return parser
@@ -338,7 +341,7 @@ class SetGroup(command.Command):
class ShowGroup(show.ShowOne):
- """Show group command"""
+ """Show group details"""
log = logging.getLogger(__name__ + '.ShowGroup')
@@ -347,7 +350,7 @@ class ShowGroup(show.ShowOne):
parser.add_argument(
'group',
metavar='<group>',
- help='Name or ID of group to display',
+ help='Group to display (name or ID)',
)
parser.add_argument(
'--domain',
diff --git a/openstackclient/identity/v3/project.py b/openstackclient/identity/v3/project.py
index 2c2d408e..28eb4277 100644
--- a/openstackclient/identity/v3/project.py
+++ b/openstackclient/identity/v3/project.py
@@ -21,7 +21,7 @@ import six
from cliff import command
from cliff import lister
from cliff import show
-from keystoneclient.openstack.common.apiclient import exceptions as ksc_exc
+from keystoneclient import exceptions as ksc_exc
from openstackclient.common import parseractions
from openstackclient.common import utils
@@ -117,16 +117,17 @@ class CreateProject(show.ShowOne):
class DeleteProject(command.Command):
- """Delete an existing project"""
+ """Delete project(s)"""
log = logging.getLogger(__name__ + '.DeleteProject')
def get_parser(self, prog_name):
parser = super(DeleteProject, self).get_parser(prog_name)
parser.add_argument(
- 'project',
+ 'projects',
metavar='<project>',
- help='Project to delete (name or ID)',
+ nargs="+",
+ help='Project(s) to delete (name or ID)',
)
parser.add_argument(
'--domain',
@@ -139,16 +140,18 @@ class DeleteProject(command.Command):
self.log.debug('take_action(%s)', parsed_args)
identity_client = self.app.client_manager.identity
+ domain = None
if parsed_args.domain:
domain = common.find_domain(identity_client, parsed_args.domain)
- project = utils.find_resource(identity_client.projects,
- parsed_args.project,
- domain_id=domain.id)
- else:
- project = utils.find_resource(identity_client.projects,
- parsed_args.project)
-
- identity_client.projects.delete(project.id)
+ for project in parsed_args.projects:
+ if domain is not None:
+ project_obj = utils.find_resource(identity_client.projects,
+ project,
+ domain_id=domain.id)
+ else:
+ project_obj = utils.find_resource(identity_client.projects,
+ project)
+ identity_client.projects.delete(project_obj.id)
return
diff --git a/openstackclient/identity/v3/region.py b/openstackclient/identity/v3/region.py
index cce3417d..5fb73913 100644
--- a/openstackclient/identity/v3/region.py
+++ b/openstackclient/identity/v3/region.py
@@ -35,22 +35,22 @@ class CreateRegion(show.ShowOne):
# seems like poor UX, we will only support user-defined IDs.
parser.add_argument(
'region',
- metavar='<region>',
- help=_('New region'),
+ metavar='<region-id>',
+ help=_('New region ID'),
)
parser.add_argument(
'--parent-region',
- metavar='<parent-region>',
- help=_('The parent region of new region'),
+ metavar='<region-id>',
+ help=_('Parent region ID'),
)
parser.add_argument(
'--description',
- metavar='<region-description>',
+ metavar='<description>',
help=_('New region description'),
)
parser.add_argument(
'--url',
- metavar='<region-url>',
+ metavar='<url>',
help=_('New region url'),
)
@@ -82,8 +82,8 @@ class DeleteRegion(command.Command):
parser = super(DeleteRegion, self).get_parser(prog_name)
parser.add_argument(
'region',
- metavar='<region>',
- help=_('Region to delete'),
+ metavar='<region-id>',
+ help=_('Region ID to delete'),
)
return parser
@@ -104,8 +104,8 @@ class ListRegion(lister.Lister):
parser = super(ListRegion, self).get_parser(prog_name)
parser.add_argument(
'--parent-region',
- metavar='<parent-region>',
- help=_('Filter by parent region'),
+ metavar='<region-id>',
+ help=_('Filter by parent region ID'),
)
return parser
@@ -137,22 +137,22 @@ class SetRegion(command.Command):
parser = super(SetRegion, self).get_parser(prog_name)
parser.add_argument(
'region',
- metavar='<region>',
- help=_('Region to change'),
+ metavar='<region-id>',
+ help=_('Region ID to modify'),
)
parser.add_argument(
'--parent-region',
- metavar='<parent-region>',
- help=_('New parent region of the region'),
+ metavar='<region-id>',
+ help=_('New parent region ID'),
)
parser.add_argument(
'--description',
- metavar='<region-description>',
+ metavar='<description>',
help=_('New region description'),
)
parser.add_argument(
'--url',
- metavar='<region-url>',
+ metavar='<url>',
help=_('New region url'),
)
return parser
@@ -179,7 +179,7 @@ class SetRegion(command.Command):
class ShowRegion(show.ShowOne):
- """Show region"""
+ """Display region details"""
log = logging.getLogger(__name__ + '.ShowRegion')
@@ -187,8 +187,8 @@ class ShowRegion(show.ShowOne):
parser = super(ShowRegion, self).get_parser(prog_name)
parser.add_argument(
'region',
- metavar='<region>',
- help=_('Region to display'),
+ metavar='<region-id>',
+ help=_('Region ID to display'),
)
return parser
diff --git a/openstackclient/identity/v3/role.py b/openstackclient/identity/v3/role.py
index 017ffd76..d680278e 100644
--- a/openstackclient/identity/v3/role.py
+++ b/openstackclient/identity/v3/role.py
@@ -22,7 +22,7 @@ import sys
from cliff import command
from cliff import lister
from cliff import show
-from keystoneclient.openstack.common.apiclient import exceptions as ksc_exc
+from keystoneclient import exceptions as ksc_exc
from openstackclient.common import utils
from openstackclient.i18n import _ # noqa
@@ -177,16 +177,17 @@ class CreateRole(show.ShowOne):
class DeleteRole(command.Command):
- """Delete an existing role"""
+ """Delete role(s)"""
log = logging.getLogger(__name__ + '.DeleteRole')
def get_parser(self, prog_name):
parser = super(DeleteRole, self).get_parser(prog_name)
parser.add_argument(
- 'role',
+ 'roles',
metavar='<role>',
- help='Role to delete (name or ID)',
+ nargs="+",
+ help='Role(s) to delete (name or ID)',
)
return parser
@@ -194,12 +195,12 @@ class DeleteRole(command.Command):
self.log.debug('take_action(%s)', parsed_args)
identity_client = self.app.client_manager.identity
- role = utils.find_resource(
- identity_client.roles,
- parsed_args.role,
- )
-
- identity_client.roles.delete(role.id)
+ for role in parsed_args.roles:
+ role_obj = utils.find_resource(
+ identity_client.roles,
+ role,
+ )
+ identity_client.roles.delete(role_obj.id)
return
diff --git a/openstackclient/identity/v3/role_assignment.py b/openstackclient/identity/v3/role_assignment.py
index 5cc97e8d..f053b608 100644
--- a/openstackclient/identity/v3/role_assignment.py
+++ b/openstackclient/identity/v3/role_assignment.py
@@ -21,7 +21,7 @@ from openstackclient.common import utils
class ListRoleAssignment(lister.Lister):
- """Lists role assignments according to the given filters"""
+ """List role assignments"""
log = logging.getLogger(__name__ + '.ListRoleAssignment')
@@ -36,29 +36,29 @@ class ListRoleAssignment(lister.Lister):
parser.add_argument(
'--role',
metavar='<role>',
- help='Name or ID of role to filter',
+ help='Role to filter (name or ID)',
)
user_or_group = parser.add_mutually_exclusive_group()
user_or_group.add_argument(
'--user',
metavar='<user>',
- help='Name or ID of user to filter',
+ help='User to filter (name or ID)',
)
user_or_group.add_argument(
'--group',
metavar='<group>',
- help='Name or ID of group to filter',
+ help='Group to filter (name or ID)',
)
domain_or_project = parser.add_mutually_exclusive_group()
domain_or_project.add_argument(
'--domain',
metavar='<domain>',
- help='Name or ID of domain to filter',
+ help='Domain to filter (name or ID)',
)
domain_or_project.add_argument(
'--project',
metavar='<project>',
- help='Name or ID of project to filter',
+ help='Project to filter (name or ID)',
)
return parser
diff --git a/openstackclient/identity/v3/service.py b/openstackclient/identity/v3/service.py
index 4f622269..f4c5d426 100644
--- a/openstackclient/identity/v3/service.py
+++ b/openstackclient/identity/v3/service.py
@@ -43,6 +43,11 @@ class CreateService(show.ShowOne):
metavar='<service-name>',
help='New service name',
)
+ parser.add_argument(
+ '--description',
+ metavar='<description>',
+ help='New service description',
+ )
enable_group = parser.add_mutually_exclusive_group()
enable_group.add_argument(
'--enable',
@@ -67,6 +72,7 @@ class CreateService(show.ShowOne):
service = identity_client.services.create(
name=parsed_args.name,
type=parsed_args.type,
+ description=parsed_args.description,
enabled=enabled,
)
@@ -137,6 +143,11 @@ class SetService(command.Command):
metavar='<service-name>',
help='New service name',
)
+ parser.add_argument(
+ '--description',
+ metavar='<description>',
+ help='New service description',
+ )
enable_group = parser.add_mutually_exclusive_group()
enable_group.add_argument(
'--enable',
@@ -156,6 +167,7 @@ class SetService(command.Command):
if (not parsed_args.name
and not parsed_args.type
+ and not parsed_args.description
and not parsed_args.enable
and not parsed_args.disable):
return
@@ -167,6 +179,8 @@ class SetService(command.Command):
kwargs['type'] = parsed_args.type
if parsed_args.name:
kwargs['name'] = parsed_args.name
+ if parsed_args.description:
+ kwargs['description'] = parsed_args.description
if parsed_args.enable:
kwargs['enabled'] = True
if parsed_args.disable:
diff --git a/openstackclient/identity/v3/user.py b/openstackclient/identity/v3/user.py
index d7ccff53..a60c8c83 100644
--- a/openstackclient/identity/v3/user.py
+++ b/openstackclient/identity/v3/user.py
@@ -22,7 +22,7 @@ import six
from cliff import command
from cliff import lister
from cliff import show
-from keystoneclient.openstack.common.apiclient import exceptions as ksc_exc
+from keystoneclient import exceptions as ksc_exc
from openstackclient.common import utils
from openstackclient.i18n import _ # noqa
@@ -138,16 +138,17 @@ class CreateUser(show.ShowOne):
class DeleteUser(command.Command):
- """Delete user"""
+ """Delete user(s)"""
log = logging.getLogger(__name__ + '.DeleteUser')
def get_parser(self, prog_name):
parser = super(DeleteUser, self).get_parser(prog_name)
parser.add_argument(
- 'user',
+ 'users',
metavar='<user>',
- help='User to delete (name or ID)',
+ nargs="+",
+ help='User(s) to delete (name or ID)',
)
parser.add_argument(
'--domain',
@@ -160,16 +161,18 @@ class DeleteUser(command.Command):
self.log.debug('take_action(%s)', parsed_args)
identity_client = self.app.client_manager.identity
+ domain = None
if parsed_args.domain:
domain = common.find_domain(identity_client, parsed_args.domain)
- user = utils.find_resource(identity_client.users,
- parsed_args.user,
- domain_id=domain.id)
- else:
- user = utils.find_resource(identity_client.users,
- parsed_args.user)
-
- identity_client.users.delete(user.id)
+ for user in parsed_args.users:
+ if domain is not None:
+ user_obj = utils.find_resource(identity_client.users,
+ user,
+ domain_id=domain.id)
+ else:
+ user_obj = utils.find_resource(identity_client.users,
+ user)
+ identity_client.users.delete(user_obj.id)
return
diff --git a/openstackclient/image/v1/image.py b/openstackclient/image/v1/image.py
index 32dd388c..ca1eead4 100644
--- a/openstackclient/image/v1/image.py
+++ b/openstackclient/image/v1/image.py
@@ -262,16 +262,17 @@ class CreateImage(show.ShowOne):
class DeleteImage(command.Command):
- """Delete an image"""
+ """Delete image(s)"""
log = logging.getLogger(__name__ + ".DeleteImage")
def get_parser(self, prog_name):
parser = super(DeleteImage, self).get_parser(prog_name)
parser.add_argument(
- "image",
+ "images",
metavar="<image>",
- help="Name or ID of image to delete",
+ nargs="+",
+ help="Image(s) to delete (name or ID)",
)
return parser
@@ -279,11 +280,12 @@ class DeleteImage(command.Command):
self.log.debug("take_action(%s)", parsed_args)
image_client = self.app.client_manager.image
- image = utils.find_resource(
- image_client.images,
- parsed_args.image,
- )
- image_client.images.delete(image.id)
+ for image in parsed_args.images:
+ image_obj = utils.find_resource(
+ image_client.images,
+ image,
+ )
+ image_client.images.delete(image_obj.id)
class ListImage(lister.Lister):
diff --git a/openstackclient/image/v2/image.py b/openstackclient/image/v2/image.py
index c12ff11a..63351c6d 100644
--- a/openstackclient/image/v2/image.py
+++ b/openstackclient/image/v2/image.py
@@ -27,16 +27,17 @@ from openstackclient.common import utils
class DeleteImage(command.Command):
- """Delete an image"""
+ """Delete image(s)"""
log = logging.getLogger(__name__ + ".DeleteImage")
def get_parser(self, prog_name):
parser = super(DeleteImage, self).get_parser(prog_name)
parser.add_argument(
- "image",
+ "images",
metavar="<image>",
- help="Name or ID of image to delete",
+ nargs="+",
+ help="Image(s) to delete (name or ID)",
)
return parser
@@ -44,11 +45,12 @@ class DeleteImage(command.Command):
self.log.debug("take_action(%s)", parsed_args)
image_client = self.app.client_manager.image
- image = utils.find_resource(
- image_client.images,
- parsed_args.image,
- )
- image_client.images.delete(image.id)
+ for image in parsed_args.images:
+ image_obj = utils.find_resource(
+ image_client.images,
+ image,
+ )
+ image_client.images.delete(image_obj.id)
class ListImage(lister.Lister):
diff --git a/openstackclient/network/v2/network.py b/openstackclient/network/v2/network.py
index f34666ba..0d68f82d 100644
--- a/openstackclient/network/v2/network.py
+++ b/openstackclient/network/v2/network.py
@@ -86,26 +86,27 @@ class CreateNetwork(show.ShowOne):
class DeleteNetwork(command.Command):
- """Delete a network"""
+ """Delete network(s)"""
log = logging.getLogger(__name__ + '.DeleteNetwork')
def get_parser(self, prog_name):
parser = super(DeleteNetwork, self).get_parser(prog_name)
parser.add_argument(
- 'identifier',
+ 'networks',
metavar="<network>",
- help=("Name or identifier of network to delete")
+ nargs="+",
+ help=("Network(s) to delete (name or ID)")
)
return parser
def take_action(self, parsed_args):
self.log.debug('take_action(%s)' % parsed_args)
client = self.app.client_manager.network
- _id = common.find(client, 'network', 'networks',
- parsed_args.identifier)
delete_method = getattr(client, "delete_network")
- delete_method(_id)
+ for network in parsed_args.networks:
+ _id = common.find(client, 'network', 'networks', network)
+ delete_method(_id)
return
diff --git a/openstackclient/object/v1/container.py b/openstackclient/object/v1/container.py
index ead3df45..b75888e4 100644
--- a/openstackclient/object/v1/container.py
+++ b/openstackclient/object/v1/container.py
@@ -27,7 +27,7 @@ from openstackclient.common import utils
class CreateContainer(lister.Lister):
- """Create a container"""
+ """Create new container"""
log = logging.getLogger(__name__ + '.CreateContainer')
@@ -35,9 +35,9 @@ class CreateContainer(lister.Lister):
parser = super(CreateContainer, self).get_parser(prog_name)
parser.add_argument(
'containers',
- metavar='<container>',
+ metavar='<container-name>',
nargs="+",
- help='Container name(s) to create',
+ help='New container name(s)',
)
return parser
@@ -60,7 +60,7 @@ class CreateContainer(lister.Lister):
class DeleteContainer(command.Command):
- """Delete a container"""
+ """Delete container"""
log = logging.getLogger(__name__ + '.DeleteContainer')
@@ -70,7 +70,7 @@ class DeleteContainer(command.Command):
'containers',
metavar='<container>',
nargs="+",
- help='Container name(s) to delete',
+ help='Container(s) to delete',
)
return parser
@@ -157,7 +157,7 @@ class ListContainer(lister.Lister):
class SaveContainer(command.Command):
- """Save the contents of a container locally"""
+ """Save container contents locally"""
log = logging.getLogger(__name__ + ".SaveContainer")
@@ -166,7 +166,7 @@ class SaveContainer(command.Command):
parser.add_argument(
'container',
metavar='<container>',
- help='Container name to save',
+ help='Container to save',
)
return parser
@@ -179,7 +179,7 @@ class SaveContainer(command.Command):
class ShowContainer(show.ShowOne):
- """Show container information"""
+ """Show container details"""
log = logging.getLogger(__name__ + '.ShowContainer')
@@ -188,7 +188,7 @@ class ShowContainer(show.ShowOne):
parser.add_argument(
'container',
metavar='<container>',
- help='Container name to display',
+ help='Container to display',
)
return parser
diff --git a/openstackclient/object/v1/object.py b/openstackclient/object/v1/object.py
index cbe9da2f..781dd047 100644
--- a/openstackclient/object/v1/object.py
+++ b/openstackclient/object/v1/object.py
@@ -27,7 +27,7 @@ from openstackclient.common import utils
class CreateObject(lister.Lister):
- """Upload an object to a container"""
+ """Upload object to container"""
log = logging.getLogger(__name__ + '.CreateObject')
@@ -36,13 +36,13 @@ class CreateObject(lister.Lister):
parser.add_argument(
'container',
metavar='<container>',
- help='Container to store new object',
+ help='Container for new object',
)
parser.add_argument(
'objects',
- metavar='<object-name>',
+ metavar='<filename>',
nargs="+",
- help='Local path of object(s) to upload',
+ help='Local filename(s) to upload',
)
return parser
@@ -66,7 +66,7 @@ class CreateObject(lister.Lister):
class DeleteObject(command.Command):
- """Delete an object within a container"""
+ """Delete object from container"""
log = logging.getLogger(__name__ + '.DeleteObject')
@@ -75,11 +75,11 @@ class DeleteObject(command.Command):
parser.add_argument(
'container',
metavar='<container>',
- help='Container that stores the object to delete',
+ help='Delete object(s) from <container>',
)
parser.add_argument(
'objects',
- metavar='<object-name>',
+ metavar='<object>',
nargs="+",
help='Object(s) to delete',
)
@@ -104,8 +104,8 @@ class ListObject(lister.Lister):
parser = super(ListObject, self).get_parser(prog_name)
parser.add_argument(
"container",
- metavar="<container-name>",
- help="List contents of container-name",
+ metavar="<container>",
+ help="Container to list",
)
parser.add_argument(
"--prefix",
@@ -188,7 +188,7 @@ class ListObject(lister.Lister):
class SaveObject(command.Command):
- """Save an object locally"""
+ """Save object locally"""
log = logging.getLogger(__name__ + ".SaveObject")
@@ -197,17 +197,17 @@ class SaveObject(command.Command):
parser.add_argument(
"--file",
metavar="<filename>",
- help="Downloaded object filename [defaults to object name]",
+ help="Destination filename (defaults to object name)",
)
parser.add_argument(
'container',
metavar='<container>',
- help='Container name that has the object',
+ help='Download <object> from <container>',
)
parser.add_argument(
"object",
metavar="<object>",
- help="Name of the object to save",
+ help="Object to save",
)
return parser
@@ -222,7 +222,7 @@ class SaveObject(command.Command):
class ShowObject(show.ShowOne):
- """Show object information"""
+ """Show object details"""
log = logging.getLogger(__name__ + '.ShowObject')
@@ -231,12 +231,12 @@ class ShowObject(show.ShowOne):
parser.add_argument(
'container',
metavar='<container>',
- help='Container name for object to display',
+ help='Display <object> from <container>',
)
parser.add_argument(
'object',
metavar='<object>',
- help='Object name to display',
+ help='Object to display',
)
return parser
diff --git a/openstackclient/tests/compute/v2/test_server.py b/openstackclient/tests/compute/v2/test_server.py
index 19c13440..d51beef3 100644
--- a/openstackclient/tests/compute/v2/test_server.py
+++ b/openstackclient/tests/compute/v2/test_server.py
@@ -232,7 +232,7 @@ class TestServerDelete(TestServer):
compute_fakes.server_id,
]
verifylist = [
- ('server', compute_fakes.server_id),
+ ('servers', [compute_fakes.server_id]),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
diff --git a/openstackclient/tests/identity/v2_0/test_project.py b/openstackclient/tests/identity/v2_0/test_project.py
index 833b5d84..0c5ef77f 100644
--- a/openstackclient/tests/identity/v2_0/test_project.py
+++ b/openstackclient/tests/identity/v2_0/test_project.py
@@ -15,7 +15,7 @@
import copy
-from keystoneclient.openstack.common.apiclient import exceptions as ksc_exc
+from keystoneclient import exceptions as ksc_exc
from openstackclient.identity.v2_0 import project
from openstackclient.tests import fakes
@@ -326,7 +326,7 @@ class TestProjectDelete(TestProject):
identity_fakes.project_id,
]
verifylist = [
- ('project', identity_fakes.project_id),
+ ('projects', [identity_fakes.project_id]),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
diff --git a/openstackclient/tests/identity/v2_0/test_role.py b/openstackclient/tests/identity/v2_0/test_role.py
index 67467747..2e3a2863 100644
--- a/openstackclient/tests/identity/v2_0/test_role.py
+++ b/openstackclient/tests/identity/v2_0/test_role.py
@@ -16,7 +16,7 @@
import copy
import mock
-from keystoneclient.openstack.common.apiclient import exceptions as ksc_exc
+from keystoneclient import exceptions as ksc_exc
from openstackclient.common import exceptions
from openstackclient.identity.v2_0 import role
@@ -234,7 +234,7 @@ class TestRoleDelete(TestRole):
identity_fakes.role_name,
]
verifylist = [
- ('role', identity_fakes.role_name),
+ ('roles', [identity_fakes.role_name]),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
diff --git a/openstackclient/tests/identity/v2_0/test_user.py b/openstackclient/tests/identity/v2_0/test_user.py
index a025dd7d..ccdf240e 100644
--- a/openstackclient/tests/identity/v2_0/test_user.py
+++ b/openstackclient/tests/identity/v2_0/test_user.py
@@ -16,7 +16,7 @@
import copy
import mock
-from keystoneclient.openstack.common.apiclient import exceptions as ksc_exc
+from keystoneclient import exceptions as ksc_exc
from openstackclient.identity.v2_0 import user
from openstackclient.tests import fakes
from openstackclient.tests.identity.v2_0 import fakes as identity_fakes
@@ -443,7 +443,7 @@ class TestUserDelete(TestUser):
identity_fakes.user_id,
]
verifylist = [
- ('user', identity_fakes.user_id),
+ ('users', [identity_fakes.user_id]),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
diff --git a/openstackclient/tests/identity/v3/fakes.py b/openstackclient/tests/identity/v3/fakes.py
index 88716e97..3afb0cd9 100644
--- a/openstackclient/tests/identity/v3/fakes.py
+++ b/openstackclient/tests/identity/v3/fakes.py
@@ -147,11 +147,13 @@ ROLE = {
service_id = 's-123'
service_name = 'Texaco'
service_type = 'gas'
+service_description = 'oil brand'
SERVICE = {
'id': service_id,
'name': service_name,
'type': service_type,
+ 'description': service_description,
'enabled': True,
'links': base_url + 'services/' + service_id,
}
diff --git a/openstackclient/tests/identity/v3/test_domain.py b/openstackclient/tests/identity/v3/test_domain.py
index 8dad5bcc..cfec10e7 100644
--- a/openstackclient/tests/identity/v3/test_domain.py
+++ b/openstackclient/tests/identity/v3/test_domain.py
@@ -46,7 +46,6 @@ class TestDomainCreate(TestDomain):
identity_fakes.domain_name,
]
verifylist = [
- ('enabled', True),
('name', identity_fakes.domain_name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -81,7 +80,6 @@ class TestDomainCreate(TestDomain):
]
verifylist = [
('description', 'new desc'),
- ('enabled', True),
('name', identity_fakes.domain_name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -115,7 +113,7 @@ class TestDomainCreate(TestDomain):
identity_fakes.domain_name,
]
verifylist = [
- ('enabled', True),
+ ('enable', True),
('name', identity_fakes.domain_name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -149,7 +147,7 @@ class TestDomainCreate(TestDomain):
identity_fakes.domain_name,
]
verifylist = [
- ('enabled', False),
+ ('disable', True),
('name', identity_fakes.domain_name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -333,7 +331,7 @@ class TestDomainSet(TestDomain):
identity_fakes.domain_id,
]
verifylist = [
- ('enabled', True),
+ ('enable', True),
('domain', identity_fakes.domain_id),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -356,7 +354,7 @@ class TestDomainSet(TestDomain):
identity_fakes.domain_id,
]
verifylist = [
- ('disabled', True),
+ ('disable', True),
('domain', identity_fakes.domain_id),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
diff --git a/openstackclient/tests/identity/v3/test_project.py b/openstackclient/tests/identity/v3/test_project.py
index 1060a277..d16f9732 100644
--- a/openstackclient/tests/identity/v3/test_project.py
+++ b/openstackclient/tests/identity/v3/test_project.py
@@ -353,7 +353,7 @@ class TestProjectDelete(TestProject):
identity_fakes.project_id,
]
verifylist = [
- ('project', identity_fakes.project_id),
+ ('projects', [identity_fakes.project_id]),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
diff --git a/openstackclient/tests/identity/v3/test_role.py b/openstackclient/tests/identity/v3/test_role.py
index 3d2a402b..1a9e6aa7 100644
--- a/openstackclient/tests/identity/v3/test_role.py
+++ b/openstackclient/tests/identity/v3/test_role.py
@@ -271,7 +271,7 @@ class TestRoleDelete(TestRole):
identity_fakes.role_name,
]
verifylist = [
- ('role', identity_fakes.role_name),
+ ('roles', [identity_fakes.role_name]),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
diff --git a/openstackclient/tests/identity/v3/test_service.py b/openstackclient/tests/identity/v3/test_service.py
index 57db77b1..5e4dc585 100644
--- a/openstackclient/tests/identity/v3/test_service.py
+++ b/openstackclient/tests/identity/v3/test_service.py
@@ -51,6 +51,7 @@ class TestServiceCreate(TestService):
]
verifylist = [
('name', identity_fakes.service_name),
+ ('description', None),
('enable', False),
('disable', False),
('type', identity_fakes.service_type),
@@ -64,12 +65,50 @@ class TestServiceCreate(TestService):
self.services_mock.create.assert_called_with(
name=identity_fakes.service_name,
type=identity_fakes.service_type,
+ description=None,
enabled=True,
)
- collist = ('enabled', 'id', 'name', 'type')
+ collist = ('description', 'enabled', 'id', 'name', 'type')
self.assertEqual(columns, collist)
datalist = (
+ identity_fakes.service_description,
+ True,
+ identity_fakes.service_id,
+ identity_fakes.service_name,
+ identity_fakes.service_type,
+ )
+ self.assertEqual(data, datalist)
+
+ def test_service_create_description(self):
+ arglist = [
+ '--description', identity_fakes.service_description,
+ identity_fakes.service_type,
+ ]
+ verifylist = [
+ ('name', None),
+ ('description', identity_fakes.service_description),
+ ('enable', False),
+ ('disable', False),
+ ('type', identity_fakes.service_type),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # DisplayCommandBase.take_action() returns two tuples
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # ServiceManager.create(name=, type=, enabled=, **kwargs)
+ self.services_mock.create.assert_called_with(
+ name=None,
+ type=identity_fakes.service_type,
+ description=identity_fakes.service_description,
+ enabled=True,
+ )
+
+ collist = ('description', 'enabled', 'id', 'name', 'type')
+ self.assertEqual(columns, collist)
+ datalist = (
+ identity_fakes.service_description,
True,
identity_fakes.service_id,
identity_fakes.service_name,
@@ -84,6 +123,7 @@ class TestServiceCreate(TestService):
]
verifylist = [
('name', None),
+ ('description', None),
('enable', True),
('disable', False),
('type', identity_fakes.service_type),
@@ -97,12 +137,14 @@ class TestServiceCreate(TestService):
self.services_mock.create.assert_called_with(
name=None,
type=identity_fakes.service_type,
+ description=None,
enabled=True,
)
- collist = ('enabled', 'id', 'name', 'type')
+ collist = ('description', 'enabled', 'id', 'name', 'type')
self.assertEqual(columns, collist)
datalist = (
+ identity_fakes.service_description,
True,
identity_fakes.service_id,
identity_fakes.service_name,
@@ -117,6 +159,7 @@ class TestServiceCreate(TestService):
]
verifylist = [
('name', None),
+ ('description', None),
('enable', False),
('disable', True),
('type', identity_fakes.service_type),
@@ -130,12 +173,14 @@ class TestServiceCreate(TestService):
self.services_mock.create.assert_called_with(
name=None,
type=identity_fakes.service_type,
+ description=None,
enabled=False,
)
- collist = ('enabled', 'id', 'name', 'type')
+ collist = ('description', 'enabled', 'id', 'name', 'type')
self.assertEqual(columns, collist)
datalist = (
+ identity_fakes.service_description,
True,
identity_fakes.service_id,
identity_fakes.service_name,
@@ -239,6 +284,7 @@ class TestServiceSet(TestService):
verifylist = [
('type', None),
('name', None),
+ ('description', None),
('enable', False),
('disable', False),
('service', identity_fakes.service_name),
@@ -256,6 +302,7 @@ class TestServiceSet(TestService):
verifylist = [
('type', identity_fakes.service_type),
('name', None),
+ ('description', None),
('enable', False),
('disable', False),
('service', identity_fakes.service_name),
@@ -283,6 +330,7 @@ class TestServiceSet(TestService):
verifylist = [
('type', None),
('name', identity_fakes.service_name),
+ ('description', None),
('enable', False),
('disable', False),
('service', identity_fakes.service_name),
@@ -302,6 +350,34 @@ class TestServiceSet(TestService):
**kwargs
)
+ def test_service_set_description(self):
+ arglist = [
+ '--description', identity_fakes.service_description,
+ identity_fakes.service_name,
+ ]
+ verifylist = [
+ ('type', None),
+ ('name', None),
+ ('description', identity_fakes.service_description),
+ ('enable', False),
+ ('disable', False),
+ ('service', identity_fakes.service_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.run(parsed_args)
+ self.assertEqual(result, 0)
+
+ # Set expected values
+ kwargs = {
+ 'description': identity_fakes.service_description,
+ }
+ # ServiceManager.update(service, name=, type=, enabled=, **kwargs)
+ self.services_mock.update.assert_called_with(
+ identity_fakes.service_id,
+ **kwargs
+ )
+
def test_service_set_enable(self):
arglist = [
'--enable',
@@ -310,6 +386,7 @@ class TestServiceSet(TestService):
verifylist = [
('type', None),
('name', None),
+ ('description', None),
('enable', True),
('disable', False),
('service', identity_fakes.service_name),
@@ -337,6 +414,7 @@ class TestServiceSet(TestService):
verifylist = [
('type', None),
('name', None),
+ ('description', None),
('enable', False),
('disable', True),
('service', identity_fakes.service_name),
@@ -388,9 +466,10 @@ class TestServiceShow(TestService):
identity_fakes.service_name,
)
- collist = ('enabled', 'id', 'name', 'type')
+ collist = ('description', 'enabled', 'id', 'name', 'type')
self.assertEqual(columns, collist)
datalist = (
+ identity_fakes.service_description,
True,
identity_fakes.service_id,
identity_fakes.service_name,
diff --git a/openstackclient/tests/identity/v3/test_user.py b/openstackclient/tests/identity/v3/test_user.py
index af58b230..dd517e19 100644
--- a/openstackclient/tests/identity/v3/test_user.py
+++ b/openstackclient/tests/identity/v3/test_user.py
@@ -469,7 +469,7 @@ class TestUserDelete(TestUser):
identity_fakes.user_id,
]
verifylist = [
- ('user', identity_fakes.user_id),
+ ('users', [identity_fakes.user_id]),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
diff --git a/openstackclient/tests/image/v1/test_image.py b/openstackclient/tests/image/v1/test_image.py
index a0566930..4d21ac48 100644
--- a/openstackclient/tests/image/v1/test_image.py
+++ b/openstackclient/tests/image/v1/test_image.py
@@ -288,7 +288,7 @@ class TestImageDelete(TestImage):
image_fakes.image_id,
]
verifylist = [
- ('image', image_fakes.image_id),
+ ('images', [image_fakes.image_id]),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
diff --git a/openstackclient/tests/image/v2/test_image.py b/openstackclient/tests/image/v2/test_image.py
index 3e9eeebb..bc61a89f 100644
--- a/openstackclient/tests/image/v2/test_image.py
+++ b/openstackclient/tests/image/v2/test_image.py
@@ -51,7 +51,7 @@ class TestImageDelete(TestImage):
image_fakes.image_id,
]
verifylist = [
- ('image', image_fakes.image_id),
+ ('images', [image_fakes.image_id]),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
diff --git a/openstackclient/tests/network/v2/test_network.py b/openstackclient/tests/network/v2/test_network.py
index 468db5e0..b893229f 100644
--- a/openstackclient/tests/network/v2/test_network.py
+++ b/openstackclient/tests/network/v2/test_network.py
@@ -120,7 +120,7 @@ class TestDeleteNetwork(common.TestNetworkBase):
FAKE_NAME,
]
verifylist = [
- ('identifier', FAKE_NAME),
+ ('networks', [FAKE_NAME]),
]
lister = mock.Mock(return_value={RESOURCES: [RECORD]})
self.app.client_manager.network.list_networks = lister
diff --git a/openstackclient/volume/v1/backup.py b/openstackclient/volume/v1/backup.py
index 992fa7be..8c16ba25 100644
--- a/openstackclient/volume/v1/backup.py
+++ b/openstackclient/volume/v1/backup.py
@@ -73,25 +73,27 @@ class CreateBackup(show.ShowOne):
class DeleteBackup(command.Command):
- """Delete backup command"""
+ """Delete backup(s)"""
log = logging.getLogger(__name__ + '.DeleteBackup')
def get_parser(self, prog_name):
parser = super(DeleteBackup, self).get_parser(prog_name)
parser.add_argument(
- 'backup',
+ 'backups',
metavar='<backup>',
- help='Name or ID of backup to delete',
+ nargs="+",
+ help='Backup(s) to delete (name or ID)',
)
return parser
def take_action(self, parsed_args):
self.log.debug('take_action(%s)', parsed_args)
volume_client = self.app.client_manager.volume
- backup_id = utils.find_resource(volume_client.backups,
- parsed_args.backup).id
- volume_client.backups.delete(backup_id)
+ for backup in parsed_args.backups:
+ backup_id = utils.find_resource(volume_client.backups,
+ backup).id
+ volume_client.backups.delete(backup_id)
return
diff --git a/openstackclient/volume/v1/snapshot.py b/openstackclient/volume/v1/snapshot.py
index 9cc3c4c1..c9e1baca 100644
--- a/openstackclient/volume/v1/snapshot.py
+++ b/openstackclient/volume/v1/snapshot.py
@@ -74,25 +74,27 @@ class CreateSnapshot(show.ShowOne):
class DeleteSnapshot(command.Command):
- """Delete snapshot command"""
+ """Delete snapshot(s)"""
log = logging.getLogger(__name__ + '.DeleteSnapshot')
def get_parser(self, prog_name):
parser = super(DeleteSnapshot, self).get_parser(prog_name)
parser.add_argument(
- 'snapshot',
+ 'snapshots',
metavar='<snapshot>',
- help='Name or ID of snapshot to delete',
+ nargs="+",
+ help='Snapshot(s) to delete (name or ID)',
)
return parser
def take_action(self, parsed_args):
self.log.debug('take_action(%s)', parsed_args)
volume_client = self.app.client_manager.volume
- snapshot_id = utils.find_resource(volume_client.volume_snapshots,
- parsed_args.snapshot).id
- volume_client.volume_snapshots.delete(snapshot_id)
+ for snapshot in parsed_args.snapshots:
+ snapshot_id = utils.find_resource(volume_client.volume_snapshots,
+ snapshot).id
+ volume_client.volume_snapshots.delete(snapshot_id)
return
diff --git a/openstackclient/volume/v1/volume.py b/openstackclient/volume/v1/volume.py
index 84c216d3..d82f6b4b 100644
--- a/openstackclient/volume/v1/volume.py
+++ b/openstackclient/volume/v1/volume.py
@@ -155,35 +155,37 @@ class CreateVolume(show.ShowOne):
class DeleteVolume(command.Command):
- """Delete a volume"""
+ """Delete volume(s)"""
log = logging.getLogger(__name__ + '.DeleteVolume')
def get_parser(self, prog_name):
parser = super(DeleteVolume, self).get_parser(prog_name)
parser.add_argument(
- 'volume',
+ 'volumes',
metavar='<volume>',
- help='Volume to delete (name or ID)',
+ nargs="+",
+ help='Volume(s) to delete (name or ID)',
)
parser.add_argument(
'--force',
dest='force',
action='store_true',
default=False,
- help='Attempt forced removal of a volume, regardless of state',
+ help='Attempt forced removal of volume(s), regardless of state',
)
return parser
def take_action(self, parsed_args):
self.log.debug('take_action(%s)', parsed_args)
volume_client = self.app.client_manager.volume
- volume = utils.find_resource(
- volume_client.volumes, parsed_args.volume)
- if parsed_args.force:
- volume_client.volumes.force_delete(volume.id)
- else:
- volume_client.volumes.delete(volume.id)
+ for volume in parsed_args.volumes:
+ volume_obj = utils.find_resource(
+ volume_client.volumes, volume)
+ if parsed_args.force:
+ volume_client.volumes.force_delete(volume_obj.id)
+ else:
+ volume_client.volumes.delete(volume_obj.id)
return
@@ -221,6 +223,25 @@ class ListVolume(lister.Lister):
def take_action(self, parsed_args):
self.log.debug('take_action(%s)', parsed_args)
+ volume_client = self.app.client_manager.volume
+ compute_client = self.app.client_manager.compute
+
+ def _format_attach(attachments):
+ """Return a formatted string of a volume's attached instances
+
+ :param volume: a volume.attachments field
+ :rtype: a string of formatted instances
+ """
+
+ msg = ''
+ for attachment in attachments:
+ server = attachment['server_id']
+ if server in server_cache.keys():
+ server = server_cache[server].name
+ device = attachment['device']
+ msg += 'Attached to %s on %s ' % (server, device)
+ return msg
+
if parsed_args.long:
columns = (
'ID',
@@ -229,7 +250,7 @@ class ListVolume(lister.Lister):
'Size',
'Volume Type',
'Bootable',
- 'Attached to',
+ 'Attachments',
'Metadata',
)
column_headers = (
@@ -239,7 +260,7 @@ class ListVolume(lister.Lister):
'Size',
'Type',
'Bootable',
- 'Attached',
+ 'Attached to',
'Properties',
)
else:
@@ -248,28 +269,38 @@ class ListVolume(lister.Lister):
'Display Name',
'Status',
'Size',
- 'Attached to',
+ 'Attachments',
)
column_headers = (
'ID',
'Display Name',
'Status',
'Size',
- 'Attached',
+ 'Attached to',
)
+
+ # Cache the server list
+ server_cache = {}
+ try:
+ for s in compute_client.servers.list():
+ server_cache[s.id] = s
+ except Exception:
+ # Just forget it if there's any trouble
+ pass
+
search_opts = {
'all_tenants': parsed_args.all_projects,
'display_name': parsed_args.name,
'status': parsed_args.status,
}
- volume_client = self.app.client_manager.volume
data = volume_client.volumes.list(search_opts=search_opts)
return (column_headers,
(utils.get_item_properties(
s, columns,
- formatters={'Metadata': utils.format_dict},
+ formatters={'Metadata': utils.format_dict,
+ 'Attachments': _format_attach},
) for s in data))