support multi-delete for volume-type
Added the ability to delete multiple volume types at once. Note there are no unit tests exist for v1 volume-types, so instead a functional test was created. Partial-Bug: #1592906 Change-Id: I99f3f22901ab35252b91a3072b14de7d19cb17ca
This commit is contained in:
parent
f5ae23ab86
commit
4e62e1e2e1
@ -48,18 +48,18 @@ Create new volume type
|
|||||||
volume type delete
|
volume type delete
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
Delete volume type
|
Delete volume type(s)
|
||||||
|
|
||||||
.. program:: volume type delete
|
.. program:: volume type delete
|
||||||
.. code:: bash
|
.. code:: bash
|
||||||
|
|
||||||
os volume type delete
|
os volume type delete
|
||||||
<volume-type>
|
<volume-type> [<volume-type> ...]
|
||||||
|
|
||||||
.. _volume_type_delete-volume-type:
|
.. _volume_type_delete-volume-type:
|
||||||
.. describe:: <volume-type>
|
.. describe:: <volume-type>
|
||||||
|
|
||||||
Volume type to delete (name or ID)
|
Volume type(s) to delete (name or ID)
|
||||||
|
|
||||||
volume type list
|
volume type list
|
||||||
----------------
|
----------------
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from functional.tests.volume.v1 import common
|
from functional.tests.volume.v1 import common
|
||||||
@ -59,3 +60,15 @@ class VolumeTypeTests(common.BaseVolumeTests):
|
|||||||
self.assertEqual("", raw_output)
|
self.assertEqual("", raw_output)
|
||||||
raw_output = self.openstack('volume type show ' + self.NAME + opts)
|
raw_output = self.openstack('volume type show ' + self.NAME + opts)
|
||||||
self.assertEqual("c='d'\n", raw_output)
|
self.assertEqual("c='d'\n", raw_output)
|
||||||
|
|
||||||
|
def test_multi_delete(self):
|
||||||
|
vol_type1 = uuid.uuid4().hex
|
||||||
|
vol_type2 = uuid.uuid4().hex
|
||||||
|
self.openstack('volume type create ' + vol_type1)
|
||||||
|
time.sleep(5)
|
||||||
|
self.openstack('volume type create ' + vol_type2)
|
||||||
|
time.sleep(5)
|
||||||
|
cmd = 'volume type delete %s %s' % (vol_type1, vol_type2)
|
||||||
|
time.sleep(5)
|
||||||
|
raw_output = self.openstack(cmd)
|
||||||
|
self.assertOutput('', raw_output)
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from functional.tests.volume.v2 import common
|
from functional.tests.volume.v2 import common
|
||||||
@ -69,3 +70,15 @@ class VolumeTypeTests(common.BaseVolumeTests):
|
|||||||
raw_output = self.openstack(
|
raw_output = self.openstack(
|
||||||
'volume type unset --project admin ' + self.NAME)
|
'volume type unset --project admin ' + self.NAME)
|
||||||
self.assertEqual("", raw_output)
|
self.assertEqual("", raw_output)
|
||||||
|
|
||||||
|
def test_multi_delete(self):
|
||||||
|
vol_type1 = uuid.uuid4().hex
|
||||||
|
vol_type2 = uuid.uuid4().hex
|
||||||
|
self.openstack('volume type create ' + vol_type1)
|
||||||
|
time.sleep(5)
|
||||||
|
self.openstack('volume type create ' + vol_type2)
|
||||||
|
time.sleep(5)
|
||||||
|
cmd = 'volume type delete %s %s' % (vol_type1, vol_type2)
|
||||||
|
time.sleep(5)
|
||||||
|
raw_output = self.openstack(cmd)
|
||||||
|
self.assertOutput('', raw_output)
|
||||||
|
@ -128,13 +128,13 @@ class TestTypeDelete(TestType):
|
|||||||
self.volume_type.id
|
self.volume_type.id
|
||||||
]
|
]
|
||||||
verifylist = [
|
verifylist = [
|
||||||
("volume_type", self.volume_type.id)
|
("volume_types", [self.volume_type.id])
|
||||||
]
|
]
|
||||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
result = self.cmd.take_action(parsed_args)
|
result = self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
self.types_mock.delete.assert_called_with(self.volume_type.id)
|
self.types_mock.delete.assert_called_with(self.volume_type)
|
||||||
self.assertIsNone(result)
|
self.assertIsNone(result)
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,14 +15,20 @@
|
|||||||
|
|
||||||
"""Volume v1 Type action implementations"""
|
"""Volume v1 Type action implementations"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
from osc_lib.cli import parseractions
|
from osc_lib.cli import parseractions
|
||||||
from osc_lib.command import command
|
from osc_lib.command import command
|
||||||
|
from osc_lib import exceptions
|
||||||
from osc_lib import utils
|
from osc_lib import utils
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from openstackclient.i18n import _
|
from openstackclient.i18n import _
|
||||||
|
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class CreateVolumeType(command.ShowOne):
|
class CreateVolumeType(command.ShowOne):
|
||||||
"""Create new volume type"""
|
"""Create new volume type"""
|
||||||
|
|
||||||
@ -56,22 +62,39 @@ class CreateVolumeType(command.ShowOne):
|
|||||||
|
|
||||||
|
|
||||||
class DeleteVolumeType(command.Command):
|
class DeleteVolumeType(command.Command):
|
||||||
"""Delete volume type"""
|
"""Delete volume type(s)"""
|
||||||
|
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
parser = super(DeleteVolumeType, self).get_parser(prog_name)
|
parser = super(DeleteVolumeType, self).get_parser(prog_name)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'volume_type',
|
'volume_types',
|
||||||
metavar='<volume-type>',
|
metavar='<volume-type>',
|
||||||
help=_('Volume type to delete (name or ID)'),
|
nargs='+',
|
||||||
|
help=_('Volume type(s) to delete (name or ID)'),
|
||||||
)
|
)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
volume_client = self.app.client_manager.volume
|
volume_client = self.app.client_manager.volume
|
||||||
volume_type_id = utils.find_resource(
|
result = 0
|
||||||
volume_client.volume_types, parsed_args.volume_type).id
|
|
||||||
volume_client.volume_types.delete(volume_type_id)
|
for volume_type in parsed_args.volume_types:
|
||||||
|
try:
|
||||||
|
vol_type = utils.find_resource(volume_client.volume_types,
|
||||||
|
volume_type)
|
||||||
|
|
||||||
|
volume_client.volume_types.delete(vol_type)
|
||||||
|
except Exception as e:
|
||||||
|
result += 1
|
||||||
|
LOG.error(_("Failed to delete volume type with "
|
||||||
|
"name or ID '%(volume_type)s': %(e)s")
|
||||||
|
% {'volume_type': volume_type, 'e': e})
|
||||||
|
|
||||||
|
if result > 0:
|
||||||
|
total = len(parsed_args.volume_types)
|
||||||
|
msg = (_("%(result)s of %(total)s volume types failed "
|
||||||
|
"to delete.") % {'result': result, 'total': total})
|
||||||
|
raise exceptions.CommandError(msg)
|
||||||
|
|
||||||
|
|
||||||
class ListVolumeType(command.Lister):
|
class ListVolumeType(command.Lister):
|
||||||
|
@ -92,22 +92,39 @@ class CreateVolumeType(command.ShowOne):
|
|||||||
|
|
||||||
|
|
||||||
class DeleteVolumeType(command.Command):
|
class DeleteVolumeType(command.Command):
|
||||||
"""Delete volume type"""
|
"""Delete volume type(s)"""
|
||||||
|
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
parser = super(DeleteVolumeType, self).get_parser(prog_name)
|
parser = super(DeleteVolumeType, self).get_parser(prog_name)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"volume_type",
|
"volume_types",
|
||||||
metavar="<volume-type>",
|
metavar="<volume-type>",
|
||||||
help=_("Volume type to delete (name or ID)")
|
nargs="+",
|
||||||
|
help=_("Volume type(s) to delete (name or ID)")
|
||||||
)
|
)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
volume_client = self.app.client_manager.volume
|
volume_client = self.app.client_manager.volume
|
||||||
volume_type = utils.find_resource(
|
result = 0
|
||||||
volume_client.volume_types, parsed_args.volume_type)
|
|
||||||
volume_client.volume_types.delete(volume_type.id)
|
for volume_type in parsed_args.volume_types:
|
||||||
|
try:
|
||||||
|
vol_type = utils.find_resource(volume_client.volume_types,
|
||||||
|
volume_type)
|
||||||
|
|
||||||
|
volume_client.volume_types.delete(vol_type)
|
||||||
|
except Exception as e:
|
||||||
|
result += 1
|
||||||
|
LOG.error(_("Failed to delete volume type with "
|
||||||
|
"name or ID '%(volume_type)s': %(e)s")
|
||||||
|
% {'volume_type': volume_type, 'e': e})
|
||||||
|
|
||||||
|
if result > 0:
|
||||||
|
total = len(parsed_args.volume_types)
|
||||||
|
msg = (_("%(result)s of %(total)s volume types failed "
|
||||||
|
"to delete.") % {'result': result, 'total': total})
|
||||||
|
raise exceptions.CommandError(msg)
|
||||||
|
|
||||||
|
|
||||||
class ListVolumeType(command.Lister):
|
class ListVolumeType(command.Lister):
|
||||||
|
5
releasenotes/notes/bug-1592906-e69b37377278d9c2.yaml
Normal file
5
releasenotes/notes/bug-1592906-e69b37377278d9c2.yaml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Support bulk deletion for ``volume type delete``.
|
||||||
|
[Bug `1592906 <https://bugs.launchpad.net/bugs/1592906>`_]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user