Merge "Add update to volume and snapshot controllers"

This commit is contained in:
Jenkins 2012-09-18 20:13:30 +00:00 committed by Gerrit Code Review
commit 45e67e8b77
10 changed files with 221 additions and 6 deletions

View File

@ -173,6 +173,39 @@ class SnapshotsController(wsgi.Controller):
return {'snapshot': retval}
@wsgi.serializers(xml=SnapshotTemplate)
def update(self, req, id, body):
"""Update a snapshot."""
context = req.environ['cinder.context']
if not body:
raise exc.HTTPUnprocessableEntity()
if not 'snapshot' in body:
raise exc.HTTPUnprocessableEntity()
snapshot = body['snapshot']
update_dict = {}
valid_update_keys = (
'display_name',
'display_description',
)
for key in valid_update_keys:
if key in snapshot:
update_dict[key] = snapshot[key]
try:
snapshot = self.volume_api.get_snapshot(context, id)
self.volume_api.update_snapshot(context, snapshot, update_dict)
except exception.NotFound:
raise exc.HTTPNotFound()
snapshot.update(update_dict)
return {'snapshot': _translate_snapshot_detail_view(context, snapshot)}
def create_resource(ext_mgr):
return wsgi.Resource(SnapshotsController(ext_mgr))

View File

@ -338,6 +338,39 @@ class VolumeController(wsgi.Controller):
"""Return volume search options allowed by non-admin."""
return ('display_name', 'status')
@wsgi.serializers(xml=VolumeTemplate)
def update(self, req, id, body):
"""Update a volume."""
context = req.environ['cinder.context']
if not body:
raise exc.HTTPUnprocessableEntity()
if not 'volume' in body:
raise exc.HTTPUnprocessableEntity()
volume = body['volume']
update_dict = {}
valid_update_keys = (
'display_name',
'display_description',
)
for key in valid_update_keys:
if key in volume:
update_dict[key] = volume[key]
try:
volume = self.volume_api.get(context, id)
self.volume_api.update(context, volume, update_dict)
except exception.NotFound:
raise exc.HTTPNotFound()
volume.update(update_dict)
return {'volume': _translate_volume_detail_view(context, volume)}
def create_resource(ext_mgr):
return wsgi.Resource(VolumeController(ext_mgr))

View File

@ -277,3 +277,7 @@ def stub_snapshot_get_all(self):
def stub_snapshot_get_all_by_project(self, context):
return [stub_snapshot(1)]
def stub_snapshot_update(self, context, *args, **param):
pass

View File

@ -118,6 +118,49 @@ class SnapshotApiTest(test.TestCase):
self.assertEqual(resp_dict['snapshot']['display_description'],
snapshot['display_description'])
def test_snapshot_update(self):
self.stubs.Set(volume.api.API, "get_snapshot", stub_snapshot_get)
self.stubs.Set(volume.api.API, "update_snapshot",
fakes.stub_snapshot_update)
updates = {
"display_name": "Updated Test Name",
}
body = {"snapshot": updates}
req = fakes.HTTPRequest.blank('/v1/snapshots/%s' % UUID)
res_dict = self.controller.update(req, UUID, body)
expected = {'snapshot': {
'id': UUID,
'volume_id': 12,
'status': 'available',
'size': 100,
'created_at': None,
'display_name': 'Updated Test Name',
'display_description': 'Default description',
}}
self.assertEquals(expected, res_dict)
def test_snapshot_update_missing_body(self):
body = {}
req = fakes.HTTPRequest.blank('/v1/snapshots/%s' % UUID)
self.assertRaises(webob.exc.HTTPUnprocessableEntity,
self.controller.update, req, UUID, body)
def test_snapshot_update_invalid_body(self):
body = {'display_name': 'missing top level snapshot key'}
req = fakes.HTTPRequest.blank('/v1/snapshots/%s' % UUID)
self.assertRaises(webob.exc.HTTPUnprocessableEntity,
self.controller.update, req, UUID, body)
def test_snapshot_update_not_found(self):
self.stubs.Set(volume.api.API, "get_snapshot", stub_snapshot_get)
updates = {
"display_name": "Updated Test Name",
}
body = {"snapshot": updates}
req = fakes.HTTPRequest.blank('/v1/snapshots/not-the-uuid')
self.assertRaises(webob.exc.HTTPNotFound, self.controller.update, req,
'not-the-uuid', body)
def test_snapshot_delete(self):
self.stubs.Set(volume.api.API, "get_snapshot", stub_snapshot_get)
self.stubs.Set(volume.api.API, "delete_snapshot", stub_snapshot_delete)

