Merge "Reset state robustification for volume os-reset_status"
This commit is contained in:
commit
ef08a0eb30
@ -132,10 +132,6 @@ class VolumeAdminController(AdminController):
|
||||
message)
|
||||
|
||||
def _update(self, *args, **kwargs):
|
||||
context = args[0]
|
||||
volume_id = args[1]
|
||||
volume = objects.Volume.get_by_id(context, volume_id)
|
||||
self.authorize(context, 'reset_status', target_obj=volume)
|
||||
db.volume_update(*args, **kwargs)
|
||||
|
||||
def _get(self, *args, **kwargs):
|
||||
@ -165,6 +161,53 @@ class VolumeAdminController(AdminController):
|
||||
|
||||
return update
|
||||
|
||||
@wsgi.response(HTTPStatus.ACCEPTED)
|
||||
@wsgi.action('os-reset_status')
|
||||
def _reset_status(self, req, id, body):
|
||||
"""Reset status on the volume."""
|
||||
|
||||
def _clean_volume_attachment(context, id):
|
||||
attachments = (
|
||||
db.volume_attachment_get_all_by_volume_id(context, id))
|
||||
for attachment in attachments:
|
||||
db.volume_detached(context.elevated(), id, attachment.id)
|
||||
db.volume_admin_metadata_delete(context.elevated(), id,
|
||||
'attached_mode')
|
||||
|
||||
# any exceptions raised will be handled at the wsgi level
|
||||
update = self.validate_update(req, body=body)
|
||||
context = req.environ['cinder.context']
|
||||
volume = objects.Volume.get_by_id(context, id)
|
||||
self.authorize(context, 'reset_status', target_obj=volume)
|
||||
|
||||
# at this point, we still don't know if we're going to
|
||||
# reset the volume's state. Need to check what the caller
|
||||
# is requesting first.
|
||||
if update.get('status') in ('deleting', 'error_deleting'
|
||||
'detaching'):
|
||||
msg = _("Cannot reset-state to %s"
|
||||
% update.get('status'))
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
if update.get('status') == 'in-use':
|
||||
attachments = (
|
||||
db.volume_attachment_get_all_by_volume_id(context, id))
|
||||
if not attachments:
|
||||
msg = _("Cannot reset-state to in-use "
|
||||
"because volume does not have any attachments.")
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
msg = "Updating %(resource)s '%(id)s' with '%(update)r'"
|
||||
LOG.debug(msg, {'resource': self.resource_name, 'id': id,
|
||||
'update': update})
|
||||
self._notify_reset_status(context, id, 'reset_status.start')
|
||||
|
||||
self._update(context, id, update)
|
||||
self._remove_worker(context, id)
|
||||
if update.get('attach_status') == 'detached':
|
||||
_clean_volume_attachment(context, id)
|
||||
|
||||
self._notify_reset_status(context, id, 'reset_status.end')
|
||||
|
||||
@wsgi.response(HTTPStatus.ACCEPTED)
|
||||
@wsgi.action('os-force_detach')
|
||||
@validation.schema(admin_actions.force_detach)
|
||||
|
@ -39,6 +39,7 @@ from cinder.tests.unit.api.v3 import fakes as v3_fakes
|
||||
from cinder.tests.unit import cast_as_call
|
||||
from cinder.tests.unit import fake_constants as fake
|
||||
from cinder.tests.unit import fake_snapshot
|
||||
from cinder.tests.unit import fake_volume
|
||||
from cinder.tests.unit import test
|
||||
from cinder.tests.unit import utils as test_utils
|
||||
from cinder.volume import api as volume_api
|
||||
@ -217,6 +218,77 @@ class AdminActionsTest(BaseAdminTest):
|
||||
self.assertEqual(fields.VolumeAttachStatus.DETACHED,
|
||||
volume['attach_status'])
|
||||
|
||||
def test_reset_detached_status_to_attached(self):
|
||||
volume = db.volume_create(self.ctx,
|
||||
{'status': 'available',
|
||||
'attach_status':
|
||||
fields.VolumeAttachStatus.DETACHED,
|
||||
'volume_type_id': fake.VOLUME_TYPE_ID})
|
||||
resp = self._issue_volume_reset(self.ctx,
|
||||
volume,
|
||||
{'attach_status':
|
||||
fields.VolumeAttachStatus.ATTACHED})
|
||||
self.assertEqual(HTTPStatus.ACCEPTED, resp.status_int)
|
||||
volume = db.volume_get(self.ctx, volume['id'])
|
||||
self.assertEqual(fields.VolumeAttachStatus.ATTACHED,
|
||||
volume['attach_status'])
|
||||
|
||||
def test_reset_attached_status_to_attached(self):
|
||||
volume = db.volume_create(self.ctx,
|
||||
{'status': 'available',
|
||||
'attach_status':
|
||||
fields.VolumeAttachStatus.ATTACHED,
|
||||
'volume_type_id': fake.VOLUME_TYPE_ID})
|
||||
resp = self._issue_volume_reset(self.ctx,
|
||||
volume,
|
||||
{'attach_status':
|
||||
fields.VolumeAttachStatus.ATTACHED})
|
||||
self.assertEqual(HTTPStatus.ACCEPTED, resp.status_int)
|
||||
volume = db.volume_get(self.ctx, volume['id'])
|
||||
self.assertEqual(fields.VolumeAttachStatus.ATTACHED,
|
||||
volume['attach_status'])
|
||||
|
||||
def test_reset_in_use_to_in_use_fail(self):
|
||||
volume = db.volume_create(self.ctx,
|
||||
{'status': 'in-use',
|
||||
'attach_status':
|
||||
fields.VolumeAttachStatus.ATTACHED,
|
||||
'volume_type_id': fake.VOLUME_TYPE_ID})
|
||||
resp = self._issue_volume_reset(self.ctx,
|
||||
volume,
|
||||
{'status': 'in-use'})
|
||||
self.assertEqual(HTTPStatus.BAD_REQUEST, resp.status_int)
|
||||
|
||||
def test_reset_available_to_in_use_on_nonattached_volume_fail(self):
|
||||
volume = db.volume_create(self.ctx,
|
||||
{'status': 'available',
|
||||
'attach_status':
|
||||
fields.VolumeAttachStatus.DETACHED,
|
||||
'volume_type_id': fake.VOLUME_TYPE_ID})
|
||||
resp = self._issue_volume_reset(self.ctx,
|
||||
volume,
|
||||
{'status': 'in-use'})
|
||||
self.assertEqual(HTTPStatus.BAD_REQUEST, resp.status_int)
|
||||
|
||||
@mock.patch('cinder.db.volume_attachment_get_all_by_volume_id')
|
||||
def test_reset_available_to_in_use_on_attached_volume(
|
||||
self, get_attachment):
|
||||
volume = db.volume_create(self.ctx,
|
||||
{'status': 'available',
|
||||
'attach_status':
|
||||
fields.VolumeAttachStatus.ATTACHED,
|
||||
'volume_type_id': fake.VOLUME_TYPE_ID})
|
||||
resp = self._issue_volume_reset(self.ctx,
|
||||
volume,
|
||||
{'status': 'in-use'})
|
||||
db_attachment = fake_volume.volume_attachment_db_obj()
|
||||
get_attachment.return_value = [db_attachment]
|
||||
self.assertEqual(HTTPStatus.ACCEPTED, resp.status_int)
|
||||
volume = db.volume_get(self.ctx, volume['id'])
|
||||
self.assertEqual(fields.VolumeAttachStatus.ATTACHED,
|
||||
volume['attach_status'])
|
||||
self.assertEqual('in-use', volume['status'])
|
||||
|
||||
def test_reset_migration_invalid_status(self):
|
||||
volume = db.volume_create(self.ctx, {'migration_status': None,
|
||||
'volume_type_id':
|
||||
|
Loading…
Reference in New Issue
Block a user