5
from nose import with_setup
6
from nose.tools import eq_ as eq, assert_raises
7
from rados import Rados
8
from rbd import (RBD, Image, ImageNotFound, InvalidArgument, ImageExists,
9
ImageBusy, ImageHasSnapshots)
15
IMG_SIZE = 8 << 20 # 8 MiB
16
IMG_ORDER = 22 # 4 MiB objects
20
rados = Rados(conffile='')
22
assert rados.pool_exists('rbd')
24
ioctx = rados.open_ioctx('rbd')
33
features = os.getenv("RBD_FEATURES")
34
if features is not None:
35
RBD().create(ioctx, IMG_NAME, IMG_SIZE, IMG_ORDER, old_format=False,
36
features=int(features))
38
RBD().create(ioctx, IMG_NAME, IMG_SIZE, IMG_ORDER, old_format=True)
41
RBD().remove(ioctx, IMG_NAME)
50
def test_context_manager():
51
with Rados(conffile='') as cluster:
52
with cluster.open_ioctx('rbd') as ioctx:
53
RBD().create(ioctx, IMG_NAME, IMG_SIZE)
54
with Image(ioctx, IMG_NAME) as image:
57
read = image.read(0, 256)
58
RBD().remove(ioctx, IMG_NAME)
61
def test_remove_dne():
62
assert_raises(ImageNotFound, remove_image)
64
def test_list_empty():
65
eq([], RBD().list(ioctx))
67
@with_setup(create_image, remove_image)
69
eq([IMG_NAME], RBD().list(ioctx))
71
@with_setup(create_image, remove_image)
74
rbd.rename(ioctx, IMG_NAME, IMG_NAME + '2')
75
eq([IMG_NAME + '2'], rbd.list(ioctx))
76
rbd.rename(ioctx, IMG_NAME + '2', IMG_NAME)
77
eq([IMG_NAME], rbd.list(ioctx))
80
l = [random.Random().getrandbits(64) for _ in xrange(size/8)]
81
return struct.pack((size/8)*'Q', *l)
83
def check_stat(info, size, order):
84
assert 'block_name_prefix' in info
85
eq(info['size'], size)
86
eq(info['order'], order)
87
eq(info['num_objs'], size / (1 << order))
88
eq(info['obj_size'], 1 << order)
89
eq(info['parent_pool'], -1)
90
eq(info['parent_name'], '')
92
class TestImage(object):
97
self.image = Image(ioctx, IMG_NAME)
104
info = self.image.stat()
105
check_stat(info, IMG_SIZE, IMG_ORDER)
107
def test_write(self):
108
data = rand_data(256)
109
self.image.write(data, 0)
112
data = self.image.read(0, 20)
115
def test_large_write(self):
116
data = rand_data(IMG_SIZE)
117
self.image.write(data, 0)
119
def test_large_read(self):
120
data = self.image.read(0, IMG_SIZE)
121
eq(data, '\0' * IMG_SIZE)
123
def test_write_read(self):
124
data = rand_data(256)
126
self.image.write(data, offset)
127
read = self.image.read(offset, 256)
130
def test_read_bad_offset(self):
131
assert_raises(InvalidArgument, self.image.read, IMG_SIZE + 1, IMG_SIZE)
133
def test_resize(self):
134
new_size = IMG_SIZE * 2
135
self.image.resize(new_size)
136
info = self.image.stat()
137
check_stat(info, new_size, IMG_ORDER)
139
def test_resize_down(self):
140
new_size = IMG_SIZE / 2
141
data = rand_data(256)
142
self.image.write(data, IMG_SIZE / 2);
143
self.image.resize(new_size)
144
self.image.resize(IMG_SIZE)
145
read = self.image.read(IMG_SIZE / 2, 256)
148
def test_resize_bytes(self):
149
new_size = IMG_SIZE / 2 - 5
150
data = rand_data(256)
151
self.image.write(data, IMG_SIZE / 2 - 10);
152
self.image.resize(new_size)
153
self.image.resize(IMG_SIZE)
154
read = self.image.read(IMG_SIZE / 2 - 10, 5)
156
read = self.image.read(IMG_SIZE / 2 - 5, 251)
161
data = rand_data(256)
162
self.image.write(data, 256)
163
self.image.copy(ioctx, IMG_NAME + '2')
164
assert_raises(ImageExists, self.image.copy, ioctx, IMG_NAME + '2')
165
copy = Image(ioctx, IMG_NAME + '2')
166
copy_data = copy.read(256, 256)
168
self.rbd.remove(ioctx, IMG_NAME + '2')
171
def test_create_snap(self):
173
self.image.create_snap('snap1')
174
read = self.image.read(0, 256)
176
data = rand_data(256)
177
self.image.write(data, 0)
178
read = self.image.read(0, 256)
180
at_snapshot = Image(ioctx, IMG_NAME, 'snap1')
181
snap_data = at_snapshot.read(0, 256)
183
eq(snap_data, '\0' * 256)
184
self.image.remove_snap('snap1')
186
def test_list_snaps(self):
187
eq([], list(self.image.list_snaps()))
188
self.image.create_snap('snap1')
189
eq(['snap1'], map(lambda snap: snap['name'], self.image.list_snaps()))
190
self.image.create_snap('snap2')
191
eq(['snap1', 'snap2'], map(lambda snap: snap['name'], self.image.list_snaps()))
192
self.image.remove_snap('snap1')
193
self.image.remove_snap('snap2')
195
def test_remove_snap(self):
196
eq([], list(self.image.list_snaps()))
197
self.image.create_snap('snap1')
198
eq(['snap1'], map(lambda snap: snap['name'], self.image.list_snaps()))
199
self.image.remove_snap('snap1')
200
eq([], list(self.image.list_snaps()))
202
def test_remove_with_snap(self):
203
self.image.create_snap('snap1')
204
assert_raises(ImageHasSnapshots, remove_image)
205
self.image.remove_snap('snap1')
207
def test_remove_with_watcher(self):
208
assert_raises(ImageBusy, remove_image)
210
def test_rollback_to_snap(self):
211
self.image.write('\0' * 256, 0)
212
self.image.create_snap('snap1')
213
read = self.image.read(0, 256)
215
data = rand_data(256)
216
self.image.write(data, 0)
217
read = self.image.read(0, 256)
219
self.image.rollback_to_snap('snap1')
220
read = self.image.read(0, 256)
222
self.image.remove_snap('snap1')
224
def test_rollback_to_snap_sparse(self):
225
self.image.create_snap('snap1')
226
read = self.image.read(0, 256)
228
data = rand_data(256)
229
self.image.write(data, 0)
230
read = self.image.read(0, 256)
232
self.image.rollback_to_snap('snap1')
233
read = self.image.read(0, 256)
235
self.image.remove_snap('snap1')
237
def test_rollback_with_resize(self):
238
read = self.image.read(0, 256)
240
data = rand_data(256)
241
self.image.write(data, 0)
242
self.image.create_snap('snap1')
243
read = self.image.read(0, 256)
245
new_size = IMG_SIZE * 2
246
self.image.resize(new_size)
247
check_stat(self.image.stat(), new_size, IMG_ORDER)
248
self.image.write(data, new_size - 256)
249
self.image.create_snap('snap2')
250
read = self.image.read(new_size - 256, 256)
252
self.image.rollback_to_snap('snap1')
253
check_stat(self.image.stat(), IMG_SIZE, IMG_ORDER)
254
assert_raises(InvalidArgument, self.image.read, new_size - 256, 256)
255
self.image.rollback_to_snap('snap2')
256
check_stat(self.image.stat(), new_size, IMG_ORDER)
257
read = self.image.read(new_size - 256, 256)
259
self.image.remove_snap('snap1')
260
self.image.remove_snap('snap2')
262
def test_set_snap(self):
263
self.image.write('\0' * 256, 0)
264
self.image.create_snap('snap1')
265
read = self.image.read(0, 256)
267
data = rand_data(256)
268
self.image.write(data, 0)
269
read = self.image.read(0, 256)
271
self.image.set_snap('snap1')
272
read = self.image.read(0, 256)
274
self.image.remove_snap('snap1')
276
def test_set_no_snap(self):
277
self.image.write('\0' * 256, 0)
278
self.image.create_snap('snap1')
279
read = self.image.read(0, 256)
281
data = rand_data(256)
282
self.image.write(data, 0)
283
read = self.image.read(0, 256)
285
self.image.set_snap('snap1')
286
read = self.image.read(0, 256)
288
self.image.set_snap(None)
289
read = self.image.read(0, 256)
291
self.image.remove_snap('snap1')
293
def test_set_snap_sparse(self):
294
self.image.create_snap('snap1')
295
read = self.image.read(0, 256)
297
data = rand_data(256)
298
self.image.write(data, 0)
299
read = self.image.read(0, 256)
301
self.image.set_snap('snap1')
302
read = self.image.read(0, 256)
304
self.image.remove_snap('snap1')
306
def test_many_snaps(self):
308
for i in xrange(num_snaps):
309
self.image.create_snap(str(i))
310
snaps = sorted(self.image.list_snaps(),
311
key=lambda snap: int(snap['name']))
312
eq(len(snaps), num_snaps)
313
for i, snap in enumerate(snaps):
314
eq(snap['size'], IMG_SIZE)
315
eq(snap['name'], str(i))
316
for i in xrange(num_snaps):
317
self.image.remove_snap(str(i))
319
def test_set_snap_deleted(self):
320
self.image.write('\0' * 256, 0)
321
self.image.create_snap('snap1')
322
read = self.image.read(0, 256)
324
data = rand_data(256)
325
self.image.write(data, 0)
326
read = self.image.read(0, 256)
328
self.image.set_snap('snap1')
329
self.image.remove_snap('snap1')
330
assert_raises(ImageNotFound, self.image.read, 0, 256)
331
self.image.set_snap(None)
332
read = self.image.read(0, 256)
335
def test_set_snap_recreated(self):
336
self.image.write('\0' * 256, 0)
337
self.image.create_snap('snap1')
338
read = self.image.read(0, 256)
340
data = rand_data(256)
341
self.image.write(data, 0)
342
read = self.image.read(0, 256)
344
self.image.set_snap('snap1')
345
self.image.remove_snap('snap1')
346
self.image.create_snap('snap1')
347
assert_raises(ImageNotFound, self.image.read, 0, 256)
348
self.image.set_snap(None)
349
read = self.image.read(0, 256)
351
self.image.remove_snap('snap1')