View File

@ -179,6 +179,59 @@ class VolumeApiTest(test.TestCase):
req,
body)
def test_volume_update(self):
self.stubs.Set(volume_api.API, "update", fakes.stub_volume_update)
updates = {
"display_name": "Updated Test Name",
}
body = {"volume": updates}
req = fakes.HTTPRequest.blank('/v1/volumes/1')
res_dict = self.controller.update(req, '1', body)
expected = {'volume': {
'status': 'fakestatus',
'display_description': 'displaydesc',
'availability_zone': 'fakeaz',
'display_name': 'Updated Test Name',
'attachments': [{
'id': '1',
'volume_id': '1',
'server_id': 'fakeuuid',
'device': '/',
}],
'volume_type': 'vol_type_name',
'snapshot_id': None,
'metadata': {},
'id': '1',
'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
'size': 1,
}}
self.assertEquals(res_dict, expected)
def test_update_empty_body(self):
body = {}
req = fakes.HTTPRequest.blank('/v1/volumes/1')
self.assertRaises(webob.exc.HTTPUnprocessableEntity,
self.controller.update,
req, '1', body)
def test_update_invalid_body(self):
body = {'display_name': 'missing top level volume key'}
req = fakes.HTTPRequest.blank('/v1/volumes/1')
self.assertRaises(webob.exc.HTTPUnprocessableEntity,
self.controller.update,
req, '1', body)
def test_update_not_found(self):
self.stubs.Set(volume_api.API, "get", fakes.stub_volume_get_notfound)
updates = {
"display_name": "Updated Test Name",
}
body = {"volume": updates}
req = fakes.HTTPRequest.blank('/v1/volumes/1')
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.update,
req, '1', body)
def test_volume_list(self):
self.stubs.Set(volume_api.API, 'get_all',
fakes.stub_volume_get_all_by_project)

View File

@ -214,3 +214,6 @@ class TestOpenStackClient(object):
def delete_volume(self, volume_id):
return self.api_delete('/volumes/%s' % volume_id)
def put_volume(self, volume_id, volume):
return self.api_put('/volumes/%s' % volume_id, volume)['volume']

View File

@ -177,5 +177,22 @@ class VolumesTest(integrated_helpers._IntegratedTestBase):
self.assertEqual(created_volume_id, found_volume['id'])
self.assertEqual(availability_zone, found_volume['availability_zone'])
def test_create_and_update_volume(self):
# Create vol1
created_volume = self.api.post_volume({'volume': {
'size': 1, 'display_name': 'vol1'}})
self.assertEqual(created_volume['display_name'], 'vol1')
created_volume_id = created_volume['id']
# update volume
body = {'volume': {'display_name': 'vol-one'}}
updated_volume = self.api.put_volume(created_volume_id, body)
self.assertEqual(updated_volume['display_name'], 'vol-one')
# check for update
found_volume = self.api.get_volume(created_volume_id)
self.assertEqual(created_volume_id, found_volume['id'])
self.assertEqual(found_volume['display_name'], 'vol-one')
if __name__ == "__main__":
unittest.main()

View File

@ -23,6 +23,7 @@
"volume:delete_snapshot": [],
"volume:get_snapshot": [],
"volume:get_all_snapshots": [],
"volume:update_snapshot": [],
"volume_extension:volume_admin_actions:reset_status": [["rule:admin_api"]],
"volume_extension:snapshot_admin_actions:reset_status": [["rule:admin_api"]],

View File

