| 12 | 12 |
# License for the specific language governing permissions and limitations
|
| 13 | 13 |
# under the License.
|
| 14 | 14 |
|
|
15 |
|
|
16 |
from tempest.common import utils
|
|
17 |
from tempest.common import waiters
|
| 15 | 18 |
from tempest import config
|
| 16 | 19 |
from tempest.lib import decorators
|
|
20 |
import testtools
|
| 17 | 21 |
|
| 18 | 22 |
from cinder_tempest_plugin.api.volume import base
|
| 19 | 23 |
|
|
| 118 | 122 |
self._delete_vol_and_wait(volume_1)
|
| 119 | 123 |
self._delete_vol_and_wait(volume_2)
|
| 120 | 124 |
self._delete_vol_and_wait(volume_3)
|
|
125 |
|
|
126 |
|
|
127 |
class VolumeImageDependencyTests(base.BaseVolumeTest):
|
|
128 |
"""Volume<->image dependency tests.
|
|
129 |
|
|
130 |
These tests perform clones to/from volumes and images,
|
|
131 |
deleting images/volumes that other volumes were cloned from.
|
|
132 |
|
|
133 |
Images and volumes are expected to be independent at the OpenStack
|
|
134 |
level, but in some configurations (i.e. when using Ceph as storage
|
|
135 |
for both Cinder and Glance) it was possible to end up with images
|
|
136 |
or volumes that could not be deleted. This was fixed for RBD in
|
|
137 |
Cinder 2024.1 change I009d0748f.
|
|
138 |
|
|
139 |
"""
|
|
140 |
|
|
141 |
min_microversion = '3.40'
|
|
142 |
|
|
143 |
@classmethod
|
|
144 |
def del_image(cls, image_id):
|
|
145 |
images_client = cls.os_primary.image_client_v2
|
|
146 |
images_client.delete_image(image_id)
|
|
147 |
images_client.wait_for_resource_deletion(image_id)
|
|
148 |
|
|
149 |
@testtools.skipUnless(CONF.volume_feature_enabled.volume_image_dep_tests,
|
|
150 |
reason='Volume/image dependency tests not enabled.')
|
|
151 |
@utils.services('image', 'volume')
|
|
152 |
@decorators.idempotent_id('7a9fba78-2e4b-42b1-9898-bb4a60685320')
|
|
153 |
def test_image_volume_dependencies_1(self):
|
|
154 |
# image -> volume
|
|
155 |
image_args = {
|
|
156 |
'disk_format': 'raw',
|
|
157 |
'container_format': 'bare',
|
|
158 |
'name': 'image-for-test-7a9fba78-2e4b-42b1-9898-bb4a60685320'
|
|
159 |
}
|
|
160 |
image = self.create_image_with_data(**image_args)
|
|
161 |
|
|
162 |
# create a volume from the image
|
|
163 |
vol_args = {'name': ('volume1-for-test'
|
|
164 |
'7a9fba78-2e4b-42b1-9898-bb4a60685320'),
|
|
165 |
'imageRef': image['id']}
|
|
166 |
volume1 = self.create_volume(**vol_args)
|
|
167 |
waiters.wait_for_volume_resource_status(self.volumes_client,
|
|
168 |
volume1['id'],
|
|
169 |
'available')
|
|
170 |
|
|
171 |
self.volumes_client.delete_volume(volume1['id'])
|
|
172 |
self.volumes_client.wait_for_resource_deletion(volume1['id'])
|
|
173 |
|
|
174 |
self.del_image(image['id'])
|
|
175 |
|
|
176 |
@testtools.skipUnless(CONF.volume_feature_enabled.volume_image_dep_tests,
|
|
177 |
reason='Volume/image dependency tests not enabled.')
|
|
178 |
@utils.services('image', 'volume')
|
|
179 |
@decorators.idempotent_id('0e20bd6e-440f-41d8-9b5d-fc047ac00423')
|
|
180 |
def test_image_volume_dependencies_2(self):
|
|
181 |
# image -> volume -> volume
|
|
182 |
|
|
183 |
image_args = {
|
|
184 |
'disk_format': 'raw',
|
|
185 |
'container_format': 'bare',
|
|
186 |
'name': 'image-for-test-0e20bd6e-440f-41d8-9b5d-fc047ac00423'
|
|
187 |
}
|
|
188 |
image = self.create_image_with_data(**image_args)
|
|
189 |
|
|
190 |
# create a volume from the image
|
|
191 |
vol_args = {'name': ('volume1-for-test'
|
|
192 |
'0e20bd6e-440f-41d8-9b5d-fc047ac00423'),
|
|
193 |
'imageRef': image['id']}
|
|
194 |
volume1 = self.create_volume(**vol_args)
|
|
195 |
waiters.wait_for_volume_resource_status(self.volumes_client,
|
|
196 |
volume1['id'],
|
|
197 |
'available')
|
|
198 |
|
|
199 |
vol2_args = {'name': ('volume2-for-test-'
|
|
200 |
'0e20bd6e-440f-41d8-9b5d-fc047ac00423'),
|
|
201 |
'source_volid': volume1['id']}
|
|
202 |
volume2 = self.create_volume(**vol2_args)
|
|
203 |
waiters.wait_for_volume_resource_status(self.volumes_client,
|
|
204 |
volume2['id'],
|
|
205 |
'available')
|
|
206 |
|
|
207 |
self.volumes_client.delete_volume(volume1['id'])
|
|
208 |
self.volumes_client.wait_for_resource_deletion(volume1['id'])
|
|
209 |
|
|
210 |
self.del_image(image['id'])
|
|
211 |
|
|
212 |
@testtools.skipUnless(CONF.volume_feature_enabled.volume_image_dep_tests,
|
|
213 |
reason='Volume/image dependency tests not enabled.')
|
|
214 |
@decorators.idempotent_id('e6050452-06bd-4c7f-9912-45178c83e379')
|
|
215 |
@utils.services('image', 'volume')
|
|
216 |
def test_image_volume_dependencies_3(self):
|
|
217 |
# image -> volume -> snap -> volume
|
|
218 |
|
|
219 |
image_args = {
|
|
220 |
'disk_format': 'raw',
|
|
221 |
'container_format': 'bare',
|
|
222 |
'name': 'image-for-test-e6050452-06bd-4c7f-9912-45178c83e379'
|
|
223 |
}
|
|
224 |
image = self.create_image_with_data(**image_args)
|
|
225 |
|
|
226 |
# create a volume from the image
|
|
227 |
vol_args = {'name': ('volume1-for-test'
|
|
228 |
'e6050452-06bd-4c7f-9912-45178c83e379'),
|
|
229 |
'imageRef': image['id']}
|
|
230 |
volume1 = self.create_volume(**vol_args)
|
|
231 |
waiters.wait_for_volume_resource_status(self.volumes_client,
|
|
232 |
volume1['id'],
|
|
233 |
'available')
|
|
234 |
|
|
235 |
snapshot1 = self.create_snapshot(volume1['id'])
|
|
236 |
|
|
237 |
vol2_args = {'name': ('volume2-for-test-'
|
|
238 |
'e6050452-06bd-4c7f-9912-45178c83e379'),
|
|
239 |
'snapshot_id': snapshot1['id']}
|
|
240 |
volume2 = self.create_volume(**vol2_args)
|
|
241 |
waiters.wait_for_volume_resource_status(self.volumes_client,
|
|
242 |
volume2['id'],
|
|
243 |
'available')
|
|
244 |
|
|
245 |
self.snapshots_client.delete_snapshot(snapshot1['id'])
|
|
246 |
self.snapshots_client.wait_for_resource_deletion(snapshot1['id'])
|
|
247 |
|
|
248 |
self.volumes_client.delete_volume(volume2['id'])
|
|
249 |
self.volumes_client.wait_for_resource_deletion(volume2['id'])
|
|
250 |
|
|
251 |
self.del_image(image['id'])
|
|
252 |
|
|
253 |
self.volumes_client.delete_volume(volume1['id'])
|
|
254 |
self.volumes_client.wait_for_resource_deletion(volume1['id'])
|