from cinder import consistencygroup as consistencygroupAPI
from cinder import exception
from cinder.i18n import _, _LI
+from cinder.image import glance
from cinder.openstack.common import log as logging
from cinder.openstack.common import uuidutils
from cinder import utils
volumes = self._view_builder.summary_list(req, limited_list)
return volumes
- def _image_uuid_from_href(self, image_href):
- # If the image href was generated by nova api, strip image_href
+ def _image_uuid_from_ref(self, image_ref, context):
+ # If the image ref was generated by nova api, strip image_ref
# down to an id.
+ image_uuid = None
try:
- image_uuid = image_href.split('/').pop()
- except (TypeError, AttributeError):
+ image_uuid = image_ref.split('/').pop()
+ except AttributeError:
msg = _("Invalid imageRef provided.")
raise exc.HTTPBadRequest(explanation=msg)
- if not uuidutils.is_uuid_like(image_uuid):
- msg = _("Invalid imageRef provided.")
- raise exc.HTTPBadRequest(explanation=msg)
+ image_service = glance.get_default_image_service()
- return image_uuid
+ # First see if this is an actual image ID
+ if uuidutils.is_uuid_like(image_uuid):
+ try:
+ image = image_service.show(context, image_uuid)
+ if 'id' in image:
+ return image['id']
+ except Exception:
+ # Pass and see if there is a matching image name
+ pass
+
+ # Could not find by ID, check if it is an image name
+ try:
+ params = {'filters': {'name': image_ref}}
+ images = list(image_service.detail(context, **params))
+ if len(images) > 1:
+ msg = _("Multiple matches found for '%s', use an ID to be more"
+ " specific.") % image_ref
+ raise exc.HTTPConflict(msg)
+ for img in images:
+ return img['id']
+ except Exception:
+ # Pass and let default not found error handling take care of it
+ pass
+
+ msg = _("Invalid image identifier or unable to "
+ "access requested image.")
+ raise exc.HTTPBadRequest(explanation=msg)
@wsgi.response(202)
@wsgi.serializers(xml=VolumeTemplate)
LOG.info(_LI("Create volume of %s GB"), size, context=context)
if self.ext_mgr.is_loaded('os-image-create'):
- image_href = volume.get('imageRef')
- if image_href is not None:
- image_uuid = self._image_uuid_from_href(image_href)
+ image_ref = volume.get('imageRef')
+ if image_ref is not None:
+ image_uuid = self._image_uuid_from_ref(image_ref, context)
kwargs['image_id'] = image_uuid
kwargs['availability_zone'] = volume.get('availability_zone', None)
req,
body)
+ def test_volume_create_with_image_name(self):
+ self.stubs.Set(db, 'volume_get', stubs.stub_volume_get_db)
+ self.stubs.Set(volume_api.API, "create", stubs.stub_volume_create)
+ self.stubs.Set(fake_image._FakeImageService,
+ "detail",
+ stubs.stub_image_service_detail)
+
+ test_id = "Fedora-x86_64-20-20140618-sda"
+ self.ext_mgr.extensions = {'os-image-create': 'fake'}
+ vol = {"size": '1',
+ "name": "Volume Test Name",
+ "description": "Volume Test Desc",
+ "availability_zone": "nova",
+ "imageRef": test_id}
+ ex = {'volume': {'attachments': [{'device': '/',
+ 'host_name': None,
+ 'id': '1',
+ 'server_id': 'fakeuuid',
+ 'volume_id': '1'}],
+ 'availability_zone': 'nova',
+ 'bootable': 'false',
+ 'consistencygroup_id': None,
+ 'created_at': datetime.datetime(1900, 1, 1, 1, 1, 1),
+ 'description': 'Volume Test Desc',
+ 'encrypted': False,
+ 'id': '1',
+ 'links':
+ [{'href': 'http://localhost/v2/fakeproject/volumes/1',
+ 'rel': 'self'},
+ {'href': 'http://localhost/fakeproject/volumes/1',
+ 'rel': 'bookmark'}],
+ 'metadata': {},
+ 'name': 'Volume Test Name',
+ 'replication_status': 'disabled',
+ 'size': '1',
+ 'snapshot_id': None,
+ 'source_volid': None,
+ 'status': 'fakestatus',
+ 'user_id': 'fakeuser',
+ 'volume_type': 'vol_type_name'}}
+ body = {"volume": vol}
+ req = fakes.HTTPRequest.blank('/v2/volumes')
+ res_dict = self.controller.create(req, body)
+ self.assertEqual(ex, res_dict)
+
+ def test_volume_create_with_image_name_has_multiple(self):
+ self.stubs.Set(db, 'volume_get', stubs.stub_volume_get_db)
+ self.stubs.Set(volume_api.API, "create", stubs.stub_volume_create)
+ self.stubs.Set(fake_image._FakeImageService,
+ "detail",
+ stubs.stub_image_service_detail)
+
+ test_id = "multi"
+ self.ext_mgr.extensions = {'os-image-create': 'fake'}
+ vol = {"size": '1',
+ "name": "Volume Test Name",
+ "description": "Volume Test Desc",
+ "availability_zone": "nova",
+ "imageRef": test_id}
+ body = {"volume": vol}
+ req = fakes.HTTPRequest.blank('/v2/volumes')
+ self.assertRaises(webob.exc.HTTPBadRequest,
+ self.controller.create,
+ req,
+ body)
+
+ def test_volume_create_with_image_name_no_match(self):
+ self.stubs.Set(db, 'volume_get', stubs.stub_volume_get_db)
+ self.stubs.Set(volume_api.API, "create", stubs.stub_volume_create)
+ self.stubs.Set(fake_image._FakeImageService,
+ "detail",
+ stubs.stub_image_service_detail)
+
+ test_id = "MissingName"
+ self.ext_mgr.extensions = {'os-image-create': 'fake'}
+ vol = {"size": '1',
+ "name": "Volume Test Name",
+ "description": "Volume Test Desc",
+ "availability_zone": "nova",
+ "imageRef": test_id}
+ body = {"volume": vol}
+ req = fakes.HTTPRequest.blank('/v2/volumes')
+ self.assertRaises(webob.exc.HTTPBadRequest,
+ self.controller.create,
+ req,
+ body)
+
def test_volume_update(self):
self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_get)
self.stubs.Set(volume_api.API, "update", stubs.stub_volume_update)