Fix NoneType error for volume snapshot create command

In volume snapshot command, <volume> is the same
as <snapshot-name> when --volume is not specified,
but <volume> cannot be None, so when <snapshot-name>
is not specified (<snapshot-name> is None), a NoneType
error appears.
So make <snapshot-name> no longer optional, it should
be always present.

Change-Id: I3d9f10753a8ef601e70816421c160598e2cc811f
Closes-bug: #1659894
This commit is contained in:
Huanxuan Ao 2017-03-08 10:01:16 +08:00 committed by Dean Troyer
parent bf1f47c1be
commit 1c49a1f01d
7 changed files with 42 additions and 38 deletions

View File

@ -27,6 +27,21 @@ Backwards Incompatible Changes
.. * Remove in: <5.0> .. * Remove in: <5.0>
.. * Commit: <tbd> .. * Commit: <tbd>
Release 3.10
------------
1. The positional argument ``<snapshot-name>`` of the ``volume snapshot create``
command is no longer optional.
Previously when the ``--volume`` option was
present ``<snapshot-name>`` defaulted to the ``--volume`` value. When the
``--volume`` option is not present now it defaults to the value of
``<snapshot-name>``.
* As of: 3.10
* Bug: 1659894
* Commit: https://review.openstack.org/440497
Release 3.0 Release 3.0
----------- -----------

View File

@ -49,7 +49,7 @@ Create new volume snapshot
.. _volume_snapshot_create-snapshot-name: .. _volume_snapshot_create-snapshot-name:
.. describe:: <snapshot-name> .. describe:: <snapshot-name>
Name of the new snapshot (default to None) Name of the new snapshot
volume snapshot delete volume snapshot delete
---------------------- ----------------------

View File

@ -18,6 +18,7 @@ from mock import call
from osc_lib import exceptions from osc_lib import exceptions
from osc_lib import utils 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.tests.unit.volume.v1 import fakes as volume_fakes
from openstackclient.volume.v1 import volume_snapshot from openstackclient.volume.v1 import volume_snapshot
@ -98,26 +99,17 @@ class TestSnapshotCreate(TestSnapshot):
def test_snapshot_create_without_name(self): def test_snapshot_create_without_name(self):
arglist = [ arglist = [
"--volume", self.new_snapshot.volume_id, "--volume", self.new_snapshot.volume_id,
"--description", self.new_snapshot.display_description,
"--force"
] ]
verifylist = [ verifylist = [
("volume", self.new_snapshot.volume_id), ("volume", self.new_snapshot.volume_id),
("description", self.new_snapshot.display_description),
("force", True)
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist) self.assertRaises(
tests_utils.ParserException,
columns, data = self.cmd.take_action(parsed_args) self.check_parser,
self.cmd,
self.snapshots_mock.create.assert_called_with( arglist,
self.new_snapshot.volume_id, verifylist,
True,
None,
self.new_snapshot.display_description,
) )
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data)
def test_snapshot_create_without_volume(self): def test_snapshot_create_without_volume(self):
arglist = [ arglist = [

View File

@ -20,6 +20,7 @@ from osc_lib import exceptions
from osc_lib import utils from osc_lib import utils
from openstackclient.tests.unit.identity.v3 import fakes as project_fakes from openstackclient.tests.unit.identity.v3 import fakes as project_fakes
from openstackclient.tests.unit import utils as tests_utils
from openstackclient.tests.unit.volume.v2 import fakes as volume_fakes from openstackclient.tests.unit.volume.v2 import fakes as volume_fakes
from openstackclient.volume.v2 import volume_snapshot from openstackclient.volume.v2 import volume_snapshot
@ -107,27 +108,17 @@ class TestSnapshotCreate(TestSnapshot):
def test_snapshot_create_without_name(self): def test_snapshot_create_without_name(self):
arglist = [ arglist = [
"--volume", self.new_snapshot.volume_id, "--volume", self.new_snapshot.volume_id,
"--description", self.new_snapshot.description,
"--force"
] ]
verifylist = [ verifylist = [
("volume", self.new_snapshot.volume_id), ("volume", self.new_snapshot.volume_id),
("description", self.new_snapshot.description),
("force", True)
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist) self.assertRaises(
tests_utils.ParserException,
columns, data = self.cmd.take_action(parsed_args) self.check_parser,
self.cmd,
self.snapshots_mock.create.assert_called_with( arglist,
self.new_snapshot.volume_id, verifylist,
force=True,
name=None,
description=self.new_snapshot.description,
metadata=None,
) )
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data)
def test_snapshot_create_without_volume(self): def test_snapshot_create_without_volume(self):
arglist = [ arglist = [
@ -156,17 +147,19 @@ class TestSnapshotCreate(TestSnapshot):
self.assertEqual(self.columns, columns) self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data) self.assertEqual(self.data, data)
def test_snapshot_create_without_remote_source(self): def test_snapshot_create_with_remote_source(self):
arglist = [ arglist = [
'--remote-source', 'source-name=test_source_name', '--remote-source', 'source-name=test_source_name',
'--remote-source', 'source-id=test_source_id', '--remote-source', 'source-id=test_source_id',
'--volume', self.new_snapshot.volume_id, '--volume', self.new_snapshot.volume_id,
self.new_snapshot.name,
] ]
ref_dict = {'source-name': 'test_source_name', ref_dict = {'source-name': 'test_source_name',
'source-id': 'test_source_id'} 'source-id': 'test_source_id'}
verifylist = [ verifylist = [
('remote_source', ref_dict), ('remote_source', ref_dict),
('volume', self.new_snapshot.volume_id), ('volume', self.new_snapshot.volume_id),
("snapshot_name", self.new_snapshot.name),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@ -175,7 +168,7 @@ class TestSnapshotCreate(TestSnapshot):
self.snapshots_mock.manage.assert_called_with( self.snapshots_mock.manage.assert_called_with(
volume_id=self.new_snapshot.volume_id, volume_id=self.new_snapshot.volume_id,
ref=ref_dict, ref=ref_dict,
name=None, name=self.new_snapshot.name,
description=None, description=None,
metadata=None, metadata=None,
) )

View File

@ -38,8 +38,7 @@ class CreateVolumeSnapshot(command.ShowOne):
parser.add_argument( parser.add_argument(
'snapshot_name', 'snapshot_name',
metavar='<snapshot-name>', metavar='<snapshot-name>',
nargs="?", help=_('Name of the new snapshot'),
help=_('Name of the snapshot (default to None)'),
) )
parser.add_argument( parser.add_argument(
'--volume', '--volume',

View File

@ -38,8 +38,7 @@ class CreateVolumeSnapshot(command.ShowOne):
parser.add_argument( parser.add_argument(
"snapshot_name", "snapshot_name",
metavar="<snapshot-name>", metavar="<snapshot-name>",
nargs="?", help=_("Name of the new snapshot"),
help=_("Name of the new snapshot (default to None)")
) )
parser.add_argument( parser.add_argument(
"--volume", "--volume",

View File

@ -0,0 +1,6 @@
---
fixes:
- |
Now the positional parameter ``<snapshot-name>`` of ``volume snapshot create``
command is no longer optional, it should be always present.
[Bug `1659894 <https://bugs.launchpad.net/bugs/1659894>`_]