def test_detach_volume_wait_error(self): server = dict(id='server001') attachments = [{'server_id': 'server001', 'device': 'device001'}] vol = {'id': 'volume001', 'status': 'attached', 'name': '', 'attachments': attachments} volume = meta.obj_to_dict(fakes.FakeVolume(**vol)) vol['status'] = 'error' vol['attachments'] = [] errored_volume = meta.obj_to_dict(fakes.FakeVolume(**vol)) self.register_uris([ dict(method='DELETE', uri=self.get_mock_url( 'compute', 'public', append=['servers', server['id'], 'os-volume_attachments', volume.id])), dict(method='GET', uri=self.get_mock_url( 'volumev2', 'public', append=['volumes', 'detail']), json={'volumes': [errored_volume]})]) with testtools.ExpectedException( shade.OpenStackCloudException, "Error in detaching volume %s" % errored_volume['id'] ): self.cloud.detach_volume(server, volume) self.assert_calls()
def test_detach_volume_wait(self): server = dict(id='server001') attachments = [{'server_id': 'server001', 'device': 'device001'}] vol = { 'id': 'volume001', 'status': 'attached', 'name': '', 'attachments': attachments } volume = meta.obj_to_munch(fakes.FakeVolume(**vol)) vol['status'] = 'available' vol['attachments'] = [] avail_volume = meta.obj_to_munch(fakes.FakeVolume(**vol)) self.register_uris([ dict(method='DELETE', uri=self.get_mock_url('compute', 'public', append=[ 'servers', server['id'], 'os-volume_attachments', volume.id ])), dict(method='GET', uri=self.get_mock_url('volumev2', 'public', append=['volumes', 'detail']), json={'volumes': [avail_volume]}) ]) self.cloud.detach_volume(server, volume) self.assert_calls()
def test_list_volumes(self): fake_volume = fakes.FakeVolume('volume1', 'available', 'Volume 1 Display Name') fake_volume_dict = meta.obj_to_munch(fake_volume) fake_volume2 = fakes.FakeVolume('volume2', 'available', 'Volume 2 Display Name') fake_volume2_dict = meta.obj_to_munch(fake_volume2) self.register_uris([ dict(method='GET', uri=self.get_mock_url( 'volumev2', 'public', append=['volumes', 'detail']), json={'volumes': [fake_volume_dict]}), dict(method='GET', uri=self.get_mock_url( 'volumev2', 'public', append=['volumes', 'detail']), json={'volumes': [fake_volume_dict, fake_volume2_dict]})]) self.assertEqual( [self.cloud._normalize_volume(fake_volume_dict)], self.cloud.list_volumes()) # this call should hit the cache self.assertEqual( [self.cloud._normalize_volume(fake_volume_dict)], self.cloud.list_volumes()) self.cloud.list_volumes.invalidate(self.cloud) self.assertEqual( [self.cloud._normalize_volume(fake_volume_dict), self.cloud._normalize_volume(fake_volume2_dict)], self.cloud.list_volumes()) self.assert_calls()
def test_attach_volume_wait(self): server = dict(id='server001') vol = {'id': 'volume001', 'status': 'available', 'name': '', 'attachments': []} volume = meta.obj_to_dict(fakes.FakeVolume(**vol)) vol['attachments'] = [{'server_id': server['id'], 'device': 'device001'}] vol['status'] = 'attached' attached_volume = meta.obj_to_dict(fakes.FakeVolume(**vol)) rattach = {'server_id': server['id'], 'device': 'device001', 'volumeId': volume['id'], 'id': 'attachmentId'} self.register_uris([ dict(method='POST', uri=self.get_mock_url( 'compute', 'public', append=['servers', server['id'], 'os-volume_attachments']), json={'volumeAttachment': rattach}, validate=dict(json={ 'volumeAttachment': { 'volumeId': vol['id']}})), dict(method='GET', uri=self.get_mock_url( 'volumev2', 'public', append=['volumes', 'detail']), json={'volumes': [volume]}), dict(method='GET', uri=self.get_mock_url( 'volumev2', 'public', append=['volumes', 'detail']), json={'volumes': [attached_volume]})]) # defaults to wait=True ret = self.cloud.attach_volume(server, volume) self.assertEqual(rattach, ret) self.assert_calls()
def test_attach_volume_wait_error(self): server = dict(id='server001') vol = {'id': 'volume001', 'status': 'available', 'name': '', 'attachments': []} volume = meta.obj_to_dict(fakes.FakeVolume(**vol)) vol['status'] = 'error' errored_volume = meta.obj_to_dict(fakes.FakeVolume(**vol)) rattach = {'server_id': server['id'], 'device': 'device001', 'volumeId': volume['id'], 'id': 'attachmentId'} self.register_uris([ dict(method='POST', uri=self.get_mock_url( 'compute', 'public', append=['servers', server['id'], 'os-volume_attachments']), json={'volumeAttachment': rattach}, validate=dict(json={ 'volumeAttachment': { 'volumeId': vol['id']}})), dict(method='GET', uri=self.get_mock_url( 'volumev2', 'public', append=['volumes', 'detail']), json={'volumes': [errored_volume]})]) with testtools.ExpectedException( shade.OpenStackCloudException, "Error in attaching volume %s" % errored_volume['id'] ): self.cloud.attach_volume(server, volume) self.assert_calls()
def test_create_volume_invalidates(self, cinder_mock): fake_volb4 = fakes.FakeVolume('volume1', 'available', 'Volume 1 Display Name') fake_volb4_dict = _utils.normalize_volumes( [meta.obj_to_dict(fake_volb4)])[0] cinder_mock.volumes.list.return_value = [fake_volb4] self.assertEqual([fake_volb4_dict], self.cloud.list_volumes()) volume = dict(display_name='junk_vol', size=1, display_description='test junk volume') fake_vol = fakes.FakeVolume('12345', 'creating', '') fake_vol_dict = meta.obj_to_dict(fake_vol) fake_vol_dict = _utils.normalize_volumes([meta.obj_to_dict(fake_vol) ])[0] cinder_mock.volumes.create.return_value = fake_vol cinder_mock.volumes.list.return_value = [fake_volb4, fake_vol] def creating_available(): def now_available(): fake_vol.status = 'available' fake_vol_dict['status'] = 'available' return mock.DEFAULT cinder_mock.volumes.list.side_effect = now_available return mock.DEFAULT cinder_mock.volumes.list.side_effect = creating_available self.cloud.create_volume(wait=True, timeout=None, **volume) self.assertTrue(cinder_mock.volumes.create.called) self.assertEqual(3, cinder_mock.volumes.list.call_count) # If cache was not invalidated, we would not see our own volume here # because the first volume was available and thus would already be # cached. self.assertEqual([fake_volb4_dict, fake_vol_dict], self.cloud.list_volumes()) # And now delete and check same thing since list is cached as all # available fake_vol.status = 'deleting' fake_vol_dict = meta.obj_to_dict(fake_vol) def deleting_gone(): def now_gone(): cinder_mock.volumes.list.return_value = [fake_volb4] return mock.DEFAULT cinder_mock.volumes.list.side_effect = now_gone return mock.DEFAULT cinder_mock.volumes.list.return_value = [fake_volb4, fake_vol] cinder_mock.volumes.list.side_effect = deleting_gone cinder_mock.volumes.delete.return_value = fake_vol_dict self.cloud.delete_volume('12345') self.assertEqual([fake_volb4_dict], self.cloud.list_volumes())
def test_list_volumes_creating_invalidates(self, cinder_mock): fake_volume = fakes.FakeVolume('volume1', 'creating', 'Volume 1 Display Name') fake_volume_dict = meta.obj_to_dict(fake_volume) cinder_mock.volumes.list.return_value = [fake_volume] self.assertEqual([fake_volume_dict], self.cloud.list_volumes()) fake_volume2 = fakes.FakeVolume('volume2', 'available', 'Volume 2 Display Name') fake_volume2_dict = meta.obj_to_dict(fake_volume2) cinder_mock.volumes.list.return_value = [fake_volume, fake_volume2] self.assertEqual([fake_volume_dict, fake_volume2_dict], self.cloud.list_volumes())
def test_list_volumes_with_pagination(self): vol1 = meta.obj_to_munch(fakes.FakeVolume('01', 'available', 'vol1')) vol2 = meta.obj_to_munch(fakes.FakeVolume('02', 'available', 'vol2')) self.register_uris([ dict(method='GET', uri=self.get_mock_url('volumev2', 'public', append=['volumes', 'detail']), json={ 'volumes': [vol1], 'volumes_links': [{ 'href': self.get_mock_url('volumev2', 'public', append=['volumes', 'detail'], qs_elements=['marker=01']), 'rel': 'next' }] }), dict(method='GET', uri=self.get_mock_url('volumev2', 'public', append=['volumes', 'detail'], qs_elements=['marker=01']), json={ 'volumes': [vol2], 'volumes_links': [{ 'href': self.get_mock_url('volumev2', 'public', append=['volumes', 'detail'], qs_elements=['marker=02']), 'rel': 'next' }] }), dict(method='GET', uri=self.get_mock_url('volumev2', 'public', append=['volumes', 'detail'], qs_elements=['marker=02']), json={'volumes': []}) ]) self.assertEqual([ self.cloud._normalize_volume(vol1), self.cloud._normalize_volume(vol2) ], self.cloud.list_volumes()) self.assert_calls()
def test_set_volume_bootable_false(self): vol = { 'id': 'volume001', 'status': 'attached', 'name': '', 'attachments': [] } volume = meta.obj_to_munch(fakes.FakeVolume(**vol)) self.register_uris([ dict(method='GET', uri=self.get_mock_url('volumev2', 'public', append=['volumes', 'detail']), json={'volumes': [volume]}), dict(method='POST', uri=self.get_mock_url('volumev2', 'public', append=['volumes', volume.id, 'action']), json={'os-set_bootable': { 'bootable': False }}), ]) self.cloud.set_volume_bootable(volume['id']) self.assert_calls()
def test_attach_volume_exception(self): server = dict(id='server001') vol = { 'id': 'volume001', 'status': 'available', 'name': '', 'attachments': [] } volume = meta.obj_to_munch(fakes.FakeVolume(**vol)) self.register_uris([ dict(method='POST', uri=self.get_mock_url( 'compute', 'public', append=['servers', server['id'], 'os-volume_attachments']), status_code=404, validate=dict( json={'volumeAttachment': { 'volumeId': vol['id'] }})) ]) with testtools.ExpectedException( shade.OpenStackCloudURINotFound, "Error attaching volume %s to server %s" % (volume['id'], server['id'])): self.cloud.attach_volume(server, volume, wait=False) self.assert_calls()
def test_delete_volume_force(self): vol = { 'id': 'volume001', 'status': 'attached', 'name': '', 'attachments': [] } volume = meta.obj_to_munch(fakes.FakeVolume(**vol)) self.register_uris([ dict(method='GET', uri=self.get_mock_url('volumev2', 'public', append=['volumes', 'detail']), json={'volumes': [volume]}), dict(method='POST', uri=self.get_mock_url('volumev2', 'public', append=['volumes', volume.id, 'action']), json={'os-force_delete': None}), dict(method='GET', uri=self.get_mock_url('volumev2', 'public', append=['volumes', 'detail']), json={'volumes': []}) ]) self.assertTrue(self.cloud.delete_volume(volume['id'], force=True)) self.assert_calls()
def test_attach_volume(self): server = dict(id='server001') vol = { 'id': 'volume001', 'status': 'available', 'name': '', 'attachments': [] } volume = meta.obj_to_munch(fakes.FakeVolume(**vol)) rattach = { 'server_id': server['id'], 'device': 'device001', 'volumeId': volume['id'], 'id': 'attachmentId' } self.register_uris([ dict(method='POST', uri=self.get_mock_url( 'compute', 'public', append=['servers', server['id'], 'os-volume_attachments']), json={'volumeAttachment': rattach}, validate=dict( json={'volumeAttachment': { 'volumeId': vol['id'] }})) ]) ret = self.cloud.attach_volume(server, volume, wait=False) self.assertEqual(rattach, ret) self.assert_calls()
def test_list_volumes(self, cinder_mock): fake_volume = fakes.FakeVolume('volume1', 'available', 'Volume 1 Display Name') fake_volume_dict = _utils.normalize_volumes( [meta.obj_to_dict(fake_volume)])[0] cinder_mock.volumes.list.return_value = [fake_volume] self.assertEqual([fake_volume_dict], self.cloud.list_volumes()) fake_volume2 = fakes.FakeVolume('volume2', 'available', 'Volume 2 Display Name') fake_volume2_dict = _utils.normalize_volumes( [meta.obj_to_dict(fake_volume2)])[0] cinder_mock.volumes.list.return_value = [fake_volume, fake_volume2] self.assertEqual([fake_volume_dict], self.cloud.list_volumes()) self.cloud.list_volumes.invalidate(self.cloud) self.assertEqual([fake_volume_dict, fake_volume2_dict], self.cloud.list_volumes())
def test_create_bootable_volume(self): vol1 = meta.obj_to_munch(fakes.FakeVolume('01', 'available', 'vol1')) self.register_uris([ dict(method='POST', uri=self.get_mock_url('volumev2', 'public', append=['volumes']), json={'volume': vol1}, validate=dict(json={'volume': { 'size': 50, 'name': 'vol1', }})), dict(method='GET', uri=self.get_mock_url('volumev2', 'public', append=['volumes', 'detail']), json={'volumes': [vol1]}), dict(method='POST', uri=self.get_mock_url('volumev2', 'public', append=['volumes', '01', 'action']), validate=dict(json={'os-set_bootable': { 'bootable': True }})), ]) self.cloud.create_volume(50, name='vol1', bootable=True) self.assert_calls()
def test_get_volume_by_id(self): vol1 = meta.obj_to_munch(fakes.FakeVolume('01', 'available', 'vol1')) self.register_uris([ dict(method='GET', uri=self.get_mock_url('volumev2', 'public', append=['volumes', '01']), json={'volume': vol1}) ]) self.assertEqual(self.cloud._normalize_volume(vol1), self.cloud.get_volume_by_id('01')) self.assert_calls()
def test_has_volume(self): mock_cloud = mock.MagicMock() fake_volume = fakes.FakeVolume( id='volume1', status='available', name='Volume 1 Display Name', attachments=[{'device': '/dev/sda0'}]) fake_volume_dict = meta.obj_to_dict(fake_volume) mock_cloud.get_volumes.return_value = [fake_volume_dict] hostvars = meta.get_hostvars_from_server( mock_cloud, meta.obj_to_dict(FakeServer())) self.assertEquals('volume1', hostvars['volumes'][0]['id']) self.assertEquals('/dev/sda0', hostvars['volumes'][0]['device'])
def test_delete_volume_gone_away(self): vol = {'id': 'volume001', 'status': 'attached', 'name': '', 'attachments': []} volume = meta.obj_to_dict(fakes.FakeVolume(**vol)) self.register_uris([ dict(method='GET', uri=self.get_mock_url( 'volumev2', 'public', append=['volumes', 'detail']), json={'volumes': [volume]}), dict(method='DELETE', uri=self.get_mock_url( 'volumev2', 'public', append=['volumes', volume.id]), status_code=404)]) self.assertFalse(self.cloud.delete_volume(volume['id'])) self.assert_calls()
def test_list_volumes_with_pagination_next_link_fails_all_attempts(self): vol1 = meta.obj_to_munch(fakes.FakeVolume('01', 'available', 'vol1')) uris = [] attempts = 5 for i in range(attempts): uris.extend([ dict(method='GET', uri=self.get_mock_url('volumev2', 'public', append=['volumes', 'detail']), json={ 'volumes': [vol1], 'volumes_links': [{ 'href': self.get_mock_url('volumev2', 'public', append=['volumes', 'detail'], qs_elements=['marker=01']), 'rel': 'next' }] }), dict(method='GET', uri=self.get_mock_url('volumev2', 'public', append=['volumes', 'detail'], qs_elements=['marker=01']), status_code=404) ]) self.register_uris(uris) # Check that found volumes are returned even if pagination didn't # complete because call to get next link 404'ed for all the allowed # attempts self.assertEqual([self.cloud._normalize_volume(vol1)], self.cloud.list_volumes()) self.assert_calls()
def test_create_boot_attach_volume(self): build_server = fakes.make_fake_server('1234', '', 'BUILD') active_server = fakes.make_fake_server('1234', '', 'BUILD') vol = { 'id': 'volume001', 'status': 'available', 'name': '', 'attachments': [] } volume = meta.obj_to_munch(fakes.FakeVolume(**vol)) self.register_uris( [ dict(method='GET', uri=self.get_mock_url('network', 'public', append=['v2.0', 'networks.json']), json={'networks': []}), dict(method='POST', uri=self.get_mock_url('compute', 'public', append=['os-volumes_boot']), json={'server': build_server}, validate=dict( json={ 'server': { u'flavorRef': 'flavor-id', u'imageRef': 'image-id', u'max_count': 1, u'min_count': 1, u'block_device_mapping_v2': [ { u'boot_index': 0, u'delete_on_termination': True, u'destination_type': u'local', u'source_type': u'image', u'uuid': u'image-id' }, { u'boot_index': u'-1', u'delete_on_termination': False, u'destination_type': u'volume', u'source_type': u'volume', u'uuid': u'volume001' } ], u'name': u'server-name' } })), dict(method='GET', uri=self.get_mock_url('compute', 'public', append=['servers', '1234']), json={'server': active_server}), ]) self.cloud.create_server(name='server-name', image=dict(id='image-id'), flavor=dict(id='flavor-id'), boot_from_volume=False, volumes=[volume], wait=False) self.assert_calls()
def test_create_volume_invalidates(self): fake_volb4 = meta.obj_to_munch( fakes.FakeVolume('volume1', 'available', '')) _id = '12345' fake_vol_creating = meta.obj_to_munch( fakes.FakeVolume(_id, 'creating', '')) fake_vol_avail = meta.obj_to_munch( fakes.FakeVolume(_id, 'available', '')) def now_deleting(request, context): fake_vol_avail['status'] = 'deleting' self.register_uris([ dict(method='GET', uri=self.get_mock_url( 'volumev2', 'public', append=['volumes', 'detail']), json={'volumes': [fake_volb4]}), dict(method='POST', uri=self.get_mock_url( 'volumev2', 'public', append=['volumes']), json={'volume': fake_vol_creating}), dict(method='GET', uri=self.get_mock_url( 'volumev2', 'public', append=['volumes', 'detail']), json={'volumes': [fake_volb4, fake_vol_creating]}), dict(method='GET', uri=self.get_mock_url( 'volumev2', 'public', append=['volumes', 'detail']), json={'volumes': [fake_volb4, fake_vol_avail]}), dict(method='GET', uri=self.get_mock_url( 'volumev2', 'public', append=['volumes', 'detail']), json={'volumes': [fake_volb4, fake_vol_avail]}), dict(method='DELETE', uri=self.get_mock_url( 'volumev2', 'public', append=['volumes', _id]), json=now_deleting), dict(method='GET', uri=self.get_mock_url( 'volumev2', 'public', append=['volumes', 'detail']), json={'volumes': [fake_volb4]})]) self.assertEqual( [self.cloud._normalize_volume(fake_volb4)], self.cloud.list_volumes()) volume = dict(display_name='junk_vol', size=1, display_description='test junk volume') self.cloud.create_volume(wait=True, timeout=None, **volume) # If cache was not invalidated, we would not see our own volume here # because the first volume was available and thus would already be # cached. self.assertEqual( [self.cloud._normalize_volume(fake_volb4), self.cloud._normalize_volume(fake_vol_avail)], self.cloud.list_volumes()) self.cloud.delete_volume(_id) # And now delete and check same thing since list is cached as all # available self.assertEqual( [self.cloud._normalize_volume(fake_volb4)], self.cloud.list_volumes()) self.assert_calls()