Merge "Add ability to specify mode to attachment-create"

This commit is contained in:
Zuul 2018-07-18 20:38:27 +00:00 committed by Gerrit Code Review
commit 49507ea1c0
8 changed files with 49 additions and 50 deletions

View File

@ -145,6 +145,8 @@ SUPPORT_VOLUME_TYPE_FILTER = '3.52'
SUPPORT_VOLUME_SCHEMA_CHANGES = '3.53' SUPPORT_VOLUME_SCHEMA_CHANGES = '3.53'
ATTACHMENT_CREATE_MODE_ARG = '3.54'
def get_mv_header(version): def get_mv_header(version):
"""Gets a formatted HTTP microversion header. """Gets a formatted HTTP microversion header.

View File

@ -125,6 +125,7 @@ REST_API_VERSION_HISTORY = """
2. Update volume API expects user to pass at least one valid 2. Update volume API expects user to pass at least one valid
parameter in the request body in order to update the volume. parameter in the request body in order to update the volume.
Also, additional parameters will not be allowed. Also, additional parameters will not be allowed.
* 3.54 - Add ``mode`` argument to attachment-create.
""" """
# The minimum and maximum versions of the API supported # The minimum and maximum versions of the API supported
@ -132,9 +133,9 @@ REST_API_VERSION_HISTORY = """
# minimum version of the API supported. # minimum version of the API supported.
# Explicitly using /v2 endpoints will still work # Explicitly using /v2 endpoints will still work
_MIN_API_VERSION = "3.0" _MIN_API_VERSION = "3.0"
_MAX_API_VERSION = "3.53" _MAX_API_VERSION = "3.54"
_LEGACY_API_VERSION2 = "2.0" _LEGACY_API_VERSION2 = "2.0"
UPDATED = "2018-06-29T05:34:49Z" UPDATED = "2018-07-17T00:00:00Z"
# NOTE(cyeoh): min and max versions declared as functions so we can # NOTE(cyeoh): min and max versions declared as functions so we can

View File

@ -433,3 +433,7 @@ volume APIs.
the volume was updated. the volume was updated.
But in 3.53, user will need to pass at least one valid parameter in the request But in 3.53, user will need to pass at least one valid parameter in the request
body otherwise it will return 400 error. body otherwise it will return 400 error.
3.54
----
Add ``mode`` argument to attachment-create.

View File

@ -164,14 +164,23 @@ class AttachmentsController(wsgi.Controller):
volume_ref = objects.Volume.get_by_id( volume_ref = objects.Volume.get_by_id(
context, context,
volume_uuid) volume_uuid)
connector = body['attachment'].get('connector', None) args = {'connector': body['attachment'].get('connector', None)}
if req.api_version_request.matches(mv.ATTACHMENT_CREATE_MODE_ARG):
# We check for attach_mode here and default to `null`
# if nothing's provided. This seems odd to not just
# set `rw`, BUT we want to keep compatability with
# setting the mode via the connector for now, so we
# use `null` as an identifier to distinguish that case
args['attach_mode'] = body['attachment'].get('mode', 'null')
err_msg = None err_msg = None
try: try:
attachment_ref = ( attachment_ref = (
self.volume_api.attachment_create(context, self.volume_api.attachment_create(context,
volume_ref, volume_ref,
instance_uuid, instance_uuid,
connector=connector)) **args))
except (exception.NotAuthorized, except (exception.NotAuthorized,
exception.InvalidVolume): exception.InvalidVolume):
raise raise

View File

@ -57,7 +57,7 @@ class AttachmentManagerTestCase(test.TestCase):
self.assertEqual(fake.UUID2, aref.instance_uuid) self.assertEqual(fake.UUID2, aref.instance_uuid)
self.assertIsNone(aref.attach_time) self.assertIsNone(aref.attach_time)
self.assertEqual('reserved', aref.attach_status) self.assertEqual('reserved', aref.attach_status)
self.assertIsNone(aref.attach_mode) self.assertEqual('null', aref.attach_mode)
self.assertEqual(vref.id, aref.volume_id) self.assertEqual(vref.id, aref.volume_id)
self.assertEqual({}, aref.connection_info) self.assertEqual({}, aref.connection_info)
@ -162,7 +162,7 @@ class AttachmentManagerTestCase(test.TestCase):
self.assertEqual(fake.UUID2, aref.instance_uuid) self.assertEqual(fake.UUID2, aref.instance_uuid)
self.assertIsNone(aref.attach_time) self.assertIsNone(aref.attach_time)
self.assertEqual('reserved', aref.attach_status) self.assertEqual('reserved', aref.attach_status)
self.assertIsNone(aref.attach_mode) self.assertEqual('null', aref.attach_mode)
self.assertEqual(vref.id, aref.volume_id) self.assertEqual(vref.id, aref.volume_id)
self.assertEqual({}, aref.connection_info) self.assertEqual({}, aref.connection_info)

View File

