1# Copyright 2010 United States Government as represented by the 2# Administrator of the National Aeronautics and Space Administration. 3# All Rights Reserved. 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); you may 6# not use this file except in compliance with the License. You may obtain 7# a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14# License for the specific language governing permissions and limitations 15# under the License. 16import mock 17from oslo_config import cfg 18 19from cinder import context 20from cinder import db 21from cinder import exception 22from cinder import objects 23from cinder.objects import fields 24from cinder import service 25from cinder.tests.unit.api import fakes 26from cinder.tests.unit import utils as tests_utils 27from cinder.tests.unit import volume as base 28 29 30CONF = cfg.CONF 31 32 33class VolumeCleanupTestCase(base.BaseVolumeTestCase): 34 MOCK_WORKER = False 35 36 def setUp(self): 37 super(VolumeCleanupTestCase, self).setUp() 38 self.service_id = 1 39 self.mock_object(service.Service, 'service_id', self.service_id) 40 self.patch('cinder.volume.utils.clear_volume', autospec=True) 41 42 def _assert_workers_are_removed(self): 43 workers = db.worker_get_all(self.context, read_deleted='yes') 44 self.assertListEqual([], workers) 45 46 def test_init_host_clears_uploads_available_volume(self): 47 """init_host will clean an available volume stuck in uploading.""" 48 volume = tests_utils.create_volume(self.context, status='uploading', 49 size=0, host=CONF.host) 50 51 db.worker_create(self.context, resource_type='Volume', 52 resource_id=volume.id, status=volume.status, 53 service_id=self.service_id) 54 55 self.volume.init_host(service_id=service.Service.service_id) 56 volume.refresh() 57 self.assertEqual("available", volume.status) 58 self._assert_workers_are_removed() 59 60 @mock.patch('cinder.manager.CleanableManager.init_host') 61 def test_init_host_clears_uploads_in_use_volume(self, init_host_mock): 62 """init_host will clean an in-use volume stuck in uploading.""" 63 volume = tests_utils.create_volume(self.context, status='uploading', 64 size=0, host=CONF.host) 65 66 db.worker_create(self.context, resource_type='Volume', 67 resource_id=volume.id, status=volume.status, 68 service_id=self.service_id) 69 70 fake_uuid = fakes.get_fake_uuid() 71 tests_utils.attach_volume(self.context, volume.id, fake_uuid, 72 'fake_host', '/dev/vda') 73 self.volume.init_host(service_id=mock.sentinel.service_id) 74 init_host_mock.assert_called_once_with( 75 service_id=mock.sentinel.service_id, added_to_cluster=None) 76 volume.refresh() 77 self.assertEqual("in-use", volume.status) 78 self._assert_workers_are_removed() 79 80 @mock.patch('cinder.image.image_utils.cleanup_temporary_file') 81 def test_init_host_clears_downloads(self, mock_cleanup_tmp_file): 82 """Test that init_host will unwedge a volume stuck in downloading.""" 83 volume = tests_utils.create_volume(self.context, status='downloading', 84 size=0, host=CONF.host) 85 db.worker_create(self.context, resource_type='Volume', 86 resource_id=volume.id, status=volume.status, 87 service_id=self.service_id) 88 mock_clear = self.mock_object(self.volume.driver, 'clear_download') 89 90 self.volume.init_host(service_id=service.Service.service_id) 91 self.assertEqual(1, mock_clear.call_count) 92 self.assertEqual(volume.id, mock_clear.call_args[0][1].id) 93 volume.refresh() 94 self.assertEqual("error", volume['status']) 95 mock_cleanup_tmp_file.assert_called_once_with(CONF.host) 96 97 self.volume.delete_volume(self.context, volume=volume) 98 self._assert_workers_are_removed() 99 100 @mock.patch('cinder.image.image_utils.cleanup_temporary_file') 101 def test_init_host_resumes_deletes(self, mock_cleanup_tmp_file): 102 """init_host will resume deleting volume in deleting status.""" 103 volume = tests_utils.create_volume(self.context, status='deleting', 104 size=0, host=CONF.host) 105 106 db.worker_create(self.context, resource_type='Volume', 107 resource_id=volume.id, status=volume.status, 108 service_id=self.service_id) 109 110 self.volume.init_host(service_id=service.Service.service_id) 111 112 self.assertRaises(exception.VolumeNotFound, db.volume_get, 113 context.get_admin_context(), volume.id) 114 mock_cleanup_tmp_file.assert_called_once_with(CONF.host) 115 self._assert_workers_are_removed() 116 117 @mock.patch('cinder.image.image_utils.cleanup_temporary_file') 118 def test_create_volume_fails_with_creating_and_downloading_status( 119 self, mock_cleanup_tmp_file): 120 """Test init_host_with_service in case of volume. 121 122 While the status of volume is 'creating' or 'downloading', 123 volume process down. 124 After process restarting this 'creating' status is changed to 'error'. 125 """ 126 for status in ('creating', 'downloading'): 127 volume = tests_utils.create_volume(self.context, status=status, 128 size=0, host=CONF.host) 129 130 db.worker_create(self.context, resource_type='Volume', 131 resource_id=volume.id, status=volume.status, 132 service_id=self.service_id) 133 134 self.volume.init_host(service_id=service.Service.service_id) 135 volume.refresh() 136 137 self.assertEqual('error', volume['status']) 138 self.volume.delete_volume(self.context, volume) 139 self.assertTrue(mock_cleanup_tmp_file.called) 140 self._assert_workers_are_removed() 141 142 def test_create_snapshot_fails_with_creating_status(self): 143 """Test init_host_with_service in case of snapshot. 144 145 While the status of snapshot is 'creating', volume process 146 down. After process restarting this 'creating' status is 147 changed to 'error'. 148 """ 149 volume = tests_utils.create_volume(self.context, 150 **self.volume_params) 151 snapshot = tests_utils.create_snapshot( 152 self.context, 153 volume.id, 154 status=fields.SnapshotStatus.CREATING) 155 db.worker_create(self.context, resource_type='Snapshot', 156 resource_id=snapshot.id, status=snapshot.status, 157 service_id=self.service_id) 158 159 self.volume.init_host(service_id=service.Service.service_id) 160 161 snapshot_obj = objects.Snapshot.get_by_id(self.context, snapshot.id) 162 163 self.assertEqual(fields.SnapshotStatus.ERROR, snapshot_obj.status) 164 self.assertEqual(service.Service.service_id, 165 self.volume.service_id) 166 self._assert_workers_are_removed() 167 168 self.volume.delete_snapshot(self.context, snapshot_obj) 169 self.volume.delete_volume(self.context, volume) 170 171 def test_init_host_clears_deleting_snapshots(self): 172 """Test that init_host will delete a snapshot stuck in deleting.""" 173 volume = tests_utils.create_volume(self.context, status='deleting', 174 size=1, host=CONF.host) 175 snapshot = tests_utils.create_snapshot(self.context, 176 volume.id, status='deleting') 177 178 db.worker_create(self.context, resource_type='Volume', 179 resource_id=volume.id, status=volume.status, 180 service_id=self.service_id) 181 182 self.volume.init_host(service_id=self.service_id) 183 self.assertRaises(exception.VolumeNotFound, volume.refresh) 184 self.assertRaises(exception.SnapshotNotFound, snapshot.refresh) 185