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:
Steve Martinelli 2016-06-16 14:25:33 -04:00
parent f5ae23ab86
commit 4e62e1e2e1
7 changed files with 88 additions and 17 deletions

View File

@ -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
---------------- ----------------

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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):

View File

@ -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):

View File

@ -0,0 +1,5 @@
---
features:
- Support bulk deletion for ``volume type delete``.
[Bug `1592906 <https://bugs.launchpad.net/bugs/1592906>`_]