@ -43,31 +43,6 @@ class AttachmentManagerTestCase(test.TestCase):
self.manager.stats = {'allocated_capacity_gb': 100, self.manager.stats = {'allocated_capacity_gb': 100,
'pools': {}} 'pools': {}}
@mock.patch.object(db, 'volume_admin_metadata_update')
@mock.patch('cinder.message.api.API.create', mock.Mock())
def test_attachment_update_with_readonly_volume(self, mock_update):
mock_update.return_value = {'readonly': 'True'}
vref = tests_utils.create_volume(self.context, **{'status':
'available'})
self.manager.create_volume(self.context, vref)
attachment_ref = db.volume_attach(self.context,
{'volume_id': vref.id,
'volume_host': vref.host,
'attach_status': 'reserved',
'instance_uuid': fake.UUID1})
with mock.patch.object(self.manager,
'_notify_about_volume_usage',
return_value=None), mock.patch.object(
self.manager, '_connection_create'):
self.assertRaises(exception.InvalidVolumeAttachMode,
self.manager.attachment_update,
self.context, vref, {}, attachment_ref.id)
attachment = db.volume_attachment_get(self.context,
attachment_ref.id)
self.assertEqual(fields.VolumeAttachStatus.ERROR_ATTACHING,
attachment['attach_status'])
def test_attachment_update(self): def test_attachment_update(self):
"""Test attachment_update.""" """Test attachment_update."""
volume_params = {'status': 'available'} volume_params = {'status': 'available'}
@ -84,7 +59,8 @@ class AttachmentManagerTestCase(test.TestCase):
values = {'volume_id': vref.id, values = {'volume_id': vref.id,
'attached_host': vref.host, 'attached_host': vref.host,
'attach_status': 'reserved', 'attach_status': 'reserved',
'instance_uuid': fake.UUID1} 'instance_uuid': fake.UUID1,
'attach_mode': 'rw'}
attachment_ref = db.volume_attach(self.context, values) attachment_ref = db.volume_attach(self.context, values)
with mock.patch.object( with mock.patch.object(
self.manager, '_notify_about_volume_usage'),\ self.manager, '_notify_about_volume_usage'),\

View File

@ -2115,7 +2115,8 @@ class API(base.Base):
ctxt, ctxt,
volume_ref, volume_ref,
instance_uuid, instance_uuid,
connector=None): connector=None,
attach_mode='null'):
"""Create an attachment record for the specified volume.""" """Create an attachment record for the specified volume."""
ctxt.authorize(attachment_policy.CREATE_POLICY, target_obj=volume_ref) ctxt.authorize(attachment_policy.CREATE_POLICY, target_obj=volume_ref)
connection_info = {} connection_info = {}
@ -2129,10 +2130,23 @@ class API(base.Base):
connector, connector,
attachment_ref.id)) attachment_ref.id))
attachment_ref.connection_info = connection_info attachment_ref.connection_info = connection_info
# Use of admin_metadata for RO settings is deprecated
# switch to using mode argument to attachment-create
if self.db.volume_admin_metadata_get( if self.db.volume_admin_metadata_get(
ctxt.elevated(), ctxt.elevated(),
volume_ref['id']).get('readonly', False): volume_ref['id']).get('readonly', False):
LOG.warning("Using volume_admin_metadata to set "
"Read Only mode is deprecated! Please "
"use the mode argument in attachment-create.")
attachment_ref.attach_mode = 'ro' attachment_ref.attach_mode = 'ro'
# for now we have to let the admin_metadata override
# so we're using an else in the next step here, in
# other words, using volume_admin_metadata and mode params
# are NOT compatible
else:
attachment_ref.attach_mode = attach_mode
attachment_ref.save() attachment_ref.save()
return attachment_ref return attachment_ref

View File

@ -4387,29 +4387,22 @@ class VolumeManager(manager.CleanableManager,
self._notify_about_volume_usage(context, vref, 'attach.start') self._notify_about_volume_usage(context, vref, 'attach.start')
attachment_ref = objects.VolumeAttachment.get_by_id(context, attachment_ref = objects.VolumeAttachment.get_by_id(context,
attachment_id) attachment_id)
# Check to see if a mode parameter was set during attachment-create;
# this seems kinda wonky, but it's how we're keeping back compatability
# with the use of connector.mode for now. In other words, we're
# making sure we still honor ro settings from the connector but
# we override that if a value was specified in attachment-create
if attachment_ref.attach_mode != 'null':
mode = attachment_ref.attach_mode
connector['mode'] = mode
connection_info = self._connection_create(context, connection_info = self._connection_create(context,
vref, vref,
attachment_ref, attachment_ref,
connector) connector)
# FIXME(jdg): get rid of this admin_meta option here, the only thing
# it does is enforce that a volume is R/O, that should be done via a
# type and not *more* metadata
volume_metadata = self.db.volume_admin_metadata_update(
context.elevated(),
attachment_ref.volume_id,
{'attached_mode': mode}, False)
# The prior seting of mode in the attachment_ref overrides any
# settings within the connector when dealing with read only
# attachment options
if mode != 'ro' and attachment_ref.attach_mode == 'ro':
connector['mode'] = 'ro'
mode = 'ro'
try: try:
if volume_metadata.get('readonly') == 'True' and mode != 'ro':
raise exception.InvalidVolumeAttachMode(mode=mode,
volume_id=vref.id)
utils.require_driver_initialized(self.driver) utils.require_driver_initialized(self.driver)
self.driver.attach_volume(context, self.driver.attach_volume(context,
vref, vref,