@ -158,7 +158,7 @@ class VolumeTestCase(test.TestCase):
"""Test volume can be created from a snapshot."""
volume_src = self._create_volume()
self.volume.create_volume(self.context, volume_src['id'])
snapshot_id = self._create_snapshot(volume_src['id'])
snapshot_id = self._create_snapshot(volume_src['id'])['id']
self.volume.create_snapshot(self.context, volume_src['id'],
snapshot_id)
volume_dst = self._create_volume(0, snapshot_id)
@ -250,13 +250,13 @@ class VolumeTestCase(test.TestCase):
snap['project_id'] = 'fake'
snap['volume_id'] = volume_id
snap['status'] = "creating"
return db.snapshot_create(context.get_admin_context(), snap)['id']
return db.snapshot_create(context.get_admin_context(), snap)
def test_create_delete_snapshot(self):
"""Test snapshot can be created and deleted."""
volume = self._create_volume()
self.volume.create_volume(self.context, volume['id'])
snapshot_id = self._create_snapshot(volume['id'])
snapshot_id = self._create_snapshot(volume['id'])['id']
self.volume.create_snapshot(self.context, volume['id'], snapshot_id)
self.assertEqual(snapshot_id,
db.snapshot_get(context.get_admin_context(),
@ -318,7 +318,7 @@ class VolumeTestCase(test.TestCase):
"""Test volume can't be deleted with dependent snapshots."""
volume = self._create_volume()
self.volume.create_volume(self.context, volume['id'])
snapshot_id = self._create_snapshot(volume['id'])
snapshot_id = self._create_snapshot(volume['id'])['id']
self.volume.create_snapshot(self.context, volume['id'], snapshot_id)
self.assertEqual(snapshot_id,
db.snapshot_get(context.get_admin_context(),
@ -340,7 +340,7 @@ class VolumeTestCase(test.TestCase):
"""Test snapshot can be created and deleted."""
volume = self._create_volume()
self.volume.create_volume(self.context, volume['id'])
snapshot_id = self._create_snapshot(volume['id'])
snapshot_id = self._create_snapshot(volume['id'])['id']
self.volume.create_snapshot(self.context, volume['id'], snapshot_id)
snapshot = db.snapshot_get(context.get_admin_context(),
snapshot_id)
@ -388,7 +388,7 @@ class VolumeTestCase(test.TestCase):
volume = self._create_volume()
volume_id = volume['id']
self.volume.create_volume(self.context, volume_id)
snapshot_id = self._create_snapshot(volume_id)
snapshot_id = self._create_snapshot(volume_id)['id']
self.volume.create_snapshot(self.context, volume_id, snapshot_id)
self.mox.StubOutWithMock(self.volume.driver, 'delete_snapshot')
@ -717,6 +717,30 @@ class VolumeTestCase(test.TestCase):
volume = db.volume_get(self.context, volume['id'])
self.assertEqual(volume['status'], "in-use")
def test_volume_api_update(self):
# create a raw vol
volume = self._create_volume()
# use volume.api to update name
volume_api = cinder.volume.api.API()
update_dict = {'display_name': 'test update name'}
volume_api.update(self.context, volume, update_dict)
# read changes from db
vol = db.volume_get(context.get_admin_context(), volume['id'])
self.assertEquals(vol['display_name'], 'test update name')
def test_volume_api_update_snapshot(self):
# create raw snapshot
volume = self._create_volume()
snapshot = self._create_snapshot(volume['id'])
self.assertEquals(snapshot['display_name'], None)
# use volume.api to update name
volume_api = cinder.volume.api.API()
update_dict = {'display_name': 'test update name'}
volume_api.update_snapshot(self.context, snapshot, update_dict)
# read changes from db
snap = db.snapshot_get(context.get_admin_context(), snapshot['id'])
self.assertEquals(snap['display_name'], 'test update name')
class DriverTestCase(test.TestCase):
"""Base Test class for Drivers."""

View File

@ -455,6 +455,10 @@ class API(base.Base):
{"method": "delete_snapshot",
"args": {"snapshot_id": snapshot['id']}})
@wrap_check_policy
def update_snapshot(self, context, snapshot, fields):
self.db.snapshot_update(context, snapshot['id'], fields)
@wrap_check_policy
def get_volume_metadata(self, context, volume):
"""Get all metadata associated with a volume."""