summaryrefslogtreecommitdiff
path: root/openstackclient
diff options
context:
space:
mode:
Diffstat (limited to 'openstackclient')
-rw-r--r--openstackclient/api/auth.py5
-rw-r--r--openstackclient/common/command.py5
-rw-r--r--openstackclient/common/exceptions.py5
-rw-r--r--openstackclient/common/logs.py5
-rw-r--r--openstackclient/common/parseractions.py5
-rw-r--r--openstackclient/common/quota.py57
-rw-r--r--openstackclient/common/timing.py5
-rw-r--r--openstackclient/common/utils.py5
-rw-r--r--openstackclient/compute/v2/hypervisor.py28
-rw-r--r--openstackclient/compute/v2/server.py2
-rw-r--r--openstackclient/network/v2/network.py14
-rw-r--r--openstackclient/network/v2/port.py29
-rw-r--r--openstackclient/network/v2/router.py19
-rw-r--r--openstackclient/network/v2/subnet.py120
-rw-r--r--openstackclient/network/v2/subnet_pool.py116
-rw-r--r--openstackclient/tests/functional/common/test_quota.py24
-rwxr-xr-xopenstackclient/tests/functional/post_test_hook.sh8
-rw-r--r--openstackclient/tests/functional/volume/v1/test_transfer_request.py53
-rw-r--r--openstackclient/tests/functional/volume/v1/test_volume.py11
-rw-r--r--openstackclient/tests/functional/volume/v1/test_volume_type.py15
-rw-r--r--openstackclient/tests/functional/volume/v2/test_transfer_request.py53
-rw-r--r--openstackclient/tests/functional/volume/v2/test_volume.py11
-rw-r--r--openstackclient/tests/functional/volume/v2/test_volume_type.py15
-rw-r--r--openstackclient/tests/unit/common/test_quota.py233
-rw-r--r--openstackclient/tests/unit/compute/v2/fakes.py12
-rw-r--r--openstackclient/tests/unit/compute/v2/test_flavor.py2
-rw-r--r--openstackclient/tests/unit/compute/v2/test_hypervisor.py78
-rw-r--r--openstackclient/tests/unit/compute/v2/test_server.py2
-rw-r--r--openstackclient/tests/unit/compute/v2/test_server_backup.py6
-rw-r--r--openstackclient/tests/unit/compute/v2/test_server_image.py4
-rw-r--r--openstackclient/tests/unit/compute/v2/test_service.py2
-rw-r--r--openstackclient/tests/unit/fakes.py2
-rw-r--r--openstackclient/tests/unit/identity/v2_0/test_catalog.py4
-rw-r--r--openstackclient/tests/unit/identity/v2_0/test_role_assignment.py2
-rw-r--r--openstackclient/tests/unit/identity/v3/fakes.py4
-rw-r--r--openstackclient/tests/unit/identity/v3/test_catalog.py4
-rw-r--r--openstackclient/tests/unit/identity/v3/test_credential.py2
-rw-r--r--openstackclient/tests/unit/identity/v3/test_group.py6
-rw-r--r--openstackclient/tests/unit/identity/v3/test_role_assignment.py2
-rw-r--r--openstackclient/tests/unit/image/v1/test_image.py2
-rw-r--r--openstackclient/tests/unit/image/v2/fakes.py2
-rw-r--r--openstackclient/tests/unit/network/v2/fakes.py28
-rw-r--r--openstackclient/tests/unit/network/v2/test_address_scope.py2
-rw-r--r--openstackclient/tests/unit/network/v2/test_floating_ip.py4
-rw-r--r--openstackclient/tests/unit/network/v2/test_network.py12
-rw-r--r--openstackclient/tests/unit/network/v2/test_network_agent.py2
-rw-r--r--openstackclient/tests/unit/network/v2/test_network_rbac.py2
-rw-r--r--openstackclient/tests/unit/network/v2/test_port.py35
-rw-r--r--openstackclient/tests/unit/network/v2/test_router.py57
-rw-r--r--openstackclient/tests/unit/network/v2/test_security_group.py4
-rw-r--r--openstackclient/tests/unit/network/v2/test_security_group_rule.py4
-rw-r--r--openstackclient/tests/unit/network/v2/test_subnet.py176
-rw-r--r--openstackclient/tests/unit/network/v2/test_subnet_pool.py187
-rw-r--r--openstackclient/tests/unit/test_shell.py3
-rw-r--r--openstackclient/tests/unit/volume/v1/fakes.py276
-rw-r--r--openstackclient/tests/unit/volume/v1/test_qos_specs.py77
-rw-r--r--openstackclient/tests/unit/volume/v1/test_transfer_request.py156
-rw-r--r--openstackclient/tests/unit/volume/v1/test_type.py347
-rw-r--r--openstackclient/tests/unit/volume/v1/test_volume.py513
-rw-r--r--openstackclient/tests/unit/volume/v2/fakes.py69
-rw-r--r--openstackclient/tests/unit/volume/v2/test_snapshot.py49
-rw-r--r--openstackclient/tests/unit/volume/v2/test_transfer_request.py156
-rw-r--r--openstackclient/tests/unit/volume/v2/test_volume.py125
-rw-r--r--openstackclient/tests/volume/v1/test_service.py286
-rw-r--r--openstackclient/volume/v1/backup.py26
-rw-r--r--openstackclient/volume/v1/qos_specs.py26
-rw-r--r--openstackclient/volume/v1/snapshot.py49
-rw-r--r--openstackclient/volume/v1/volume.py61
-rw-r--r--openstackclient/volume/v1/volume_transfer_request.py77
-rw-r--r--openstackclient/volume/v1/volume_type.py6
-rw-r--r--openstackclient/volume/v2/snapshot.py35
-rw-r--r--openstackclient/volume/v2/volume.py60
-rw-r--r--openstackclient/volume/v2/volume_transfer_request.py75
-rw-r--r--openstackclient/volume/v2/volume_type.py2
74 files changed, 3243 insertions, 723 deletions
diff --git a/openstackclient/api/auth.py b/openstackclient/api/auth.py
index d62a82dc..7c520f49 100644
--- a/openstackclient/api/auth.py
+++ b/openstackclient/api/auth.py
@@ -14,12 +14,15 @@
# NOTE(dtroyer): This file is deprecated in Jun 2016, remove after 4.x release
# or Jun 2017.
+import inspect
import sys
from osc_lib.api.auth import * # noqa
+parent_import = inspect.getouterframes(inspect.currentframe())[1][1]
sys.stderr.write(
"WARNING: %s is deprecated and will be removed after Jun 2017. "
- "Please use osc_lib.api.auth\n" % __name__
+ "Please use osc_lib.api.auth. This warning is caused by an "
+ "out-of-date import in %s\n" % (__name__, parent_import)
)
diff --git a/openstackclient/common/command.py b/openstackclient/common/command.py
index 29c1534d..44954da3 100644
--- a/openstackclient/common/command.py
+++ b/openstackclient/common/command.py
@@ -15,12 +15,15 @@
# NOTE(dtroyer): This file is deprecated in Jun 2016, remove after 4.x release
# or Jun 2017.
+import inspect
import sys
from osc_lib.command.command import * # noqa
+parent_import = inspect.getouterframes(inspect.currentframe())[1][1]
sys.stderr.write(
"WARNING: %s is deprecated and will be removed after Jun 2017. "
- "Please use osc_lib.command.command\n" % __name__
+ "Please use osc_lib.command.command. This warning is caused by an "
+ "out-of-date import in %s\n" % (__name__, parent_import)
)
diff --git a/openstackclient/common/exceptions.py b/openstackclient/common/exceptions.py
index 7124074c..ed497e7b 100644
--- a/openstackclient/common/exceptions.py
+++ b/openstackclient/common/exceptions.py
@@ -14,12 +14,15 @@
# NOTE(dtroyer): This file is deprecated in Jun 2016, remove after 4.x release
# or Jun 2017.
+import inspect
import sys
from osc_lib.exceptions import * # noqa
+parent_import = inspect.getouterframes(inspect.currentframe())[1][1]
sys.stderr.write(
"WARNING: %s is deprecated and will be removed after Jun 2017. "
- "Please use osc_lib.exceptions\n" % __name__
+ "Please use osc_lib.exceptions. This warning is caused by an "
+ "out-of-date import in %s\n" % (__name__, parent_import)
)
diff --git a/openstackclient/common/logs.py b/openstackclient/common/logs.py
index 8aa97d5b..24bf07eb 100644
--- a/openstackclient/common/logs.py
+++ b/openstackclient/common/logs.py
@@ -14,13 +14,16 @@
# NOTE(dtroyer): This file is deprecated in Jun 2016, remove after 4.x release
# or Jun 2017.
+import inspect
import sys
from osc_lib.logs import * # noqa
from osc_lib.logs import _FileFormatter # noqa
+parent_import = inspect.getouterframes(inspect.currentframe())[1][1]
sys.stderr.write(
"WARNING: %s is deprecated and will be removed after Jun 2017. "
- "Please use osc_lib.logs\n" % __name__
+ "Please use osc_lib.logs. This warning is caused by an "
+ "out-of-date import in %s\n" % (__name__, parent_import)
)
diff --git a/openstackclient/common/parseractions.py b/openstackclient/common/parseractions.py
index fa5148ec..3af3a017 100644
--- a/openstackclient/common/parseractions.py
+++ b/openstackclient/common/parseractions.py
@@ -14,12 +14,15 @@
# NOTE(dtroyer): This file is deprecated in Jun 2016, remove after 4.x release
# or Jun 2017.
+import inspect
import sys
from osc_lib.cli.parseractions import * # noqa
+parent_import = inspect.getouterframes(inspect.currentframe())[1][1]
sys.stderr.write(
"WARNING: %s is deprecated and will be removed after Jun 2017. "
- "Please use osc_lib.cli.parseractions\n" % __name__
+ "Please use osc_lib.cli.parseractions. This warning is caused by an "
+ "out-of-date import in %s\n" % (__name__, parent_import)
)
diff --git a/openstackclient/common/quota.py b/openstackclient/common/quota.py
index 5d53171c..8f099cc9 100644
--- a/openstackclient/common/quota.py
+++ b/openstackclient/common/quota.py
@@ -43,11 +43,20 @@ COMPUTE_QUOTAS = {
}
VOLUME_QUOTAS = {
+ 'backups': 'backups',
+ 'backup_gigabytes': 'backup-gigabytes',
'gigabytes': 'gigabytes',
+ 'per_volume_gigabytes': 'per-volume-gigabytes',
'snapshots': 'snapshots',
'volumes': 'volumes',
}
+IMPACT_VOLUME_TYPE_QUOTAS = [
+ 'gigabytes',
+ 'snapshots',
+ 'volumes',
+]
+
NOVA_NETWORK_QUOTAS = {
'floating_ips': 'floating-ips',
'security_group_rules': 'secgroup-rules',
@@ -65,8 +74,8 @@ NETWORK_QUOTAS = {
'rbac_policy': 'rbac-policies',
'vip': 'vips',
'subnetpool': 'subnetpools',
- 'member': 'members',
- 'health_monitor': 'health-monitors',
+ 'healthmonitor': 'health-monitors',
+ 'l7policy': 'l7policies',
}
@@ -128,7 +137,8 @@ class SetQuota(command.Command):
for k, v in VOLUME_QUOTAS.items():
value = getattr(parsed_args, k, None)
if value is not None:
- if parsed_args.volume_type:
+ if (parsed_args.volume_type and
+ k in IMPACT_VOLUME_TYPE_QUOTAS):
k = k + '_%s' % parsed_args.volume_type
volume_kwargs[k] = value
@@ -144,36 +154,34 @@ class SetQuota(command.Command):
if value is not None:
compute_kwargs[k] = value
- if parsed_args.project:
- project = utils.find_resource(
- identity_client.projects,
- parsed_args.project,
- )
-
if parsed_args.quota_class:
if compute_kwargs:
compute_client.quota_classes.update(
- project.id,
+ parsed_args.project,
**compute_kwargs)
if volume_kwargs:
volume_client.quota_classes.update(
- project.id,
+ parsed_args.project,
**volume_kwargs)
if network_kwargs:
sys.stderr.write("Network quotas are ignored since quota class"
"is not supported.")
else:
+ project = utils.find_resource(
+ identity_client.projects,
+ parsed_args.project,
+ ).id
if compute_kwargs:
compute_client.quotas.update(
- project.id,
+ project,
**compute_kwargs)
if volume_kwargs:
volume_client.quotas.update(
- project.id,
+ project,
**volume_kwargs)
if network_kwargs:
network_client.update_quota(
- project.id,
+ project,
**network_kwargs)
@@ -220,15 +228,15 @@ class ShowQuota(command.ShowOne):
return project
def get_compute_volume_quota(self, client, parsed_args):
- project = self._get_project(parsed_args)
-
try:
if parsed_args.quota_class:
- quota = client.quota_classes.get(project)
- elif parsed_args.default:
- quota = client.quotas.defaults(project)
+ quota = client.quota_classes.get(parsed_args.project)
else:
- quota = client.quotas.get(project)
+ project = self._get_project(parsed_args)
+ if parsed_args.default:
+ quota = client.quotas.defaults(project)
+ else:
+ quota = client.quotas.get(project)
except Exception as e:
if type(e).__name__ == 'EndpointNotFound':
return {}
@@ -237,11 +245,16 @@ class ShowQuota(command.ShowOne):
return quota._info
def get_network_quota(self, parsed_args):
- if parsed_args.quota_class or parsed_args.default:
+ if parsed_args.quota_class:
return {}
if self.app.client_manager.is_network_endpoint_enabled():
project = self._get_project(parsed_args)
- return self.app.client_manager.network.get_quota(project)
+ client = self.app.client_manager.network
+ if parsed_args.default:
+ network_quota = client.get_quota_default(project)
+ else:
+ network_quota = client.get_quota(project)
+ return network_quota
else:
return {}
diff --git a/openstackclient/common/timing.py b/openstackclient/common/timing.py
index facbec35..444f0cb2 100644
--- a/openstackclient/common/timing.py
+++ b/openstackclient/common/timing.py
@@ -14,12 +14,15 @@
# NOTE(dtroyer): This file is deprecated in Jun 2016, remove after 4.x release
# or Jun 2017.
+import inspect
import sys
from osc_lib.command.timing import * # noqa
+parent_import = inspect.getouterframes(inspect.currentframe())[1][1]
sys.stderr.write(
"WARNING: %s is deprecated and will be removed after Jun 2017. "
- "Please use osc_lib.command.timing\n" % __name__
+ "Please use osc_lib.command.timing. This warning is caused by an "
+ "out-of-date import in %s\n" % (__name__, parent_import)
)
diff --git a/openstackclient/common/utils.py b/openstackclient/common/utils.py
index 73cd3dc9..aeb3aea7 100644
--- a/openstackclient/common/utils.py
+++ b/openstackclient/common/utils.py
@@ -14,12 +14,15 @@
# NOTE(dtroyer): This file is deprecated in Jun 2016, remove after 4.x release
# or Jun 2017.
+import inspect
import sys
from osc_lib.utils import * # noqa
+parent_import = inspect.getouterframes(inspect.currentframe())[1][1]
sys.stderr.write(
"WARNING: %s is deprecated and will be removed after Jun 2017. "
- "Please use osc_lib.utils\n" % __name__
+ "Please use osc_lib.utils. This warning is caused by an "
+ "out-of-date import in %s\n" % (__name__, parent_import)
)
diff --git a/openstackclient/compute/v2/hypervisor.py b/openstackclient/compute/v2/hypervisor.py
index 00625050..0222e899 100644
--- a/openstackclient/compute/v2/hypervisor.py
+++ b/openstackclient/compute/v2/hypervisor.py
@@ -17,6 +17,7 @@
import re
+from novaclient import exceptions as nova_exceptions
from osc_lib.command import command
from osc_lib import utils
import six
@@ -94,17 +95,22 @@ class ShowHypervisor(command.ShowOne):
if service_host in aggregate.hosts]
hypervisor["aggregates"] = member_of
- uptime = compute_client.hypervisors.uptime(hypervisor['id'])._info
- # Extract data from uptime value
- # format: 0 up 0, 0 users, load average: 0, 0, 0
- # example: 17:37:14 up 2:33, 3 users, load average: 0.33, 0.36, 0.34
- m = re.match("(.+)\sup\s+(.+),\s+(.+)\susers,\s+load average:\s(.+)",
- uptime['uptime'])
- if m:
- hypervisor["host_time"] = m.group(1)
- hypervisor["uptime"] = m.group(2)
- hypervisor["users"] = m.group(3)
- hypervisor["load_average"] = m.group(4)
+ try:
+ uptime = compute_client.hypervisors.uptime(hypervisor['id'])._info
+ # Extract data from uptime value
+ # format: 0 up 0, 0 users, load average: 0, 0, 0
+ # example: 17:37:14 up 2:33, 3 users,
+ # load average: 0.33, 0.36, 0.34
+ m = re.match(
+ "\s*(.+)\sup\s+(.+),\s+(.+)\susers?,\s+load average:\s(.+)",
+ uptime['uptime'])
+ if m:
+ hypervisor["host_time"] = m.group(1)
+ hypervisor["uptime"] = m.group(2)
+ hypervisor["users"] = m.group(3)
+ hypervisor["load_average"] = m.group(4)
+ except nova_exceptions.HTTPNotImplemented:
+ pass
hypervisor["service_id"] = hypervisor["service"]["id"]
hypervisor["service_host"] = hypervisor["service"]["host"]
diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py
index 3e6903b7..1ca31497 100644
--- a/openstackclient/compute/v2/server.py
+++ b/openstackclient/compute/v2/server.py
@@ -1677,7 +1677,7 @@ class SshServer(command.Command):
if parsed_args.login:
login = parsed_args.login
else:
- login = self.app.client_manager._username
+ login = self.app.client_manager.auth_ref.username
if parsed_args.verbose:
cmd += " -v"
diff --git a/openstackclient/network/v2/network.py b/openstackclient/network/v2/network.py
index ccc02fd8..31b173e1 100644
--- a/openstackclient/network/v2/network.py
+++ b/openstackclient/network/v2/network.py
@@ -78,6 +78,10 @@ def _get_attrs(client_manager, parsed_args):
parsed_args.availability_zone_hints is not None:
attrs['availability_zone_hints'] = parsed_args.availability_zone_hints
+ # set description
+ if parsed_args.description:
+ attrs['description'] = parsed_args.description
+
# update_external_network_options
if parsed_args.internal:
attrs['router:external'] = False
@@ -191,6 +195,11 @@ class CreateNetwork(common.NetworkAndComputeShowOne):
metavar='<project>',
help=_("Owner's project (name or ID)")
)
+ parser.add_argument(
+ '--description',
+ metavar='<description>',
+ help=_("Set network description")
+ )
identity_common.add_project_domain_option_to_parser(parser)
parser.add_argument(
'--availability-zone-hint',
@@ -420,6 +429,11 @@ class SetNetwork(command.Command):
action='store_true',
help=_("Do not share the network between projects")
)
+ parser.add_argument(
+ '--description',
+ metavar="<description",
+ help=_("Set network description")
+ )
port_security_group = parser.add_mutually_exclusive_group()
port_security_group.add_argument(
'--enable-port-security',
diff --git a/openstackclient/network/v2/port.py b/openstackclient/network/v2/port.py
index 05c5a012..0df78e43 100644
--- a/openstackclient/network/v2/port.py
+++ b/openstackclient/network/v2/port.py
@@ -346,15 +346,26 @@ class ListPort(command.Lister):
"network:dhcp).")
)
parser.add_argument(
+ '--network',
+ metavar='<network>',
+ help=_("List only ports connected to this network (name or ID)"))
+ device_group = parser.add_mutually_exclusive_group()
+ device_group.add_argument(
'--router',
metavar='<router>',
dest='router',
help=_("List only ports attached to this router (name or ID)")
)
+ device_group.add_argument(
+ '--server',
+ metavar='<server>',
+ help=_("List only ports attached to this server (name or ID)"),
+ )
return parser
def take_action(self, parsed_args):
- client = self.app.client_manager.network
+ network_client = self.app.client_manager.network
+ compute_client = self.app.client_manager.compute
columns = (
'id',
@@ -373,11 +384,19 @@ class ListPort(command.Lister):
if parsed_args.device_owner is not None:
filters['device_owner'] = parsed_args.device_owner
if parsed_args.router:
- _router = client.find_router(parsed_args.router,
- ignore_missing=False)
+ _router = network_client.find_router(parsed_args.router,
+ ignore_missing=False)
filters['device_id'] = _router.id
-
- data = client.ports(**filters)
+ if parsed_args.server:
+ server = utils.find_resource(compute_client.servers,
+ parsed_args.server)
+ filters['device_id'] = server.id
+ if parsed_args.network:
+ network = network_client.find_network(parsed_args.network,
+ ignore_missing=False)
+ filters['network_id'] = network.id
+
+ data = network_client.ports(**filters)
return (column_headers,
(utils.get_item_properties(
diff --git a/openstackclient/network/v2/router.py b/openstackclient/network/v2/router.py
index f6d96d03..03134b8c 100644
--- a/openstackclient/network/v2/router.py
+++ b/openstackclient/network/v2/router.py
@@ -119,7 +119,7 @@ class AddPortToRouter(command.Command):
def take_action(self, parsed_args):
client = self.app.client_manager.network
port = client.find_port(parsed_args.port, ignore_missing=False)
- client.router_add_interface(client.find_router(
+ client.add_interface_to_router(client.find_router(
parsed_args.router, ignore_missing=False), port_id=port.id)
@@ -144,7 +144,7 @@ class AddSubnetToRouter(command.Command):
client = self.app.client_manager.network
subnet = client.find_subnet(parsed_args.subnet,
ignore_missing=False)
- client.router_add_interface(
+ client.add_interface_to_router(
client.find_router(parsed_args.router,
ignore_missing=False),
subnet_id=subnet.id)
@@ -281,13 +281,20 @@ class ListRouter(command.Lister):
columns = columns + (
'routes',
'external_gateway_info',
- 'availability_zones'
)
column_headers = column_headers + (
'Routes',
'External gateway info',
- 'Availability zones'
)
+ # availability zone will be available only when
+ # router_availability_zone extension is enabled
+ if client.find_extension("router_availability_zone"):
+ columns = columns + (
+ 'availability_zones',
+ )
+ column_headers = column_headers + (
+ 'Availability zones',
+ )
data = client.routers()
return (column_headers,
@@ -317,7 +324,7 @@ class RemovePortFromRouter(command.Command):
def take_action(self, parsed_args):
client = self.app.client_manager.network
port = client.find_port(parsed_args.port, ignore_missing=False)
- client.router_remove_interface(client.find_router(
+ client.remove_interface_from_router(client.find_router(
parsed_args.router, ignore_missing=False), port_id=port.id)
@@ -342,7 +349,7 @@ class RemoveSubnetFromRouter(command.Command):
client = self.app.client_manager.network
subnet = client.find_subnet(parsed_args.subnet,
ignore_missing=False)
- client.router_remove_interface(
+ client.remove_interface_from_router(
client.find_router(parsed_args.router,
ignore_missing=False),
subnet_id=subnet.id)
diff --git a/openstackclient/network/v2/subnet.py b/openstackclient/network/v2/subnet.py
index 6feb8aa0..76453487 100644
--- a/openstackclient/network/v2/subnet.py
+++ b/openstackclient/network/v2/subnet.py
@@ -28,9 +28,14 @@ from openstackclient.identity import common as identity_common
LOG = logging.getLogger(__name__)
-def _update_arguments(obj_list, parsed_args_list):
+def _update_arguments(obj_list, parsed_args_list, option):
for item in parsed_args_list:
- obj_list.remove(item)
+ try:
+ obj_list.remove(item)
+ except ValueError:
+ msg = (_("Subnet does not contain %(option)s %(value)s") %
+ {'option': option, 'value': item})
+ raise exceptions.CommandError(msg)
def _format_allocation_pools(data):
@@ -191,6 +196,8 @@ def _get_attrs(client_manager, parsed_args, is_create=True):
if ('service_types' in parsed_args and
parsed_args.service_types is not None):
attrs['service_types'] = parsed_args.service_types
+ if parsed_args.description is not None:
+ attrs['description'] = parsed_args.description
return attrs
@@ -289,6 +296,11 @@ class CreateSubnet(command.ShowOne):
metavar='<network>',
help=_("Network this subnet belongs to (name or ID)")
)
+ parser.add_argument(
+ '--description',
+ metavar='<description>',
+ help=_("Set subnet description")
+ )
_get_common_parse_arguments(parser)
return parser
@@ -376,9 +388,41 @@ class ListSubnet(command.Lister):
"Must be a valid device owner value for a network port "
"(repeat option to list multiple service types)")
)
+ parser.add_argument(
+ '--project',
+ metavar='<project>',
+ help=_("List only subnets which belong to a given project "
+ "(name or ID) in output")
+ )
+ identity_common.add_project_domain_option_to_parser(parser)
+ parser.add_argument(
+ '--network',
+ metavar='<network>',
+ help=_("List only subnets which belong to a given network "
+ "(name or ID) in output")
+ )
+ parser.add_argument(
+ '--gateway',
+ metavar='<gateway>',
+ help=_("List only subnets of given gateway IP in output")
+ )
+ parser.add_argument(
+ '--name',
+ metavar='<name>',
+ help=_("List only subnets of given name in output")
+ )
+ parser.add_argument(
+ '--subnet-range',
+ metavar='<subnet-range>',
+ help=_("List only subnets of given subnet range "
+ "(in CIDR notation) in output "
+ "e.g.: --subnet-range 10.10.0.0/16")
+ )
return parser
def take_action(self, parsed_args):
+ identity_client = self.app.client_manager.identity
+ network_client = self.app.client_manager.network
filters = {}
if parsed_args.ip_version:
filters['ip_version'] = parsed_args.ip_version
@@ -388,7 +432,24 @@ class ListSubnet(command.Lister):
filters['enable_dhcp'] = False
if parsed_args.service_types:
filters['service_types'] = parsed_args.service_types
- data = self.app.client_manager.network.subnets(**filters)
+ if parsed_args.project:
+ project_id = identity_common.find_project(
+ identity_client,
+ parsed_args.project,
+ parsed_args.project_domain,
+ ).id
+ filters['tenant_id'] = project_id
+ if parsed_args.network:
+ network_id = network_client.find_network(parsed_args.network,
+ ignore_missing=False).id
+ filters['network_id'] = network_id
+ if parsed_args.gateway:
+ filters['gateway_ip'] = parsed_args.gateway
+ if parsed_args.name:
+ filters['name'] = parsed_args.name
+ if parsed_args.subnet_range:
+ filters['cidr'] = parsed_args.subnet_range
+ data = network_client.subnets(**filters)
headers = ('ID', 'Name', 'Network', 'Subnet')
columns = ('id', 'name', 'network_id', 'cidr')
@@ -442,6 +503,11 @@ class SetSubnet(command.Command):
"'none': This subnet will not use a gateway, "
"e.g.: --gateway 192.168.9.1, --gateway none.")
)
+ parser.add_argument(
+ '--description',
+ metavar='<description>',
+ help=_("Set subnet description")
+ )
_get_common_parse_arguments(parser)
return parser
@@ -493,9 +559,9 @@ class UnsetSubnet(command.Command):
dest='allocation_pools',
action=parseractions.MultiKeyValueAction,
required_keys=['start', 'end'],
- help=_('Allocation pool to be removed from this subnet '
- 'e.g.: start=192.168.199.2,end=192.168.199.254 '
- '(repeat option to unset multiple Allocation pools)')
+ help=_('Allocation pool IP addresses to be removed from this '
+ 'subnet e.g.: start=192.168.199.2,end=192.168.199.254 '
+ '(repeat option to unset multiple allocation pools)')
)
parser.add_argument(
'--dns-nameserver',
@@ -503,7 +569,7 @@ class UnsetSubnet(command.Command):
action='append',
dest='dns_nameservers',
help=_('DNS server to be removed from this subnet '
- '(repeat option to set multiple DNS servers)')
+ '(repeat option to unset multiple DNS servers)')
)
parser.add_argument(
'--host-route',
@@ -540,39 +606,25 @@ class UnsetSubnet(command.Command):
tmp_obj = copy.deepcopy(obj)
attrs = {}
if parsed_args.dns_nameservers:
- try:
- _update_arguments(tmp_obj.dns_nameservers,
- parsed_args.dns_nameservers)
- except ValueError as error:
- msg = (_("%s not in dns-nameservers") % str(error))
- raise exceptions.CommandError(msg)
+ _update_arguments(tmp_obj.dns_nameservers,
+ parsed_args.dns_nameservers,
+ 'dns-nameserver')
attrs['dns_nameservers'] = tmp_obj.dns_nameservers
if parsed_args.host_routes:
- try:
- _update_arguments(
- tmp_obj.host_routes,
- convert_entries_to_nexthop(parsed_args.host_routes))
- except ValueError as error:
- msg = (_("Subnet does not have %s in host-routes") %
- str(error))
- raise exceptions.CommandError(msg)
+ _update_arguments(
+ tmp_obj.host_routes,
+ convert_entries_to_nexthop(parsed_args.host_routes),
+ 'host-route')
attrs['host_routes'] = tmp_obj.host_routes
if parsed_args.allocation_pools:
- try:
- _update_arguments(tmp_obj.allocation_pools,
- parsed_args.allocation_pools)
- except ValueError as error:
- msg = (_("Subnet does not have %s in allocation-pools") %
- str(error))
- raise exceptions.CommandError(msg)
+ _update_arguments(tmp_obj.allocation_pools,
+ parsed_args.allocation_pools,
+ 'allocation-pool')
attrs['allocation_pools'] = tmp_obj.allocation_pools
if parsed_args.service_types:
- try:
- _update_arguments(tmp_obj.service_types,
- parsed_args.service_types)
- except ValueError as error:
- msg = (_("%s not in service-types") % str(error))
- raise exceptions.CommandError(msg)
+ _update_arguments(tmp_obj.service_types,
+ parsed_args.service_types,
+ 'service-type')
attrs['service_types'] = tmp_obj.service_types
if attrs:
client.update_subnet(obj, **attrs)
diff --git a/openstackclient/network/v2/subnet_pool.py b/openstackclient/network/v2/subnet_pool.py
index d3fab8ac..a01d2f7b 100644
--- a/openstackclient/network/v2/subnet_pool.py
+++ b/openstackclient/network/v2/subnet_pool.py
@@ -81,6 +81,9 @@ def _get_attrs(client_manager, parsed_args):
).id
attrs['tenant_id'] = project_id
+ if parsed_args.description is not None:
+ attrs['description'] = parsed_args.description
+
return attrs
@@ -167,6 +170,11 @@ class CreateSubnetPool(command.ShowOne):
action='store_true',
help=_("Set this subnet pool as not shared"),
)
+ parser.add_argument(
+ '--description',
+ metavar='<description>',
+ help=_("Set subnet pool description")
+ )
return parser
def take_action(self, parsed_args):
@@ -226,41 +234,82 @@ class ListSubnetPool(command.Lister):
default=False,
help=_("List additional fields in output")
)
+ shared_group = parser.add_mutually_exclusive_group()
+ shared_group.add_argument(
+ '--share',
+ action='store_true',
+ help=_("List subnets shared between projects"),
+ )
+ shared_group.add_argument(
+ '--no-share',
+ action='store_true',
+ help=_("List subnets not shared between projects"),
+ )
+ default_group = parser.add_mutually_exclusive_group()
+ default_group.add_argument(
+ '--default',
+ action='store_true',
+ help=_("List subnets used as the default external subnet pool"),
+ )
+ default_group.add_argument(
+ '--no-default',
+ action='store_true',
+ help=_("List subnets not used as the default external subnet pool")
+ )
+ parser.add_argument(
+ '--project',
+ metavar='<project>',
+ help=_("List subnets according to their project (name or ID)")
+ )
+ identity_common.add_project_domain_option_to_parser(parser)
+ parser.add_argument(
+ '--name',
+ metavar='<name>',
+ help=_("List only subnets of given name in output")
+ )
+ parser.add_argument(
+ '--address-scope',
+ metavar='<address-scope>',
+ help=_("List only subnets of given address scope (name or ID) "
+ "in output")
+ )
return parser
def take_action(self, parsed_args):
- data = self.app.client_manager.network.subnet_pools()
-
+ identity_client = self.app.client_manager.identity
+ network_client = self.app.client_manager.network
+ filters = {}
+ if parsed_args.share:
+ filters['shared'] = True
+ elif parsed_args.no_share:
+ filters['shared'] = False
+ if parsed_args.default:
+ filters['is_default'] = True
+ elif parsed_args.no_default:
+ filters['is_default'] = False
+ if parsed_args.project:
+ project_id = identity_common.find_project(
+ identity_client,
+ parsed_args.project,
+ parsed_args.project_domain,
+ ).id
+ filters['tenant_id'] = project_id
+ if parsed_args.name is not None:
+ filters['name'] = parsed_args.name
+ if parsed_args.address_scope:
+ address_scope = network_client.find_address_scope(
+ parsed_args.address_scope,
+ ignore_missing=False)
+ filters['address_scope_id'] = address_scope.id
+ data = network_client.subnet_pools(**filters)
+
+ headers = ('ID', 'Name', 'Prefixes')
+ columns = ('id', 'name', 'prefixes')
if parsed_args.long:
- headers = (
- 'ID',
- 'Name',
- 'Prefixes',
- 'Default Prefix Length',
- 'Address Scope',
- 'Default Subnet Pool',
- 'Shared',
- )
- columns = (
- 'id',
- 'name',
- 'prefixes',
- 'default_prefixlen',
- 'address_scope_id',
- 'is_default',
- 'shared',
- )
- else:
- headers = (
- 'ID',
- 'Name',
- 'Prefixes',
- )
- columns = (
- 'id',
- 'name',
- 'prefixes',
- )
+ headers += ('Default Prefix Length', 'Address Scope',
+ 'Default Subnet Pool', 'Shared')
+ columns += ('default_prefixlen', 'address_scope_id',
+ 'is_default', 'shared')
return (headers,
(utils.get_item_properties(
@@ -299,6 +348,11 @@ class SetSubnetPool(command.Command):
help=_("Remove address scope associated with the subnet pool")
)
_add_default_options(parser)
+ parser.add_argument(
+ '--description',
+ metavar='<description>',
+ help=_("Set subnet pool description")
+ )
return parser
diff --git a/openstackclient/tests/functional/common/test_quota.py b/openstackclient/tests/functional/common/test_quota.py
index fd45be38..c1de9aa9 100644
--- a/openstackclient/tests/functional/common/test_quota.py
+++ b/openstackclient/tests/functional/common/test_quota.py
@@ -17,6 +17,7 @@ class QuotaTests(base.TestCase):
"""Functional tests for quota. """
# Test quota information for compute, network and volume.
EXPECTED_FIELDS = ['instances', 'networks', 'volumes']
+ EXPECTED_CLASS_FIELDS = ['instances', 'volumes']
PROJECT_NAME = None
@classmethod
@@ -25,8 +26,8 @@ class QuotaTests(base.TestCase):
cls.get_openstack_configuration_value('auth.project_name')
def test_quota_set(self):
- self.openstack('quota set --instances 11 --volumes 11 --networks 11 '
- + self.PROJECT_NAME)
+ self.openstack('quota set --instances 11 --volumes 11 --networks 11 ' +
+ self.PROJECT_NAME)
opts = self.get_opts(self.EXPECTED_FIELDS)
raw_output = self.openstack('quota show ' + self.PROJECT_NAME + opts)
self.assertEqual("11\n11\n11\n", raw_output)
@@ -40,3 +41,22 @@ class QuotaTests(base.TestCase):
raw_output = self.openstack('quota show')
for expected_field in self.EXPECTED_FIELDS:
self.assertIn(expected_field, raw_output)
+
+ def test_quota_show_with_default_option(self):
+ raw_output = self.openstack('quota show --default')
+ for expected_field in self.EXPECTED_FIELDS:
+ self.assertIn(expected_field, raw_output)
+
+ def test_quota_show_with_class_option(self):
+ raw_output = self.openstack('quota show --class')
+ for expected_field in self.EXPECTED_CLASS_FIELDS:
+ self.assertIn(expected_field, raw_output)
+
+ def test_quota_class_set(self):
+ class_name = 'default'
+ class_expected_fields = ['instances', 'volumes']
+ self.openstack('quota set --instances 11 --volumes 11 --class ' +
+ class_name)
+ opts = self.get_opts(class_expected_fields)
+ raw_output = self.openstack('quota show --class ' + class_name + opts)
+ self.assertEqual("11\n11\n", raw_output)
diff --git a/openstackclient/tests/functional/post_test_hook.sh b/openstackclient/tests/functional/post_test_hook.sh
index e555470d..b7a39cfe 100755
--- a/openstackclient/tests/functional/post_test_hook.sh
+++ b/openstackclient/tests/functional/post_test_hook.sh
@@ -18,16 +18,16 @@ function generate_testr_results {
fi
}
-OPENSTACKCLIENT_DIR=$(cd $(dirname "$0") && pwd)
+export OPENSTACKCLIENT_DIR="$BASE/new/python-openstackclient"
sudo chown -R jenkins:stack $OPENSTACKCLIENT_DIR
+# Go to the openstackclient dir
+cd $OPENSTACKCLIENT_DIR
+
# Run tests
echo "Running openstackclient functional test suite"
set +e
-# Go to the openstackclient dir
-cd $OPENSTACKCLIENT_DIR
-
# Source environment variables to kick things off
source ~stack/devstack/openrc admin admin
echo 'Running tests with:'
diff --git a/openstackclient/tests/functional/volume/v1/test_transfer_request.py b/openstackclient/tests/functional/volume/v1/test_transfer_request.py
new file mode 100644
index 00000000..d8406b02
--- /dev/null
+++ b/openstackclient/tests/functional/volume/v1/test_transfer_request.py
@@ -0,0 +1,53 @@
+# 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 uuid
+
+from openstackclient.tests.functional.volume.v1 import common
+
+
+class TransferRequestTests(common.BaseVolumeTests):
+ """Functional tests for transfer request. """
+
+ NAME = uuid.uuid4().hex
+ VOLUME_NAME = uuid.uuid4().hex
+ HEADERS = ['Name']
+ FIELDS = ['name']
+
+ @classmethod
+ def setUpClass(cls):
+ super(TransferRequestTests, cls).setUpClass()
+ opts = cls.get_opts(['display_name'])
+ raw_output = cls.openstack(
+ 'volume create --size 1 ' + cls.VOLUME_NAME + opts)
+ cls.assertOutput(cls.VOLUME_NAME + '\n', raw_output)
+
+ opts = cls.get_opts(cls.FIELDS)
+ raw_output = cls.openstack(
+ 'volume transfer request create ' +
+ cls.VOLUME_NAME +
+ ' --name ' + cls.NAME + opts)
+ cls.assertOutput(cls.NAME + '\n', raw_output)
+
+ @classmethod
+ def tearDownClass(cls):
+ raw_output_transfer = cls.openstack(
+ 'volume transfer request delete ' + cls.NAME)
+ raw_output_volume = cls.openstack(
+ 'volume delete ' + cls.VOLUME_NAME)
+ cls.assertOutput('', raw_output_transfer)
+ cls.assertOutput('', raw_output_volume)
+
+ def test_volume_transfer_request_list(self):
+ opts = self.get_opts(self.HEADERS)
+ raw_output = self.openstack('volume transfer request list' + opts)
+ self.assertIn(self.NAME, raw_output)
diff --git a/openstackclient/tests/functional/volume/v1/test_volume.py b/openstackclient/tests/functional/volume/v1/test_volume.py
index 6ac7f2bf..5e4bcbea 100644
--- a/openstackclient/tests/functional/volume/v1/test_volume.py
+++ b/openstackclient/tests/functional/volume/v1/test_volume.py
@@ -75,3 +75,14 @@ class VolumeTests(common.BaseVolumeTests):
opts = self.get_opts(["display_name", "size"])
raw_output = self.openstack('volume show ' + self.NAME + opts)
self.assertEqual(self.NAME + "\n2\n", raw_output)
+
+ def test_volume_set_bootable(self):
+ self.openstack('volume set --bootable ' + self.NAME)
+ opts = self.get_opts(["bootable"])
+ raw_output = self.openstack('volume show ' + self.NAME + opts)
+ self.assertEqual("true\n", raw_output)
+
+ self.openstack('volume set --non-bootable ' + self.NAME)
+ opts = self.get_opts(["bootable"])
+ raw_output = self.openstack('volume show ' + self.NAME + opts)
+ self.assertEqual("false\n", raw_output)
diff --git a/openstackclient/tests/functional/volume/v1/test_volume_type.py b/openstackclient/tests/functional/volume/v1/test_volume_type.py
index 538545ab..955759b6 100644
--- a/openstackclient/tests/functional/volume/v1/test_volume_type.py
+++ b/openstackclient/tests/functional/volume/v1/test_volume_type.py
@@ -61,6 +61,21 @@ class VolumeTypeTests(common.BaseVolumeTests):
raw_output = self.openstack('volume type show ' + self.NAME + opts)
self.assertEqual("c='d'\n", raw_output)
+ def test_volume_type_set_unset_multiple_properties(self):
+ raw_output = self.openstack(
+ 'volume type set --property a=b --property c=d ' + self.NAME)
+ self.assertEqual("", raw_output)
+
+ opts = self.get_opts(["properties"])
+ raw_output = self.openstack('volume type show ' + self.NAME + opts)
+ self.assertEqual("a='b', c='d'\n", raw_output)
+
+ raw_output = self.openstack(
+ 'volume type unset --property a --property c ' + self.NAME)
+ self.assertEqual("", raw_output)
+ raw_output = self.openstack('volume type show ' + self.NAME + opts)
+ self.assertEqual("\n", raw_output)
+
def test_multi_delete(self):
vol_type1 = uuid.uuid4().hex
vol_type2 = uuid.uuid4().hex
diff --git a/openstackclient/tests/functional/volume/v2/test_transfer_request.py b/openstackclient/tests/functional/volume/v2/test_transfer_request.py
new file mode 100644
index 00000000..4f02238b
--- /dev/null
+++ b/openstackclient/tests/functional/volume/v2/test_transfer_request.py
@@ -0,0 +1,53 @@
+# 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 uuid
+
+from openstackclient.tests.functional.volume.v2 import common
+
+
+class TransferRequestTests(common.BaseVolumeTests):
+ """Functional tests for transfer request. """
+
+ NAME = uuid.uuid4().hex
+ VOLUME_NAME = uuid.uuid4().hex
+ HEADERS = ['Name']
+ FIELDS = ['name']
+
+ @classmethod
+ def setUpClass(cls):
+ super(TransferRequestTests, cls).setUpClass()
+ opts = cls.get_opts(cls.FIELDS)
+
+ raw_output = cls.openstack(
+ 'volume create --size 1 ' + cls.VOLUME_NAME + opts)
+ cls.assertOutput(cls.VOLUME_NAME + '\n', raw_output)
+
+ raw_output = cls.openstack(
+ 'volume transfer request create ' +
+ cls.VOLUME_NAME +
+ ' --name ' + cls.NAME + opts)
+ cls.assertOutput(cls.NAME + '\n', raw_output)
+
+ @classmethod
+ def tearDownClass(cls):
+ raw_output_transfer = cls.openstack(
+ 'volume transfer request delete ' + cls.NAME)
+ raw_output_volume = cls.openstack(
+ 'volume delete ' + cls.VOLUME_NAME)
+ cls.assertOutput('', raw_output_transfer)
+ cls.assertOutput('', raw_output_volume)
+
+ def test_volume_transfer_request_list(self):
+ opts = self.get_opts(self.HEADERS)
+ raw_output = self.openstack('volume transfer request list' + opts)
+ self.assertIn(self.NAME, raw_output)
diff --git a/openstackclient/tests/functional/volume/v2/test_volume.py b/openstackclient/tests/functional/volume/v2/test_volume.py
index 73273573..fb880578 100644
--- a/openstackclient/tests/functional/volume/v2/test_volume.py
+++ b/openstackclient/tests/functional/volume/v2/test_volume.py
@@ -91,6 +91,17 @@ class VolumeTests(common.BaseVolumeTests):
raw_output = self.openstack('volume show ' + self.NAME + opts)
self.assertEqual(self.NAME + "\n2\n", raw_output)
+ def test_volume_set_bootable(self):
+ self.openstack('volume set --bootable ' + self.NAME)
+ opts = self.get_opts(["bootable"])
+ raw_output = self.openstack('volume show ' + self.NAME + opts)
+ self.assertEqual("true\n", raw_output)
+
+ self.openstack('volume set --non-bootable ' + self.NAME)
+ opts = self.get_opts(["bootable"])
+ raw_output = self.openstack('volume show ' + self.NAME + opts)
+ self.assertEqual("false\n", raw_output)
+
def test_volume_snapshot(self):
opts = self.get_opts(self.FIELDS)
diff --git a/openstackclient/tests/functional/volume/v2/test_volume_type.py b/openstackclient/tests/functional/volume/v2/test_volume_type.py
index b62cbb39..d8bd3a96 100644
--- a/openstackclient/tests/functional/volume/v2/test_volume_type.py
+++ b/openstackclient/tests/functional/volume/v2/test_volume_type.py
@@ -62,6 +62,21 @@ class VolumeTypeTests(common.BaseVolumeTests):
raw_output = self.openstack('volume type show ' + self.NAME + opts)
self.assertEqual("c='d'\n", raw_output)
+ def test_volume_type_set_unset_multiple_properties(self):
+ raw_output = self.openstack(
+ 'volume type set --property a=b --property c=d ' + self.NAME)
+ self.assertEqual("", raw_output)
+
+ opts = self.get_opts(["properties"])
+ raw_output = self.openstack('volume type show ' + self.NAME + opts)
+ self.assertEqual("a='b', c='d'\n", raw_output)
+
+ raw_output = self.openstack(
+ 'volume type unset --property a --property c ' + self.NAME)
+ self.assertEqual("", raw_output)
+ raw_output = self.openstack('volume type show ' + self.NAME + opts)
+ self.assertEqual("\n", raw_output)
+
def test_volume_type_set_unset_project(self):
raw_output = self.openstack(
'volume type set --project admin ' + self.NAME)
diff --git a/openstackclient/tests/unit/common/test_quota.py b/openstackclient/tests/unit/common/test_quota.py
index 4a80a2b2..7dd23373 100644
--- a/openstackclient/tests/unit/common/test_quota.py
+++ b/openstackclient/tests/unit/common/test_quota.py
@@ -18,6 +18,7 @@ from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
from openstackclient.tests.unit import fakes
from openstackclient.tests.unit.identity.v2_0 import fakes as identity_fakes
from openstackclient.tests.unit.network.v2 import fakes as network_fakes
+from openstackclient.tests.unit.volume.v2 import fakes as volume_fakes
class FakeQuotaResource(fakes.FakeResource):
@@ -43,10 +44,7 @@ class TestQuota(compute_fakes.TestComputev2):
self.quotas_mock.reset_mock()
self.quotas_class_mock = self.app.client_manager.compute.quota_classes
self.quotas_class_mock.reset_mock()
- volume_mock = mock.Mock()
- volume_mock.quotas = mock.Mock()
- self.app.client_manager.volume = volume_mock
- self.volume_quotas_mock = volume_mock.quotas
+ self.volume_quotas_mock = self.app.client_manager.volume.quotas
self.volume_quotas_mock.reset_mock()
self.volume_quotas_class_mock = \
self.app.client_manager.volume.quota_classes
@@ -66,33 +64,33 @@ class TestQuotaSet(TestQuota):
def setUp(self):
super(TestQuotaSet, self).setUp()
- self.quotas_mock.find.return_value = FakeQuotaResource(
+ self.quotas_mock.update.return_value = FakeQuotaResource(
None,
copy.deepcopy(compute_fakes.QUOTA),
loaded=True,
)
- self.quotas_mock.update.return_value = FakeQuotaResource(
+ self.volume_quotas_mock.update.return_value = FakeQuotaResource(
None,
copy.deepcopy(compute_fakes.QUOTA),
loaded=True,
)
- self.volume_quotas_mock.find.return_value = FakeQuotaResource(
+ self.projects_mock.get.return_value = fakes.FakeResource(
None,
- copy.deepcopy(compute_fakes.QUOTA),
+ copy.deepcopy(identity_fakes.PROJECT),
loaded=True,
)
- self.volume_quotas_mock.update.return_value = FakeQuotaResource(
+ self.quotas_class_mock.update.return_value = FakeQuotaResource(
None,
copy.deepcopy(compute_fakes.QUOTA),
loaded=True,
)
- self.projects_mock.get.return_value = fakes.FakeResource(
+ self.volume_quotas_class_mock.update.return_value = FakeQuotaResource(
None,
- copy.deepcopy(identity_fakes.PROJECT),
+ copy.deepcopy(compute_fakes.QUOTA),
loaded=True,
)
@@ -141,7 +139,7 @@ class TestQuotaSet(TestQuota):
self.app.client_manager.network_endpoint_enabled = False
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- self.cmd.take_action(parsed_args)
+ result = self.cmd.take_action(parsed_args)
kwargs = {
'floating_ips': compute_fakes.floating_ip_num,
@@ -161,39 +159,95 @@ class TestQuotaSet(TestQuota):
'server_group_members': compute_fakes.servgroup_members_num,
}
- self.quotas_mock.update.assert_called_with(
+ self.quotas_mock.update.assert_called_once_with(
identity_fakes.project_id,
**kwargs
)
+ self.assertIsNone(result)
def test_quota_set_volume(self):
arglist = [
- '--gigabytes', str(compute_fakes.floating_ip_num),
- '--snapshots', str(compute_fakes.fix_ip_num),
- '--volumes', str(compute_fakes.injected_file_num),
+ '--gigabytes', str(volume_fakes.QUOTA['gigabytes']),
+ '--snapshots', str(volume_fakes.QUOTA['snapshots']),
+ '--volumes', str(volume_fakes.QUOTA['volumes']),
+ '--backups', str(volume_fakes.QUOTA['backups']),
+ '--backup-gigabytes', str(volume_fakes.QUOTA['backup_gigabytes']),
+ '--per-volume-gigabytes',
+ str(volume_fakes.QUOTA['per_volume_gigabytes']),
identity_fakes.project_name,
]
verifylist = [
- ('gigabytes', compute_fakes.floating_ip_num),
- ('snapshots', compute_fakes.fix_ip_num),
- ('volumes', compute_fakes.injected_file_num),
+ ('gigabytes', volume_fakes.QUOTA['gigabytes']),
+ ('snapshots', volume_fakes.QUOTA['snapshots']),
+ ('volumes', volume_fakes.QUOTA['volumes']),
+ ('backups', volume_fakes.QUOTA['backups']),
+ ('backup_gigabytes', volume_fakes.QUOTA['backup_gigabytes']),
+ ('per_volume_gigabytes',
+ volume_fakes.QUOTA['per_volume_gigabytes']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- self.cmd.take_action(parsed_args)
+ result = self.cmd.take_action(parsed_args)
kwargs = {
- 'gigabytes': compute_fakes.floating_ip_num,
- 'snapshots': compute_fakes.fix_ip_num,
- 'volumes': compute_fakes.injected_file_num,
+ 'gigabytes': volume_fakes.QUOTA['gigabytes'],
+ 'snapshots': volume_fakes.QUOTA['snapshots'],
+ 'volumes': volume_fakes.QUOTA['volumes'],
+ 'backups': volume_fakes.QUOTA['backups'],
+ 'backup_gigabytes': volume_fakes.QUOTA['backup_gigabytes'],
+ 'per_volume_gigabytes': volume_fakes.QUOTA['per_volume_gigabytes']
}
- self.volume_quotas_mock.update.assert_called_with(
+ self.volume_quotas_mock.update.assert_called_once_with(
identity_fakes.project_id,
**kwargs
)
+ self.assertIsNone(result)
+
+ def test_quota_set_volume_with_volume_type(self):
+ arglist = [
+ '--gigabytes', str(volume_fakes.QUOTA['gigabytes']),
+ '--snapshots', str(volume_fakes.QUOTA['snapshots']),
+ '--volumes', str(volume_fakes.QUOTA['volumes']),
+ '--backups', str(volume_fakes.QUOTA['backups']),
+ '--backup-gigabytes', str(volume_fakes.QUOTA['backup_gigabytes']),
+ '--per-volume-gigabytes',
+ str(volume_fakes.QUOTA['per_volume_gigabytes']),
+ '--volume-type', 'volume_type_backend',
+ identity_fakes.project_name,
+ ]
+ verifylist = [
+ ('gigabytes', volume_fakes.QUOTA['gigabytes']),
+ ('snapshots', volume_fakes.QUOTA['snapshots']),
+ ('volumes', volume_fakes.QUOTA['volumes']),
+ ('backups', volume_fakes.QUOTA['backups']),
+ ('backup_gigabytes', volume_fakes.QUOTA['backup_gigabytes']),
+ ('per_volume_gigabytes',
+ volume_fakes.QUOTA['per_volume_gigabytes']),
+ ('volume_type', 'volume_type_backend'),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ kwargs = {
+ 'gigabytes_volume_type_backend': volume_fakes.QUOTA['gigabytes'],
+ 'snapshots_volume_type_backend': volume_fakes.QUOTA['snapshots'],
+ 'volumes_volume_type_backend': volume_fakes.QUOTA['volumes'],
+ 'backups': volume_fakes.QUOTA['backups'],
+ 'backup_gigabytes': volume_fakes.QUOTA['backup_gigabytes'],
+ 'per_volume_gigabytes': volume_fakes.QUOTA['per_volume_gigabytes']
+ }
+
+ self.volume_quotas_mock.update.assert_called_once_with(
+ identity_fakes.project_id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
def test_quota_set_network(self):
arglist = [
'--subnets', str(network_fakes.QUOTA['subnet']),
@@ -207,8 +261,8 @@ class TestQuotaSet(TestQuota):
'--rbac-policies', str(network_fakes.QUOTA['rbac_policy']),
'--ports', str(network_fakes.QUOTA['port']),
'--vips', str(network_fakes.QUOTA['vip']),
- '--members', str(network_fakes.QUOTA['member']),
- '--health-monitors', str(network_fakes.QUOTA['health_monitor']),
+ '--health-monitors', str(network_fakes.QUOTA['healthmonitor']),
+ '--l7policies', str(network_fakes.QUOTA['l7policy']),
identity_fakes.project_name,
]
verifylist = [
@@ -223,12 +277,12 @@ class TestQuotaSet(TestQuota):
('rbac_policy', network_fakes.QUOTA['rbac_policy']),
('port', network_fakes.QUOTA['port']),
('vip', network_fakes.QUOTA['vip']),
- ('member', network_fakes.QUOTA['member']),
- ('health_monitor', network_fakes.QUOTA['health_monitor']),
+ ('healthmonitor', network_fakes.QUOTA['healthmonitor']),
+ ('l7policy', network_fakes.QUOTA['l7policy']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- self.cmd.take_action(parsed_args)
+ result = self.cmd.take_action(parsed_args)
kwargs = {
'subnet': network_fakes.QUOTA['subnet'],
'network': network_fakes.QUOTA['network'],
@@ -241,13 +295,86 @@ class TestQuotaSet(TestQuota):
'rbac_policy': network_fakes.QUOTA['rbac_policy'],
'port': network_fakes.QUOTA['port'],
'vip': network_fakes.QUOTA['vip'],
- 'member': network_fakes.QUOTA['member'],
- 'health_monitor': network_fakes.QUOTA['health_monitor'],
+ 'healthmonitor': network_fakes.QUOTA['healthmonitor'],
+ 'l7policy': network_fakes.QUOTA['l7policy'],
}
- self.network_mock.update_quota.assert_called_with(
+ self.network_mock.update_quota.assert_called_once_with(
identity_fakes.project_id,
**kwargs
)
+ self.assertIsNone(result)
+
+ def test_quota_set_with_class(self):
+ arglist = [
+ '--injected-files', str(compute_fakes.injected_file_num),
+ '--injected-file-size', str(compute_fakes.injected_file_size_num),
+ '--injected-path-size', str(compute_fakes.injected_path_size_num),
+ '--key-pairs', str(compute_fakes.key_pair_num),
+ '--cores', str(compute_fakes.core_num),
+ '--ram', str(compute_fakes.ram_num),
+ '--instances', str(compute_fakes.instance_num),
+ '--properties', str(compute_fakes.property_num),
+ '--server-groups', str(compute_fakes.servgroup_num),
+ '--server-group-members', str(compute_fakes.servgroup_members_num),
+ '--gigabytes', str(compute_fakes.floating_ip_num),
+ '--snapshots', str(compute_fakes.fix_ip_num),
+ '--volumes', str(volume_fakes.QUOTA['volumes']),
+ '--network', str(network_fakes.QUOTA['network']),
+ '--class', identity_fakes.project_name,
+ ]
+ verifylist = [
+ ('injected_files', compute_fakes.injected_file_num),
+ ('injected_file_content_bytes',
+ compute_fakes.injected_file_size_num),
+ ('injected_file_path_bytes', compute_fakes.injected_path_size_num),
+ ('key_pairs', compute_fakes.key_pair_num),
+ ('cores', compute_fakes.core_num),
+ ('ram', compute_fakes.ram_num),
+ ('instances', compute_fakes.instance_num),
+ ('metadata_items', compute_fakes.property_num),
+ ('server_groups', compute_fakes.servgroup_num),
+ ('server_group_members', compute_fakes.servgroup_members_num),
+ ('gigabytes', compute_fakes.floating_ip_num),
+ ('snapshots', compute_fakes.fix_ip_num),
+ ('volumes', volume_fakes.QUOTA['volumes']),
+ ('network', network_fakes.QUOTA['network']),
+ ('project', identity_fakes.project_name),
+ ('quota_class', True),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ kwargs_compute = {
+ 'injected_files': compute_fakes.injected_file_num,
+ 'injected_file_content_bytes':
+ compute_fakes.injected_file_size_num,
+ 'injected_file_path_bytes': compute_fakes.injected_path_size_num,
+ 'key_pairs': compute_fakes.key_pair_num,
+ 'cores': compute_fakes.core_num,
+ 'ram': compute_fakes.ram_num,
+ 'instances': compute_fakes.instance_num,
+ 'metadata_items': compute_fakes.property_num,
+ 'server_groups': compute_fakes.servgroup_num,
+ 'server_group_members': compute_fakes.servgroup_members_num,
+ }
+ kwargs_volume = {
+ 'gigabytes': compute_fakes.floating_ip_num,
+ 'snapshots': compute_fakes.fix_ip_num,
+ 'volumes': volume_fakes.QUOTA['volumes'],
+ }
+
+ self.quotas_class_mock.update.assert_called_with(
+ identity_fakes.project_name,
+ **kwargs_compute
+ )
+ self.volume_quotas_class_mock.update.assert_called_with(
+ identity_fakes.project_name,
+ **kwargs_volume
+ )
+ self.assertNotCalled(self.network_mock.update_quota)
+ self.assertIsNone(result)
class TestQuotaShow(TestQuota):
@@ -269,13 +396,13 @@ class TestQuotaShow(TestQuota):
self.volume_quotas_mock.get.return_value = FakeQuotaResource(
None,
- copy.deepcopy(compute_fakes.QUOTA),
+ copy.deepcopy(volume_fakes.QUOTA),
loaded=True,
)
self.volume_quotas_mock.defaults.return_value = FakeQuotaResource(
None,
- copy.deepcopy(compute_fakes.QUOTA),
+ copy.deepcopy(volume_fakes.QUOTA),
loaded=True,
)
@@ -297,7 +424,7 @@ class TestQuotaShow(TestQuota):
self.volume_quotas_class_mock.get.return_value = FakeQuotaResource(
None,
- copy.deepcopy(compute_fakes.QUOTA),
+ copy.deepcopy(volume_fakes.QUOTA),
loaded=True,
)
@@ -313,6 +440,8 @@ class TestQuotaShow(TestQuota):
)
self.network = self.app.client_manager.network
self.network.get_quota = mock.Mock(return_value=network_fakes.QUOTA)
+ self.network.get_quota_default = mock.Mock(
+ return_value=network_fakes.QUOTA)
self.cmd = quota.ShowQuota(self.app, None)
@@ -328,10 +457,12 @@ class TestQuotaShow(TestQuota):
self.cmd.take_action(parsed_args)
- self.quotas_mock.get.assert_called_with(identity_fakes.project_id)
- self.volume_quotas_mock.get.assert_called_with(
+ self.quotas_mock.get.assert_called_once_with(identity_fakes.project_id)
+ self.volume_quotas_mock.get.assert_called_once_with(
identity_fakes.project_id)
- self.network.get_quota.assert_called_with(identity_fakes.project_id)
+ self.network.get_quota.assert_called_once_with(
+ identity_fakes.project_id)
+ self.assertNotCalled(self.network.get_quota_default)
def test_quota_show_with_default(self):
arglist = [
@@ -347,9 +478,13 @@ class TestQuotaShow(TestQuota):
self.cmd.take_action(parsed_args)
- self.quotas_mock.defaults.assert_called_with(identity_fakes.project_id)
- self.volume_quotas_mock.defaults.assert_called_with(
+ self.quotas_mock.defaults.assert_called_once_with(
+ identity_fakes.project_id)
+ self.volume_quotas_mock.defaults.assert_called_once_with(
+ identity_fakes.project_id)
+ self.network.get_quota_default.assert_called_once_with(
identity_fakes.project_id)
+ self.assertNotCalled(self.network.get_quota)
def test_quota_show_with_class(self):
arglist = [
@@ -365,17 +500,21 @@ class TestQuotaShow(TestQuota):
self.cmd.take_action(parsed_args)
- self.quotas_class_mock.get.assert_called_with(
- identity_fakes.project_id)
- self.volume_quotas_class_mock.get.assert_called_with(
- identity_fakes.project_id)
+ self.quotas_class_mock.get.assert_called_once_with(
+ identity_fakes.project_name)
+ self.volume_quotas_class_mock.get.assert_called_once_with(
+ identity_fakes.project_name)
+ self.assertNotCalled(self.network.get_quota)
+ self.assertNotCalled(self.network.get_quota_default)
def test_quota_show_no_project(self):
parsed_args = self.check_parser(self.cmd, [], [])
self.cmd.take_action(parsed_args)
- self.quotas_mock.get.assert_called_with(identity_fakes.project_id)
- self.volume_quotas_mock.get.assert_called_with(
+ self.quotas_mock.get.assert_called_once_with(identity_fakes.project_id)
+ self.volume_quotas_mock.get.assert_called_once_with(
+ identity_fakes.project_id)
+ self.network.get_quota.assert_called_once_with(
identity_fakes.project_id)
- self.network.get_quota.assert_called_with(identity_fakes.project_id)
+ self.assertNotCalled(self.network.get_quota_default)
diff --git a/openstackclient/tests/unit/compute/v2/fakes.py b/openstackclient/tests/unit/compute/v2/fakes.py
index 0e3d47ba..3c829773 100644
--- a/openstackclient/tests/unit/compute/v2/fakes.py
+++ b/openstackclient/tests/unit/compute/v2/fakes.py
@@ -128,7 +128,7 @@ class FakeAggregate(object):
"""
if aggregates is None:
aggregates = FakeAggregate.create_aggregates(count)
- return mock.MagicMock(side_effect=aggregates)
+ return mock.Mock(side_effect=aggregates)
class FakeComputev2Client(object):
@@ -519,7 +519,7 @@ class FakeSecurityGroup(object):
"""
if security_groups is None:
security_groups = FakeSecurityGroup.create_security_groups(count)
- return mock.MagicMock(side_effect=security_groups)
+ return mock.Mock(side_effect=security_groups)
class FakeSecurityGroupRule(object):
@@ -649,7 +649,7 @@ class FakeServer(object):
"""
if servers is None:
servers = FakeServer.create_servers(count)
- return mock.MagicMock(side_effect=servers)
+ return mock.Mock(side_effect=servers)
class FakeService(object):
@@ -788,7 +788,7 @@ class FakeFlavor(object):
"""
if flavors is None:
flavors = FakeFlavor.create_flavors(count)
- return mock.MagicMock(side_effect=flavors)
+ return mock.Mock(side_effect=flavors)
class FakeFlavorAccess(object):
@@ -887,7 +887,7 @@ class FakeKeypair(object):
"""
if keypairs is None:
keypairs = FakeKeypair.create_keypairs(count)
- return mock.MagicMock(side_effect=keypairs)
+ return mock.Mock(side_effect=keypairs)
class FakeAvailabilityZone(object):
@@ -1011,7 +1011,7 @@ class FakeFloatingIP(object):
"""
if floating_ips is None:
floating_ips = FakeFloatingIP.create_floating_ips(count)
- return mock.MagicMock(side_effect=floating_ips)
+ return mock.Mock(side_effect=floating_ips)
class FakeFloatingIPPool(object):
diff --git a/openstackclient/tests/unit/compute/v2/test_flavor.py b/openstackclient/tests/unit/compute/v2/test_flavor.py
index ace650eb..93ad9d14 100644
--- a/openstackclient/tests/unit/compute/v2/test_flavor.py
+++ b/openstackclient/tests/unit/compute/v2/test_flavor.py
@@ -292,7 +292,7 @@ class TestFlavorDelete(TestFlavor):
find_mock_result = [self.flavors[0], exceptions.CommandError]
self.flavors_mock.get = (
- mock.MagicMock(side_effect=find_mock_result)
+ mock.Mock(side_effect=find_mock_result)
)
self.flavors_mock.find.side_effect = exceptions.NotFound(None)
diff --git a/openstackclient/tests/unit/compute/v2/test_hypervisor.py b/openstackclient/tests/unit/compute/v2/test_hypervisor.py
index d94a107c..e39570af 100644
--- a/openstackclient/tests/unit/compute/v2/test_hypervisor.py
+++ b/openstackclient/tests/unit/compute/v2/test_hypervisor.py
@@ -15,6 +15,7 @@
import copy
+from novaclient import exceptions as nova_exceptions
from osc_lib import exceptions
from openstackclient.compute.v2 import hypervisor
@@ -159,10 +160,12 @@ class TestHypervisorShow(TestHypervisor):
'free_disk_gb',
'free_ram_mb',
'host_ip',
+ 'host_time',
'hypervisor_hostname',
'hypervisor_type',
'hypervisor_version',
'id',
+ 'load_average',
'local_gb',
'local_gb_used',
'memory_mb',
@@ -172,6 +175,8 @@ class TestHypervisorShow(TestHypervisor):
'service_id',
'state',
'status',
+ 'uptime',
+ 'users',
'vcpus',
'vcpus_used',
)
@@ -183,10 +188,12 @@ class TestHypervisorShow(TestHypervisor):
50,
1024,
'192.168.0.10',
+ '01:28:24',
self.hypervisor.hypervisor_hostname,
'QEMU',
2004001,
self.hypervisor.id,
+ '0.94, 0.62, 0.50',
50,
0,
1024,
@@ -196,6 +203,8 @@ class TestHypervisorShow(TestHypervisor):
1,
'up',
'enabled',
+ '3 days, 11:15',
+ '1',
4,
0,
)
@@ -219,3 +228,72 @@ class TestHypervisorShow(TestHypervisor):
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data)
+
+ def test_hyprvisor_show_uptime_not_implemented(self):
+ arglist = [
+ self.hypervisor.hypervisor_hostname,
+ ]
+ verifylist = [
+ ('hypervisor', self.hypervisor.hypervisor_hostname),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.hypervisors_mock.uptime.side_effect = (
+ nova_exceptions.HTTPNotImplemented(501))
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ expected_columns = (
+ 'aggregates',
+ 'cpu_info',
+ 'current_workload',
+ 'disk_available_least',
+ 'free_disk_gb',
+ 'free_ram_mb',
+ 'host_ip',
+ 'hypervisor_hostname',
+ 'hypervisor_type',
+ 'hypervisor_version',
+ 'id',
+ 'local_gb',
+ 'local_gb_used',
+ 'memory_mb',
+ 'memory_mb_used',
+ 'running_vms',
+ 'service_host',
+ 'service_id',
+ 'state',
+ 'status',
+ 'vcpus',
+ 'vcpus_used',
+ )
+ expected_data = (
+ [],
+ {'aaa': 'aaa'},
+ 0,
+ 50,
+ 50,
+ 1024,
+ '192.168.0.10',
+ self.hypervisor.hypervisor_hostname,
+ 'QEMU',
+ 2004001,
+ self.hypervisor.id,
+ 50,
+ 0,
+ 1024,
+ 512,
+ 0,
+ 'aaa',
+ 1,
+ 'up',
+ 'enabled',
+ 4,
+ 0,
+ )
+
+ self.assertEqual(expected_columns, columns)
+ self.assertEqual(expected_data, data)
diff --git a/openstackclient/tests/unit/compute/v2/test_server.py b/openstackclient/tests/unit/compute/v2/test_server.py
index d4843f51..1081b9a3 100644
--- a/openstackclient/tests/unit/compute/v2/test_server.py
+++ b/openstackclient/tests/unit/compute/v2/test_server.py
@@ -417,7 +417,7 @@ class TestServerCreate(TestServer):
@mock.patch('openstackclient.compute.v2.server.io.open')
def test_server_create_userdata(self, mock_open):
- mock_file = mock.MagicMock(name='File')
+ mock_file = mock.Mock(name='File')
mock_open.return_value = mock_file
mock_open.read.return_value = '#!/bin/sh'
diff --git a/openstackclient/tests/unit/compute/v2/test_server_backup.py b/openstackclient/tests/unit/compute/v2/test_server_backup.py
index 9aa63fc7..9a481e0a 100644
--- a/openstackclient/tests/unit/compute/v2/test_server_backup.py
+++ b/openstackclient/tests/unit/compute/v2/test_server_backup.py
@@ -101,7 +101,7 @@ class TestServerBackupCreate(TestServerBackup):
count=count,
)
- self.images_mock.get = mock.MagicMock(side_effect=images)
+ self.images_mock.get = mock.Mock(side_effect=images)
return images
def test_server_backup_defaults(self):
@@ -181,7 +181,7 @@ class TestServerBackupCreate(TestServerBackup):
count=5,
)
- self.images_mock.get = mock.MagicMock(
+ self.images_mock.get = mock.Mock(
side_effect=images,
)
@@ -230,7 +230,7 @@ class TestServerBackupCreate(TestServerBackup):
count=5,
)
- self.images_mock.get = mock.MagicMock(
+ self.images_mock.get = mock.Mock(
side_effect=images,
)
diff --git a/openstackclient/tests/unit/compute/v2/test_server_image.py b/openstackclient/tests/unit/compute/v2/test_server_image.py
index f53f08e6..47bd682f 100644
--- a/openstackclient/tests/unit/compute/v2/test_server_image.py
+++ b/openstackclient/tests/unit/compute/v2/test_server_image.py
@@ -99,8 +99,8 @@ class TestServerImageCreate(TestServerImage):
count=count,
)
- self.images_mock.get = mock.MagicMock(side_effect=images)
- self.servers_mock.create_image = mock.MagicMock(
+ self.images_mock.get = mock.Mock(side_effect=images)
+ self.servers_mock.create_image = mock.Mock(
return_value=images[0].id,
)
return images
diff --git a/openstackclient/tests/unit/compute/v2/test_service.py b/openstackclient/tests/unit/compute/v2/test_service.py
index 1fd3b7d5..8403efc9 100644
--- a/openstackclient/tests/unit/compute/v2/test_service.py
+++ b/openstackclient/tests/unit/compute/v2/test_service.py
@@ -89,7 +89,7 @@ class TestServiceDelete(TestService):
delete_mock_result = [None, exceptions.CommandError]
self.service_mock.delete = (
- mock.MagicMock(side_effect=delete_mock_result)
+ mock.Mock(side_effect=delete_mock_result)
)
try:
diff --git a/openstackclient/tests/unit/fakes.py b/openstackclient/tests/unit/fakes.py
index 786cd6d4..f2598366 100644
--- a/openstackclient/tests/unit/fakes.py
+++ b/openstackclient/tests/unit/fakes.py
@@ -200,7 +200,7 @@ class FakeResource(object):
returned, which looks like a function call.
"""
for (name, ret) in six.iteritems(methods):
- method = mock.MagicMock(return_value=ret)
+ method = mock.Mock(return_value=ret)
setattr(self, name, method)
def __repr__(self):
diff --git a/openstackclient/tests/unit/identity/v2_0/test_catalog.py b/openstackclient/tests/unit/identity/v2_0/test_catalog.py
index c32f9fb8..65af58a2 100644
--- a/openstackclient/tests/unit/identity/v2_0/test_catalog.py
+++ b/openstackclient/tests/unit/identity/v2_0/test_catalog.py
@@ -25,12 +25,12 @@ class TestCatalog(utils.TestCommand):
def setUp(self):
super(TestCatalog, self).setUp()
- self.sc_mock = mock.MagicMock()
+ self.sc_mock = mock.Mock()
self.sc_mock.service_catalog.catalog.return_value = [
self.service_catalog,
]
- self.auth_mock = mock.MagicMock()
+ self.auth_mock = mock.Mock()
self.app.client_manager.session = self.auth_mock
self.auth_mock.auth.get_auth_ref.return_value = self.sc_mock
diff --git a/openstackclient/tests/unit/identity/v2_0/test_role_assignment.py b/openstackclient/tests/unit/identity/v2_0/test_role_assignment.py
index 27306959..87643f12 100644
--- a/openstackclient/tests/unit/identity/v2_0/test_role_assignment.py
+++ b/openstackclient/tests/unit/identity/v2_0/test_role_assignment.py
@@ -170,7 +170,7 @@ class TestRoleAssignmentList(TestRoleAssignment):
def test_role_assignment_list_def_creds(self):
- auth_ref = self.app.client_manager.auth_ref = mock.MagicMock()
+ auth_ref = self.app.client_manager.auth_ref = mock.Mock()
auth_ref.project_id.return_value = identity_fakes.project_id
auth_ref.user_id.return_value = identity_fakes.user_id
diff --git a/openstackclient/tests/unit/identity/v3/fakes.py b/openstackclient/tests/unit/identity/v3/fakes.py
index 7b76fa60..75065e65 100644
--- a/openstackclient/tests/unit/identity/v3/fakes.py
+++ b/openstackclient/tests/unit/identity/v3/fakes.py
@@ -719,7 +719,7 @@ class FakeCredential(object):
if credentials is None:
credentials = FakeCredential.create_credentials(count)
- return mock.MagicMock(side_effect=credentials)
+ return mock.Mock(side_effect=credentials)
class FakeUser(object):
@@ -819,7 +819,7 @@ class FakeGroup(object):
if groups is None:
groups = FakeGroup.create_groups(count)
- return mock.MagicMock(side_effect=groups)
+ return mock.Mock(side_effect=groups)
class FakeEndpoint(object):
diff --git a/openstackclient/tests/unit/identity/v3/test_catalog.py b/openstackclient/tests/unit/identity/v3/test_catalog.py
index 986c05f3..53008e8c 100644
--- a/openstackclient/tests/unit/identity/v3/test_catalog.py
+++ b/openstackclient/tests/unit/identity/v3/test_catalog.py
@@ -50,12 +50,12 @@ class TestCatalog(utils.TestCommand):
def setUp(self):
super(TestCatalog, self).setUp()
- self.sc_mock = mock.MagicMock()
+ self.sc_mock = mock.Mock()
self.sc_mock.service_catalog.catalog.return_value = [
self.fake_service,
]
- self.auth_mock = mock.MagicMock()
+ self.auth_mock = mock.Mock()
self.app.client_manager.session = self.auth_mock
self.auth_mock.auth.get_auth_ref.return_value = self.sc_mock
diff --git a/openstackclient/tests/unit/identity/v3/test_credential.py b/openstackclient/tests/unit/identity/v3/test_credential.py
index fd3ae6b2..ce0fb5ae 100644
--- a/openstackclient/tests/unit/identity/v3/test_credential.py
+++ b/openstackclient/tests/unit/identity/v3/test_credential.py
@@ -196,7 +196,7 @@ class TestCredentialDelete(TestCredential):
delete_mock_result = [None, exceptions.CommandError]
self.credentials_mock.delete = (
- mock.MagicMock(side_effect=delete_mock_result)
+ mock.Mock(side_effect=delete_mock_result)
)
try:
diff --git a/openstackclient/tests/unit/identity/v3/test_group.py b/openstackclient/tests/unit/identity/v3/test_group.py
index d35e98c6..eb50adb5 100644
--- a/openstackclient/tests/unit/identity/v3/test_group.py
+++ b/openstackclient/tests/unit/identity/v3/test_group.py
@@ -239,7 +239,7 @@ class TestGroupDelete(TestGroup):
def test_group_delete_with_domain(self):
get_mock_result = [exceptions.CommandError, self.groups[0]]
self.groups_mock.get = (
- mock.MagicMock(side_effect=get_mock_result))
+ mock.Mock(side_effect=get_mock_result))
arglist = [
'--domain', self.domain.id,
@@ -487,7 +487,7 @@ class TestGroupSet(TestGroup):
def test_group_set_with_domain(self):
get_mock_result = [exceptions.CommandError, self.group]
self.groups_mock.get = (
- mock.MagicMock(side_effect=get_mock_result))
+ mock.Mock(side_effect=get_mock_result))
arglist = [
'--domain', self.domain.id,
@@ -550,7 +550,7 @@ class TestGroupShow(TestGroup):
def test_group_show_with_domain(self):
get_mock_result = [exceptions.CommandError, self.group]
self.groups_mock.get = (
- mock.MagicMock(side_effect=get_mock_result))
+ mock.Mock(side_effect=get_mock_result))
arglist = [
'--domain', self.domain.id,
diff --git a/openstackclient/tests/unit/identity/v3/test_role_assignment.py b/openstackclient/tests/unit/identity/v3/test_role_assignment.py
index 7102a0cd..32fbb7f1 100644
--- a/openstackclient/tests/unit/identity/v3/test_role_assignment.py
+++ b/openstackclient/tests/unit/identity/v3/test_role_assignment.py
@@ -377,7 +377,7 @@ class TestRoleAssignmentList(TestRoleAssignment):
def test_role_assignment_list_def_creds(self):
- auth_ref = self.app.client_manager.auth_ref = mock.MagicMock()
+ auth_ref = self.app.client_manager.auth_ref = mock.Mock()
auth_ref.project_id.return_value = identity_fakes.project_id
auth_ref.user_id.return_value = identity_fakes.user_id
diff --git a/openstackclient/tests/unit/image/v1/test_image.py b/openstackclient/tests/unit/image/v1/test_image.py
index c62c1ff9..a6bc80a0 100644
--- a/openstackclient/tests/unit/image/v1/test_image.py
+++ b/openstackclient/tests/unit/image/v1/test_image.py
@@ -149,7 +149,7 @@ class TestImageCreate(TestImage):
@mock.patch('openstackclient.image.v1.image.io.open', name='Open')
def test_image_create_file(self, mock_open):
- mock_file = mock.MagicMock(name='File')
+ mock_file = mock.Mock(name='File')
mock_open.return_value = mock_file
mock_open.read.return_value = image_fakes.image_data
mock_exception = {
diff --git a/openstackclient/tests/unit/image/v2/fakes.py b/openstackclient/tests/unit/image/v2/fakes.py
index 4d9f6458..8e2f587d 100644
--- a/openstackclient/tests/unit/image/v2/fakes.py
+++ b/openstackclient/tests/unit/image/v2/fakes.py
@@ -245,7 +245,7 @@ class FakeImage(object):
if images is None:
images = FakeImage.create_images(count)
- return mock.MagicMock(side_effect=images)
+ return mock.Mock(side_effect=images)
@staticmethod
def get_image_columns(image=None):
diff --git a/openstackclient/tests/unit/network/v2/fakes.py b/openstackclient/tests/unit/network/v2/fakes.py
index d33b84c5..91aebf9f 100644
--- a/openstackclient/tests/unit/network/v2/fakes.py
+++ b/openstackclient/tests/unit/network/v2/fakes.py
@@ -33,7 +33,8 @@ QUOTA = {
"port": 50,
"vip": 10,
"member": 10,
- "health_monitor": 10,
+ "healthmonitor": 10,
+ "l7policy": 5,
}
@@ -136,7 +137,7 @@ class FakeAddressScope(object):
"""
if address_scopes is None:
address_scopes = FakeAddressScope.create_address_scopes(count)
- return mock.MagicMock(side_effect=address_scopes)
+ return mock.Mock(side_effect=address_scopes)
class FakeAvailabilityZone(object):
@@ -284,6 +285,7 @@ class FakeNetwork(object):
'id': 'network-id-' + uuid.uuid4().hex,
'name': 'network-name-' + uuid.uuid4().hex,
'status': 'ACTIVE',
+ 'description': 'network-description-' + uuid.uuid4().hex,
'tenant_id': 'project-id-' + uuid.uuid4().hex,
'admin_state_up': True,
'shared': False,
@@ -344,7 +346,7 @@ class FakeNetwork(object):
"""
if networks is None:
networks = FakeNetwork.create_networks(count)
- return mock.MagicMock(side_effect=networks)
+ return mock.Mock(side_effect=networks)
class FakeNetworkSegment(object):
@@ -491,7 +493,7 @@ class FakePort(object):
"""
if ports is None:
ports = FakePort.create_ports(count)
- return mock.MagicMock(side_effect=ports)
+ return mock.Mock(side_effect=ports)
class FakeNetworkAgent(object):
@@ -558,7 +560,7 @@ class FakeNetworkAgent(object):
"""
if agents is None:
agents = FakeNetworkAgent.create_network_agents(count)
- return mock.MagicMock(side_effect=agents)
+ return mock.Mock(side_effect=agents)
class FakeNetworkRBAC(object):
@@ -628,7 +630,7 @@ class FakeNetworkRBAC(object):
"""
if rbac_policies is None:
rbac_policies = FakeNetworkRBAC.create_network_rbacs(count)
- return mock.MagicMock(side_effect=rbac_policies)
+ return mock.Mock(side_effect=rbac_policies)
class FakeRouter(object):
@@ -706,7 +708,7 @@ class FakeRouter(object):
"""
if routers is None:
routers = FakeRouter.create_routers(count)
- return mock.MagicMock(side_effect=routers)
+ return mock.Mock(side_effect=routers)
class FakeSecurityGroup(object):
@@ -779,7 +781,7 @@ class FakeSecurityGroup(object):
"""
if security_groups is None:
security_groups = FakeSecurityGroup.create_security_groups(count)
- return mock.MagicMock(side_effect=security_groups)
+ return mock.Mock(side_effect=security_groups)
class FakeSecurityGroupRule(object):
@@ -858,7 +860,7 @@ class FakeSecurityGroupRule(object):
if security_group_rules is None:
security_group_rules = (
FakeSecurityGroupRule.create_security_group_rules(count))
- return mock.MagicMock(side_effect=security_group_rules)
+ return mock.Mock(side_effect=security_group_rules)
class FakeSubnet(object):
@@ -894,6 +896,7 @@ class FakeSubnet(object):
'segment_id': None,
'service_types': [],
'subnetpool_id': None,
+ 'description': 'subnet-description-' + uuid.uuid4().hex,
}
# Overwrite default attributes.
@@ -941,7 +944,7 @@ class FakeSubnet(object):
"""
if subnets is None:
subnets = FakeSubnet.create_subnets(count)
- return mock.MagicMock(side_effect=subnets)
+ return mock.Mock(side_effect=subnets)
class FakeFloatingIP(object):
@@ -1018,7 +1021,7 @@ class FakeFloatingIP(object):
"""
if floating_ips is None:
floating_ips = FakeFloatingIP.create_floating_ips(count)
- return mock.MagicMock(side_effect=floating_ips)
+ return mock.Mock(side_effect=floating_ips)
class FakeSubnetPool(object):
@@ -1049,6 +1052,7 @@ class FakeSubnetPool(object):
'min_prefixlen': '8',
'default_quota': None,
'ip_version': '4',
+ 'description': 'subnet-pool-description-' + uuid.uuid4().hex,
}
# Overwrite default attributes.
@@ -1100,4 +1104,4 @@ class FakeSubnetPool(object):
"""
if subnet_pools is None:
subnet_pools = FakeSubnetPool.create_subnet_pools(count)
- return mock.MagicMock(side_effect=subnet_pools)
+ return mock.Mock(side_effect=subnet_pools)
diff --git a/openstackclient/tests/unit/network/v2/test_address_scope.py b/openstackclient/tests/unit/network/v2/test_address_scope.py
index 6d3f4011..12c3f1d6 100644
--- a/openstackclient/tests/unit/network/v2/test_address_scope.py
+++ b/openstackclient/tests/unit/network/v2/test_address_scope.py
@@ -216,7 +216,7 @@ class TestDeleteAddressScope(TestAddressScope):
find_mock_result = [self._address_scopes[0], exceptions.CommandError]
self.network.find_address_scope = (
- mock.MagicMock(side_effect=find_mock_result)
+ mock.Mock(side_effect=find_mock_result)
)
try:
diff --git a/openstackclient/tests/unit/network/v2/test_floating_ip.py b/openstackclient/tests/unit/network/v2/test_floating_ip.py
index a40e48f4..a77fb24b 100644
--- a/openstackclient/tests/unit/network/v2/test_floating_ip.py
+++ b/openstackclient/tests/unit/network/v2/test_floating_ip.py
@@ -204,7 +204,7 @@ class TestDeleteFloatingIPNetwork(TestFloatingIPNetwork):
find_mock_result = [self.floating_ips[0], exceptions.CommandError]
self.network.find_ip = (
- mock.MagicMock(side_effect=find_mock_result)
+ mock.Mock(side_effect=find_mock_result)
)
try:
@@ -454,7 +454,7 @@ class TestDeleteFloatingIPCompute(TestFloatingIPCompute):
find_mock_result = [self.floating_ips[0], exceptions.CommandError]
self.compute.floating_ips.get = (
- mock.MagicMock(side_effect=find_mock_result)
+ mock.Mock(side_effect=find_mock_result)
)
self.compute.floating_ips.find.side_effect = exceptions.NotFound(None)
diff --git a/openstackclient/tests/unit/network/v2/test_network.py b/openstackclient/tests/unit/network/v2/test_network.py
index 84ead093..1094131e 100644
--- a/openstackclient/tests/unit/network/v2/test_network.py
+++ b/openstackclient/tests/unit/network/v2/test_network.py
@@ -57,6 +57,7 @@ class TestCreateNetworkIdentityV3(TestNetwork):
'admin_state_up',
'availability_zone_hints',
'availability_zones',
+ 'description',
'id',
'is_default',
'name',
@@ -73,6 +74,7 @@ class TestCreateNetworkIdentityV3(TestNetwork):
network._format_admin_state(_network.admin_state_up),
utils.format_list(_network.availability_zone_hints),
utils.format_list(_network.availability_zones),
+ _network.description,
_network.id,
_network.is_default,
_network.name,
@@ -129,6 +131,7 @@ class TestCreateNetworkIdentityV3(TestNetwork):
arglist = [
"--disable",
"--share",
+ "--description", self._network.description,
"--project", self.project.name,
"--project-domain", self.domain.name,
"--availability-zone-hint", "nova",
@@ -143,6 +146,7 @@ class TestCreateNetworkIdentityV3(TestNetwork):
verifylist = [
('disable', True),
('share', True),
+ ('description', self._network.description),
('project', self.project.name),
('project_domain', self.domain.name),
('availability_zone_hints', ["nova"]),
@@ -164,6 +168,7 @@ class TestCreateNetworkIdentityV3(TestNetwork):
'availability_zone_hints': ["nova"],
'name': self._network.name,
'shared': True,
+ 'description': self._network.description,
'tenant_id': self.project.id,
'is_default': True,
'router:external': True,
@@ -216,6 +221,7 @@ class TestCreateNetworkIdentityV2(TestNetwork):
'admin_state_up',
'availability_zone_hints',
'availability_zones',
+ 'description',
'id',
'is_default',
'name',
@@ -232,6 +238,7 @@ class TestCreateNetworkIdentityV2(TestNetwork):
network._format_admin_state(_network.admin_state_up),
utils.format_list(_network.availability_zone_hints),
utils.format_list(_network.availability_zones),
+ _network.description,
_network.id,
_network.is_default,
_network.name,
@@ -532,6 +539,7 @@ class TestSetNetwork(TestNetwork):
'--enable',
'--name', 'noob',
'--share',
+ '--description', self._network.description,
'--external',
'--default',
'--provider-network-type', 'vlan',
@@ -543,6 +551,7 @@ class TestSetNetwork(TestNetwork):
verifylist = [
('network', self._network.name),
('enable', True),
+ ('description', self._network.description),
('name', 'noob'),
('share', True),
('external', True),
@@ -560,6 +569,7 @@ class TestSetNetwork(TestNetwork):
attrs = {
'name': 'noob',
'admin_state_up': True,
+ 'description': self._network.description,
'shared': True,
'router:external': True,
'is_default': True,
@@ -624,6 +634,7 @@ class TestShowNetwork(TestNetwork):
'admin_state_up',
'availability_zone_hints',
'availability_zones',
+ 'description',
'id',
'is_default',
'name',
@@ -640,6 +651,7 @@ class TestShowNetwork(TestNetwork):
network._format_admin_state(_network.admin_state_up),
utils.format_list(_network.availability_zone_hints),
utils.format_list(_network.availability_zones),
+ _network.description,
_network.id,
_network.is_default,
_network.name,
diff --git a/openstackclient/tests/unit/network/v2/test_network_agent.py b/openstackclient/tests/unit/network/v2/test_network_agent.py
index 2f17f41b..9f5b442a 100644
--- a/openstackclient/tests/unit/network/v2/test_network_agent.py
+++ b/openstackclient/tests/unit/network/v2/test_network_agent.py
@@ -96,7 +96,7 @@ class TestDeleteNetworkAgent(TestNetworkAgent):
find_mock_result = [self.network_agents[0], exceptions.CommandError]
self.network.get_agent = (
- mock.MagicMock(side_effect=find_mock_result)
+ mock.Mock(side_effect=find_mock_result)
)
try:
diff --git a/openstackclient/tests/unit/network/v2/test_network_rbac.py b/openstackclient/tests/unit/network/v2/test_network_rbac.py
index 1cd18a09..c526ae4e 100644
--- a/openstackclient/tests/unit/network/v2/test_network_rbac.py
+++ b/openstackclient/tests/unit/network/v2/test_network_rbac.py
@@ -259,7 +259,7 @@ class TestDeleteNetworkRBAC(TestNetworkRBAC):
find_mock_result = [self.rbac_policies[0], exceptions.CommandError]
self.network.find_rbac_policy = (
- mock.MagicMock(side_effect=find_mock_result)
+ mock.Mock(side_effect=find_mock_result)
)
try:
diff --git a/openstackclient/tests/unit/network/v2/test_port.py b/openstackclient/tests/unit/network/v2/test_port.py
index d5d7f330..271e8160 100644
--- a/openstackclient/tests/unit/network/v2/test_port.py
+++ b/openstackclient/tests/unit/network/v2/test_port.py
@@ -19,6 +19,7 @@ from osc_lib import exceptions
from osc_lib import utils
from openstackclient.network.v2 import port
+from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
from openstackclient.tests.unit.network.v2 import fakes as network_fakes
from openstackclient.tests.unit import utils as tests_utils
@@ -289,7 +290,7 @@ class TestDeletePort(TestPort):
find_mock_result = [self._ports[0], exceptions.CommandError]
self.network.find_port = (
- mock.MagicMock(side_effect=find_mock_result)
+ mock.Mock(side_effect=find_mock_result)
)
try:
@@ -336,7 +337,12 @@ class TestListPort(TestPort):
fake_router = network_fakes.FakeRouter.create_one_router({
'id': 'fake-router-id',
})
+ fake_network = network_fakes.FakeNetwork.create_one_network({
+ 'id': 'fake-network-id',
+ })
self.network.find_router = mock.Mock(return_value=fake_router)
+ self.network.find_network = mock.Mock(return_value=fake_network)
+ self.app.client_manager.compute = mock.Mock()
def test_port_list_no_options(self):
arglist = []
@@ -369,6 +375,26 @@ class TestListPort(TestPort):
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, list(data))
+ @mock.patch.object(utils, 'find_resource')
+ def test_port_list_with_server_option(self, mock_find):
+ fake_server = compute_fakes.FakeServer.create_one_server()
+ mock_find.return_value = fake_server
+
+ arglist = [
+ '--server', 'fake-server-name',
+ ]
+ verifylist = [
+ ('server', 'fake-server-name'),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+ self.network.ports.assert_called_once_with(
+ device_id=fake_server.id)
+ mock_find.assert_called_once_with(mock.ANY, 'fake-server-name')
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
def test_port_list_device_owner_opt(self):
arglist = [
'--device-owner', self._ports[0].device_owner,
@@ -392,11 +418,13 @@ class TestListPort(TestPort):
arglist = [
'--device-owner', self._ports[0].device_owner,
'--router', 'fake-router-name',
+ '--network', 'fake-network-name',
]
verifylist = [
('device_owner', self._ports[0].device_owner),
- ('router', 'fake-router-name')
+ ('router', 'fake-router-name'),
+ ('network', 'fake-network-name')
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -405,7 +433,8 @@ class TestListPort(TestPort):
self.network.ports.assert_called_once_with(**{
'device_owner': self._ports[0].device_owner,
- 'device_id': 'fake-router-id'
+ 'device_id': 'fake-router-id',
+ 'network_id': 'fake-network-id'
})
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, list(data))
diff --git a/openstackclient/tests/unit/network/v2/test_router.py b/openstackclient/tests/unit/network/v2/test_router.py
index 26fe655e..5ed969b4 100644
--- a/openstackclient/tests/unit/network/v2/test_router.py
+++ b/openstackclient/tests/unit/network/v2/test_router.py
@@ -40,7 +40,7 @@ class TestAddPortToRouter(TestRouter):
def setUp(self):
super(TestAddPortToRouter, self).setUp()
- self.network.router_add_interface = mock.Mock()
+ self.network.add_interface_to_router = mock.Mock()
self.cmd = router.AddPortToRouter(self.app, self.namespace)
self.network.find_router = mock.Mock(return_value=self._router)
self.network.find_port = mock.Mock(return_value=self._port)
@@ -65,9 +65,8 @@ class TestAddPortToRouter(TestRouter):
result = self.cmd.take_action(parsed_args)
- self.network.router_add_interface.assert_called_with(self._router, **{
- 'port_id': self._router.port,
- })
+ self.network.add_interface_to_router.assert_called_with(
+ self._router, **{'port_id': self._router.port, })
self.assertIsNone(result)
@@ -80,7 +79,7 @@ class TestAddSubnetToRouter(TestRouter):
def setUp(self):
super(TestAddSubnetToRouter, self).setUp()
- self.network.router_add_interface = mock.Mock()
+ self.network.add_interface_to_router = mock.Mock()
self.cmd = router.AddSubnetToRouter(self.app, self.namespace)
self.network.find_router = mock.Mock(return_value=self._router)
self.network.find_subnet = mock.Mock(return_value=self._subnet)
@@ -104,7 +103,7 @@ class TestAddSubnetToRouter(TestRouter):
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
- self.network.router_add_interface.assert_called_with(
+ self.network.add_interface_to_router.assert_called_with(
self._router, **{'subnet_id': self._router.subnet})
self.assertIsNone(result)
@@ -263,7 +262,7 @@ class TestDeleteRouter(TestRouter):
find_mock_result = [self._routers[0], exceptions.CommandError]
self.network.find_router = (
- mock.MagicMock(side_effect=find_mock_result)
+ mock.Mock(side_effect=find_mock_result)
)
try:
@@ -285,6 +284,7 @@ class TestListRouter(TestRouter):
# The routers going to be listed up.
routers = network_fakes.FakeRouter.create_routers(count=3)
+ _extensions = network_fakes.FakeExtension.create_one_extension()
columns = (
'ID',
@@ -300,6 +300,10 @@ class TestListRouter(TestRouter):
'External gateway info',
'Availability zones'
)
+ columns_long_no_az = columns + (
+ 'Routes',
+ 'External gateway info',
+ )
data = []
for r in routers:
@@ -322,6 +326,15 @@ class TestListRouter(TestRouter):
osc_utils.format_list(r.availability_zones),
)
)
+ data_long_no_az = []
+ for i in range(0, len(routers)):
+ r = routers[i]
+ data_long_no_az.append(
+ data[i] + (
+ router._format_routes(r.routes),
+ router._format_external_gateway_info(r.external_gateway_info),
+ )
+ )
def setUp(self):
super(TestListRouter, self).setUp()
@@ -330,6 +343,7 @@ class TestListRouter(TestRouter):
self.cmd = router.ListRouter(self.app, self.namespace)
self.network.routers = mock.Mock(return_value=self.routers)
+ self.network.find_extension = mock.Mock(return_value=self._extensions)
def test_router_list_no_options(self):
arglist = []
@@ -365,6 +379,27 @@ class TestListRouter(TestRouter):
self.assertEqual(self.columns_long, columns)
self.assertEqual(self.data_long, list(data))
+ def test_router_list_long_no_az(self):
+ arglist = [
+ '--long',
+ ]
+ verifylist = [
+ ('long', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # to mock, that no availability zone
+ self.network.find_extension = mock.Mock(return_value=None)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.routers.assert_called_once_with()
+ self.assertEqual(self.columns_long_no_az, columns)
+ self.assertEqual(self.data_long_no_az, list(data))
+
class TestRemovePortFromRouter(TestRouter):
'''Remove port from a Router '''
@@ -375,7 +410,7 @@ class TestRemovePortFromRouter(TestRouter):
def setUp(self):
super(TestRemovePortFromRouter, self).setUp()
- self.network.router_remove_interface = mock.Mock()
+ self.network.remove_interface_from_router = mock.Mock()
self.cmd = router.RemovePortFromRouter(self.app, self.namespace)
self.network.find_router = mock.Mock(return_value=self._router)
self.network.find_port = mock.Mock(return_value=self._port)
@@ -400,7 +435,7 @@ class TestRemovePortFromRouter(TestRouter):
result = self.cmd.take_action(parsed_args)
- self.network.router_remove_interface.assert_called_with(
+ self.network.remove_interface_from_router.assert_called_with(
self._router, **{'port_id': self._router.port})
self.assertIsNone(result)
@@ -414,7 +449,7 @@ class TestRemoveSubnetFromRouter(TestRouter):
def setUp(self):
super(TestRemoveSubnetFromRouter, self).setUp()
- self.network.router_remove_interface = mock.Mock()
+ self.network.remove_interface_from_router = mock.Mock()
self.cmd = router.RemoveSubnetFromRouter(self.app, self.namespace)
self.network.find_router = mock.Mock(return_value=self._router)
self.network.find_subnet = mock.Mock(return_value=self._subnet)
@@ -438,7 +473,7 @@ class TestRemoveSubnetFromRouter(TestRouter):
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
- self.network.router_remove_interface.assert_called_with(
+ self.network.remove_interface_from_router.assert_called_with(
self._router, **{'subnet_id': self._router.subnet})
self.assertIsNone(result)
diff --git a/openstackclient/tests/unit/network/v2/test_security_group.py b/openstackclient/tests/unit/network/v2/test_security_group.py
index 4c5b2972..2615b77a 100644
--- a/openstackclient/tests/unit/network/v2/test_security_group.py
+++ b/openstackclient/tests/unit/network/v2/test_security_group.py
@@ -279,7 +279,7 @@ class TestDeleteSecurityGroupNetwork(TestSecurityGroupNetwork):
find_mock_result = [self._security_groups[0], exceptions.CommandError]
self.network.find_security_group = (
- mock.MagicMock(side_effect=find_mock_result)
+ mock.Mock(side_effect=find_mock_result)
)
try:
@@ -365,7 +365,7 @@ class TestDeleteSecurityGroupCompute(TestSecurityGroupCompute):
find_mock_result = [self._security_groups[0], exceptions.CommandError]
self.compute.security_groups.get = (
- mock.MagicMock(side_effect=find_mock_result)
+ mock.Mock(side_effect=find_mock_result)
)
self.compute.security_groups.find.side_effect = (
exceptions.NotFound(None))
diff --git a/openstackclient/tests/unit/network/v2/test_security_group_rule.py b/openstackclient/tests/unit/network/v2/test_security_group_rule.py
index 51e18a65..96d58e5c 100644
--- a/openstackclient/tests/unit/network/v2/test_security_group_rule.py
+++ b/openstackclient/tests/unit/network/v2/test_security_group_rule.py
@@ -723,7 +723,7 @@ class TestDeleteSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork):
find_mock_result = [
self._security_group_rules[0], exceptions.CommandError]
self.network.find_security_group_rule = (
- mock.MagicMock(side_effect=find_mock_result)
+ mock.Mock(side_effect=find_mock_result)
)
try:
@@ -803,7 +803,7 @@ class TestDeleteSecurityGroupRuleCompute(TestSecurityGroupRuleCompute):
find_mock_result = [None, exceptions.CommandError]
self.compute.security_group_rules.delete = (
- mock.MagicMock(side_effect=find_mock_result)
+ mock.Mock(side_effect=find_mock_result)
)
try:
diff --git a/openstackclient/tests/unit/network/v2/test_subnet.py b/openstackclient/tests/unit/network/v2/test_subnet.py
index e31db469..58506391 100644
--- a/openstackclient/tests/unit/network/v2/test_subnet.py
+++ b/openstackclient/tests/unit/network/v2/test_subnet.py
@@ -110,6 +110,7 @@ class TestCreateSubnet(TestSubnet):
columns = (
'allocation_pools',
'cidr',
+ 'description',
'dns_nameservers',
'enable_dhcp',
'gateway_ip',
@@ -129,6 +130,7 @@ class TestCreateSubnet(TestSubnet):
data = (
subnet_v2._format_allocation_pools(_subnet.allocation_pools),
_subnet.cidr,
+ _subnet.description,
utils.format_list(_subnet.dns_nameservers),
_subnet.enable_dhcp,
_subnet.gateway_ip,
@@ -148,6 +150,7 @@ class TestCreateSubnet(TestSubnet):
data_subnet_pool = (
subnet_v2._format_allocation_pools(_subnet_from_pool.allocation_pools),
_subnet_from_pool.cidr,
+ _subnet_from_pool.description,
utils.format_list(_subnet_from_pool.dns_nameservers),
_subnet_from_pool.enable_dhcp,
_subnet_from_pool.gateway_ip,
@@ -167,6 +170,7 @@ class TestCreateSubnet(TestSubnet):
data_ipv6 = (
subnet_v2._format_allocation_pools(_subnet_ipv6.allocation_pools),
_subnet_ipv6.cidr,
+ _subnet_ipv6.description,
utils.format_list(_subnet_ipv6.dns_nameservers),
_subnet_ipv6.enable_dhcp,
_subnet_ipv6.gateway_ip,
@@ -427,6 +431,40 @@ class TestCreateSubnet(TestSubnet):
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data)
+ def test_create_with_description(self):
+ # Mock SDK calls for this test.
+ self.network.create_subnet = mock.Mock(return_value=self._subnet)
+ self._network.id = self._subnet.network_id
+
+ arglist = [
+ "--subnet-range", self._subnet.cidr,
+ "--network", self._subnet.network_id,
+ "--description", self._subnet.description,
+ self._subnet.name,
+ ]
+ verifylist = [
+ ('name', self._subnet.name),
+ ('description', self._subnet.description),
+ ('subnet_range', self._subnet.cidr),
+ ('network', self._subnet.network_id),
+ ('ip_version', self._subnet.ip_version),
+ ('gateway', 'auto'),
+
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_subnet.assert_called_once_with(**{
+ 'cidr': self._subnet.cidr,
+ 'ip_version': self._subnet.ip_version,
+ 'name': self._subnet.name,
+ 'network_id': self._subnet.network_id,
+ 'description': self._subnet.description,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
class TestDeleteSubnet(TestSubnet):
@@ -489,7 +527,7 @@ class TestDeleteSubnet(TestSubnet):
find_mock_result = [self._subnets[0], exceptions.CommandError]
self.network.find_subnet = (
- mock.MagicMock(side_effect=find_mock_result)
+ mock.Mock(side_effect=find_mock_result)
)
try:
@@ -646,7 +684,6 @@ class TestListSubnet(TestSubnet):
('service_types', ['network:router_gateway']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
-
columns, data = self.cmd.take_action(parsed_args)
filters = {'service_types': ['network:router_gateway']}
@@ -654,6 +691,24 @@ class TestListSubnet(TestSubnet):
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, list(data))
+ def test_subnet_list_project(self):
+ project = identity_fakes_v3.FakeProject.create_one_project()
+ self.projects_mock.get.return_value = project
+ arglist = [
+ '--project', project.id,
+ ]
+ verifylist = [
+ ('project', project.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {'tenant_id': project.id}
+
+ self.network.subnets.assert_called_once_with(**filters)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
def test_subnet_list_service_type_multiple(self):
arglist = [
'--service-type', 'network:router_gateway',
@@ -668,6 +723,97 @@ class TestListSubnet(TestSubnet):
columns, data = self.cmd.take_action(parsed_args)
filters = {'service_types': ['network:router_gateway',
'network:floatingip_agent_gateway']}
+ self.network.subnets.assert_called_once_with(**filters)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_subnet_list_project_domain(self):
+ project = identity_fakes_v3.FakeProject.create_one_project()
+ self.projects_mock.get.return_value = project
+ arglist = [
+ '--project', project.id,
+ '--project-domain', project.domain_id,
+ ]
+ verifylist = [
+ ('project', project.id),
+ ('project_domain', project.domain_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {'tenant_id': project.id}
+
+ self.network.subnets.assert_called_once_with(**filters)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_subnet_list_network(self):
+ network = network_fakes.FakeNetwork.create_one_network()
+ self.network.find_network = mock.Mock(return_value=network)
+ arglist = [
+ '--network', network.id,
+ ]
+ verifylist = [
+ ('network', network.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {'network_id': network.id}
+
+ self.network.subnets.assert_called_once_with(**filters)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_subnet_list_gateway(self):
+ subnet = network_fakes.FakeSubnet.create_one_subnet()
+ self.network.find_network = mock.Mock(return_value=subnet)
+ arglist = [
+ '--gateway', subnet.gateway_ip,
+ ]
+ verifylist = [
+ ('gateway', subnet.gateway_ip),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {'gateway_ip': subnet.gateway_ip}
+
+ self.network.subnets.assert_called_once_with(**filters)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_subnet_list_name(self):
+ subnet = network_fakes.FakeSubnet.create_one_subnet()
+ self.network.find_network = mock.Mock(return_value=subnet)
+ arglist = [
+ '--name', subnet.name,
+ ]
+ verifylist = [
+ ('name', subnet.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {'name': subnet.name}
+
+ self.network.subnets.assert_called_once_with(**filters)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_subnet_list_subnet_range(self):
+ subnet = network_fakes.FakeSubnet.create_one_subnet()
+ self.network.find_network = mock.Mock(return_value=subnet)
+ arglist = [
+ '--subnet-range', subnet.cidr,
+ ]
+ verifylist = [
+ ('subnet_range', subnet.cidr),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {'cidr': subnet.cidr}
self.network.subnets.assert_called_once_with(**filters)
self.assertEqual(self.columns, columns)
@@ -768,6 +914,30 @@ class TestSetSubnet(TestSubnet):
_testsubnet, **attrs)
self.assertIsNone(result)
+ def test_set_non_append_options(self):
+ arglist = [
+ "--description", "new_description",
+ "--dhcp",
+ "--gateway", self._subnet.gateway_ip,
+ self._subnet.name,
+ ]
+ verifylist = [
+ ('description', "new_description"),
+ ('dhcp', True),
+ ('gateway', self._subnet.gateway_ip),
+ ('subnet', self._subnet.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ attrs = {
+ 'enable_dhcp': True,
+ 'gateway_ip': self._subnet.gateway_ip,
+ 'description': "new_description",
+ }
+ self.network.update_subnet.assert_called_with(self._subnet, **attrs)
+ self.assertIsNone(result)
+
class TestShowSubnet(TestSubnet):
# The subnets to be shown
@@ -776,6 +946,7 @@ class TestShowSubnet(TestSubnet):
columns = (
'allocation_pools',
'cidr',
+ 'description',
'dns_nameservers',
'enable_dhcp',
'gateway_ip',
@@ -795,6 +966,7 @@ class TestShowSubnet(TestSubnet):
data = (
subnet_v2._format_allocation_pools(_subnet.allocation_pools),
_subnet.cidr,
+ _subnet.description,
utils.format_list(_subnet.dns_nameservers),
_subnet.enable_dhcp,
_subnet.gateway_ip,
diff --git a/openstackclient/tests/unit/network/v2/test_subnet_pool.py b/openstackclient/tests/unit/network/v2/test_subnet_pool.py
index 0d9494c0..fa6ffff3 100644
--- a/openstackclient/tests/unit/network/v2/test_subnet_pool.py
+++ b/openstackclient/tests/unit/network/v2/test_subnet_pool.py
@@ -50,6 +50,7 @@ class TestCreateSubnetPool(TestSubnetPool):
'address_scope_id',
'default_prefixlen',
'default_quota',
+ 'description',
'id',
'ip_version',
'is_default',
@@ -64,6 +65,7 @@ class TestCreateSubnetPool(TestSubnetPool):
_subnet_pool.address_scope_id,
_subnet_pool.default_prefixlen,
_subnet_pool.default_quota,
+ _subnet_pool.description,
_subnet_pool.id,
_subnet_pool.ip_version,
_subnet_pool.is_default,
@@ -245,6 +247,29 @@ class TestCreateSubnetPool(TestSubnetPool):
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data)
+ def test_create_with_description(self):
+ arglist = [
+ '--pool-prefix', '10.0.10.0/24',
+ '--description', self._subnet_pool.description,
+ self._subnet_pool.name,
+ ]
+ verifylist = [
+ ('prefixes', ['10.0.10.0/24']),
+ ('description', self._subnet_pool.description),
+ ('name', self._subnet_pool.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = (self.cmd.take_action(parsed_args))
+
+ self.network.create_subnet_pool.assert_called_once_with(**{
+ 'name': self._subnet_pool.name,
+ 'prefixes': ['10.0.10.0/24'],
+ 'description': self._subnet_pool.description,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
class TestDeleteSubnetPool(TestSubnetPool):
@@ -310,7 +335,7 @@ class TestDeleteSubnetPool(TestSubnetPool):
find_mock_result = [self._subnet_pools[0], exceptions.CommandError]
self.network.find_subnet_pool = (
- mock.MagicMock(side_effect=find_mock_result)
+ mock.Mock(side_effect=find_mock_result)
)
try:
@@ -400,6 +425,144 @@ class TestListSubnetPool(TestSubnetPool):
self.assertEqual(self.columns_long, columns)
self.assertEqual(self.data_long, list(data))
+ def test_subnet_pool_list_no_share(self):
+ arglist = [
+ '--no-share',
+ ]
+ verifylist = [
+ ('share', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {'shared': False}
+
+ self.network.subnet_pools.assert_called_once_with(**filters)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_subnet_pool_list_share(self):
+ arglist = [
+ '--share',
+ ]
+ verifylist = [
+ ('share', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {'shared': True}
+
+ self.network.subnet_pools.assert_called_once_with(**filters)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_subnet_pool_list_no_default(self):
+ arglist = [
+ '--no-default',
+ ]
+ verifylist = [
+ ('default', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {'is_default': False}
+
+ self.network.subnet_pools.assert_called_once_with(**filters)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_subnet_pool_list_default(self):
+ arglist = [
+ '--default',
+ ]
+ verifylist = [
+ ('default', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {'is_default': True}
+
+ self.network.subnet_pools.assert_called_once_with(**filters)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_subnet_pool_list_project(self):
+ project = identity_fakes_v3.FakeProject.create_one_project()
+ self.projects_mock.get.return_value = project
+ arglist = [
+ '--project', project.id,
+ ]
+ verifylist = [
+ ('project', project.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {'tenant_id': project.id}
+
+ self.network.subnet_pools.assert_called_once_with(**filters)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_subnet_pool_list_project_domain(self):
+ project = identity_fakes_v3.FakeProject.create_one_project()
+ self.projects_mock.get.return_value = project
+ arglist = [
+ '--project', project.id,
+ '--project-domain', project.domain_id,
+ ]
+ verifylist = [
+ ('project', project.id),
+ ('project_domain', project.domain_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {'tenant_id': project.id}
+
+ self.network.subnet_pools.assert_called_once_with(**filters)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_subnet_pool_list_name(self):
+ subnet_pool = network_fakes.FakeSubnetPool.create_one_subnet_pool()
+ self.network.find_network = mock.Mock(return_value=subnet_pool)
+ arglist = [
+ '--name', subnet_pool.name,
+ ]
+ verifylist = [
+ ('name', subnet_pool.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {'name': subnet_pool.name}
+
+ self.network.subnet_pools.assert_called_once_with(**filters)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_subnet_pool_list_address_scope(self):
+ addr_scope = network_fakes.FakeAddressScope.create_one_address_scope()
+ self.network.find_address_scope = mock.Mock(return_value=addr_scope)
+ arglist = [
+ '--address-scope', addr_scope.id,
+ ]
+ verifylist = [
+ ('address_scope', addr_scope.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {'address_scope_id': addr_scope.id}
+
+ self.network.subnet_pools.assert_called_once_with(**filters)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
class TestSetSubnetPool(TestSubnetPool):
@@ -611,6 +774,26 @@ class TestSetSubnetPool(TestSubnetPool):
self.assertRaises(tests_utils.ParserException, self.check_parser,
self.cmd, arglist, verifylist)
+ def test_set_description(self):
+ arglist = [
+ '--description', 'new_description',
+ self._subnet_pool.name,
+ ]
+ verifylist = [
+ ('description', "new_description"),
+ ('subnet_pool', self._subnet_pool.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'description': "new_description",
+ }
+ self.network.update_subnet_pool.assert_called_once_with(
+ self._subnet_pool, **attrs)
+ self.assertIsNone(result)
+
class TestShowSubnetPool(TestSubnetPool):
@@ -621,6 +804,7 @@ class TestShowSubnetPool(TestSubnetPool):
'address_scope_id',
'default_prefixlen',
'default_quota',
+ 'description',
'id',
'ip_version',
'is_default',
@@ -636,6 +820,7 @@ class TestShowSubnetPool(TestSubnetPool):
_subnet_pool.address_scope_id,
_subnet_pool.default_prefixlen,
_subnet_pool.default_quota,
+ _subnet_pool.description,
_subnet_pool.id,
_subnet_pool.ip_version,
_subnet_pool.is_default,
diff --git a/openstackclient/tests/unit/test_shell.py b/openstackclient/tests/unit/test_shell.py
index 87cd7f51..3d91da9b 100644
--- a/openstackclient/tests/unit/test_shell.py
+++ b/openstackclient/tests/unit/test_shell.py
@@ -413,9 +413,6 @@ class TestShellCli(TestShell):
class TestShellArgV(TestShell):
"""Test the deferred help flag"""
- def setUp(self):
- super(TestShellArgV, self).setUp()
-
def test_shell_argv(self):
"""Test argv decoding
diff --git a/openstackclient/tests/unit/volume/v1/fakes.py b/openstackclient/tests/unit/volume/v1/fakes.py
index c6fee7d1..33374499 100644
--- a/openstackclient/tests/unit/volume/v1/fakes.py
+++ b/openstackclient/tests/unit/volume/v1/fakes.py
@@ -13,7 +13,10 @@
# under the License.
#
+import copy
import mock
+import random
+import uuid
from openstackclient.tests.unit import fakes
from openstackclient.tests.unit.identity.v2_0 import fakes as identity_fakes
@@ -143,9 +146,12 @@ class FakeTransfer(object):
"""
# Set default attribute
transfer_info = {
- 'volume_id': 'ce26708d-a7f8-4b4b-9861-4a80256615a7',
+ 'auth_key': 'key-' + uuid.uuid4().hex,
+ 'created_at': 'time-' + uuid.uuid4().hex,
+ 'volume_id': 'volume-id-' + uuid.uuid4().hex,
'name': 'fake_transfer_name',
- 'id': '731a7f53-aa92-4fbd-9de3-6f7d729c926b'
+ 'id': 'id-' + uuid.uuid4().hex,
+ 'links': 'links-' + uuid.uuid4().hex,
}
# Overwrite default attributes if there are some attributes set
@@ -160,6 +166,43 @@ class FakeTransfer(object):
return transfer
+ @staticmethod
+ def create_transfers(attrs=None, count=2):
+ """Create multiple fake transfers.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes of transfer
+ :param Integer count:
+ The number of transfers to be faked
+ :return:
+ A list of FakeResource objects
+ """
+ transfers = []
+ for n in range(0, count):
+ transfers.append(FakeTransfer.create_one_transfer(attrs))
+
+ return transfers
+
+ @staticmethod
+ def get_transfers(transfers=None, count=2):
+ """Get an iterable MagicMock object with a list of faked transfers.
+
+ If transfers list is provided, then initialize the Mock object with the
+ list. Otherwise create one.
+
+ :param List transfers:
+ A list of FakeResource objects faking transfers
+ :param Integer count:
+ The number of transfers to be faked
+ :return
+ An iterable Mock object with side_effect set to a list of faked
+ transfers
+ """
+ if transfers is None:
+ transfers = FakeTransfer.create_transfers(count)
+
+ return mock.Mock(side_effect=transfers)
+
class FakeService(object):
"""Fake one or more Services."""
@@ -231,7 +274,160 @@ class FakeService(object):
if services is None:
services = FakeService.create_services(count)
- return mock.MagicMock(side_effect=services)
+ return mock.Mock(side_effect=services)
+
+
+class FakeQos(object):
+ """Fake one or more Qos specification."""
+
+ @staticmethod
+ def create_one_qos(attrs=None):
+ """Create a fake Qos specification.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object with id, name, consumer, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ qos_info = {
+ "id": 'qos-id-' + uuid.uuid4().hex,
+ "name": 'qos-name-' + uuid.uuid4().hex,
+ "consumer": 'front-end',
+ "specs": {"foo": "bar", "iops": "9001"},
+ }
+
+ # Overwrite default attributes.
+ qos_info.update(attrs)
+
+ qos = fakes.FakeResource(
+ info=copy.deepcopy(qos_info),
+ loaded=True)
+ return qos
+
+ @staticmethod
+ def create_qoses(attrs=None, count=2):
+ """Create multiple fake Qos specifications.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of Qos specifications to fake
+ :return:
+ A list of FakeResource objects faking the Qos specifications
+ """
+ qoses = []
+ for i in range(0, count):
+ qos = FakeQos.create_one_qos(attrs)
+ qoses.append(qos)
+
+ return qoses
+
+ @staticmethod
+ def get_qoses(qoses=None, count=2):
+ """Get an iterable MagicMock object with a list of faked qoses.
+
+ If qoses list is provided, then initialize the Mock object with the
+ list. Otherwise create one.
+
+ :param List volumes:
+ A list of FakeResource objects faking qoses
+ :param Integer count:
+ The number of qoses to be faked
+ :return
+ An iterable Mock object with side_effect set to a list of faked
+ qoses
+ """
+ if qoses is None:
+ qoses = FakeQos.create_qoses(count)
+
+ return mock.Mock(side_effect=qoses)
+
+
+class FakeVolume(object):
+ """Fake one or more volumes."""
+
+ @staticmethod
+ def create_one_volume(attrs=None):
+ """Create a fake volume.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes of volume
+ :return:
+ A FakeResource object with id, name, status, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attribute
+ volume_info = {
+ 'id': 'volume-id' + uuid.uuid4().hex,
+ 'display_name': 'volume-name' + uuid.uuid4().hex,
+ 'display_description': 'description' + uuid.uuid4().hex,
+ 'status': 'available',
+ 'size': 10,
+ 'volume_type':
+ random.choice(['fake_lvmdriver-1', 'fake_lvmdriver-2']),
+ 'bootable': 'true',
+ 'metadata': {
+ 'key' + uuid.uuid4().hex: 'val' + uuid.uuid4().hex,
+ 'key' + uuid.uuid4().hex: 'val' + uuid.uuid4().hex,
+ 'key' + uuid.uuid4().hex: 'val' + uuid.uuid4().hex},
+ 'snapshot_id': 'snapshot-id-' + uuid.uuid4().hex,
+ 'availability_zone': 'zone' + uuid.uuid4().hex,
+ 'attachments': [{
+ 'device': '/dev/' + uuid.uuid4().hex,
+ 'server_id': uuid.uuid4().hex,
+ }, ],
+ 'created_at': 'time-' + uuid.uuid4().hex,
+ }
+
+ # Overwrite default attributes if there are some attributes set
+ volume_info.update(attrs)
+
+ volume = fakes.FakeResource(
+ None,
+ volume_info,
+ loaded=True)
+ return volume
+
+ @staticmethod
+ def create_volumes(attrs=None, count=2):
+ """Create multiple fake volumes.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes of volume
+ :param Integer count:
+ The number of volumes to be faked
+ :return:
+ A list of FakeResource objects
+ """
+ volumes = []
+ for n in range(0, count):
+ volumes.append(FakeVolume.create_one_volume(attrs))
+
+ return volumes
+
+ @staticmethod
+ def get_volumes(volumes=None, count=2):
+ """Get an iterable MagicMock object with a list of faked volumes.
+
+ If volumes list is provided, then initialize the Mock object with the
+ list. Otherwise create one.
+
+ :param List volumes:
+ A list of FakeResource objects faking volumes
+ :param Integer count:
+ The number of volumes to be faked
+ :return
+ An iterable Mock object with side_effect set to a list of faked
+ volumes
+ """
+ if volumes is None:
+ volumes = FakeVolume.create_volumes(count)
+
+ return mock.Mock(side_effect=volumes)
class FakeImagev1Client(object):
@@ -278,3 +474,77 @@ class TestVolumev1(utils.TestCommand):
endpoint=fakes.AUTH_URL,
token=fakes.AUTH_TOKEN,
)
+
+
+class FakeType(object):
+ """Fake one or more type."""
+
+ @staticmethod
+ def create_one_type(attrs=None, methods=None):
+ """Create a fake type.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param Dictionary methods:
+ A dictionary with all methods
+ :return:
+ A FakeResource object with id, name, description, etc.
+ """
+ attrs = attrs or {}
+ methods = methods or {}
+
+ # Set default attributes.
+ type_info = {
+ "id": 'type-id-' + uuid.uuid4().hex,
+ "name": 'type-name-' + uuid.uuid4().hex,
+ "description": 'type-description-' + uuid.uuid4().hex,
+ "extra_specs": {"foo": "bar"},
+ "is_public": True,
+ }
+
+ # Overwrite default attributes.
+ type_info.update(attrs)
+
+ volume_type = fakes.FakeResource(
+ info=copy.deepcopy(type_info),
+ methods=methods,
+ loaded=True)
+ return volume_type
+
+ @staticmethod
+ def create_types(attrs=None, count=2):
+ """Create multiple fake types.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of types to fake
+ :return:
+ A list of FakeResource objects faking the types
+ """
+ volume_types = []
+ for i in range(0, count):
+ volume_type = FakeType.create_one_type(attrs)
+ volume_types.append(volume_type)
+
+ return volume_types
+
+ @staticmethod
+ def get_types(types=None, count=2):
+ """Get an iterable MagicMock object with a list of faked types.
+
+ If types list is provided, then initialize the Mock object with the
+ list. Otherwise create one.
+
+ :param List types:
+ A list of FakeResource objects faking types
+ :param Integer count:
+ The number of types to be faked
+ :return
+ An iterable Mock object with side_effect set to a list of faked
+ types
+ """
+ if types is None:
+ types = FakeType.create_types(count)
+
+ return mock.Mock(side_effect=types)
diff --git a/openstackclient/tests/unit/volume/v1/test_qos_specs.py b/openstackclient/tests/unit/volume/v1/test_qos_specs.py
index 7b87ccb3..81680ab4 100644
--- a/openstackclient/tests/unit/volume/v1/test_qos_specs.py
+++ b/openstackclient/tests/unit/volume/v1/test_qos_specs.py
@@ -14,7 +14,10 @@
#
import copy
+import mock
+from mock import call
+from osc_lib import exceptions
from osc_lib import utils
from openstackclient.tests.unit import fakes
@@ -188,62 +191,106 @@ class TestQosCreate(TestQos):
class TestQosDelete(TestQos):
+ qos_specs = volume_fakes.FakeQos.create_qoses(count=2)
+
def setUp(self):
super(TestQosDelete, self).setUp()
- self.qos_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(volume_fakes.QOS),
- loaded=True,
- )
-
+ self.qos_mock.get = (
+ volume_fakes.FakeQos.get_qoses(self.qos_specs))
# Get the command object to test
self.cmd = qos_specs.DeleteQos(self.app, None)
def test_qos_delete_with_id(self):
arglist = [
- volume_fakes.qos_id
+ self.qos_specs[0].id
]
verifylist = [
- ('qos_specs', [volume_fakes.qos_id])
+ ('qos_specs', [self.qos_specs[0].id])
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
- self.qos_mock.delete.assert_called_with(volume_fakes.qos_id, False)
+ self.qos_mock.delete.assert_called_with(self.qos_specs[0].id, False)
self.assertIsNone(result)
def test_qos_delete_with_name(self):
arglist = [
- volume_fakes.qos_name
+ self.qos_specs[0].name
]
verifylist = [
- ('qos_specs', [volume_fakes.qos_name])
+ ('qos_specs', [self.qos_specs[0].name])
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
- self.qos_mock.delete.assert_called_with(volume_fakes.qos_id, False)
+ self.qos_mock.delete.assert_called_with(self.qos_specs[0].id, False)
self.assertIsNone(result)
def test_qos_delete_with_force(self):
arglist = [
'--force',
- volume_fakes.qos_id
+ self.qos_specs[0].id
]
verifylist = [
('force', True),
- ('qos_specs', [volume_fakes.qos_id])
+ ('qos_specs', [self.qos_specs[0].id])
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
- self.qos_mock.delete.assert_called_with(volume_fakes.qos_id, True)
+ self.qos_mock.delete.assert_called_with(self.qos_specs[0].id, True)
self.assertIsNone(result)
+ def test_delete_multiple_qoses(self):
+ arglist = []
+ for q in self.qos_specs:
+ arglist.append(q.id)
+ verifylist = [
+ ('qos_specs', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for q in self.qos_specs:
+ calls.append(call(q.id, False))
+ self.qos_mock.delete.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_delete_multiple_qoses_with_exception(self):
+ arglist = [
+ self.qos_specs[0].id,
+ 'unexist_qos',
+ ]
+ verifylist = [
+ ('qos_specs', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [self.qos_specs[0], exceptions.CommandError]
+ with mock.patch.object(utils, 'find_resource',
+ side_effect=find_mock_result) as find_mock:
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual(
+ '1 of 2 QoS specifications failed to delete.', str(e))
+
+ find_mock.assert_any_call(self.qos_mock, self.qos_specs[0].id)
+ find_mock.assert_any_call(self.qos_mock, 'unexist_qos')
+
+ self.assertEqual(2, find_mock.call_count)
+ self.qos_mock.delete.assert_called_once_with(
+ self.qos_specs[0].id, False
+ )
+
class TestQosDisassociate(TestQos):
diff --git a/openstackclient/tests/unit/volume/v1/test_transfer_request.py b/openstackclient/tests/unit/volume/v1/test_transfer_request.py
index f7980c34..e89c5056 100644
--- a/openstackclient/tests/unit/volume/v1/test_transfer_request.py
+++ b/openstackclient/tests/unit/volume/v1/test_transfer_request.py
@@ -12,6 +12,11 @@
# under the License.
#
+import mock
+from mock import call
+
+from osc_lib import exceptions
+from osc_lib import utils
from openstackclient.tests.unit.volume.v1 import fakes as transfer_fakes
from openstackclient.volume.v1 import volume_transfer_request
@@ -26,6 +31,155 @@ class TestTransfer(transfer_fakes.TestVolumev1):
self.transfer_mock = self.app.client_manager.volume.transfers
self.transfer_mock.reset_mock()
+ # Get a shortcut to the VolumeManager Mock
+ self.volumes_mock = self.app.client_manager.volume.volumes
+ self.volumes_mock.reset_mock()
+
+
+class TestTransferCreate(TestTransfer):
+
+ volume = transfer_fakes.FakeVolume.create_one_volume()
+
+ columns = (
+ 'auth_key',
+ 'created_at',
+ 'id',
+ 'name',
+ 'volume_id',
+ )
+
+ def setUp(self):
+ super(TestTransferCreate, self).setUp()
+
+ self.volume_transfer = transfer_fakes.FakeTransfer.create_one_transfer(
+ attrs={'volume_id': self.volume.id})
+ self.data = (
+ self.volume_transfer.auth_key,
+ self.volume_transfer.created_at,
+ self.volume_transfer.id,
+ self.volume_transfer.name,
+ self.volume_transfer.volume_id,
+ )
+
+ self.transfer_mock.create.return_value = self.volume_transfer
+ self.volumes_mock.get.return_value = self.volume
+
+ # Get the command object to test
+ self.cmd = volume_transfer_request.CreateTransferRequest(
+ self.app, None)
+
+ def test_transfer_create_without_name(self):
+ arglist = [
+ self.volume.id,
+ ]
+ verifylist = [
+ ('volume', self.volume.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.transfer_mock.create.assert_called_once_with(
+ self.volume.id, None)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_transfer_create_with_name(self):
+ arglist = [
+ '--name', self.volume_transfer.name,
+ self.volume.id,
+ ]
+ verifylist = [
+ ('name', self.volume_transfer.name),
+ ('volume', self.volume.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.transfer_mock.create.assert_called_once_with(
+ self.volume.id, self.volume_transfer.name,)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestTransferDelete(TestTransfer):
+
+ volume_transfers = transfer_fakes.FakeTransfer.create_transfers(count=2)
+
+ def setUp(self):
+ super(TestTransferDelete, self).setUp()
+
+ self.transfer_mock.get = (
+ transfer_fakes.FakeTransfer.get_transfers(self.volume_transfers))
+ self.transfer_mock.delete.return_value = None
+
+ # Get the command object to mock
+ self.cmd = volume_transfer_request.DeleteTransferRequest(
+ self.app, None)
+
+ def test_transfer_delete(self):
+ arglist = [
+ self.volume_transfers[0].id
+ ]
+ verifylist = [
+ ("transfer_request", [self.volume_transfers[0].id])
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.transfer_mock.delete.assert_called_with(
+ self.volume_transfers[0].id)
+ self.assertIsNone(result)
+
+ def test_delete_multiple_transfers(self):
+ arglist = []
+ for v in self.volume_transfers:
+ arglist.append(v.id)
+ verifylist = [
+ ('transfer_request', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for v in self.volume_transfers:
+ calls.append(call(v.id))
+ self.transfer_mock.delete.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_delete_multiple_transfers_with_exception(self):
+ arglist = [
+ self.volume_transfers[0].id,
+ 'unexist_transfer',
+ ]
+ verifylist = [
+ ('transfer_request', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [self.volume_transfers[0], exceptions.CommandError]
+ with mock.patch.object(utils, 'find_resource',
+ side_effect=find_mock_result) as find_mock:
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 volume transfer requests failed '
+ 'to delete.', str(e))
+
+ find_mock.assert_any_call(
+ self.transfer_mock, self.volume_transfers[0].id)
+ find_mock.assert_any_call(self.transfer_mock, 'unexist_transfer')
+
+ self.assertEqual(2, find_mock.call_count)
+ self.transfer_mock.delete.assert_called_once_with(
+ self.volume_transfers[0].id,
+ )
+
class TestTransferList(TestTransfer):
@@ -38,7 +192,7 @@ class TestTransferList(TestTransfer):
self.transfer_mock.list.return_value = [self.volume_transfers]
# Get the command object to test
- self.cmd = volume_transfer_request.ListTransferRequests(self.app, None)
+ self.cmd = volume_transfer_request.ListTransferRequest(self.app, None)
def test_transfer_list_without_argument(self):
arglist = []
diff --git a/openstackclient/tests/unit/volume/v1/test_type.py b/openstackclient/tests/unit/volume/v1/test_type.py
new file mode 100644
index 00000000..35016dc6
--- /dev/null
+++ b/openstackclient/tests/unit/volume/v1/test_type.py
@@ -0,0 +1,347 @@
+#
+# 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 mock
+from mock import call
+
+from osc_lib import exceptions
+from osc_lib import utils
+
+from openstackclient.tests.unit import utils as tests_utils
+from openstackclient.tests.unit.volume.v1 import fakes as volume_fakes
+from openstackclient.volume.v1 import volume_type
+
+
+class TestType(volume_fakes.TestVolumev1):
+
+ def setUp(self):
+ super(TestType, self).setUp()
+
+ self.types_mock = self.app.client_manager.volume.volume_types
+ self.types_mock.reset_mock()
+
+
+class TestTypeCreate(TestType):
+
+ columns = (
+ 'description',
+ 'id',
+ 'is_public',
+ 'name',
+ )
+
+ def setUp(self):
+ super(TestTypeCreate, self).setUp()
+
+ self.new_volume_type = volume_fakes.FakeType.create_one_type(
+ methods={'set_keys': {'myprop': 'myvalue'}}
+ )
+ self.data = (
+ self.new_volume_type.description,
+ self.new_volume_type.id,
+ True,
+ self.new_volume_type.name,
+ )
+
+ self.types_mock.create.return_value = self.new_volume_type
+ # Get the command object to test
+ self.cmd = volume_type.CreateVolumeType(self.app, None)
+
+ def test_type_create(self):
+ arglist = [
+ self.new_volume_type.name,
+ ]
+ verifylist = [
+ ("name", self.new_volume_type.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.types_mock.create.assert_called_with(
+ self.new_volume_type.name,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestTypeDelete(TestType):
+
+ volume_types = volume_fakes.FakeType.create_types(count=2)
+
+ def setUp(self):
+ super(TestTypeDelete, self).setUp()
+
+ self.types_mock.get = volume_fakes.FakeType.get_types(
+ self.volume_types)
+ self.types_mock.delete.return_value = None
+
+ # Get the command object to mock
+ self.cmd = volume_type.DeleteVolumeType(self.app, None)
+
+ def test_type_delete(self):
+ arglist = [
+ self.volume_types[0].id
+ ]
+ verifylist = [
+ ("volume_types", [self.volume_types[0].id])
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.types_mock.delete.assert_called_with(self.volume_types[0])
+ self.assertIsNone(result)
+
+ def test_delete_multiple_types(self):
+ arglist = []
+ for t in self.volume_types:
+ arglist.append(t.id)
+ verifylist = [
+ ('volume_types', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for t in self.volume_types:
+ calls.append(call(t))
+ self.types_mock.delete.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_delete_multiple_types_with_exception(self):
+ arglist = [
+ self.volume_types[0].id,
+ 'unexist_type',
+ ]
+ verifylist = [
+ ('volume_types', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [self.volume_types[0], exceptions.CommandError]
+ with mock.patch.object(utils, 'find_resource',
+ side_effect=find_mock_result) as find_mock:
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 volume types failed to delete.',
+ str(e))
+
+ find_mock.assert_any_call(
+ self.types_mock, self.volume_types[0].id)
+ find_mock.assert_any_call(self.types_mock, 'unexist_type')
+
+ self.assertEqual(2, find_mock.call_count)
+ self.types_mock.delete.assert_called_once_with(
+ self.volume_types[0]
+ )
+
+
+class TestTypeList(TestType):
+
+ volume_types = volume_fakes.FakeType.create_types()
+
+ columns = (
+ "ID",
+ "Name"
+ )
+ columns_long = (
+ "ID",
+ "Name",
+ "Properties"
+ )
+
+ data = []
+ for t in volume_types:
+ data.append((
+ t.id,
+ t.name,
+ ))
+ data_long = []
+ for t in volume_types:
+ data_long.append((
+ t.id,
+ t.name,
+ utils.format_dict(t.extra_specs),
+ ))
+
+ def setUp(self):
+ super(TestTypeList, self).setUp()
+
+ self.types_mock.list.return_value = self.volume_types
+ # get the command to test
+ self.cmd = volume_type.ListVolumeType(self.app, None)
+
+ def test_type_list_without_options(self):
+ arglist = []
+ verifylist = [
+ ("long", False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.types_mock.list.assert_called_once_with()
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_type_list_with_options(self):
+ arglist = [
+ "--long",
+ ]
+ verifylist = [
+ ("long", True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.types_mock.list.assert_called_once_with()
+ self.assertEqual(self.columns_long, columns)
+ self.assertEqual(self.data_long, list(data))
+
+
+class TestTypeSet(TestType):
+
+ volume_type = volume_fakes.FakeType.create_one_type(
+ methods={'set_keys': None})
+
+ def setUp(self):
+ super(TestTypeSet, self).setUp()
+
+ self.types_mock.get.return_value = self.volume_type
+
+ # Get the command object to test
+ self.cmd = volume_type.SetVolumeType(self.app, None)
+
+ def test_type_set_nothing(self):
+ arglist = [
+ self.volume_type.id,
+ ]
+ verifylist = [
+ ('volume_type', self.volume_type.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.assertIsNone(result)
+
+ def test_type_set_property(self):
+ arglist = [
+ '--property', 'myprop=myvalue',
+ self.volume_type.id,
+ ]
+ verifylist = [
+ ('property', {'myprop': 'myvalue'}),
+ ('volume_type', self.volume_type.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.volume_type.set_keys.assert_called_once_with(
+ {'myprop': 'myvalue'})
+ self.assertIsNone(result)
+
+
+class TestTypeShow(TestType):
+
+ columns = (
+ 'description',
+ 'id',
+ 'is_public',
+ 'name',
+ 'properties',
+ )
+
+ def setUp(self):
+ super(TestTypeShow, self).setUp()
+
+ self.volume_type = volume_fakes.FakeType.create_one_type()
+ self.data = (
+ self.volume_type.description,
+ self.volume_type.id,
+ True,
+ self.volume_type.name,
+ utils.format_dict(self.volume_type.extra_specs)
+ )
+
+ self.types_mock.get.return_value = self.volume_type
+
+ # Get the command object to test
+ self.cmd = volume_type.ShowVolumeType(self.app, None)
+
+ def test_type_show(self):
+ arglist = [
+ self.volume_type.id
+ ]
+ verifylist = [
+ ("volume_type", self.volume_type.id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.types_mock.get.assert_called_with(self.volume_type.id)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestTypeUnset(TestType):
+
+ volume_type = volume_fakes.FakeType.create_one_type(
+ methods={'unset_keys': None})
+
+ def setUp(self):
+ super(TestTypeUnset, self).setUp()
+
+ self.types_mock.get.return_value = self.volume_type
+
+ # Get the command object to test
+ self.cmd = volume_type.UnsetVolumeType(self.app, None)
+
+ def test_type_unset(self):
+ arglist = [
+ '--property', 'property',
+ '--property', 'multi_property',
+ self.volume_type.id,
+ ]
+ verifylist = [
+ ('property', ['property', 'multi_property']),
+ ('volume_type', self.volume_type.id),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.volume_type.unset_keys.assert_called_once_with(
+ ['property', 'multi_property'])
+ self.assertIsNone(result)
+
+ def test_type_unset_failed_with_missing_volume_type_argument(self):
+ arglist = [
+ '--property', 'property',
+ '--property', 'multi_property',
+ ]
+ verifylist = [
+ ('property', ['property', 'multi_property']),
+ ]
+
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser,
+ self.cmd,
+ arglist,
+ verifylist)
diff --git a/openstackclient/tests/unit/volume/v1/test_volume.py b/openstackclient/tests/unit/volume/v1/test_volume.py
index f90566fd..895f1f87 100644
--- a/openstackclient/tests/unit/volume/v1/test_volume.py
+++ b/openstackclient/tests/unit/volume/v1/test_volume.py
@@ -13,8 +13,13 @@
# under the License.
#
+import argparse
import copy
import mock
+from mock import call
+
+from osc_lib import exceptions
+from osc_lib import utils
from openstackclient.tests.unit import fakes
from openstackclient.tests.unit.identity.v2_0 import fakes as identity_fakes
@@ -43,6 +48,14 @@ class TestVolume(volume_fakes.TestVolumev1):
self.images_mock = self.app.client_manager.image.images
self.images_mock.reset_mock()
+ def setup_volumes_mock(self, count):
+ volumes = volume_fakes.FakeVolume.create_volumes(count=count)
+
+ self.volumes_mock.get = volume_fakes.FakeVolume.get_volumes(
+ volumes,
+ 0)
+ return volumes
+
# TODO(dtroyer): The volume create tests are incomplete, only the minimal
# options and the options that require additional processing
@@ -54,48 +67,50 @@ class TestVolumeCreate(TestVolume):
user = identity_fakes.FakeUser.create_one_user()
columns = (
- 'attach_status',
+ 'attachments',
'availability_zone',
+ 'bootable',
+ 'created_at',
'display_description',
'display_name',
'id',
'properties',
'size',
+ 'snapshot_id',
'status',
'type',
)
- datalist = (
- 'detached',
- volume_fakes.volume_zone,
- volume_fakes.volume_description,
- volume_fakes.volume_name,
- volume_fakes.volume_id,
- volume_fakes.volume_metadata_str,
- volume_fakes.volume_size,
- volume_fakes.volume_status,
- volume_fakes.volume_type,
- )
def setUp(self):
super(TestVolumeCreate, self).setUp()
-
- self.volumes_mock.create.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(volume_fakes.VOLUME),
- loaded=True,
+ self.new_volume = volume_fakes.FakeVolume.create_one_volume()
+ self.datalist = (
+ self.new_volume.attachments,
+ self.new_volume.availability_zone,
+ self.new_volume.bootable,
+ self.new_volume.created_at,
+ self.new_volume.display_description,
+ self.new_volume.display_name,
+ self.new_volume.id,
+ utils.format_dict(self.new_volume.metadata),
+ self.new_volume.size,
+ self.new_volume.snapshot_id,
+ self.new_volume.status,
+ self.new_volume.volume_type,
)
+ self.volumes_mock.create.return_value = self.new_volume
# Get the command object to test
self.cmd = volume.CreateVolume(self.app, None)
def test_volume_create_min_options(self):
arglist = [
- '--size', str(volume_fakes.volume_size),
- volume_fakes.volume_name,
+ '--size', str(self.new_volume.size),
+ self.new_volume.display_name,
]
verifylist = [
- ('size', volume_fakes.volume_size),
- ('name', volume_fakes.volume_name),
+ ('size', self.new_volume.size),
+ ('name', self.new_volume.display_name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -110,10 +125,10 @@ class TestVolumeCreate(TestVolume):
# project_id=, availability_zone=,
# metadata=, imageRef=)
self.volumes_mock.create.assert_called_with(
- volume_fakes.volume_size,
+ self.new_volume.size,
None,
None,
- volume_fakes.volume_name,
+ self.new_volume.display_name,
None,
None,
None,
@@ -127,18 +142,18 @@ class TestVolumeCreate(TestVolume):
def test_volume_create_options(self):
arglist = [
- '--size', str(volume_fakes.volume_size),
- '--description', volume_fakes.volume_description,
- '--type', volume_fakes.volume_type,
- '--availability-zone', volume_fakes.volume_zone,
- volume_fakes.volume_name,
+ '--size', str(self.new_volume.size),
+ '--description', self.new_volume.display_description,
+ '--type', self.new_volume.volume_type,
+ '--availability-zone', self.new_volume.availability_zone,
+ self.new_volume.display_name,
]
verifylist = [
- ('size', volume_fakes.volume_size),
- ('description', volume_fakes.volume_description),
- ('type', volume_fakes.volume_type),
- ('availability_zone', volume_fakes.volume_zone),
- ('name', volume_fakes.volume_name),
+ ('size', self.new_volume.size),
+ ('description', self.new_volume.display_description),
+ ('type', self.new_volume.volume_type),
+ ('availability_zone', self.new_volume.availability_zone),
+ ('name', self.new_volume.display_name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -153,15 +168,15 @@ class TestVolumeCreate(TestVolume):
# project_id=, availability_zone=,
# metadata=, imageRef=)
self.volumes_mock.create.assert_called_with(
- volume_fakes.volume_size,
+ self.new_volume.size,
None,
None,
- volume_fakes.volume_name,
- volume_fakes.volume_description,
- volume_fakes.volume_type,
+ self.new_volume.display_name,
+ self.new_volume.display_description,
+ self.new_volume.volume_type,
None,
None,
- volume_fakes.volume_zone,
+ self.new_volume.availability_zone,
None,
None,
)
@@ -176,16 +191,16 @@ class TestVolumeCreate(TestVolume):
self.users_mock.get.return_value = self.user
arglist = [
- '--size', str(volume_fakes.volume_size),
+ '--size', str(self.new_volume.size),
'--project', self.project.id,
'--user', self.user.id,
- volume_fakes.volume_name,
+ self.new_volume.display_name,
]
verifylist = [
- ('size', volume_fakes.volume_size),
+ ('size', self.new_volume.size),
('project', self.project.id),
('user', self.user.id),
- ('name', volume_fakes.volume_name),
+ ('name', self.new_volume.display_name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -200,10 +215,10 @@ class TestVolumeCreate(TestVolume):
# project_id=, availability_zone=,
# metadata=, imageRef=)
self.volumes_mock.create.assert_called_with(
- volume_fakes.volume_size,
+ self.new_volume.size,
None,
None,
- volume_fakes.volume_name,
+ self.new_volume.display_name,
None,
None,
self.user.id,
@@ -223,16 +238,16 @@ class TestVolumeCreate(TestVolume):
self.users_mock.get.return_value = self.user
arglist = [
- '--size', str(volume_fakes.volume_size),
+ '--size', str(self.new_volume.size),
'--project', self.project.name,
'--user', self.user.name,
- volume_fakes.volume_name,
+ self.new_volume.display_name,
]
verifylist = [
- ('size', volume_fakes.volume_size),
+ ('size', self.new_volume.size),
('project', self.project.name),
('user', self.user.name),
- ('name', volume_fakes.volume_name),
+ ('name', self.new_volume.display_name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -247,10 +262,10 @@ class TestVolumeCreate(TestVolume):
# project_id=, availability_zone=,
# metadata=, imageRef=)
self.volumes_mock.create.assert_called_with(
- volume_fakes.volume_size,
+ self.new_volume.size,
None,
None,
- volume_fakes.volume_name,
+ self.new_volume.display_name,
None,
None,
self.user.id,
@@ -267,13 +282,13 @@ class TestVolumeCreate(TestVolume):
arglist = [
'--property', 'Alpha=a',
'--property', 'Beta=b',
- '--size', str(volume_fakes.volume_size),
- volume_fakes.volume_name,
+ '--size', str(self.new_volume.size),
+ self.new_volume.display_name,
]
verifylist = [
('property', {'Alpha': 'a', 'Beta': 'b'}),
- ('size', volume_fakes.volume_size),
- ('name', volume_fakes.volume_name),
+ ('size', self.new_volume.size),
+ ('name', self.new_volume.display_name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -288,10 +303,10 @@ class TestVolumeCreate(TestVolume):
# project_id=, availability_zone=,
# metadata=, imageRef=)
self.volumes_mock.create.assert_called_with(
- volume_fakes.volume_size,
+ self.new_volume.size,
None,
None,
- volume_fakes.volume_name,
+ self.new_volume.display_name,
None,
None,
None,
@@ -313,13 +328,13 @@ class TestVolumeCreate(TestVolume):
arglist = [
'--image', volume_fakes.image_id,
- '--size', str(volume_fakes.volume_size),
- volume_fakes.volume_name,
+ '--size', str(self.new_volume.size),
+ self.new_volume.display_name,
]
verifylist = [
('image', volume_fakes.image_id),
- ('size', volume_fakes.volume_size),
- ('name', volume_fakes.volume_name),
+ ('size', self.new_volume.size),
+ ('name', self.new_volume.display_name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -334,10 +349,10 @@ class TestVolumeCreate(TestVolume):
# project_id=, availability_zone=,
# metadata=, imageRef=)
self.volumes_mock.create.assert_called_with(
- volume_fakes.volume_size,
+ self.new_volume.size,
None,
None,
- volume_fakes.volume_name,
+ self.new_volume.display_name,
None,
None,
None,
@@ -359,13 +374,13 @@ class TestVolumeCreate(TestVolume):
arglist = [
'--image', volume_fakes.image_name,
- '--size', str(volume_fakes.volume_size),
- volume_fakes.volume_name,
+ '--size', str(self.new_volume.size),
+ self.new_volume.display_name,
]
verifylist = [
('image', volume_fakes.image_name),
- ('size', volume_fakes.volume_size),
- ('name', volume_fakes.volume_name),
+ ('size', self.new_volume.size),
+ ('name', self.new_volume.display_name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -380,10 +395,10 @@ class TestVolumeCreate(TestVolume):
# project_id=, availability_zone=,
# metadata=, imageRef=)
self.volumes_mock.create.assert_called_with(
- volume_fakes.volume_size,
+ self.new_volume.size,
None,
None,
- volume_fakes.volume_name,
+ self.new_volume.display_name,
None,
None,
None,
@@ -397,8 +412,100 @@ class TestVolumeCreate(TestVolume):
self.assertEqual(self.datalist, data)
+class TestVolumeDelete(TestVolume):
+
+ def setUp(self):
+ super(TestVolumeDelete, self).setUp()
+
+ self.volumes_mock.delete.return_value = None
+
+ # Get the command object to mock
+ self.cmd = volume.DeleteVolume(self.app, None)
+
+ def test_volume_delete_one_volume(self):
+ volumes = self.setup_volumes_mock(count=1)
+
+ arglist = [
+ volumes[0].id
+ ]
+ verifylist = [
+ ("force", False),
+ ("volumes", [volumes[0].id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.volumes_mock.delete.assert_called_once_with(volumes[0].id)
+ self.assertIsNone(result)
+
+ def test_volume_delete_multi_volumes(self):
+ volumes = self.setup_volumes_mock(count=3)
+
+ arglist = [v.id for v in volumes]
+ verifylist = [
+ ('force', False),
+ ('volumes', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ calls = [call(v.id) for v in volumes]
+ self.volumes_mock.delete.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_volume_delete_multi_volumes_with_exception(self):
+ volumes = self.setup_volumes_mock(count=2)
+
+ arglist = [
+ volumes[0].id,
+ 'unexist_volume',
+ ]
+ verifylist = [
+ ('force', False),
+ ('volumes', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [volumes[0], exceptions.CommandError]
+ with mock.patch.object(utils, 'find_resource',
+ side_effect=find_mock_result) as find_mock:
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 volumes failed to delete.',
+ str(e))
+
+ find_mock.assert_any_call(self.volumes_mock, volumes[0].id)
+ find_mock.assert_any_call(self.volumes_mock, 'unexist_volume')
+
+ self.assertEqual(2, find_mock.call_count)
+ self.volumes_mock.delete.assert_called_once_with(volumes[0].id)
+
+ def test_volume_delete_with_force(self):
+ volumes = self.setup_volumes_mock(count=1)
+
+ arglist = [
+ '--force',
+ volumes[0].id,
+ ]
+ verifylist = [
+ ('force', True),
+ ('volumes', [volumes[0].id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.volumes_mock.force_delete.assert_called_once_with(volumes[0].id)
+ self.assertIsNone(result)
+
+
class TestVolumeList(TestVolume):
+ _volume = volume_fakes.FakeVolume.create_one_volume()
columns = (
'ID',
'Display Name',
@@ -406,26 +513,23 @@ class TestVolumeList(TestVolume):
'Size',
'Attached to',
)
+ server = _volume.attachments[0]['server_id']
+ device = _volume.attachments[0]['device']
+ msg = 'Attached to %s on %s ' % (server, device)
datalist = (
(
- volume_fakes.volume_id,
- volume_fakes.volume_name,
- volume_fakes.volume_status,
- volume_fakes.volume_size,
- '',
+ _volume.id,
+ _volume.display_name,
+ _volume.status,
+ _volume.size,
+ msg,
),
)
def setUp(self):
super(TestVolumeList, self).setUp()
- self.volumes_mock.list.return_value = [
- fakes.FakeResource(
- None,
- copy.deepcopy(volume_fakes.VOLUME),
- loaded=True,
- ),
- ]
+ self.volumes_mock.list.return_value = [self._volume]
# Get the command object to test
self.cmd = volume.ListVolume(self.app, None)
@@ -437,6 +541,7 @@ class TestVolumeList(TestVolume):
('all_projects', False),
('name', None),
('status', None),
+ ('limit', None),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -447,13 +552,14 @@ class TestVolumeList(TestVolume):
def test_volume_list_name(self):
arglist = [
- '--name', volume_fakes.volume_name,
+ '--name', self._volume.display_name,
]
verifylist = [
('long', False),
('all_projects', False),
- ('name', volume_fakes.volume_name),
+ ('name', self._volume.display_name),
('status', None),
+ ('limit', None),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -463,13 +569,14 @@ class TestVolumeList(TestVolume):
def test_volume_list_status(self):
arglist = [
- '--status', volume_fakes.volume_status,
+ '--status', self._volume.status,
]
verifylist = [
('long', False),
('all_projects', False),
('name', None),
- ('status', volume_fakes.volume_status),
+ ('status', self._volume.status),
+ ('limit', None),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -486,6 +593,7 @@ class TestVolumeList(TestVolume):
('all_projects', True),
('name', None),
('status', None),
+ ('limit', None),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -502,6 +610,7 @@ class TestVolumeList(TestVolume):
('all_projects', False),
('name', None),
('status', None),
+ ('limit', None),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -521,47 +630,76 @@ class TestVolumeList(TestVolume):
self.assertEqual(collist, columns)
datalist = ((
- volume_fakes.volume_id,
- volume_fakes.volume_name,
- volume_fakes.volume_status,
- volume_fakes.volume_size,
- volume_fakes.volume_type,
- '',
- '',
- "Alpha='a', Beta='b', Gamma='g'",
+ self._volume.id,
+ self._volume.display_name,
+ self._volume.status,
+ self._volume.size,
+ self._volume.volume_type,
+ self._volume.bootable,
+ self.msg,
+ utils.format_dict(self._volume.metadata),
), )
self.assertEqual(datalist, tuple(data))
+ def test_volume_list_with_limit(self):
+ arglist = [
+ '--limit', '2',
+ ]
+ verifylist = [
+ ('long', False),
+ ('all_projects', False),
+ ('name', None),
+ ('status', None),
+ ('limit', 2),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.volumes_mock.list.assert_called_once_with(
+ limit=2,
+ search_opts={
+ 'status': None,
+ 'display_name': None,
+ 'all_tenants': False, }
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_volume_list_negative_limit(self):
+ arglist = [
+ "--limit", "-2",
+ ]
+ verifylist = [
+ ("limit", -2),
+ ]
+ self.assertRaises(argparse.ArgumentTypeError, self.check_parser,
+ self.cmd, arglist, verifylist)
+
class TestVolumeSet(TestVolume):
+ _volume = volume_fakes.FakeVolume.create_one_volume()
+
def setUp(self):
super(TestVolumeSet, self).setUp()
- self.volumes_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(volume_fakes.VOLUME),
- loaded=True,
- )
+ self.volumes_mock.get.return_value = self._volume
- self.volumes_mock.update.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(volume_fakes.VOLUME),
- loaded=True,
- )
+ self.volumes_mock.update.return_value = self._volume
# Get the command object to test
self.cmd = volume.SetVolume(self.app, None)
def test_volume_set_no_options(self):
arglist = [
- volume_fakes.volume_name,
+ self._volume.display_name,
]
verifylist = [
('name', None),
('description', None),
('size', None),
('property', None),
- ('volume', volume_fakes.volume_name),
+ ('volume', self._volume.display_name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -571,14 +709,14 @@ class TestVolumeSet(TestVolume):
def test_volume_set_name(self):
arglist = [
'--name', 'qwerty',
- volume_fakes.volume_name,
+ self._volume.display_name,
]
verifylist = [
('name', 'qwerty'),
('description', None),
('size', None),
('property', None),
- ('volume', volume_fakes.volume_name),
+ ('volume', self._volume.display_name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -589,7 +727,7 @@ class TestVolumeSet(TestVolume):
'display_name': 'qwerty',
}
self.volumes_mock.update.assert_called_with(
- volume_fakes.volume_id,
+ self._volume.id,
**kwargs
)
self.assertIsNone(result)
@@ -597,14 +735,14 @@ class TestVolumeSet(TestVolume):
def test_volume_set_description(self):
arglist = [
'--description', 'new desc',
- volume_fakes.volume_name,
+ self._volume.display_name,
]
verifylist = [
('name', None),
('description', 'new desc'),
('size', None),
('property', None),
- ('volume', volume_fakes.volume_name),
+ ('volume', self._volume.display_name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -615,7 +753,7 @@ class TestVolumeSet(TestVolume):
'display_description': 'new desc',
}
self.volumes_mock.update.assert_called_with(
- volume_fakes.volume_id,
+ self._volume.id,
**kwargs
)
self.assertIsNone(result)
@@ -623,14 +761,14 @@ class TestVolumeSet(TestVolume):
def test_volume_set_size(self):
arglist = [
'--size', '130',
- volume_fakes.volume_name,
+ self._volume.display_name,
]
verifylist = [
('name', None),
('description', None),
('size', 130),
('property', None),
- ('volume', volume_fakes.volume_name),
+ ('volume', self._volume.display_name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -639,23 +777,24 @@ class TestVolumeSet(TestVolume):
# Set expected values
size = 130
self.volumes_mock.extend.assert_called_with(
- volume_fakes.volume_id,
+ self._volume.id,
size
)
self.assertIsNone(result)
@mock.patch.object(volume.LOG, 'error')
def test_volume_set_size_smaller(self, mock_log_error):
+ self._volume.status = 'available'
arglist = [
- '--size', '100',
- volume_fakes.volume_name,
+ '--size', '1',
+ self._volume.display_name,
]
verifylist = [
('name', None),
('description', None),
- ('size', 100),
+ ('size', 1),
('property', None),
- ('volume', volume_fakes.volume_name),
+ ('volume', self._volume.display_name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -663,22 +802,22 @@ class TestVolumeSet(TestVolume):
mock_log_error.assert_called_with("New size must be greater "
"than %s GB",
- volume_fakes.volume_size)
+ self._volume.size)
self.assertIsNone(result)
@mock.patch.object(volume.LOG, 'error')
def test_volume_set_size_not_available(self, mock_log_error):
- self.volumes_mock.get.return_value.status = 'error'
+ self._volume.status = 'error'
arglist = [
'--size', '130',
- volume_fakes.volume_name,
+ self._volume.display_name,
]
verifylist = [
('name', None),
('description', None),
('size', 130),
('property', None),
- ('volume', volume_fakes.volume_name),
+ ('volume', self._volume.display_name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -692,14 +831,16 @@ class TestVolumeSet(TestVolume):
def test_volume_set_property(self):
arglist = [
'--property', 'myprop=myvalue',
- volume_fakes.volume_name,
+ self._volume.display_name,
]
verifylist = [
('name', None),
('description', None),
('size', None),
('property', {'myprop': 'myvalue'}),
- ('volume', volume_fakes.volume_name),
+ ('volume', self._volume.display_name),
+ ('bootable', False),
+ ('non_bootable', False)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -710,7 +851,131 @@ class TestVolumeSet(TestVolume):
'myprop': 'myvalue'
}
self.volumes_mock.set_metadata.assert_called_with(
- volume_fakes.volume_id,
+ self._volume.id,
metadata
)
self.assertIsNone(result)
+
+ def test_volume_set_bootable(self):
+ arglist = [
+ ['--bootable', self._volume.id],
+ ['--non-bootable', self._volume.id]
+ ]
+ verifylist = [
+ [
+ ('bootable', True),
+ ('non_bootable', False),
+ ('volume', self._volume.id)
+ ],
+ [
+ ('bootable', False),
+ ('non_bootable', True),
+ ('volume', self._volume.id)
+ ]
+ ]
+ for index in range(len(arglist)):
+ parsed_args = self.check_parser(
+ self.cmd, arglist[index], verifylist[index])
+
+ self.cmd.take_action(parsed_args)
+ self.volumes_mock.set_bootable.assert_called_with(
+ self._volume.id, verifylist[index][0][1])
+
+
+class TestVolumeShow(TestVolume):
+
+ columns = (
+ 'attachments',
+ 'availability_zone',
+ 'bootable',
+ 'created_at',
+ 'display_description',
+ 'display_name',
+ 'id',
+ 'properties',
+ 'size',
+ 'snapshot_id',
+ 'status',
+ 'type',
+ )
+
+ def setUp(self):
+ super(TestVolumeShow, self).setUp()
+ self._volume = volume_fakes.FakeVolume.create_one_volume()
+ self.datalist = (
+ self._volume.attachments,
+ self._volume.availability_zone,
+ self._volume.bootable,
+ self._volume.created_at,
+ self._volume.display_description,
+ self._volume.display_name,
+ self._volume.id,
+ utils.format_dict(self._volume.metadata),
+ self._volume.size,
+ self._volume.snapshot_id,
+ self._volume.status,
+ self._volume.volume_type,
+ )
+ self.volumes_mock.get.return_value = self._volume
+ # Get the command object to test
+ self.cmd = volume.ShowVolume(self.app, None)
+
+ def test_volume_show(self):
+ arglist = [
+ self._volume.id
+ ]
+ verifylist = [
+ ("volume", self._volume.id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.volumes_mock.get.assert_called_with(self._volume.id)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+
+class TestVolumeUnset(TestVolume):
+
+ _volume = volume_fakes.FakeVolume.create_one_volume()
+
+ def setUp(self):
+ super(TestVolumeUnset, self).setUp()
+
+ self.volumes_mock.get.return_value = self._volume
+
+ self.volumes_mock.delete_metadata.return_value = None
+ # Get the command object to test
+ self.cmd = volume.UnsetVolume(self.app, None)
+
+ def test_volume_unset_no_options(self):
+ arglist = [
+ self._volume.display_name,
+ ]
+ verifylist = [
+ ('property', None),
+ ('volume', self._volume.display_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.assertIsNone(result)
+
+ def test_volume_unset_property(self):
+ arglist = [
+ '--property', 'myprop',
+ self._volume.display_name,
+ ]
+ verifylist = [
+ ('property', ['myprop']),
+ ('volume', self._volume.display_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.volumes_mock.delete_metadata.assert_called_with(
+ self._volume.id, ['myprop']
+ )
+ self.assertIsNone(result)
diff --git a/openstackclient/tests/unit/volume/v2/fakes.py b/openstackclient/tests/unit/volume/v2/fakes.py
index a958c468..8d7ac831 100644
--- a/openstackclient/tests/unit/volume/v2/fakes.py
+++ b/openstackclient/tests/unit/volume/v2/fakes.py
@@ -25,6 +25,19 @@ from openstackclient.tests.unit.image.v2 import fakes as image_fakes
from openstackclient.tests.unit import utils
+QUOTA = {
+ "gigabytes": 1000,
+ "volumes": 11,
+ "snapshots": 10,
+ "backups": 10,
+ "backup_gigabytes": 1000,
+ "per_volume_gigabytes": -1,
+ "gigabytes_volume_type_backend": -1,
+ "volumes_volume_type_backend": -1,
+ "snapshots_volume_type_backend": -1,
+}
+
+
class FakeTransfer(object):
"""Fake one or more Transfer."""
@@ -39,9 +52,12 @@ class FakeTransfer(object):
"""
# Set default attribute
transfer_info = {
- 'volume_id': 'ce26708d-a7f8-4b4b-9861-4a80256615a7',
+ 'auth_key': 'key-' + uuid.uuid4().hex,
+ 'created_at': 'time-' + uuid.uuid4().hex,
+ 'volume_id': 'volume-id-' + uuid.uuid4().hex,
'name': 'fake_transfer_name',
- 'id': '731a7f53-aa92-4fbd-9de3-6f7d729c926b'
+ 'id': 'id-' + uuid.uuid4().hex,
+ 'links': 'links-' + uuid.uuid4().hex,
}
# Overwrite default attributes if there are some attributes set
@@ -56,6 +72,43 @@ class FakeTransfer(object):
return transfer
+ @staticmethod
+ def create_transfers(attrs=None, count=2):
+ """Create multiple fake transfers.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes of transfer
+ :param Integer count:
+ The number of transfers to be faked
+ :return:
+ A list of FakeResource objects
+ """
+ transfers = []
+ for n in range(0, count):
+ transfers.append(FakeTransfer.create_one_transfer(attrs))
+
+ return transfers
+
+ @staticmethod
+ def get_transfers(transfers=None, count=2):
+ """Get an iterable MagicMock object with a list of faked transfers.
+
+ If transfers list is provided, then initialize the Mock object with the
+ list. Otherwise create one.
+
+ :param List transfers:
+ A list of FakeResource objects faking transfers
+ :param Integer count:
+ The number of transfers to be faked
+ :return
+ An iterable Mock object with side_effect set to a list of faked
+ transfers
+ """
+ if transfers is None:
+ transfers = FakeTransfer.create_transfers(count)
+
+ return mock.Mock(side_effect=transfers)
+
class FakeTypeAccess(object):
"""Fake one or more volume type access."""
@@ -167,6 +220,10 @@ class FakeVolumeClient(object):
self.transfers.resource_class = fakes.FakeResource(None, {})
self.services = mock.Mock()
self.services.resource_class = fakes.FakeResource(None, {})
+ self.quotas = mock.Mock()
+ self.quotas.resource_class = fakes.FakeResource(None, {})
+ self.quota_classes = mock.Mock()
+ self.quota_classes.resource_class = fakes.FakeResource(None, {})
self.auth_token = kwargs['token']
self.management_url = kwargs['endpoint']
@@ -274,7 +331,7 @@ class FakeVolume(object):
if volumes is None:
volumes = FakeVolume.create_volumes(count)
- return mock.MagicMock(side_effect=volumes)
+ return mock.Mock(side_effect=volumes)
@staticmethod
def get_volume_columns(volume=None):
@@ -435,7 +492,7 @@ class FakeBackup(object):
if backups is None:
backups = FakeBackup.create_backups(count)
- return mock.MagicMock(side_effect=backups)
+ return mock.Mock(side_effect=backups)
class FakeExtension(object):
@@ -566,7 +623,7 @@ class FakeQos(object):
if qoses is None:
qoses = FakeQos.create_qoses(count)
- return mock.MagicMock(side_effect=qoses)
+ return mock.Mock(side_effect=qoses)
class FakeSnapshot(object):
@@ -639,7 +696,7 @@ class FakeSnapshot(object):
if snapshots is None:
snapshots = FakeSnapshot.create_snapshots(count)
- return mock.MagicMock(side_effect=snapshots)
+ return mock.Mock(side_effect=snapshots)
class FakeType(object):
diff --git a/openstackclient/tests/unit/volume/v2/test_snapshot.py b/openstackclient/tests/unit/volume/v2/test_snapshot.py
index 333d8d72..d355662d 100644
--- a/openstackclient/tests/unit/volume/v2/test_snapshot.py
+++ b/openstackclient/tests/unit/volume/v2/test_snapshot.py
@@ -376,6 +376,55 @@ class TestSnapshotSet(TestSnapshot):
self.snapshot.id, "error")
self.assertIsNone(result)
+ def test_volume_set_state_failed(self):
+ self.snapshots_mock.reset_state.side_effect = exceptions.CommandError()
+ arglist = [
+ '--state', 'error',
+ self.snapshot.id
+ ]
+ verifylist = [
+ ('state', 'error'),
+ ('snapshot', self.snapshot.id)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('One or more of the set operations failed',
+ str(e))
+ self.snapshots_mock.reset_state.assert_called_once_with(
+ self.snapshot.id, 'error')
+
+ def test_volume_set_name_and_state_failed(self):
+ self.snapshots_mock.reset_state.side_effect = exceptions.CommandError()
+ arglist = [
+ '--state', 'error',
+ "--name", "new_snapshot",
+ self.snapshot.id
+ ]
+ verifylist = [
+ ('state', 'error'),
+ ("name", "new_snapshot"),
+ ('snapshot', self.snapshot.id)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('One or more of the set operations failed',
+ str(e))
+ kwargs = {
+ "name": "new_snapshot",
+ }
+ self.snapshots_mock.update.assert_called_once_with(
+ self.snapshot.id, **kwargs)
+ self.snapshots_mock.reset_state.assert_called_once_with(
+ self.snapshot.id, 'error')
+
class TestSnapshotShow(TestSnapshot):
diff --git a/openstackclient/tests/unit/volume/v2/test_transfer_request.py b/openstackclient/tests/unit/volume/v2/test_transfer_request.py
index 32108c02..b4f89089 100644
--- a/openstackclient/tests/unit/volume/v2/test_transfer_request.py
+++ b/openstackclient/tests/unit/volume/v2/test_transfer_request.py
@@ -12,6 +12,11 @@
# under the License.
#
+import mock
+from mock import call
+
+from osc_lib import exceptions
+from osc_lib import utils
from openstackclient.tests.unit.volume.v2 import fakes as transfer_fakes
from openstackclient.volume.v2 import volume_transfer_request
@@ -26,6 +31,155 @@ class TestTransfer(transfer_fakes.TestVolume):
self.transfer_mock = self.app.client_manager.volume.transfers
self.transfer_mock.reset_mock()
+ # Get a shortcut to the VolumeManager Mock
+ self.volumes_mock = self.app.client_manager.volume.volumes
+ self.volumes_mock.reset_mock()
+
+
+class TestTransferCreate(TestTransfer):
+
+ volume = transfer_fakes.FakeVolume.create_one_volume()
+
+ columns = (
+ 'auth_key',
+ 'created_at',
+ 'id',
+ 'name',
+ 'volume_id',
+ )
+
+ def setUp(self):
+ super(TestTransferCreate, self).setUp()
+
+ self.volume_transfer = transfer_fakes.FakeTransfer.create_one_transfer(
+ attrs={'volume_id': self.volume.id})
+ self.data = (
+ self.volume_transfer.auth_key,
+ self.volume_transfer.created_at,
+ self.volume_transfer.id,
+ self.volume_transfer.name,
+ self.volume_transfer.volume_id,
+ )
+
+ self.transfer_mock.create.return_value = self.volume_transfer
+ self.volumes_mock.get.return_value = self.volume
+
+ # Get the command object to test
+ self.cmd = volume_transfer_request.CreateTransferRequest(
+ self.app, None)
+
+ def test_transfer_create_without_name(self):
+ arglist = [
+ self.volume.id,
+ ]
+ verifylist = [
+ ('volume', self.volume.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.transfer_mock.create.assert_called_once_with(
+ self.volume.id, None)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_transfer_create_with_name(self):
+ arglist = [
+ '--name', self.volume_transfer.name,
+ self.volume.id,
+ ]
+ verifylist = [
+ ('name', self.volume_transfer.name),
+ ('volume', self.volume.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.transfer_mock.create.assert_called_once_with(
+ self.volume.id, self.volume_transfer.name,)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestTransferDelete(TestTransfer):
+
+ volume_transfers = transfer_fakes.FakeTransfer.create_transfers(count=2)
+
+ def setUp(self):
+ super(TestTransferDelete, self).setUp()
+
+ self.transfer_mock.get = (
+ transfer_fakes.FakeTransfer.get_transfers(self.volume_transfers))
+ self.transfer_mock.delete.return_value = None
+
+ # Get the command object to mock
+ self.cmd = volume_transfer_request.DeleteTransferRequest(
+ self.app, None)
+
+ def test_transfer_delete(self):
+ arglist = [
+ self.volume_transfers[0].id
+ ]
+ verifylist = [
+ ("transfer_request", [self.volume_transfers[0].id])
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.transfer_mock.delete.assert_called_with(
+ self.volume_transfers[0].id)
+ self.assertIsNone(result)
+
+ def test_delete_multiple_transfers(self):
+ arglist = []
+ for v in self.volume_transfers:
+ arglist.append(v.id)
+ verifylist = [
+ ('transfer_request', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for v in self.volume_transfers:
+ calls.append(call(v.id))
+ self.transfer_mock.delete.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_delete_multiple_transfers_with_exception(self):
+ arglist = [
+ self.volume_transfers[0].id,
+ 'unexist_transfer',
+ ]
+ verifylist = [
+ ('transfer_request', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [self.volume_transfers[0], exceptions.CommandError]
+ with mock.patch.object(utils, 'find_resource',
+ side_effect=find_mock_result) as find_mock:
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 volume transfer requests failed '
+ 'to delete.', str(e))
+
+ find_mock.assert_any_call(
+ self.transfer_mock, self.volume_transfers[0].id)
+ find_mock.assert_any_call(self.transfer_mock, 'unexist_transfer')
+
+ self.assertEqual(2, find_mock.call_count)
+ self.transfer_mock.delete.assert_called_once_with(
+ self.volume_transfers[0].id,
+ )
+
class TestTransferList(TestTransfer):
@@ -38,7 +192,7 @@ class TestTransferList(TestTransfer):
self.transfer_mock.list.return_value = [self.volume_transfers]
# Get the command object to test
- self.cmd = volume_transfer_request.ListTransferRequests(self.app, None)
+ self.cmd = volume_transfer_request.ListTransferRequest(self.app, None)
def test_transfer_list_without_argument(self):
arglist = []
diff --git a/openstackclient/tests/unit/volume/v2/test_volume.py b/openstackclient/tests/unit/volume/v2/test_volume.py
index 66f8f74d..5bdde9de 100644
--- a/openstackclient/tests/unit/volume/v2/test_volume.py
+++ b/openstackclient/tests/unit/volume/v2/test_volume.py
@@ -12,6 +12,7 @@
# under the License.
#
+import argparse
import mock
from mock import call
@@ -553,6 +554,8 @@ class TestVolumeList(TestVolume):
('all_projects', False),
('name', None),
('status', None),
+ ('marker', None),
+ ('limit', None),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -581,6 +584,8 @@ class TestVolumeList(TestVolume):
('long', False),
('all_projects', False),
('status', None),
+ ('marker', None),
+ ('limit', None),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -611,6 +616,8 @@ class TestVolumeList(TestVolume):
('long', False),
('all_projects', False),
('status', None),
+ ('marker', None),
+ ('limit', None),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -639,6 +646,8 @@ class TestVolumeList(TestVolume):
('long', False),
('all_projects', False),
('status', None),
+ ('marker', None),
+ ('limit', None),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -668,6 +677,8 @@ class TestVolumeList(TestVolume):
('long', False),
('all_projects', False),
('status', None),
+ ('marker', None),
+ ('limit', None),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -696,6 +707,8 @@ class TestVolumeList(TestVolume):
('all_projects', False),
('name', self.mock_volume.name),
('status', None),
+ ('marker', None),
+ ('limit', None),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -724,6 +737,8 @@ class TestVolumeList(TestVolume):
('all_projects', False),
('name', None),
('status', self.mock_volume.status),
+ ('marker', None),
+ ('limit', None),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -752,6 +767,8 @@ class TestVolumeList(TestVolume):
('all_projects', True),
('name', None),
('status', None),
+ ('marker', None),
+ ('limit', None),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -780,6 +797,8 @@ class TestVolumeList(TestVolume):
('all_projects', False),
('name', None),
('status', None),
+ ('marker', None),
+ ('limit', None),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -813,6 +832,58 @@ class TestVolumeList(TestVolume):
), )
self.assertEqual(datalist, tuple(data))
+ def test_volume_list_with_marker_and_limit(self):
+ arglist = [
+ "--marker", self.mock_volume.id,
+ "--limit", "2",
+ ]
+ verifylist = [
+ ('long', False),
+ ('all_projects', False),
+ ('name', None),
+ ('status', None),
+ ('marker', self.mock_volume.id),
+ ('limit', 2),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+
+ server = self.mock_volume.attachments[0]['server_id']
+ device = self.mock_volume.attachments[0]['device']
+ msg = 'Attached to %s on %s ' % (server, device)
+ datalist = ((
+ self.mock_volume.id,
+ self.mock_volume.name,
+ self.mock_volume.status,
+ self.mock_volume.size,
+ msg,
+ ), )
+
+ self.volumes_mock.list.assert_called_once_with(
+ marker=self.mock_volume.id,
+ limit=2,
+ search_opts={
+ 'status': None,
+ 'project_id': None,
+ 'user_id': None,
+ 'display_name': None,
+ 'all_tenants': False, }
+ )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_volume_list_negative_limit(self):
+ arglist = [
+ "--limit", "-2",
+ ]
+ verifylist = [
+ ("limit", -2),
+ ]
+ self.assertRaises(argparse.ArgumentTypeError, self.check_parser,
+ self.cmd, arglist, verifylist)
+
class TestVolumeSet(TestVolume):
@@ -834,6 +905,8 @@ class TestVolumeSet(TestVolume):
verifylist = [
('image_property', {'Alpha': 'a', 'Beta': 'b'}),
('volume', self.new_volume.id),
+ ('bootable', False),
+ ('non_bootable', False)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -881,6 +954,31 @@ class TestVolumeSet(TestVolume):
self.volumes_mock.reset_state.assert_called_with(
self.new_volume.id, 'error')
+ def test_volume_set_bootable(self):
+ arglist = [
+ ['--bootable', self.new_volume.id],
+ ['--non-bootable', self.new_volume.id]
+ ]
+ verifylist = [
+ [
+ ('bootable', True),
+ ('non_bootable', False),
+ ('volume', self.new_volume.id)
+ ],
+ [
+ ('bootable', False),
+ ('non_bootable', True),
+ ('volume', self.new_volume.id)
+ ]
+ ]
+ for index in range(len(arglist)):
+ parsed_args = self.check_parser(
+ self.cmd, arglist[index], verifylist[index])
+
+ self.cmd.take_action(parsed_args)
+ self.volumes_mock.set_bootable.assert_called_with(
+ self.new_volume.id, verifylist[index][0][1])
+
class TestVolumeShow(TestVolume):
@@ -964,3 +1062,30 @@ class TestVolumeUnset(TestVolume):
self.volumes_mock.delete_image_metadata.assert_called_with(
self.new_volume.id, parsed_args_unset.image_property)
+
+ def test_volume_unset_image_property_fail(self):
+ self.volumes_mock.delete_image_metadata.side_effect = (
+ exceptions.CommandError())
+ arglist = [
+ '--image-property', 'Alpha',
+ '--property', 'Beta',
+ self.new_volume.id,
+ ]
+ verifylist = [
+ ('image_property', ['Alpha']),
+ ('property', ['Beta']),
+ ('volume', self.new_volume.id),
+ ]
+ parsed_args = self.check_parser(
+ self.cmd_unset, arglist, verifylist)
+
+ try:
+ self.cmd_unset.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('One or more of the unset operations failed',
+ str(e))
+ self.volumes_mock.delete_image_metadata.assert_called_with(
+ self.new_volume.id, parsed_args.image_property)
+ self.volumes_mock.delete_metadata.assert_called_with(
+ self.new_volume.id, parsed_args.property)
diff --git a/openstackclient/tests/volume/v1/test_service.py b/openstackclient/tests/volume/v1/test_service.py
deleted file mode 100644
index 273a1156..00000000
--- a/openstackclient/tests/volume/v1/test_service.py
+++ /dev/null
@@ -1,286 +0,0 @@
-#
-# 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.
-#
-
-from osc_lib import exceptions
-
-from openstackclient.tests.volume.v1 import fakes as service_fakes
-from openstackclient.volume.v1 import service
-
-
-class TestService(service_fakes.TestVolumev1):
-
- def setUp(self):
- super(TestService, self).setUp()
-
- # Get a shortcut to the ServiceManager Mock
- self.service_mock = self.app.client_manager.volume.services
- self.service_mock.reset_mock()
-
-
-class TestServiceList(TestService):
-
- # The service to be listed
- services = service_fakes.FakeService.create_one_service()
-
- def setUp(self):
- super(TestServiceList, self).setUp()
-
- self.service_mock.list.return_value = [self.services]
-
- # Get the command object to test
- self.cmd = service.ListService(self.app, None)
-
- def test_service_list(self):
- arglist = [
- '--host', self.services.host,
- '--service', self.services.binary,
- ]
- verifylist = [
- ('host', self.services.host),
- ('service', self.services.binary),
- ]
- parsed_args = self.check_parser(self.cmd, arglist, verifylist)
-
- # In base command class Lister in cliff, abstract method take_action()
- # returns a tuple containing the column names and an iterable
- # containing the data to be listed.
- columns, data = self.cmd.take_action(parsed_args)
-
- expected_columns = [
- 'Binary',
- 'Host',
- 'Zone',
- 'Status',
- 'State',
- 'Updated At',
- ]
-
- # confirming if all expected columns are present in the result.
- self.assertEqual(expected_columns, columns)
-
- datalist = ((
- self.services.binary,
- self.services.host,
- self.services.zone,
- self.services.status,
- self.services.state,
- self.services.updated_at,
- ), )
-
- # confirming if all expected values are present in the result.
- self.assertEqual(datalist, tuple(data))
-
- # checking if proper call was made to list services
- self.service_mock.list.assert_called_with(
- self.services.host,
- self.services.binary,
- )
-
- # checking if prohibited columns are present in output
- self.assertNotIn("Disabled Reason", columns)
- self.assertNotIn(self.services.disabled_reason,
- tuple(data))
-
- def test_service_list_with_long_option(self):
- arglist = [
- '--host', self.services.host,
- '--service', self.services.binary,
- '--long'
- ]
- verifylist = [
- ('host', self.services.host),
- ('service', self.services.binary),
- ('long', True)
- ]
- parsed_args = self.check_parser(self.cmd, arglist, verifylist)
-
- # In base command class Lister in cliff, abstract method take_action()
- # returns a tuple containing the column names and an iterable
- # containing the data to be listed.
- columns, data = self.cmd.take_action(parsed_args)
-
- expected_columns = [
- 'Binary',
- 'Host',
- 'Zone',
- 'Status',
- 'State',
- 'Updated At',
- 'Disabled Reason'
- ]
-
- # confirming if all expected columns are present in the result.
- self.assertEqual(expected_columns, columns)
-
- datalist = ((
- self.services.binary,
- self.services.host,
- self.services.zone,
- self.services.status,
- self.services.state,
- self.services.updated_at,
- self.services.disabled_reason,
- ), )
-
- # confirming if all expected values are present in the result.
- self.assertEqual(datalist, tuple(data))
-
- self.service_mock.list.assert_called_with(
- self.services.host,
- self.services.binary,
- )
-
-
-class TestServiceSet(TestService):
-
- service = service_fakes.FakeService.create_one_service()
-
- def setUp(self):
- super(TestServiceSet, self).setUp()
-
- self.service_mock.enable.return_value = self.service
- self.service_mock.disable.return_value = self.service
- self.service_mock.disable_log_reason.return_value = self.service
-
- self.cmd = service.SetService(self.app, None)
-
- def test_service_set_nothing(self):
- arglist = [
- self.service.host,
- self.service.binary,
- ]
- verifylist = [
- ('host', self.service.host),
- ('service', self.service.binary),
- ]
- parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- result = self.cmd.take_action(parsed_args)
-
- self.service_mock.enable.assert_not_called()
- self.service_mock.disable.assert_not_called()
- self.service_mock.disable_log_reason.assert_not_called()
- self.assertIsNone(result)
-
- def test_service_set_enable(self):
- arglist = [
- '--enable',
- self.service.host,
- self.service.binary,
- ]
- verifylist = [
- ('enable', True),
- ('host', self.service.host),
- ('service', self.service.binary),
- ]
- parsed_args = self.check_parser(self.cmd, arglist, verifylist)
-
- result = self.cmd.take_action(parsed_args)
-
- self.service_mock.enable.assert_called_with(
- self.service.host,
- self.service.binary
- )
- self.service_mock.disable.assert_not_called()
- self.service_mock.disable_log_reason.assert_not_called()
- self.assertIsNone(result)
-
- def test_service_set_disable(self):
- arglist = [
- '--disable',
- self.service.host,
- self.service.binary,
- ]
- verifylist = [
- ('disable', True),
- ('host', self.service.host),
- ('service', self.service.binary),
- ]
- parsed_args = self.check_parser(self.cmd, arglist, verifylist)
-
- result = self.cmd.take_action(parsed_args)
-
- self.service_mock.disable.assert_called_with(
- self.service.host,
- self.service.binary
- )
- self.service_mock.enable.assert_not_called()
- self.service_mock.disable_log_reason.assert_not_called()
- self.assertIsNone(result)
-
- def test_service_set_disable_with_reason(self):
- reason = 'earthquake'
- arglist = [
- '--disable',
- '--disable-reason', reason,
- self.service.host,
- self.service.binary,
- ]
- verifylist = [
- ('disable', True),
- ('disable_reason', reason),
- ('host', self.service.host),
- ('service', self.service.binary),
- ]
- parsed_args = self.check_parser(self.cmd, arglist, verifylist)
-
- result = self.cmd.take_action(parsed_args)
-
- self.service_mock.disable_log_reason.assert_called_with(
- self.service.host,
- self.service.binary,
- reason
- )
- self.assertIsNone(result)
-
- def test_service_set_only_with_disable_reason(self):
- reason = 'earthquake'
- arglist = [
- '--disable-reason', reason,
- self.service.host,
- self.service.binary,
- ]
- verifylist = [
- ('disable_reason', reason),
- ('host', self.service.host),
- ('service', self.service.binary),
- ]
- parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- try:
- self.cmd.take_action(parsed_args)
- self.fail("CommandError should be raised.")
- except exceptions.CommandError as e:
- self.assertEqual("Cannot specify option --disable-reason without "
- "--disable specified.", str(e))
-
- def test_service_set_enable_with_disable_reason(self):
- reason = 'earthquake'
- arglist = [
- '--enable',
- '--disable-reason', reason,
- self.service.host,
- self.service.binary,
- ]
- verifylist = [
- ('enable', True),
- ('disable_reason', reason),
- ('host', self.service.host),
- ('service', self.service.binary),
- ]
- parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- try:
- self.cmd.take_action(parsed_args)
- self.fail("CommandError should be raised.")
- except exceptions.CommandError as e:
- self.assertEqual("Cannot specify option --disable-reason without "
- "--disable specified.", str(e))
diff --git a/openstackclient/volume/v1/backup.py b/openstackclient/volume/v1/backup.py
index 539ed369..c9d0ca0d 100644
--- a/openstackclient/volume/v1/backup.py
+++ b/openstackclient/volume/v1/backup.py
@@ -19,12 +19,16 @@ import copy
import logging
from osc_lib.command import command
+from osc_lib import exceptions
from osc_lib import utils
import six
from openstackclient.i18n import _
+LOG = logging.getLogger(__name__)
+
+
class CreateVolumeBackup(command.ShowOne):
"""Create new volume backup"""
@@ -100,10 +104,24 @@ class DeleteVolumeBackup(command.Command):
def take_action(self, parsed_args):
volume_client = self.app.client_manager.volume
- for backup in parsed_args.backups:
- backup_id = utils.find_resource(volume_client.backups,
- backup).id
- volume_client.backups.delete(backup_id)
+ result = 0
+
+ for i in parsed_args.backups:
+ try:
+ backup_id = utils.find_resource(
+ volume_client.backups, i).id
+ volume_client.backups.delete(backup_id)
+ except Exception as e:
+ result += 1
+ LOG.error(_("Failed to delete backup with "
+ "name or ID '%(backup)s': %(e)s"),
+ {'backup': i, 'e': e})
+
+ if result > 0:
+ total = len(parsed_args.backups)
+ msg = (_("%(result)s of %(total)s backups failed "
+ "to delete.") % {'result': result, 'total': total})
+ raise exceptions.CommandError(msg)
class DeleteBackup(DeleteVolumeBackup):
diff --git a/openstackclient/volume/v1/qos_specs.py b/openstackclient/volume/v1/qos_specs.py
index c5850871..b982c0e6 100644
--- a/openstackclient/volume/v1/qos_specs.py
+++ b/openstackclient/volume/v1/qos_specs.py
@@ -15,14 +15,20 @@
"""Volume v1 QoS action implementations"""
+import logging
+
from osc_lib.cli import parseractions
from osc_lib.command import command
+from osc_lib import exceptions
from osc_lib import utils
import six
from openstackclient.i18n import _
+LOG = logging.getLogger(__name__)
+
+
class AssociateQos(command.Command):
"""Associate a QoS specification to a volume type"""
@@ -113,9 +119,23 @@ class DeleteQos(command.Command):
def take_action(self, parsed_args):
volume_client = self.app.client_manager.volume
- for qos in parsed_args.qos_specs:
- qos_spec = utils.find_resource(volume_client.qos_specs, qos)
- volume_client.qos_specs.delete(qos_spec.id, parsed_args.force)
+ result = 0
+
+ for i in parsed_args.qos_specs:
+ try:
+ qos_spec = utils.find_resource(volume_client.qos_specs, i)
+ volume_client.qos_specs.delete(qos_spec.id, parsed_args.force)
+ except Exception as e:
+ result += 1
+ LOG.error(_("Failed to delete QoS specification with "
+ "name or ID '%(qos)s': %(e)s"),
+ {'qos': i, 'e': e})
+
+ if result > 0:
+ total = len(parsed_args.qos_specs)
+ msg = (_("%(result)s of %(total)s QoS specifications failed"
+ " to delete.") % {'result': result, 'total': total})
+ raise exceptions.CommandError(msg)
class DisassociateQos(command.Command):
diff --git a/openstackclient/volume/v1/snapshot.py b/openstackclient/volume/v1/snapshot.py
index bb3a1fc3..c4d113a3 100644
--- a/openstackclient/volume/v1/snapshot.py
+++ b/openstackclient/volume/v1/snapshot.py
@@ -16,15 +16,20 @@
"""Volume v1 Snapshot action implementations"""
import copy
+import logging
from osc_lib.cli import parseractions
from osc_lib.command import command
+from osc_lib import exceptions
from osc_lib import utils
import six
from openstackclient.i18n import _
+LOG = logging.getLogger(__name__)
+
+
class CreateSnapshot(command.ShowOne):
"""Create new snapshot"""
@@ -88,10 +93,24 @@ class DeleteSnapshot(command.Command):
def take_action(self, parsed_args):
volume_client = self.app.client_manager.volume
- for snapshot in parsed_args.snapshots:
- snapshot_id = utils.find_resource(volume_client.volume_snapshots,
- snapshot).id
- volume_client.volume_snapshots.delete(snapshot_id)
+ result = 0
+
+ for i in parsed_args.snapshots:
+ try:
+ snapshot_id = utils.find_resource(
+ volume_client.volume_snapshots, i).id
+ volume_client.volume_snapshots.delete(snapshot_id)
+ except Exception as e:
+ result += 1
+ LOG.error(_("Failed to delete snapshot with "
+ "name or ID '%(snapshot)s': %(e)s"),
+ {'snapshot': i, 'e': e})
+
+ if result > 0:
+ total = len(parsed_args.snapshots)
+ msg = (_("%(result)s of %(total)s snapshots failed "
+ "to delete.") % {'result': result, 'total': total})
+ raise exceptions.CommandError(msg)
class ListSnapshot(command.Lister):
@@ -199,17 +218,31 @@ class SetSnapshot(command.Command):
snapshot = utils.find_resource(volume_client.volume_snapshots,
parsed_args.snapshot)
+ result = 0
if parsed_args.property:
- volume_client.volume_snapshots.set_metadata(snapshot.id,
- parsed_args.property)
+ try:
+ volume_client.volume_snapshots.set_metadata(
+ snapshot.id, parsed_args.property)
+ except Exception as e:
+ LOG.error(_("Failed to set snapshot property: %s"), e)
+ result += 1
kwargs = {}
if parsed_args.name:
kwargs['display_name'] = parsed_args.name
if parsed_args.description:
kwargs['display_description'] = parsed_args.description
-
- snapshot.update(**kwargs)
+ if kwargs:
+ try:
+ snapshot.update(**kwargs)
+ except Exception as e:
+ LOG.error(_("Failed to update snapshot display name "
+ "or display description: %s"), e)
+ result += 1
+
+ if result > 0:
+ raise exceptions.CommandError(_("One or more of the "
+ "set operations failed"))
class ShowSnapshot(command.ShowOne):
diff --git a/openstackclient/volume/v1/volume.py b/openstackclient/volume/v1/volume.py
index 820673bb..89fa2014 100644
--- a/openstackclient/volume/v1/volume.py
+++ b/openstackclient/volume/v1/volume.py
@@ -20,6 +20,7 @@ import logging
from osc_lib.cli import parseractions
from osc_lib.command import command
+from osc_lib import exceptions
from osc_lib import utils
import six
@@ -184,13 +185,27 @@ class DeleteVolume(command.Command):
def take_action(self, parsed_args):
volume_client = self.app.client_manager.volume
- 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)
+ result = 0
+
+ for i in parsed_args.volumes:
+ try:
+ volume_obj = utils.find_resource(
+ volume_client.volumes, i)
+ if parsed_args.force:
+ volume_client.volumes.force_delete(volume_obj.id)
+ else:
+ volume_client.volumes.delete(volume_obj.id)
+ except Exception as e:
+ result += 1
+ LOG.error(_("Failed to delete volume with "
+ "name or ID '%(volume)s': %(e)s"),
+ {'volume': i, 'e': e})
+
+ if result > 0:
+ total = len(parsed_args.volumes)
+ msg = (_("%(result)s of %(total)s volumes failed "
+ "to delete.") % {'result': result, 'total': total})
+ raise exceptions.CommandError(msg)
class ListVolume(command.Lister):
@@ -220,6 +235,13 @@ class ListVolume(command.Lister):
default=False,
help=_('List additional fields in output'),
)
+ parser.add_argument(
+ '--limit',
+ type=int,
+ action=parseractions.NonNegativeAction,
+ metavar='<limit>',
+ help=_('Maximum number of volumes to display'),
+ )
return parser
def take_action(self, parsed_args):
@@ -295,7 +317,10 @@ class ListVolume(command.Lister):
'status': parsed_args.status,
}
- data = volume_client.volumes.list(search_opts=search_opts)
+ data = volume_client.volumes.list(
+ search_opts=search_opts,
+ limit=parsed_args.limit,
+ )
return (column_headers,
(utils.get_item_properties(
@@ -338,6 +363,17 @@ class SetVolume(command.Command):
help=_('Set a property on this volume '
'(repeat option to set multiple properties)'),
)
+ bootable_group = parser.add_mutually_exclusive_group()
+ bootable_group.add_argument(
+ "--bootable",
+ action="store_true",
+ help=_("Mark volume as bootable")
+ )
+ bootable_group.add_argument(
+ "--non-bootable",
+ action="store_true",
+ help=_("Mark volume as non-bootable")
+ )
return parser
def take_action(self, parsed_args):
@@ -357,7 +393,12 @@ class SetVolume(command.Command):
if parsed_args.property:
volume_client.volumes.set_metadata(volume.id, parsed_args.property)
-
+ if parsed_args.bootable or parsed_args.non_bootable:
+ try:
+ volume_client.volumes.set_bootable(
+ volume.id, parsed_args.bootable)
+ except Exception as e:
+ LOG.error(_("Failed to set volume bootable property: %s"), e)
kwargs = {}
if parsed_args.name:
kwargs['display_name'] = parsed_args.name
@@ -411,10 +452,8 @@ class UnsetVolume(command.Command):
'--property',
metavar='<key>',
action='append',
- default=[],
help=_('Remove a property from volume '
'(repeat option to remove multiple properties)'),
- required=True,
)
return parser
diff --git a/openstackclient/volume/v1/volume_transfer_request.py b/openstackclient/volume/v1/volume_transfer_request.py
index 5d8ff683..a985f8e5 100644
--- a/openstackclient/volume/v1/volume_transfer_request.py
+++ b/openstackclient/volume/v1/volume_transfer_request.py
@@ -12,19 +12,90 @@
# under the License.
#
-"""Volume v2 transfer action implementations"""
+"""Volume v1 transfer action implementations"""
+
+import logging
from osc_lib.command import command
+from osc_lib import exceptions
from osc_lib import utils
+import six
from openstackclient.i18n import _
-class ListTransferRequests(command.Lister):
+LOG = logging.getLogger(__name__)
+
+
+class CreateTransferRequest(command.ShowOne):
+ """Create volume transfer request."""
+
+ def get_parser(self, prog_name):
+ parser = super(CreateTransferRequest, self).get_parser(prog_name)
+ parser.add_argument(
+ '--name',
+ metavar="<name>",
+ help=_('New transfer request name (default to None)')
+ )
+ parser.add_argument(
+ 'volume',
+ metavar="<volume>",
+ help=_('Volume to transfer (name or ID)')
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ volume_client = self.app.client_manager.volume
+ volume_id = utils.find_resource(
+ volume_client.volumes, parsed_args.volume).id
+ volume_transfer_request = volume_client.transfers.create(
+ volume_id, parsed_args.name,
+ )
+ volume_transfer_request._info.pop("links", None)
+
+ return zip(*sorted(six.iteritems(volume_transfer_request._info)))
+
+
+class DeleteTransferRequest(command.Command):
+ """Delete volume transfer request(s)."""
+
+ def get_parser(self, prog_name):
+ parser = super(DeleteTransferRequest, self).get_parser(prog_name)
+ parser.add_argument(
+ 'transfer_request',
+ metavar="<transfer-request>",
+ nargs="+",
+ help=_('Volume transfer request(s) to delete (name or ID)'),
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ volume_client = self.app.client_manager.volume
+ result = 0
+
+ for t in parsed_args.transfer_request:
+ try:
+ transfer_request_id = utils.find_resource(
+ volume_client.transfers, t).id
+ volume_client.transfers.delete(transfer_request_id)
+ except Exception as e:
+ result += 1
+ LOG.error(_("Failed to delete volume transfer request "
+ "with name or ID '%(transfer)s': %(e)s")
+ % {'transfer': t, 'e': e})
+
+ if result > 0:
+ total = len(parsed_args.transfer_request)
+ msg = (_("%(result)s of %(total)s volume transfer requests failed"
+ " to delete.") % {'result': result, 'total': total})
+ raise exceptions.CommandError(msg)
+
+
+class ListTransferRequest(command.Lister):
"""Lists all volume transfer requests."""
def get_parser(self, prog_name):
- parser = super(ListTransferRequests, self).get_parser(prog_name)
+ parser = super(ListTransferRequest, self).get_parser(prog_name)
parser.add_argument(
'--all-projects',
dest='all_projects',
diff --git a/openstackclient/volume/v1/volume_type.py b/openstackclient/volume/v1/volume_type.py
index 3fe4fa05..625b34dc 100644
--- a/openstackclient/volume/v1/volume_type.py
+++ b/openstackclient/volume/v1/volume_type.py
@@ -55,10 +55,9 @@ class CreateVolumeType(command.ShowOne):
if parsed_args.property:
result = volume_type.set_keys(parsed_args.property)
volume_type._info.update({'properties': utils.format_dict(result)})
+ volume_type._info.pop("os-volume-type-access:is_public", None)
- info = {}
- info.update(volume_type._info)
- return zip(*sorted(six.iteritems(info)))
+ return zip(*sorted(six.iteritems(volume_type._info)))
class DeleteVolumeType(command.Command):
@@ -171,6 +170,7 @@ class ShowVolumeType(command.ShowOne):
volume_client.volume_types, parsed_args.volume_type)
properties = utils.format_dict(volume_type._info.pop('extra_specs'))
volume_type._info.update({'properties': properties})
+ volume_type._info.pop("os-volume-type-access:is_public", None)
return zip(*sorted(six.iteritems(volume_type._info)))
diff --git a/openstackclient/volume/v2/snapshot.py b/openstackclient/volume/v2/snapshot.py
index 8304a5eb..0d826551 100644
--- a/openstackclient/volume/v2/snapshot.py
+++ b/openstackclient/volume/v2/snapshot.py
@@ -240,19 +240,40 @@ class SetSnapshot(command.Command):
snapshot = utils.find_resource(volume_client.volume_snapshots,
parsed_args.snapshot)
+ result = 0
+ if parsed_args.property:
+ try:
+ volume_client.volume_snapshots.set_metadata(
+ snapshot.id, parsed_args.property)
+ except Exception as e:
+ LOG.error(_("Failed to set snapshot property: %s"), e)
+ result += 1
+
+ if parsed_args.state:
+ try:
+ volume_client.volume_snapshots.reset_state(
+ snapshot.id, parsed_args.state)
+ except Exception as e:
+ LOG.error(_("Failed to set snapshot state: %s"), e)
+ result += 1
+
kwargs = {}
if parsed_args.name:
kwargs['name'] = parsed_args.name
if parsed_args.description:
kwargs['description'] = parsed_args.description
+ if kwargs:
+ try:
+ volume_client.volume_snapshots.update(
+ snapshot.id, **kwargs)
+ except Exception as e:
+ LOG.error(_("Failed to update snapshot name "
+ "or description: %s"), e)
+ result += 1
- if parsed_args.property:
- volume_client.volume_snapshots.set_metadata(snapshot.id,
- parsed_args.property)
- if parsed_args.state:
- volume_client.volume_snapshots.reset_state(snapshot.id,
- parsed_args.state)
- volume_client.volume_snapshots.update(snapshot.id, **kwargs)
+ if result > 0:
+ raise exceptions.CommandError(_("One or more of the "
+ "set operations failed"))
class ShowSnapshot(command.ShowOne):
diff --git a/openstackclient/volume/v2/volume.py b/openstackclient/volume/v2/volume.py
index bd201e00..0805b2be 100644
--- a/openstackclient/volume/v2/volume.py
+++ b/openstackclient/volume/v2/volume.py
@@ -246,6 +246,18 @@ class ListVolume(command.Lister):
default=False,
help=_('List additional fields in output'),
)
+ parser.add_argument(
+ '--marker',
+ metavar='<marker>',
+ help=_('The last volume ID of the previous page'),
+ )
+ parser.add_argument(
+ '--limit',
+ type=int,
+ action=parseractions.NonNegativeAction,
+ metavar='<limit>',
+ help=_('Maximum number of volumes to display'),
+ )
return parser
def take_action(self, parsed_args):
@@ -328,7 +340,11 @@ class ListVolume(command.Lister):
'status': parsed_args.status,
}
- data = volume_client.volumes.list(search_opts=search_opts)
+ data = volume_client.volumes.list(
+ search_opts=search_opts,
+ marker=parsed_args.marker,
+ limit=parsed_args.limit,
+ )
return (column_headers,
(utils.get_item_properties(
@@ -388,6 +404,17 @@ class SetVolume(command.Command):
'"deleting", "in-use", "attaching", "detaching", '
'"error_deleting" or "maintenance")'),
)
+ bootable_group = parser.add_mutually_exclusive_group()
+ bootable_group.add_argument(
+ "--bootable",
+ action="store_true",
+ help=_("Mark volume as bootable")
+ )
+ bootable_group.add_argument(
+ "--non-bootable",
+ action="store_true",
+ help=_("Mark volume as non-bootable")
+ )
return parser
def take_action(self, parsed_args):
@@ -430,6 +457,13 @@ class SetVolume(command.Command):
except Exception as e:
LOG.error(_("Failed to set volume state: %s"), e)
result += 1
+ if parsed_args.bootable or parsed_args.non_bootable:
+ try:
+ volume_client.volumes.set_bootable(
+ volume.id, parsed_args.bootable)
+ except Exception as e:
+ LOG.error(_("Failed to set volume bootable property: %s"), e)
+ result += 1
kwargs = {}
if parsed_args.name:
@@ -456,7 +490,7 @@ class ShowVolume(command.ShowOne):
parser = super(ShowVolume, self).get_parser(prog_name)
parser.add_argument(
'volume',
- metavar="<volume-id>",
+ metavar="<volume>",
help=_("Volume to display (name or ID)")
)
return parser
@@ -511,9 +545,23 @@ class UnsetVolume(command.Command):
volume = utils.find_resource(
volume_client.volumes, parsed_args.volume)
+ result = 0
if parsed_args.property:
- volume_client.volumes.delete_metadata(
- volume.id, parsed_args.property)
+ try:
+ volume_client.volumes.delete_metadata(
+ volume.id, parsed_args.property)
+ except Exception as e:
+ LOG.error(_("Failed to unset volume property: %s"), e)
+ result += 1
+
if parsed_args.image_property:
- volume_client.volumes.delete_image_metadata(
- volume.id, parsed_args.image_property)
+ try:
+ volume_client.volumes.delete_image_metadata(
+ volume.id, parsed_args.image_property)
+ except Exception as e:
+ LOG.error(_("Failed to unset image property: %s"), e)
+ result += 1
+
+ if result > 0:
+ raise exceptions.CommandError(_("One or more of the "
+ "unset operations failed"))
diff --git a/openstackclient/volume/v2/volume_transfer_request.py b/openstackclient/volume/v2/volume_transfer_request.py
index 5d8ff683..8e79807c 100644
--- a/openstackclient/volume/v2/volume_transfer_request.py
+++ b/openstackclient/volume/v2/volume_transfer_request.py
@@ -14,17 +14,88 @@
"""Volume v2 transfer action implementations"""
+import logging
+
from osc_lib.command import command
+from osc_lib import exceptions
from osc_lib import utils
+import six
from openstackclient.i18n import _
-class ListTransferRequests(command.Lister):
+LOG = logging.getLogger(__name__)
+
+
+class CreateTransferRequest(command.ShowOne):
+ """Create volume transfer request."""
+
+ def get_parser(self, prog_name):
+ parser = super(CreateTransferRequest, self).get_parser(prog_name)
+ parser.add_argument(
+ '--name',
+ metavar="<name>",
+ help=_('New transfer request name (default to None)'),
+ )
+ parser.add_argument(
+ 'volume',
+ metavar="<volume>",
+ help=_('Volume to transfer (name or ID)'),
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ volume_client = self.app.client_manager.volume
+ volume_id = utils.find_resource(
+ volume_client.volumes, parsed_args.volume).id
+ volume_transfer_request = volume_client.transfers.create(
+ volume_id, parsed_args.name,
+ )
+ volume_transfer_request._info.pop("links", None)
+
+ return zip(*sorted(six.iteritems(volume_transfer_request._info)))
+
+
+class DeleteTransferRequest(command.Command):
+ """Delete volume transfer request(s)."""
+
+ def get_parser(self, prog_name):
+ parser = super(DeleteTransferRequest, self).get_parser(prog_name)
+ parser.add_argument(
+ 'transfer_request',
+ metavar="<transfer-request>",
+ nargs="+",
+ help=_('Volume transfer request(s) to delete (name or ID)'),
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ volume_client = self.app.client_manager.volume
+ result = 0
+
+ for t in parsed_args.transfer_request:
+ try:
+ transfer_request_id = utils.find_resource(
+ volume_client.transfers, t).id
+ volume_client.transfers.delete(transfer_request_id)
+ except Exception as e:
+ result += 1
+ LOG.error(_("Failed to delete volume transfer request "
+ "with name or ID '%(transfer)s': %(e)s")
+ % {'transfer': t, 'e': e})
+
+ if result > 0:
+ total = len(parsed_args.transfer_request)
+ msg = (_("%(result)s of %(total)s volume transfer requests failed"
+ " to delete.") % {'result': result, 'total': total})
+ raise exceptions.CommandError(msg)
+
+
+class ListTransferRequest(command.Lister):
"""Lists all volume transfer requests."""
def get_parser(self, prog_name):
- parser = super(ListTransferRequests, self).get_parser(prog_name)
+ parser = super(ListTransferRequest, self).get_parser(prog_name)
parser.add_argument(
'--all-projects',
dest='all_projects',
diff --git a/openstackclient/volume/v2/volume_type.py b/openstackclient/volume/v2/volume_type.py
index e42fffe0..80a1f21b 100644
--- a/openstackclient/volume/v2/volume_type.py
+++ b/openstackclient/volume/v2/volume_type.py
@@ -110,6 +110,7 @@ class CreateVolumeType(command.ShowOne):
if parsed_args.property:
result = volume_type.set_keys(parsed_args.property)
volume_type._info.update({'properties': utils.format_dict(result)})
+ volume_type._info.pop("os-volume-type-access:is_public", None)
return zip(*sorted(six.iteritems(volume_type._info)))
@@ -318,6 +319,7 @@ class ShowVolumeType(command.ShowOne):
'%(type)s: %(e)s')
LOG.error(msg % {'type': volume_type.id, 'e': e})
volume_type._info.update({'access_project_ids': access_project_ids})
+ volume_type._info.pop("os-volume-type-access:is_public", None)
return zip(*sorted(six.iteritems(volume_type._info)))