]> git.proxmox.com Git - mirror_zfs.git/blame - contrib/pyzfs/libzfs_core/test/test_libzfs_core.py
Implement a new type of zfs receive: corrective receive (-c)
[mirror_zfs.git] / contrib / pyzfs / libzfs_core / test / test_libzfs_core.py
CommitLineData
85ce3f4f 1#
2# Copyright 2015 ClusterHQ
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
6abf9225
AG
16
17"""
18Tests for `libzfs_core` operations.
19
20These are mostly functional and conformance tests that validate
21that the operations produce expected effects or fail with expected
22exceptions.
23"""
9de8c0cd 24from __future__ import absolute_import, division, print_function
6abf9225
AG
25
26import unittest
27import contextlib
28import errno
29import filecmp
30import os
31import platform
32import resource
33import shutil
34import stat
35import subprocess
4b1c4062 36import sys
6abf9225
AG
37import tempfile
38import time
39import uuid
85ce3f4f 40import itertools
41import zlib
6abf9225
AG
42from .. import _libzfs_core as lzc
43from .. import exceptions as lzc_exc
85ce3f4f 44from .._nvlist import packed_nvlist_out
6abf9225
AG
45
46
47def _print(*args):
48 for arg in args:
9de8c0cd
AR
49 print(arg, end=' ')
50 print()
6abf9225
AG
51
52
53@contextlib.contextmanager
54def suppress(exceptions=None):
55 try:
56 yield
57 except BaseException as e:
58 if exceptions is None or isinstance(e, exceptions):
59 pass
60 else:
61 raise
62
63
64@contextlib.contextmanager
65def _zfs_mount(fs):
66 mntdir = tempfile.mkdtemp()
67 if platform.system() == 'SunOS':
68 mount_cmd = ['mount', '-F', 'zfs', fs, mntdir]
69 else:
70 mount_cmd = ['mount', '-t', 'zfs', fs, mntdir]
71 unmount_cmd = ['umount', '-f', mntdir]
72
73 try:
74 subprocess.check_output(mount_cmd, stderr=subprocess.STDOUT)
75 try:
76 yield mntdir
77 finally:
78 with suppress():
79 subprocess.check_output(unmount_cmd, stderr=subprocess.STDOUT)
80 except subprocess.CalledProcessError as e:
9de8c0cd 81 print('failed to mount %s @ %s : %s' % (fs, mntdir, e.output))
6abf9225
AG
82 raise
83 finally:
84 os.rmdir(mntdir)
85
86
87# XXX On illumos it is impossible to explicitly mount a snapshot.
88# So, either we need to implicitly mount it using .zfs/snapshot/
89# or we need to create a clone and mount it readonly (and discard
90# it afterwards).
91# At the moment the former approach is implemented.
92
93# This dictionary is used to keep track of mounted filesystems
94# (not snapshots), so that we do not try to mount a filesystem
95# more than once in the case more than one snapshot of the
96# filesystem is accessed from the same context or the filesystem
97# and its snapshot are accessed.
98_mnttab = {}
99
100
101@contextlib.contextmanager
102def _illumos_mount_fs(fs):
103 if fs in _mnttab:
104 yield _mnttab[fs]
105 else:
106 with _zfs_mount(fs) as mntdir:
107 _mnttab[fs] = mntdir
108 try:
109 yield mntdir
110 finally:
111 _mnttab.pop(fs, None)
112
113
114@contextlib.contextmanager
115def _illumos_mount_snap(fs):
116 (base, snap) = fs.split('@', 1)
117 with _illumos_mount_fs(base) as mntdir:
118 yield os.path.join(mntdir, '.zfs', 'snapshot', snap)
119
120
121@contextlib.contextmanager
122def _zfs_mount_illumos(fs):
123 if '@' not in fs:
124 with _illumos_mount_fs(fs) as mntdir:
125 yield mntdir
126 else:
127 with _illumos_mount_snap(fs) as mntdir:
128 yield mntdir
129
130
131if platform.system() == 'SunOS':
132 zfs_mount = _zfs_mount_illumos
133else:
134 zfs_mount = _zfs_mount
135
136
137@contextlib.contextmanager
138def cleanup_fd():
139 fd = os.open('/dev/zfs', os.O_EXCL)
140 try:
141 yield fd
142 finally:
143 os.close(fd)
144
145
146@contextlib.contextmanager
147def os_open(name, mode):
148 fd = os.open(name, mode)
149 try:
150 yield fd
151 finally:
152 os.close(fd)
153
154
155@contextlib.contextmanager
156def dev_null():
f8c4d63a
AR
157 with tempfile.TemporaryFile(suffix='.zstream') as fd:
158 yield fd.fileno()
6abf9225
AG
159
160
161@contextlib.contextmanager
162def dev_zero():
163 with os_open('/dev/zero', os.O_RDONLY) as fd:
164 yield fd
165
166
167@contextlib.contextmanager
168def temp_file_in_fs(fs):
169 with zfs_mount(fs) as mntdir:
170 with tempfile.NamedTemporaryFile(dir=mntdir) as f:
171 for i in range(1024):
4b1c4062 172 f.write(b'x' * 1024)
6abf9225
AG
173 f.flush()
174 yield f.name
175
176
177def make_snapshots(fs, before, modified, after):
178 def _maybe_snap(snap):
179 if snap is not None:
180 if not snap.startswith(fs):
4b1c4062 181 snap = fs + b'@' + snap
6abf9225
AG
182 lzc.lzc_snapshot([snap])
183 return snap
184
185 before = _maybe_snap(before)
186 with temp_file_in_fs(fs) as name:
187 modified = _maybe_snap(modified)
188 after = _maybe_snap(after)
189
190 return (name, (before, modified, after))
191
192
193@contextlib.contextmanager
194def streams(fs, first, second):
195 (filename, snaps) = make_snapshots(fs, None, first, second)
d8d418ff 196 with tempfile.TemporaryFile(suffix='.zstream') as full:
6abf9225
AG
197 lzc.lzc_send(snaps[1], None, full.fileno())
198 full.seek(0)
199 if snaps[2] is not None:
d8d418ff 200 with tempfile.TemporaryFile(suffix='.zstream') as incremental:
6abf9225
AG
201 lzc.lzc_send(snaps[2], snaps[1], incremental.fileno())
202 incremental.seek(0)
203 yield (filename, (full, incremental))
204 else:
205 yield (filename, (full, None))
206
207
85ce3f4f 208@contextlib.contextmanager
209def encrypted_filesystem():
4b1c4062 210 fs = ZFSTest.pool.getFilesystem(b"encrypted")
85ce3f4f 211 name = fs.getName()
212 filename = None
213 key = os.urandom(lzc.WRAPPING_KEY_LEN)
214 with tempfile.NamedTemporaryFile() as f:
215 filename = "file://" + f.name
216 props = {
4b1c4062
BB
217 b"encryption": lzc.zio_encrypt.ZIO_CRYPT_AES_256_CCM,
218 b"keylocation": filename.encode(),
219 b"keyformat": lzc.zfs_keyformat.ZFS_KEYFORMAT_RAW,
85ce3f4f 220 }
221 lzc.lzc_create(name, 'zfs', props=props, key=key)
222 yield (name, key)
223
224
6abf9225
AG
225def runtimeSkipIf(check_method, message):
226 def _decorator(f):
227 def _f(_self, *args, **kwargs):
228 if check_method(_self):
229 return _self.skipTest(message)
230 else:
231 return f(_self, *args, **kwargs)
232 _f.__name__ = f.__name__
233 return _f
234 return _decorator
235
236
237def skipIfFeatureAvailable(feature, message):
85ce3f4f 238 return runtimeSkipIf(
239 lambda _self: _self.__class__.pool.isPoolFeatureAvailable(feature),
240 message)
6abf9225
AG
241
242
243def skipUnlessFeatureEnabled(feature, message):
85ce3f4f 244 return runtimeSkipIf(
245 lambda _self: not _self.__class__.pool.isPoolFeatureEnabled(feature),
246 message)
6abf9225
AG
247
248
249def skipUnlessBookmarksSupported(f):
85ce3f4f 250 return skipUnlessFeatureEnabled(
251 'bookmarks', 'bookmarks are not enabled')(f)
6abf9225
AG
252
253
254def snap_always_unmounted_before_destruction():
1966e959 255 # Apparently OpenZFS automatically unmounts the snapshot
6abf9225 256 # only if it is mounted at its default .zfs/snapshot
1966e959 257 # mountpoint under Linux.
85ce3f4f 258 return (
259 platform.system() != 'Linux', 'snapshot is not auto-unmounted')
6abf9225
AG
260
261
262def illumos_bug_6379():
263 # zfs_ioc_hold() panics on a bad cleanup fd
85ce3f4f 264 return (
265 platform.system() == 'SunOS',
266 'see https://www.illumos.org/issues/6379')
6abf9225
AG
267
268
269def needs_support(function):
85ce3f4f 270 return unittest.skipUnless(
271 lzc.is_supported(function),
272 '{} not available'.format(function.__name__))
6abf9225
AG
273
274
275class ZFSTest(unittest.TestCase):
276 POOL_FILE_SIZE = 128 * 1024 * 1024
4b1c4062 277 FILESYSTEMS = [b'fs1', b'fs2', b'fs1/fs']
6abf9225
AG
278
279 pool = None
280 misc_pool = None
281 readonly_pool = None
282
283 @classmethod
284 def setUpClass(cls):
285 try:
286 cls.pool = _TempPool(filesystems=cls.FILESYSTEMS)
287 cls.misc_pool = _TempPool()
288 cls.readonly_pool = _TempPool(
289 filesystems=cls.FILESYSTEMS, readonly=True)
290 cls.pools = [cls.pool, cls.misc_pool, cls.readonly_pool]
291 except Exception:
292 cls._cleanUp()
293 raise
294
295 @classmethod
296 def tearDownClass(cls):
297 cls._cleanUp()
298
299 @classmethod
300 def _cleanUp(cls):
301 for pool in [cls.pool, cls.misc_pool, cls.readonly_pool]:
302 if pool is not None:
303 pool.cleanUp()
304
305 def setUp(self):
306 pass
307
308 def tearDown(self):
309 for pool in ZFSTest.pools:
310 pool.reset()
311
312 def assertExists(self, name):
313 self.assertTrue(
314 lzc.lzc_exists(name), 'ZFS dataset %s does not exist' % (name, ))
315
316 def assertNotExists(self, name):
317 self.assertFalse(
318 lzc.lzc_exists(name), 'ZFS dataset %s exists' % (name, ))
319
320 def test_exists(self):
321 self.assertExists(ZFSTest.pool.makeName())
322
323 def test_exists_in_ro_pool(self):
324 self.assertExists(ZFSTest.readonly_pool.makeName())
325
326 def test_exists_failure(self):
4b1c4062 327 self.assertNotExists(ZFSTest.pool.makeName(b'nonexistent'))
6abf9225
AG
328
329 def test_create_fs(self):
4b1c4062 330 name = ZFSTest.pool.makeName(b"fs1/fs/test1")
6abf9225
AG
331
332 lzc.lzc_create(name)
333 self.assertExists(name)
334
335 def test_create_zvol(self):
4b1c4062
BB
336 name = ZFSTest.pool.makeName(b"fs1/fs/zvol")
337 props = {b"volsize": 1024 * 1024}
6abf9225
AG
338
339 lzc.lzc_create(name, ds_type='zvol', props=props)
340 self.assertExists(name)
341 # On Gentoo with ZFS 0.6.5.4 the volume is busy
342 # and can not be destroyed right after its creation.
343 # A reason for this is unknown at the moment.
344 # Because of that the post-test clean up could fail.
345 time.sleep(0.1)
346
347 def test_create_fs_with_prop(self):
4b1c4062
BB
348 name = ZFSTest.pool.makeName(b"fs1/fs/test2")
349 props = {b"atime": 0}
6abf9225
AG
350
351 lzc.lzc_create(name, props=props)
352 self.assertExists(name)
353
354 def test_create_fs_wrong_ds_type(self):
4b1c4062 355 name = ZFSTest.pool.makeName(b"fs1/fs/test1")
6abf9225
AG
356
357 with self.assertRaises(lzc_exc.DatasetTypeInvalid):
358 lzc.lzc_create(name, ds_type='wrong')
359
6abf9225 360 def test_create_fs_below_zvol(self):
4b1c4062
BB
361 name = ZFSTest.pool.makeName(b"fs1/fs/zvol")
362 props = {b"volsize": 1024 * 1024}
6abf9225
AG
363
364 lzc.lzc_create(name, ds_type='zvol', props=props)
365 with self.assertRaises(lzc_exc.WrongParent):
4b1c4062 366 lzc.lzc_create(name + b'/fs')
6abf9225 367
d8d418ff 368 def test_create_zvol_below_zvol(self):
369 name = ZFSTest.pool.makeName(b"fs1/fs/zvol")
370 props = {b"volsize": 1024 * 1024}
371
372 lzc.lzc_create(name, ds_type='zvol', props=props)
373 with self.assertRaises(lzc_exc.WrongParent):
374 lzc.lzc_create(name + b'/zvol', ds_type='zvol', props=props)
375
6abf9225 376 def test_create_fs_duplicate(self):
4b1c4062 377 name = ZFSTest.pool.makeName(b"fs1/fs/test6")
6abf9225
AG
378
379 lzc.lzc_create(name)
380
381 with self.assertRaises(lzc_exc.FilesystemExists):
382 lzc.lzc_create(name)
383
384 def test_create_fs_in_ro_pool(self):
4b1c4062 385 name = ZFSTest.readonly_pool.makeName(b"fs")
6abf9225
AG
386
387 with self.assertRaises(lzc_exc.ReadOnlyPool):
388 lzc.lzc_create(name)
389
390 def test_create_fs_without_parent(self):
4b1c4062 391 name = ZFSTest.pool.makeName(b"fs1/nonexistent/test")
6abf9225
AG
392
393 with self.assertRaises(lzc_exc.ParentNotFound):
394 lzc.lzc_create(name)
395 self.assertNotExists(name)
396
397 def test_create_fs_in_nonexistent_pool(self):
4b1c4062 398 name = b"no-such-pool/fs"
6abf9225
AG
399
400 with self.assertRaises(lzc_exc.ParentNotFound):
401 lzc.lzc_create(name)
402 self.assertNotExists(name)
403
404 def test_create_fs_with_invalid_prop(self):
4b1c4062
BB
405 name = ZFSTest.pool.makeName(b"fs1/fs/test3")
406 props = {b"BOGUS": 0}
6abf9225
AG
407
408 with self.assertRaises(lzc_exc.PropertyInvalid):
409 lzc.lzc_create(name, 'zfs', props)
410 self.assertNotExists(name)
411
412 def test_create_fs_with_invalid_prop_type(self):
4b1c4062
BB
413 name = ZFSTest.pool.makeName(b"fs1/fs/test4")
414 props = {b"recordsize": b"128k"}
6abf9225
AG
415
416 with self.assertRaises(lzc_exc.PropertyInvalid):
417 lzc.lzc_create(name, 'zfs', props)
418 self.assertNotExists(name)
419
420 def test_create_fs_with_invalid_prop_val(self):
4b1c4062
BB
421 name = ZFSTest.pool.makeName(b"fs1/fs/test5")
422 props = {b"atime": 20}
6abf9225
AG
423
424 with self.assertRaises(lzc_exc.PropertyInvalid):
425 lzc.lzc_create(name, 'zfs', props)
426 self.assertNotExists(name)
427
428 def test_create_fs_with_invalid_name(self):
4b1c4062 429 name = ZFSTest.pool.makeName(b"@badname")
6abf9225
AG
430
431 with self.assertRaises(lzc_exc.NameInvalid):
432 lzc.lzc_create(name)
433 self.assertNotExists(name)
434
435 def test_create_fs_with_invalid_pool_name(self):
4b1c4062 436 name = b"bad!pool/fs"
6abf9225
AG
437
438 with self.assertRaises(lzc_exc.NameInvalid):
439 lzc.lzc_create(name)
440 self.assertNotExists(name)
441
85ce3f4f 442 def test_create_encrypted_fs(self):
4b1c4062 443 fs = ZFSTest.pool.getFilesystem(b"encrypted")
85ce3f4f 444 name = fs.getName()
445 filename = None
446 with tempfile.NamedTemporaryFile() as f:
447 filename = "file://" + f.name
448 props = {
4b1c4062
BB
449 b"encryption": lzc.zio_encrypt.ZIO_CRYPT_AES_256_CCM,
450 b"keylocation": filename.encode(),
451 b"keyformat": lzc.zfs_keyformat.ZFS_KEYFORMAT_RAW,
85ce3f4f 452 }
453 key = os.urandom(lzc.WRAPPING_KEY_LEN)
454 lzc.lzc_create(name, 'zfs', props=props, key=key)
4b1c4062 455 self.assertEqual(fs.getProperty("encryption"), b"aes-256-ccm")
9de8c0cd 456 self.assertEqual(fs.getProperty("encryptionroot"), name)
4b1c4062
BB
457 self.assertEqual(fs.getProperty("keylocation"), filename.encode())
458 self.assertEqual(fs.getProperty("keyformat"), b"raw")
85ce3f4f 459
6abf9225 460 def test_snapshot(self):
4b1c4062 461 snapname = ZFSTest.pool.makeName(b"@snap")
6abf9225
AG
462 snaps = [snapname]
463
464 lzc.lzc_snapshot(snaps)
465 self.assertExists(snapname)
466
467 def test_snapshot_empty_list(self):
468 lzc.lzc_snapshot([])
469
470 def test_snapshot_user_props(self):
4b1c4062 471 snapname = ZFSTest.pool.makeName(b"@snap")
6abf9225 472 snaps = [snapname]
4b1c4062 473 props = {b"user:foo": b"bar"}
6abf9225
AG
474
475 lzc.lzc_snapshot(snaps, props)
476 self.assertExists(snapname)
477
478 def test_snapshot_invalid_props(self):
4b1c4062 479 snapname = ZFSTest.pool.makeName(b"@snap")
6abf9225 480 snaps = [snapname]
4b1c4062 481 props = {b"foo": b"bar"}
6abf9225
AG
482
483 with self.assertRaises(lzc_exc.SnapshotFailure) as ctx:
484 lzc.lzc_snapshot(snaps, props)
485
9de8c0cd 486 self.assertEqual(len(ctx.exception.errors), len(snaps))
6abf9225
AG
487 for e in ctx.exception.errors:
488 self.assertIsInstance(e, lzc_exc.PropertyInvalid)
489 self.assertNotExists(snapname)
490
491 def test_snapshot_ro_pool(self):
4b1c4062
BB
492 snapname1 = ZFSTest.readonly_pool.makeName(b"@snap")
493 snapname2 = ZFSTest.readonly_pool.makeName(b"fs1@snap")
6abf9225
AG
494 snaps = [snapname1, snapname2]
495
496 with self.assertRaises(lzc_exc.SnapshotFailure) as ctx:
497 lzc.lzc_snapshot(snaps)
498
499 # NB: one common error is reported.
9de8c0cd 500 self.assertEqual(len(ctx.exception.errors), 1)
6abf9225
AG
501 for e in ctx.exception.errors:
502 self.assertIsInstance(e, lzc_exc.ReadOnlyPool)
503 self.assertNotExists(snapname1)
504 self.assertNotExists(snapname2)
505
506 def test_snapshot_nonexistent_pool(self):
4b1c4062 507 snapname = b"no-such-pool@snap"
6abf9225
AG
508 snaps = [snapname]
509
510 with self.assertRaises(lzc_exc.SnapshotFailure) as ctx:
511 lzc.lzc_snapshot(snaps)
512
9de8c0cd 513 self.assertEqual(len(ctx.exception.errors), 1)
6abf9225
AG
514 for e in ctx.exception.errors:
515 self.assertIsInstance(e, lzc_exc.FilesystemNotFound)
516
517 def test_snapshot_nonexistent_fs(self):
4b1c4062 518 snapname = ZFSTest.pool.makeName(b"nonexistent@snap")
6abf9225
AG
519 snaps = [snapname]
520
521 with self.assertRaises(lzc_exc.SnapshotFailure) as ctx:
522 lzc.lzc_snapshot(snaps)
523
9de8c0cd 524 self.assertEqual(len(ctx.exception.errors), 1)
6abf9225
AG
525 for e in ctx.exception.errors:
526 self.assertIsInstance(e, lzc_exc.FilesystemNotFound)
527
528 def test_snapshot_nonexistent_and_existent_fs(self):
4b1c4062
BB
529 snapname1 = ZFSTest.pool.makeName(b"@snap")
530 snapname2 = ZFSTest.pool.makeName(b"nonexistent@snap")
6abf9225
AG
531 snaps = [snapname1, snapname2]
532
533 with self.assertRaises(lzc_exc.SnapshotFailure) as ctx:
534 lzc.lzc_snapshot(snaps)
535
9de8c0cd 536 self.assertEqual(len(ctx.exception.errors), 1)
6abf9225
AG
537 for e in ctx.exception.errors:
538 self.assertIsInstance(e, lzc_exc.FilesystemNotFound)
539 self.assertNotExists(snapname1)
540 self.assertNotExists(snapname2)
541
6abf9225 542 def test_multiple_snapshots_nonexistent_fs(self):
4b1c4062
BB
543 snapname1 = ZFSTest.pool.makeName(b"nonexistent@snap1")
544 snapname2 = ZFSTest.pool.makeName(b"nonexistent@snap2")
6abf9225
AG
545 snaps = [snapname1, snapname2]
546
547 with self.assertRaises(lzc_exc.SnapshotFailure) as ctx:
548 lzc.lzc_snapshot(snaps)
549
550 # XXX two errors should be reported but alas
9de8c0cd 551 self.assertEqual(len(ctx.exception.errors), 1)
6abf9225 552 for e in ctx.exception.errors:
85ce3f4f 553 self.assertIsInstance(e, lzc_exc.DuplicateSnapshots)
6abf9225
AG
554 self.assertNotExists(snapname1)
555 self.assertNotExists(snapname2)
556
6abf9225 557 def test_multiple_snapshots_multiple_nonexistent_fs(self):
4b1c4062
BB
558 snapname1 = ZFSTest.pool.makeName(b"nonexistent1@snap")
559 snapname2 = ZFSTest.pool.makeName(b"nonexistent2@snap")
6abf9225
AG
560 snaps = [snapname1, snapname2]
561
562 with self.assertRaises(lzc_exc.SnapshotFailure) as ctx:
563 lzc.lzc_snapshot(snaps)
564
9de8c0cd 565 self.assertEqual(len(ctx.exception.errors), 2)
6abf9225
AG
566 for e in ctx.exception.errors:
567 self.assertIsInstance(e, lzc_exc.FilesystemNotFound)
568 self.assertNotExists(snapname1)
569 self.assertNotExists(snapname2)
570
571 def test_snapshot_already_exists(self):
4b1c4062 572 snapname = ZFSTest.pool.makeName(b"@snap")
6abf9225
AG
573 snaps = [snapname]
574
575 lzc.lzc_snapshot(snaps)
576
577 with self.assertRaises(lzc_exc.SnapshotFailure) as ctx:
578 lzc.lzc_snapshot(snaps)
579
9de8c0cd 580 self.assertEqual(len(ctx.exception.errors), 1)
6abf9225
AG
581 for e in ctx.exception.errors:
582 self.assertIsInstance(e, lzc_exc.SnapshotExists)
583
584 def test_multiple_snapshots_for_same_fs(self):
4b1c4062
BB
585 snapname1 = ZFSTest.pool.makeName(b"@snap1")
586 snapname2 = ZFSTest.pool.makeName(b"@snap2")
6abf9225
AG
587 snaps = [snapname1, snapname2]
588
589 with self.assertRaises(lzc_exc.SnapshotFailure) as ctx:
590 lzc.lzc_snapshot(snaps)
591
9de8c0cd 592 self.assertEqual(len(ctx.exception.errors), 1)
6abf9225
AG
593 for e in ctx.exception.errors:
594 self.assertIsInstance(e, lzc_exc.DuplicateSnapshots)
595 self.assertNotExists(snapname1)
596 self.assertNotExists(snapname2)
597
598 def test_multiple_snapshots(self):
4b1c4062
BB
599 snapname1 = ZFSTest.pool.makeName(b"@snap")
600 snapname2 = ZFSTest.pool.makeName(b"fs1@snap")
6abf9225
AG
601 snaps = [snapname1, snapname2]
602
603 lzc.lzc_snapshot(snaps)
604 self.assertExists(snapname1)
605 self.assertExists(snapname2)
606
607 def test_multiple_existing_snapshots(self):
4b1c4062
BB
608 snapname1 = ZFSTest.pool.makeName(b"@snap")
609 snapname2 = ZFSTest.pool.makeName(b"fs1@snap")
6abf9225
AG
610 snaps = [snapname1, snapname2]
611
612 lzc.lzc_snapshot(snaps)
613
614 with self.assertRaises(lzc_exc.SnapshotFailure) as ctx:
615 lzc.lzc_snapshot(snaps)
616
617 self.assertEqual(len(ctx.exception.errors), 2)
618 for e in ctx.exception.errors:
619 self.assertIsInstance(e, lzc_exc.SnapshotExists)
620
621 def test_multiple_new_and_existing_snapshots(self):
4b1c4062
BB
622 snapname1 = ZFSTest.pool.makeName(b"@snap")
623 snapname2 = ZFSTest.pool.makeName(b"fs1@snap")
624 snapname3 = ZFSTest.pool.makeName(b"fs2@snap")
6abf9225
AG
625 snaps = [snapname1, snapname2]
626 more_snaps = snaps + [snapname3]
627
628 lzc.lzc_snapshot(snaps)
629
630 with self.assertRaises(lzc_exc.SnapshotFailure) as ctx:
631 lzc.lzc_snapshot(more_snaps)
632
633 self.assertEqual(len(ctx.exception.errors), 2)
634 for e in ctx.exception.errors:
635 self.assertIsInstance(e, lzc_exc.SnapshotExists)
636 self.assertNotExists(snapname3)
637
638 def test_snapshot_multiple_errors(self):
4b1c4062
BB
639 snapname1 = ZFSTest.pool.makeName(b"@snap")
640 snapname2 = ZFSTest.pool.makeName(b"nonexistent@snap")
641 snapname3 = ZFSTest.pool.makeName(b"fs1@snap")
6abf9225
AG
642 snaps = [snapname1]
643 more_snaps = [snapname1, snapname2, snapname3]
644
645 # create 'snapname1' snapshot
646 lzc.lzc_snapshot(snaps)
647
648 # attempt to create 3 snapshots:
649 # 1. duplicate snapshot name
650 # 2. refers to filesystem that doesn't exist
651 # 3. could have succeeded if not for 1 and 2
652 with self.assertRaises(lzc_exc.SnapshotFailure) as ctx:
653 lzc.lzc_snapshot(more_snaps)
654
655 # It seems that FilesystemNotFound overrides the other error,
656 # but it doesn't have to.
657 self.assertGreater(len(ctx.exception.errors), 0)
658 for e in ctx.exception.errors:
85ce3f4f 659 self.assertIsInstance(
660 e, (lzc_exc.SnapshotExists, lzc_exc.FilesystemNotFound))
6abf9225
AG
661 self.assertNotExists(snapname2)
662 self.assertNotExists(snapname3)
663
664 def test_snapshot_different_pools(self):
4b1c4062
BB
665 snapname1 = ZFSTest.pool.makeName(b"@snap")
666 snapname2 = ZFSTest.misc_pool.makeName(b"@snap")
6abf9225
AG
667 snaps = [snapname1, snapname2]
668
669 with self.assertRaises(lzc_exc.SnapshotFailure) as ctx:
670 lzc.lzc_snapshot(snaps)
671
672 # NB: one common error is reported.
9de8c0cd 673 self.assertEqual(len(ctx.exception.errors), 1)
6abf9225
AG
674 for e in ctx.exception.errors:
675 self.assertIsInstance(e, lzc_exc.PoolsDiffer)
676 self.assertNotExists(snapname1)
677 self.assertNotExists(snapname2)
678
679 def test_snapshot_different_pools_ro_pool(self):
4b1c4062
BB
680 snapname1 = ZFSTest.pool.makeName(b"@snap")
681 snapname2 = ZFSTest.readonly_pool.makeName(b"@snap")
6abf9225
AG
682 snaps = [snapname1, snapname2]
683
684 with self.assertRaises(lzc_exc.SnapshotFailure) as ctx:
685 lzc.lzc_snapshot(snaps)
686
687 # NB: one common error is reported.
9de8c0cd 688 self.assertEqual(len(ctx.exception.errors), 1)
6abf9225
AG
689 for e in ctx.exception.errors:
690 # NB: depending on whether the first attempted snapshot is
691 # for the read-only pool a different error is reported.
692 self.assertIsInstance(
693 e, (lzc_exc.PoolsDiffer, lzc_exc.ReadOnlyPool))
694 self.assertNotExists(snapname1)
695 self.assertNotExists(snapname2)
696
697 def test_snapshot_invalid_name(self):
4b1c4062
BB
698 snapname1 = ZFSTest.pool.makeName(b"@bad&name")
699 snapname2 = ZFSTest.pool.makeName(b"fs1@bad*name")
700 snapname3 = ZFSTest.pool.makeName(b"fs2@snap")
6abf9225
AG
701 snaps = [snapname1, snapname2, snapname3]
702
703 with self.assertRaises(lzc_exc.SnapshotFailure) as ctx:
704 lzc.lzc_snapshot(snaps)
705
706 # NB: one common error is reported.
9de8c0cd 707 self.assertEqual(len(ctx.exception.errors), 1)
6abf9225
AG
708 for e in ctx.exception.errors:
709 self.assertIsInstance(e, lzc_exc.NameInvalid)
710 self.assertIsNone(e.name)
711
712 def test_snapshot_too_long_complete_name(self):
4b1c4062
BB
713 snapname1 = ZFSTest.pool.makeTooLongName(b"fs1@")
714 snapname2 = ZFSTest.pool.makeTooLongName(b"fs2@")
715 snapname3 = ZFSTest.pool.makeName(b"@snap")
6abf9225
AG
716 snaps = [snapname1, snapname2, snapname3]
717
718 with self.assertRaises(lzc_exc.SnapshotFailure) as ctx:
719 lzc.lzc_snapshot(snaps)
720
9de8c0cd 721 self.assertEqual(len(ctx.exception.errors), 2)
6abf9225
AG
722 for e in ctx.exception.errors:
723 self.assertIsInstance(e, lzc_exc.NameTooLong)
724 self.assertIsNotNone(e.name)
725
726 def test_snapshot_too_long_snap_name(self):
4b1c4062
BB
727 snapname1 = ZFSTest.pool.makeTooLongComponent(b"fs1@")
728 snapname2 = ZFSTest.pool.makeTooLongComponent(b"fs2@")
729 snapname3 = ZFSTest.pool.makeName(b"@snap")
6abf9225
AG
730 snaps = [snapname1, snapname2, snapname3]
731
732 with self.assertRaises(lzc_exc.SnapshotFailure) as ctx:
733 lzc.lzc_snapshot(snaps)
734
735 # NB: one common error is reported.
9de8c0cd 736 self.assertEqual(len(ctx.exception.errors), 1)
6abf9225
AG
737 for e in ctx.exception.errors:
738 self.assertIsInstance(e, lzc_exc.NameTooLong)
739 self.assertIsNone(e.name)
740
741 def test_destroy_nonexistent_snapshot(self):
4b1c4062
BB
742 lzc.lzc_destroy_snaps([ZFSTest.pool.makeName(b"@nonexistent")], False)
743 lzc.lzc_destroy_snaps([ZFSTest.pool.makeName(b"@nonexistent")], True)
6abf9225
AG
744
745 def test_destroy_snapshot_of_nonexistent_pool(self):
746 with self.assertRaises(lzc_exc.SnapshotDestructionFailure) as ctx:
4b1c4062 747 lzc.lzc_destroy_snaps([b"no-such-pool@snap"], False)
6abf9225
AG
748
749 for e in ctx.exception.errors:
750 self.assertIsInstance(e, lzc_exc.PoolNotFound)
751
752 with self.assertRaises(lzc_exc.SnapshotDestructionFailure) as ctx:
4b1c4062 753 lzc.lzc_destroy_snaps([b"no-such-pool@snap"], True)
6abf9225
AG
754
755 for e in ctx.exception.errors:
756 self.assertIsInstance(e, lzc_exc.PoolNotFound)
757
758 # NB: note the difference from the nonexistent pool test.
759 def test_destroy_snapshot_of_nonexistent_fs(self):
760 lzc.lzc_destroy_snaps(
4b1c4062 761 [ZFSTest.pool.makeName(b"nonexistent@snap")], False)
6abf9225 762 lzc.lzc_destroy_snaps(
4b1c4062 763 [ZFSTest.pool.makeName(b"nonexistent@snap")], True)
6abf9225
AG
764
765 # Apparently the name is not checked for validity.
766 @unittest.expectedFailure
767 def test_destroy_invalid_snap_name(self):
768 with self.assertRaises(lzc_exc.SnapshotDestructionFailure):
769 lzc.lzc_destroy_snaps(
4b1c4062 770 [ZFSTest.pool.makeName(b"@non$&*existent")], False)
6abf9225
AG
771 with self.assertRaises(lzc_exc.SnapshotDestructionFailure):
772 lzc.lzc_destroy_snaps(
4b1c4062 773 [ZFSTest.pool.makeName(b"@non$&*existent")], True)
6abf9225
AG
774
775 # Apparently the full name is not checked for length.
776 @unittest.expectedFailure
777 def test_destroy_too_long_full_snap_name(self):
4b1c4062 778 snapname1 = ZFSTest.pool.makeTooLongName(b"fs1@")
6abf9225
AG
779 snaps = [snapname1]
780
781 with self.assertRaises(lzc_exc.SnapshotDestructionFailure):
782 lzc.lzc_destroy_snaps(snaps, False)
783 with self.assertRaises(lzc_exc.SnapshotDestructionFailure):
784 lzc.lzc_destroy_snaps(snaps, True)
785
786 def test_destroy_too_long_short_snap_name(self):
4b1c4062
BB
787 snapname1 = ZFSTest.pool.makeTooLongComponent(b"fs1@")
788 snapname2 = ZFSTest.pool.makeTooLongComponent(b"fs2@")
789 snapname3 = ZFSTest.pool.makeName(b"@snap")
6abf9225
AG
790 snaps = [snapname1, snapname2, snapname3]
791
792 with self.assertRaises(lzc_exc.SnapshotDestructionFailure) as ctx:
793 lzc.lzc_destroy_snaps(snaps, False)
794
795 for e in ctx.exception.errors:
796 self.assertIsInstance(e, lzc_exc.NameTooLong)
797
798 @unittest.skipUnless(*snap_always_unmounted_before_destruction())
799 def test_destroy_mounted_snap(self):
800 snap = ZFSTest.pool.getRoot().getSnap()
801
802 lzc.lzc_snapshot([snap])
803 with zfs_mount(snap):
804 # the snapshot should be force-unmounted
805 lzc.lzc_destroy_snaps([snap], defer=False)
806 self.assertNotExists(snap)
807
808 def test_clone(self):
809 # NB: note the special name for the snapshot.
810 # Since currently we can not destroy filesystems,
811 # it would be impossible to destroy the snapshot,
812 # so no point in attempting to clean it up.
4b1c4062
BB
813 snapname = ZFSTest.pool.makeName(b"fs2@origin1")
814 name = ZFSTest.pool.makeName(b"fs1/fs/clone1")
6abf9225
AG
815
816 lzc.lzc_snapshot([snapname])
817
818 lzc.lzc_clone(name, snapname)
819 self.assertExists(name)
820
821 def test_clone_nonexistent_snapshot(self):
4b1c4062
BB
822 snapname = ZFSTest.pool.makeName(b"fs2@nonexistent")
823 name = ZFSTest.pool.makeName(b"fs1/fs/clone2")
6abf9225
AG
824
825 # XXX The error should be SnapshotNotFound
826 # but limitations of C interface do not allow
827 # to differentiate between the errors.
828 with self.assertRaises(lzc_exc.DatasetNotFound):
829 lzc.lzc_clone(name, snapname)
830 self.assertNotExists(name)
831
832 def test_clone_nonexistent_parent_fs(self):
4b1c4062
BB
833 snapname = ZFSTest.pool.makeName(b"fs2@origin3")
834 name = ZFSTest.pool.makeName(b"fs1/nonexistent/clone3")
6abf9225
AG
835
836 lzc.lzc_snapshot([snapname])
837
838 with self.assertRaises(lzc_exc.DatasetNotFound):
839 lzc.lzc_clone(name, snapname)
840 self.assertNotExists(name)
841
842 def test_clone_to_nonexistent_pool(self):
4b1c4062
BB
843 snapname = ZFSTest.pool.makeName(b"fs2@snap")
844 name = b"no-such-pool/fs"
6abf9225
AG
845
846 lzc.lzc_snapshot([snapname])
847
848 with self.assertRaises(lzc_exc.DatasetNotFound):
849 lzc.lzc_clone(name, snapname)
850 self.assertNotExists(name)
851
852 def test_clone_invalid_snap_name(self):
853 # Use a valid filesystem name of filesystem that
854 # exists as a snapshot name
4b1c4062
BB
855 snapname = ZFSTest.pool.makeName(b"fs1/fs")
856 name = ZFSTest.pool.makeName(b"fs2/clone")
6abf9225
AG
857
858 with self.assertRaises(lzc_exc.SnapshotNameInvalid):
859 lzc.lzc_clone(name, snapname)
860 self.assertNotExists(name)
861
862 def test_clone_invalid_snap_name_2(self):
863 # Use a valid filesystem name of filesystem that
864 # doesn't exist as a snapshot name
4b1c4062
BB
865 snapname = ZFSTest.pool.makeName(b"fs1/nonexistent")
866 name = ZFSTest.pool.makeName(b"fs2/clone")
6abf9225
AG
867
868 with self.assertRaises(lzc_exc.SnapshotNameInvalid):
869 lzc.lzc_clone(name, snapname)
870 self.assertNotExists(name)
871
872 def test_clone_invalid_name(self):
4b1c4062
BB
873 snapname = ZFSTest.pool.makeName(b"fs2@snap")
874 name = ZFSTest.pool.makeName(b"fs1/bad#name")
6abf9225
AG
875
876 lzc.lzc_snapshot([snapname])
877
878 with self.assertRaises(lzc_exc.FilesystemNameInvalid):
879 lzc.lzc_clone(name, snapname)
880 self.assertNotExists(name)
881
882 def test_clone_invalid_pool_name(self):
4b1c4062
BB
883 snapname = ZFSTest.pool.makeName(b"fs2@snap")
884 name = b"bad!pool/fs1"
6abf9225
AG
885
886 lzc.lzc_snapshot([snapname])
887
888 with self.assertRaises(lzc_exc.FilesystemNameInvalid):
889 lzc.lzc_clone(name, snapname)
890 self.assertNotExists(name)
891
892 def test_clone_across_pools(self):
4b1c4062
BB
893 snapname = ZFSTest.pool.makeName(b"fs2@snap")
894 name = ZFSTest.misc_pool.makeName(b"clone1")
6abf9225
AG
895
896 lzc.lzc_snapshot([snapname])
897
898 with self.assertRaises(lzc_exc.PoolsDiffer):
899 lzc.lzc_clone(name, snapname)
900 self.assertNotExists(name)
901
902 def test_clone_across_pools_to_ro_pool(self):
4b1c4062
BB
903 snapname = ZFSTest.pool.makeName(b"fs2@snap")
904 name = ZFSTest.readonly_pool.makeName(b"fs1/clone1")
6abf9225
AG
905
906 lzc.lzc_snapshot([snapname])
907
908 # it's legal to report either of the conditions
909 with self.assertRaises((lzc_exc.ReadOnlyPool, lzc_exc.PoolsDiffer)):
910 lzc.lzc_clone(name, snapname)
911 self.assertNotExists(name)
912
913 def test_destroy_cloned_fs(self):
4b1c4062
BB
914 snapname1 = ZFSTest.pool.makeName(b"fs2@origin4")
915 snapname2 = ZFSTest.pool.makeName(b"fs1@snap")
916 clonename = ZFSTest.pool.makeName(b"fs1/fs/clone4")
6abf9225
AG
917 snaps = [snapname1, snapname2]
918
919 lzc.lzc_snapshot(snaps)
920 lzc.lzc_clone(clonename, snapname1)
921
922 with self.assertRaises(lzc_exc.SnapshotDestructionFailure) as ctx:
923 lzc.lzc_destroy_snaps(snaps, False)
924
9de8c0cd 925 self.assertEqual(len(ctx.exception.errors), 1)
6abf9225
AG
926 for e in ctx.exception.errors:
927 self.assertIsInstance(e, lzc_exc.SnapshotIsCloned)
928 for snap in snaps:
929 self.assertExists(snap)
930
931 def test_deferred_destroy_cloned_fs(self):
4b1c4062
BB
932 snapname1 = ZFSTest.pool.makeName(b"fs2@origin5")
933 snapname2 = ZFSTest.pool.makeName(b"fs1@snap")
934 clonename = ZFSTest.pool.makeName(b"fs1/fs/clone5")
6abf9225
AG
935 snaps = [snapname1, snapname2]
936
937 lzc.lzc_snapshot(snaps)
938 lzc.lzc_clone(clonename, snapname1)
939
940 lzc.lzc_destroy_snaps(snaps, defer=True)
941
942 self.assertExists(snapname1)
943 self.assertNotExists(snapname2)
944
945 def test_rollback(self):
4b1c4062
BB
946 name = ZFSTest.pool.makeName(b"fs1")
947 snapname = name + b"@snap"
6abf9225
AG
948
949 lzc.lzc_snapshot([snapname])
950 ret = lzc.lzc_rollback(name)
951 self.assertEqual(ret, snapname)
952
953 def test_rollback_2(self):
4b1c4062
BB
954 name = ZFSTest.pool.makeName(b"fs1")
955 snapname1 = name + b"@snap1"
956 snapname2 = name + b"@snap2"
6abf9225
AG
957
958 lzc.lzc_snapshot([snapname1])
959 lzc.lzc_snapshot([snapname2])
960 ret = lzc.lzc_rollback(name)
961 self.assertEqual(ret, snapname2)
962
6abf9225 963 def test_rollback_no_snaps(self):
4b1c4062 964 name = ZFSTest.pool.makeName(b"fs1")
6abf9225
AG
965
966 with self.assertRaises(lzc_exc.SnapshotNotFound):
967 lzc.lzc_rollback(name)
968
969 def test_rollback_non_existent_fs(self):
4b1c4062 970 name = ZFSTest.pool.makeName(b"nonexistent")
6abf9225
AG
971
972 with self.assertRaises(lzc_exc.FilesystemNotFound):
973 lzc.lzc_rollback(name)
974
975 def test_rollback_invalid_fs_name(self):
4b1c4062 976 name = ZFSTest.pool.makeName(b"bad~name")
6abf9225
AG
977
978 with self.assertRaises(lzc_exc.NameInvalid):
979 lzc.lzc_rollback(name)
980
981 def test_rollback_snap_name(self):
4b1c4062 982 name = ZFSTest.pool.makeName(b"fs1@snap")
6abf9225
AG
983
984 with self.assertRaises(lzc_exc.NameInvalid):
985 lzc.lzc_rollback(name)
986
987 def test_rollback_snap_name_2(self):
4b1c4062 988 name = ZFSTest.pool.makeName(b"fs1@snap")
6abf9225
AG
989
990 lzc.lzc_snapshot([name])
991 with self.assertRaises(lzc_exc.NameInvalid):
992 lzc.lzc_rollback(name)
993
994 def test_rollback_too_long_fs_name(self):
995 name = ZFSTest.pool.makeTooLongName()
996
997 with self.assertRaises(lzc_exc.NameTooLong):
998 lzc.lzc_rollback(name)
999
1000 def test_rollback_to_snap_name(self):
4b1c4062
BB
1001 name = ZFSTest.pool.makeName(b"fs1")
1002 snap = name + b"@snap"
6abf9225
AG
1003
1004 lzc.lzc_snapshot([snap])
1005 lzc.lzc_rollback_to(name, snap)
1006
1007 def test_rollback_to_not_latest(self):
4b1c4062
BB
1008 fsname = ZFSTest.pool.makeName(b'fs1')
1009 snap1 = fsname + b"@snap1"
1010 snap2 = fsname + b"@snap2"
6abf9225
AG
1011
1012 lzc.lzc_snapshot([snap1])
1013 lzc.lzc_snapshot([snap2])
1014 with self.assertRaises(lzc_exc.SnapshotNotLatest):
4b1c4062 1015 lzc.lzc_rollback_to(fsname, fsname + b"@snap1")
6abf9225
AG
1016
1017 @skipUnlessBookmarksSupported
1018 def test_bookmarks(self):
1019 snaps = [ZFSTest.pool.makeName(
4b1c4062 1020 b'fs1@snap1'), ZFSTest.pool.makeName(b'fs2@snap1')]
6abf9225 1021 bmarks = [ZFSTest.pool.makeName(
4b1c4062 1022 b'fs1#bmark1'), ZFSTest.pool.makeName(b'fs2#bmark1')]
6abf9225
AG
1023 bmark_dict = {x: y for x, y in zip(bmarks, snaps)}
1024
1025 lzc.lzc_snapshot(snaps)
1026 lzc.lzc_bookmark(bmark_dict)
1027
1028 @skipUnlessBookmarksSupported
1029 def test_bookmarks_2(self):
1030 snaps = [ZFSTest.pool.makeName(
4b1c4062 1031 b'fs1@snap1'), ZFSTest.pool.makeName(b'fs2@snap1')]
6abf9225 1032 bmarks = [ZFSTest.pool.makeName(
4b1c4062 1033 b'fs1#bmark1'), ZFSTest.pool.makeName(b'fs2#bmark1')]
6abf9225 1034 bmark_dict = {x: y for x, y in zip(bmarks, snaps)}
6abf9225
AG
1035 lzc.lzc_snapshot(snaps)
1036 lzc.lzc_bookmark(bmark_dict)
1037 lzc.lzc_destroy_snaps(snaps, defer=False)
1038
a73f361f
CS
1039 @skipUnlessBookmarksSupported
1040 def test_bookmark_copying(self):
1041 snaps = [ZFSTest.pool.makeName(s) for s in [
1042 b'fs1@snap1', b'fs1@snap2', b'fs2@snap1']]
1043 bmarks = [ZFSTest.pool.makeName(x) for x in [
1044 b'fs1#bmark1', b'fs1#bmark2', b'fs2#bmark1']]
1045 bmarks_copies = [ZFSTest.pool.makeName(x) for x in [
1046 b'fs1#bmark1_copy', b'fs1#bmark2_copy', b'fs2#bmark1_copy']]
1047 bmark_dict = {x: y for x, y in zip(bmarks, snaps)}
1048 bmark_copies_dict = {x: y for x, y in zip(bmarks_copies, bmarks)}
1049
1050 for snap in snaps:
1051 lzc.lzc_snapshot([snap])
1052 lzc.lzc_bookmark(bmark_dict)
1053
1054 lzc.lzc_bookmark(bmark_copies_dict)
1055 lzc.lzc_destroy_bookmarks(bmarks_copies)
1056
1057 lzc.lzc_destroy_bookmarks(bmarks)
1058 lzc.lzc_destroy_snaps(snaps, defer=False)
1059
6abf9225
AG
1060 @skipUnlessBookmarksSupported
1061 def test_bookmarks_empty(self):
1062 lzc.lzc_bookmark({})
1063
1064 @skipUnlessBookmarksSupported
be1e69f3 1065 def test_bookmarks_foreign_source(self):
4b1c4062
BB
1066 snaps = [ZFSTest.pool.makeName(b'fs1@snap1')]
1067 bmarks = [ZFSTest.pool.makeName(b'fs2#bmark1')]
6abf9225
AG
1068 bmark_dict = {x: y for x, y in zip(bmarks, snaps)}
1069
1070 lzc.lzc_snapshot(snaps)
1071 with self.assertRaises(lzc_exc.BookmarkFailure) as ctx:
1072 lzc.lzc_bookmark(bmark_dict)
1073
1074 for e in ctx.exception.errors:
1075 self.assertIsInstance(e, lzc_exc.BookmarkMismatch)
1076
1077 @skipUnlessBookmarksSupported
1078 def test_bookmarks_invalid_name(self):
4b1c4062
BB
1079 snaps = [ZFSTest.pool.makeName(b'fs1@snap1')]
1080 bmarks = [ZFSTest.pool.makeName(b'fs1#bmark!')]
6abf9225
AG
1081 bmark_dict = {x: y for x, y in zip(bmarks, snaps)}
1082
1083 lzc.lzc_snapshot(snaps)
1084 with self.assertRaises(lzc_exc.BookmarkFailure) as ctx:
1085 lzc.lzc_bookmark(bmark_dict)
1086
1087 for e in ctx.exception.errors:
1088 self.assertIsInstance(e, lzc_exc.NameInvalid)
1089
1090 @skipUnlessBookmarksSupported
1091 def test_bookmarks_invalid_name_2(self):
4b1c4062
BB
1092 snaps = [ZFSTest.pool.makeName(b'fs1@snap1')]
1093 bmarks = [ZFSTest.pool.makeName(b'fs1@bmark')]
6abf9225
AG
1094 bmark_dict = {x: y for x, y in zip(bmarks, snaps)}
1095
1096 lzc.lzc_snapshot(snaps)
1097 with self.assertRaises(lzc_exc.BookmarkFailure) as ctx:
1098 lzc.lzc_bookmark(bmark_dict)
1099
1100 for e in ctx.exception.errors:
1101 self.assertIsInstance(e, lzc_exc.NameInvalid)
1102
1103 @skipUnlessBookmarksSupported
1104 def test_bookmarks_too_long_name(self):
4b1c4062
BB
1105 snaps = [ZFSTest.pool.makeName(b'fs1@snap1')]
1106 bmarks = [ZFSTest.pool.makeTooLongName(b'fs1#')]
6abf9225
AG
1107 bmark_dict = {x: y for x, y in zip(bmarks, snaps)}
1108
1109 lzc.lzc_snapshot(snaps)
1110 with self.assertRaises(lzc_exc.BookmarkFailure) as ctx:
1111 lzc.lzc_bookmark(bmark_dict)
1112
1113 for e in ctx.exception.errors:
1114 self.assertIsInstance(e, lzc_exc.NameTooLong)
1115
1116 @skipUnlessBookmarksSupported
1117 def test_bookmarks_too_long_name_2(self):
4b1c4062
BB
1118 snaps = [ZFSTest.pool.makeName(b'fs1@snap1')]
1119 bmarks = [ZFSTest.pool.makeTooLongComponent(b'fs1#')]
6abf9225
AG
1120 bmark_dict = {x: y for x, y in zip(bmarks, snaps)}
1121
1122 lzc.lzc_snapshot(snaps)
1123 with self.assertRaises(lzc_exc.BookmarkFailure) as ctx:
1124 lzc.lzc_bookmark(bmark_dict)
1125
1126 for e in ctx.exception.errors:
1127 self.assertIsInstance(e, lzc_exc.NameTooLong)
1128
1129 @skipUnlessBookmarksSupported
a73f361f 1130 def test_bookmarks_foreign_sources(self):
6abf9225 1131 snaps = [ZFSTest.pool.makeName(
4b1c4062 1132 b'fs1@snap1'), ZFSTest.pool.makeName(b'fs2@snap1')]
6abf9225 1133 bmarks = [ZFSTest.pool.makeName(
4b1c4062 1134 b'fs2#bmark1'), ZFSTest.pool.makeName(b'fs1#bmark1')]
6abf9225
AG
1135 bmark_dict = {x: y for x, y in zip(bmarks, snaps)}
1136
1137 lzc.lzc_snapshot(snaps)
1138 with self.assertRaises(lzc_exc.BookmarkFailure) as ctx:
1139 lzc.lzc_bookmark(bmark_dict)
1140
1141 for e in ctx.exception.errors:
1142 self.assertIsInstance(e, lzc_exc.BookmarkMismatch)
1143
1144 @skipUnlessBookmarksSupported
a73f361f 1145 def test_bookmarks_partially_foreign_sources(self):
6abf9225 1146 snaps = [ZFSTest.pool.makeName(
4b1c4062 1147 b'fs1@snap1'), ZFSTest.pool.makeName(b'fs2@snap1')]
6abf9225 1148 bmarks = [ZFSTest.pool.makeName(
4b1c4062 1149 b'fs2#bmark'), ZFSTest.pool.makeName(b'fs2#bmark1')]
6abf9225
AG
1150 bmark_dict = {x: y for x, y in zip(bmarks, snaps)}
1151
1152 lzc.lzc_snapshot(snaps)
1153 with self.assertRaises(lzc_exc.BookmarkFailure) as ctx:
1154 lzc.lzc_bookmark(bmark_dict)
1155
1156 for e in ctx.exception.errors:
1157 self.assertIsInstance(e, lzc_exc.BookmarkMismatch)
1158
1159 @skipUnlessBookmarksSupported
1160 def test_bookmarks_cross_pool(self):
1161 snaps = [ZFSTest.pool.makeName(
4b1c4062 1162 b'fs1@snap1'), ZFSTest.misc_pool.makeName(b'@snap1')]
6abf9225 1163 bmarks = [ZFSTest.pool.makeName(
4b1c4062 1164 b'fs1#bmark1'), ZFSTest.misc_pool.makeName(b'#bmark1')]
6abf9225
AG
1165 bmark_dict = {x: y for x, y in zip(bmarks, snaps)}
1166
1167 lzc.lzc_snapshot(snaps[0:1])
1168 lzc.lzc_snapshot(snaps[1:2])
1169 with self.assertRaises(lzc_exc.BookmarkFailure) as ctx:
1170 lzc.lzc_bookmark(bmark_dict)
1171
1172 for e in ctx.exception.errors:
1173 self.assertIsInstance(e, lzc_exc.PoolsDiffer)
1174
1175 @skipUnlessBookmarksSupported
1176 def test_bookmarks_missing_snap(self):
a73f361f 1177 fss = [ZFSTest.pool.makeName(b'fs1'), ZFSTest.pool.makeName(b'fs2')]
6abf9225 1178 snaps = [ZFSTest.pool.makeName(
4b1c4062 1179 b'fs1@snap1'), ZFSTest.pool.makeName(b'fs2@snap1')]
6abf9225 1180 bmarks = [ZFSTest.pool.makeName(
4b1c4062 1181 b'fs1#bmark1'), ZFSTest.pool.makeName(b'fs2#bmark1')]
6abf9225
AG
1182 bmark_dict = {x: y for x, y in zip(bmarks, snaps)}
1183
a73f361f
CS
1184 lzc.lzc_snapshot(snaps[0:1]) # only create fs1@snap1
1185
6abf9225
AG
1186 with self.assertRaises(lzc_exc.BookmarkFailure) as ctx:
1187 lzc.lzc_bookmark(bmark_dict)
1188
1189 for e in ctx.exception.errors:
1190 self.assertIsInstance(e, lzc_exc.SnapshotNotFound)
1191
a73f361f
CS
1192 # no new bookmarks are created if one or more sources do not exist
1193 for fs in fss:
1194 fsbmarks = lzc.lzc_get_bookmarks(fs)
1195 self.assertEqual(len(fsbmarks), 0)
1196
6abf9225
AG
1197 @skipUnlessBookmarksSupported
1198 def test_bookmarks_missing_snaps(self):
a73f361f 1199 fss = [ZFSTest.pool.makeName(b'fs1'), ZFSTest.pool.makeName(b'fs2')]
6abf9225 1200 snaps = [ZFSTest.pool.makeName(
4b1c4062 1201 b'fs1@snap1'), ZFSTest.pool.makeName(b'fs2@snap1')]
6abf9225 1202 bmarks = [ZFSTest.pool.makeName(
4b1c4062 1203 b'fs1#bmark1'), ZFSTest.pool.makeName(b'fs2#bmark1')]
6abf9225
AG
1204 bmark_dict = {x: y for x, y in zip(bmarks, snaps)}
1205
a73f361f
CS
1206 # do not create any snapshots
1207
6abf9225
AG
1208 with self.assertRaises(lzc_exc.BookmarkFailure) as ctx:
1209 lzc.lzc_bookmark(bmark_dict)
1210
1211 for e in ctx.exception.errors:
1212 self.assertIsInstance(e, lzc_exc.SnapshotNotFound)
1213
a73f361f
CS
1214 # no new bookmarks are created if one or more sources do not exist
1215 for fs in fss:
1216 fsbmarks = lzc.lzc_get_bookmarks(fs)
1217 self.assertEqual(len(fsbmarks), 0)
1218
6abf9225
AG
1219 @skipUnlessBookmarksSupported
1220 def test_bookmarks_for_the_same_snap(self):
4b1c4062
BB
1221 snap = ZFSTest.pool.makeName(b'fs1@snap1')
1222 bmark1 = ZFSTest.pool.makeName(b'fs1#bmark1')
1223 bmark2 = ZFSTest.pool.makeName(b'fs1#bmark2')
6abf9225
AG
1224 bmark_dict = {bmark1: snap, bmark2: snap}
1225
1226 lzc.lzc_snapshot([snap])
1227 lzc.lzc_bookmark(bmark_dict)
1228
1229 @skipUnlessBookmarksSupported
1230 def test_bookmarks_for_the_same_snap_2(self):
4b1c4062
BB
1231 snap = ZFSTest.pool.makeName(b'fs1@snap1')
1232 bmark1 = ZFSTest.pool.makeName(b'fs1#bmark1')
1233 bmark2 = ZFSTest.pool.makeName(b'fs1#bmark2')
6abf9225
AG
1234 bmark_dict1 = {bmark1: snap}
1235 bmark_dict2 = {bmark2: snap}
1236
1237 lzc.lzc_snapshot([snap])
1238 lzc.lzc_bookmark(bmark_dict1)
1239 lzc.lzc_bookmark(bmark_dict2)
1240
1241 @skipUnlessBookmarksSupported
1242 def test_bookmarks_duplicate_name(self):
4b1c4062
BB
1243 snap1 = ZFSTest.pool.makeName(b'fs1@snap1')
1244 snap2 = ZFSTest.pool.makeName(b'fs1@snap2')
1245 bmark = ZFSTest.pool.makeName(b'fs1#bmark')
6abf9225
AG
1246 bmark_dict1 = {bmark: snap1}
1247 bmark_dict2 = {bmark: snap2}
1248
1249 lzc.lzc_snapshot([snap1])
1250 lzc.lzc_snapshot([snap2])
1251 lzc.lzc_bookmark(bmark_dict1)
1252 with self.assertRaises(lzc_exc.BookmarkFailure) as ctx:
1253 lzc.lzc_bookmark(bmark_dict2)
1254
1255 for e in ctx.exception.errors:
1256 self.assertIsInstance(e, lzc_exc.BookmarkExists)
1257
1258 @skipUnlessBookmarksSupported
1259 def test_get_bookmarks(self):
4b1c4062
BB
1260 snap1 = ZFSTest.pool.makeName(b'fs1@snap1')
1261 snap2 = ZFSTest.pool.makeName(b'fs1@snap2')
1262 bmark = ZFSTest.pool.makeName(b'fs1#bmark')
1263 bmark1 = ZFSTest.pool.makeName(b'fs1#bmark1')
1264 bmark2 = ZFSTest.pool.makeName(b'fs1#bmark2')
6abf9225
AG
1265 bmark_dict1 = {bmark1: snap1, bmark2: snap2}
1266 bmark_dict2 = {bmark: snap2}
1267
1268 lzc.lzc_snapshot([snap1])
1269 lzc.lzc_snapshot([snap2])
1270 lzc.lzc_bookmark(bmark_dict1)
1271 lzc.lzc_bookmark(bmark_dict2)
1272 lzc.lzc_destroy_snaps([snap1, snap2], defer=False)
1273
4b1c4062 1274 bmarks = lzc.lzc_get_bookmarks(ZFSTest.pool.makeName(b'fs1'))
9de8c0cd 1275 self.assertEqual(len(bmarks), 3)
4b1c4062 1276 for b in b'bmark', b'bmark1', b'bmark2':
6abf9225
AG
1277 self.assertIn(b, bmarks)
1278 self.assertIsInstance(bmarks[b], dict)
9de8c0cd 1279 self.assertEqual(len(bmarks[b]), 0)
6abf9225 1280
4b1c4062
BB
1281 bmarks = lzc.lzc_get_bookmarks(ZFSTest.pool.makeName(b'fs1'),
1282 [b'guid', b'createtxg', b'creation'])
9de8c0cd 1283 self.assertEqual(len(bmarks), 3)
4b1c4062 1284 for b in b'bmark', b'bmark1', b'bmark2':
6abf9225
AG
1285 self.assertIn(b, bmarks)
1286 self.assertIsInstance(bmarks[b], dict)
9de8c0cd 1287 self.assertEqual(len(bmarks[b]), 3)
6abf9225
AG
1288
1289 @skipUnlessBookmarksSupported
1290 def test_get_bookmarks_invalid_property(self):
4b1c4062
BB
1291 snap = ZFSTest.pool.makeName(b'fs1@snap')
1292 bmark = ZFSTest.pool.makeName(b'fs1#bmark')
6abf9225
AG
1293 bmark_dict = {bmark: snap}
1294
1295 lzc.lzc_snapshot([snap])
1296 lzc.lzc_bookmark(bmark_dict)
1297
1298 bmarks = lzc.lzc_get_bookmarks(
4b1c4062 1299 ZFSTest.pool.makeName(b'fs1'), [b'badprop'])
9de8c0cd 1300 self.assertEqual(len(bmarks), 1)
4b1c4062 1301 for b in (b'bmark', ):
6abf9225
AG
1302 self.assertIn(b, bmarks)
1303 self.assertIsInstance(bmarks[b], dict)
9de8c0cd 1304 self.assertEqual(len(bmarks[b]), 0)
6abf9225
AG
1305
1306 @skipUnlessBookmarksSupported
1307 def test_get_bookmarks_nonexistent_fs(self):
1308 with self.assertRaises(lzc_exc.FilesystemNotFound):
4b1c4062 1309 lzc.lzc_get_bookmarks(ZFSTest.pool.makeName(b'nonexistent'))
6abf9225
AG
1310
1311 @skipUnlessBookmarksSupported
1312 def test_destroy_bookmarks(self):
4b1c4062
BB
1313 snap = ZFSTest.pool.makeName(b'fs1@snap')
1314 bmark = ZFSTest.pool.makeName(b'fs1#bmark')
6abf9225
AG
1315 bmark_dict = {bmark: snap}
1316
1317 lzc.lzc_snapshot([snap])
1318 lzc.lzc_bookmark(bmark_dict)
1319
1320 lzc.lzc_destroy_bookmarks(
4b1c4062
BB
1321 [bmark, ZFSTest.pool.makeName(b'fs1#nonexistent')])
1322 bmarks = lzc.lzc_get_bookmarks(ZFSTest.pool.makeName(b'fs1'))
9de8c0cd 1323 self.assertEqual(len(bmarks), 0)
6abf9225
AG
1324
1325 @skipUnlessBookmarksSupported
1326 def test_destroy_bookmarks_invalid_name(self):
4b1c4062
BB
1327 snap = ZFSTest.pool.makeName(b'fs1@snap')
1328 bmark = ZFSTest.pool.makeName(b'fs1#bmark')
6abf9225
AG
1329 bmark_dict = {bmark: snap}
1330
1331 lzc.lzc_snapshot([snap])
1332 lzc.lzc_bookmark(bmark_dict)
1333
1334 with self.assertRaises(lzc_exc.BookmarkDestructionFailure) as ctx:
1335 lzc.lzc_destroy_bookmarks(
4b1c4062 1336 [bmark, ZFSTest.pool.makeName(b'fs1/nonexistent')])
6abf9225
AG
1337 for e in ctx.exception.errors:
1338 self.assertIsInstance(e, lzc_exc.NameInvalid)
1339
4b1c4062 1340 bmarks = lzc.lzc_get_bookmarks(ZFSTest.pool.makeName(b'fs1'))
9de8c0cd 1341 self.assertEqual(len(bmarks), 1)
4b1c4062 1342 self.assertIn(b'bmark', bmarks)
6abf9225
AG
1343
1344 @skipUnlessBookmarksSupported
1345 def test_destroy_bookmark_nonexistent_fs(self):
4b1c4062
BB
1346 lzc.lzc_destroy_bookmarks(
1347 [ZFSTest.pool.makeName(b'nonexistent#bmark')])
6abf9225
AG
1348
1349 @skipUnlessBookmarksSupported
1350 def test_destroy_bookmarks_empty(self):
1351 lzc.lzc_bookmark({})
1352
1353 def test_snaprange_space(self):
4b1c4062
BB
1354 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
1355 snap2 = ZFSTest.pool.makeName(b"fs1@snap2")
1356 snap3 = ZFSTest.pool.makeName(b"fs1@snap")
6abf9225
AG
1357
1358 lzc.lzc_snapshot([snap1])
1359 lzc.lzc_snapshot([snap2])
1360 lzc.lzc_snapshot([snap3])
1361
1362 space = lzc.lzc_snaprange_space(snap1, snap2)
9de8c0cd 1363 self.assertIsInstance(space, (int, int))
6abf9225 1364 space = lzc.lzc_snaprange_space(snap2, snap3)
9de8c0cd 1365 self.assertIsInstance(space, (int, int))
6abf9225 1366 space = lzc.lzc_snaprange_space(snap1, snap3)
9de8c0cd 1367 self.assertIsInstance(space, (int, int))
6abf9225
AG
1368
1369 def test_snaprange_space_2(self):
4b1c4062
BB
1370 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
1371 snap2 = ZFSTest.pool.makeName(b"fs1@snap2")
1372 snap3 = ZFSTest.pool.makeName(b"fs1@snap")
6abf9225
AG
1373
1374 lzc.lzc_snapshot([snap1])
4b1c4062 1375 with zfs_mount(ZFSTest.pool.makeName(b"fs1")) as mntdir:
6abf9225
AG
1376 with tempfile.NamedTemporaryFile(dir=mntdir) as f:
1377 for i in range(1024):
4b1c4062 1378 f.write(b'x' * 1024)
6abf9225
AG
1379 f.flush()
1380 lzc.lzc_snapshot([snap2])
1381 lzc.lzc_snapshot([snap3])
1382
1383 space = lzc.lzc_snaprange_space(snap1, snap2)
1384 self.assertGreater(space, 1024 * 1024)
1385 space = lzc.lzc_snaprange_space(snap2, snap3)
1386 self.assertGreater(space, 1024 * 1024)
1387 space = lzc.lzc_snaprange_space(snap1, snap3)
1388 self.assertGreater(space, 1024 * 1024)
1389
1390 def test_snaprange_space_same_snap(self):
4b1c4062 1391 snap = ZFSTest.pool.makeName(b"fs1@snap")
6abf9225 1392
4b1c4062 1393 with zfs_mount(ZFSTest.pool.makeName(b"fs1")) as mntdir:
6abf9225
AG
1394 with tempfile.NamedTemporaryFile(dir=mntdir) as f:
1395 for i in range(1024):
4b1c4062 1396 f.write(b'x' * 1024)
6abf9225
AG
1397 f.flush()
1398 lzc.lzc_snapshot([snap])
1399
1400 space = lzc.lzc_snaprange_space(snap, snap)
1401 self.assertGreater(space, 1024 * 1024)
9de8c0cd 1402 self.assertAlmostEqual(space, 1024 * 1024, delta=1024 * 1024 // 20)
6abf9225
AG
1403
1404 def test_snaprange_space_wrong_order(self):
4b1c4062
BB
1405 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
1406 snap2 = ZFSTest.pool.makeName(b"fs1@snap2")
6abf9225
AG
1407
1408 lzc.lzc_snapshot([snap1])
1409 lzc.lzc_snapshot([snap2])
1410
1411 with self.assertRaises(lzc_exc.SnapshotMismatch):
1412 lzc.lzc_snaprange_space(snap2, snap1)
1413
1414 def test_snaprange_space_unrelated(self):
4b1c4062
BB
1415 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
1416 snap2 = ZFSTest.pool.makeName(b"fs2@snap2")
6abf9225
AG
1417
1418 lzc.lzc_snapshot([snap1])
1419 lzc.lzc_snapshot([snap2])
1420
1421 with self.assertRaises(lzc_exc.SnapshotMismatch):
1422 lzc.lzc_snaprange_space(snap1, snap2)
1423
1424 def test_snaprange_space_across_pools(self):
4b1c4062
BB
1425 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
1426 snap2 = ZFSTest.misc_pool.makeName(b"@snap2")
6abf9225
AG
1427
1428 lzc.lzc_snapshot([snap1])
1429 lzc.lzc_snapshot([snap2])
1430
1431 with self.assertRaises(lzc_exc.PoolsDiffer):
1432 lzc.lzc_snaprange_space(snap1, snap2)
1433
1434 def test_snaprange_space_nonexistent(self):
4b1c4062
BB
1435 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
1436 snap2 = ZFSTest.pool.makeName(b"fs1@snap2")
6abf9225
AG
1437
1438 lzc.lzc_snapshot([snap1])
1439
1440 with self.assertRaises(lzc_exc.SnapshotNotFound) as ctx:
1441 lzc.lzc_snaprange_space(snap1, snap2)
9de8c0cd 1442 self.assertEqual(ctx.exception.name, snap2)
6abf9225
AG
1443
1444 with self.assertRaises(lzc_exc.SnapshotNotFound) as ctx:
1445 lzc.lzc_snaprange_space(snap2, snap1)
9de8c0cd 1446 self.assertEqual(ctx.exception.name, snap1)
6abf9225
AG
1447
1448 def test_snaprange_space_invalid_name(self):
4b1c4062
BB
1449 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
1450 snap2 = ZFSTest.pool.makeName(b"fs1@sn#p")
6abf9225
AG
1451
1452 lzc.lzc_snapshot([snap1])
1453
1454 with self.assertRaises(lzc_exc.NameInvalid):
1455 lzc.lzc_snaprange_space(snap1, snap2)
1456
1457 def test_snaprange_space_not_snap(self):
4b1c4062
BB
1458 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
1459 snap2 = ZFSTest.pool.makeName(b"fs1")
6abf9225
AG
1460
1461 lzc.lzc_snapshot([snap1])
1462
1463 with self.assertRaises(lzc_exc.NameInvalid):
1464 lzc.lzc_snaprange_space(snap1, snap2)
1465 with self.assertRaises(lzc_exc.NameInvalid):
1466 lzc.lzc_snaprange_space(snap2, snap1)
1467
1468 def test_snaprange_space_not_snap_2(self):
4b1c4062
BB
1469 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
1470 snap2 = ZFSTest.pool.makeName(b"fs1#bmark")
6abf9225
AG
1471
1472 lzc.lzc_snapshot([snap1])
1473
1474 with self.assertRaises(lzc_exc.NameInvalid):
1475 lzc.lzc_snaprange_space(snap1, snap2)
1476 with self.assertRaises(lzc_exc.NameInvalid):
1477 lzc.lzc_snaprange_space(snap2, snap1)
1478
1479 def test_send_space(self):
4b1c4062
BB
1480 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
1481 snap2 = ZFSTest.pool.makeName(b"fs1@snap2")
1482 snap3 = ZFSTest.pool.makeName(b"fs1@snap")
6abf9225
AG
1483
1484 lzc.lzc_snapshot([snap1])
1485 lzc.lzc_snapshot([snap2])
1486 lzc.lzc_snapshot([snap3])
1487
1488 space = lzc.lzc_send_space(snap2, snap1)
9de8c0cd 1489 self.assertIsInstance(space, (int, int))
6abf9225 1490 space = lzc.lzc_send_space(snap3, snap2)
9de8c0cd 1491 self.assertIsInstance(space, (int, int))
6abf9225 1492 space = lzc.lzc_send_space(snap3, snap1)
9de8c0cd 1493 self.assertIsInstance(space, (int, int))
6abf9225 1494 space = lzc.lzc_send_space(snap1)
9de8c0cd 1495 self.assertIsInstance(space, (int, int))
6abf9225 1496 space = lzc.lzc_send_space(snap2)
9de8c0cd 1497 self.assertIsInstance(space, (int, int))
6abf9225 1498 space = lzc.lzc_send_space(snap3)
9de8c0cd 1499 self.assertIsInstance(space, (int, int))
6abf9225
AG
1500
1501 def test_send_space_2(self):
4b1c4062
BB
1502 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
1503 snap2 = ZFSTest.pool.makeName(b"fs1@snap2")
1504 snap3 = ZFSTest.pool.makeName(b"fs1@snap")
6abf9225
AG
1505
1506 lzc.lzc_snapshot([snap1])
4b1c4062 1507 with zfs_mount(ZFSTest.pool.makeName(b"fs1")) as mntdir:
6abf9225
AG
1508 with tempfile.NamedTemporaryFile(dir=mntdir) as f:
1509 for i in range(1024):
4b1c4062 1510 f.write(b'x' * 1024)
6abf9225
AG
1511 f.flush()
1512 lzc.lzc_snapshot([snap2])
1513 lzc.lzc_snapshot([snap3])
1514
1515 space = lzc.lzc_send_space(snap2, snap1)
1516 self.assertGreater(space, 1024 * 1024)
1517
1518 space = lzc.lzc_send_space(snap3, snap2)
1519
1520 space = lzc.lzc_send_space(snap3, snap1)
1521
1522 space_empty = lzc.lzc_send_space(snap1)
1523
1524 space = lzc.lzc_send_space(snap2)
1525 self.assertGreater(space, 1024 * 1024)
1526
1527 space = lzc.lzc_send_space(snap3)
9de8c0cd 1528 self.assertEqual(space, space_empty)
6abf9225
AG
1529
1530 def test_send_space_same_snap(self):
4b1c4062 1531 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
6abf9225
AG
1532 lzc.lzc_snapshot([snap1])
1533 with self.assertRaises(lzc_exc.SnapshotMismatch):
1534 lzc.lzc_send_space(snap1, snap1)
1535
1536 def test_send_space_wrong_order(self):
4b1c4062
BB
1537 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
1538 snap2 = ZFSTest.pool.makeName(b"fs1@snap2")
6abf9225
AG
1539
1540 lzc.lzc_snapshot([snap1])
1541 lzc.lzc_snapshot([snap2])
1542
1543 with self.assertRaises(lzc_exc.SnapshotMismatch):
1544 lzc.lzc_send_space(snap1, snap2)
1545
1546 def test_send_space_unrelated(self):
4b1c4062
BB
1547 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
1548 snap2 = ZFSTest.pool.makeName(b"fs2@snap2")
6abf9225
AG
1549
1550 lzc.lzc_snapshot([snap1])
1551 lzc.lzc_snapshot([snap2])
1552
1553 with self.assertRaises(lzc_exc.SnapshotMismatch):
1554 lzc.lzc_send_space(snap1, snap2)
1555
1556 def test_send_space_across_pools(self):
4b1c4062
BB
1557 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
1558 snap2 = ZFSTest.misc_pool.makeName(b"@snap2")
6abf9225
AG
1559
1560 lzc.lzc_snapshot([snap1])
1561 lzc.lzc_snapshot([snap2])
1562
1563 with self.assertRaises(lzc_exc.PoolsDiffer):
1564 lzc.lzc_send_space(snap1, snap2)
1565
1566 def test_send_space_nonexistent(self):
4b1c4062
BB
1567 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
1568 snap2 = ZFSTest.pool.makeName(b"fs2@snap2")
6abf9225
AG
1569
1570 lzc.lzc_snapshot([snap1])
1571
1572 with self.assertRaises(lzc_exc.SnapshotNotFound) as ctx:
1573 lzc.lzc_send_space(snap1, snap2)
9de8c0cd 1574 self.assertEqual(ctx.exception.name, snap1)
6abf9225
AG
1575
1576 with self.assertRaises(lzc_exc.SnapshotNotFound) as ctx:
1577 lzc.lzc_send_space(snap2, snap1)
9de8c0cd 1578 self.assertEqual(ctx.exception.name, snap2)
6abf9225
AG
1579
1580 with self.assertRaises(lzc_exc.SnapshotNotFound) as ctx:
1581 lzc.lzc_send_space(snap2)
9de8c0cd 1582 self.assertEqual(ctx.exception.name, snap2)
6abf9225
AG
1583
1584 def test_send_space_invalid_name(self):
4b1c4062
BB
1585 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
1586 snap2 = ZFSTest.pool.makeName(b"fs1@sn!p")
6abf9225
AG
1587
1588 lzc.lzc_snapshot([snap1])
1589
1590 with self.assertRaises(lzc_exc.NameInvalid) as ctx:
1591 lzc.lzc_send_space(snap2, snap1)
9de8c0cd 1592 self.assertEqual(ctx.exception.name, snap2)
6abf9225
AG
1593 with self.assertRaises(lzc_exc.NameInvalid) as ctx:
1594 lzc.lzc_send_space(snap2)
9de8c0cd 1595 self.assertEqual(ctx.exception.name, snap2)
6abf9225
AG
1596 with self.assertRaises(lzc_exc.NameInvalid) as ctx:
1597 lzc.lzc_send_space(snap1, snap2)
9de8c0cd 1598 self.assertEqual(ctx.exception.name, snap2)
6abf9225
AG
1599
1600 def test_send_space_not_snap(self):
4b1c4062
BB
1601 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
1602 snap2 = ZFSTest.pool.makeName(b"fs1")
6abf9225
AG
1603
1604 lzc.lzc_snapshot([snap1])
1605
1606 with self.assertRaises(lzc_exc.NameInvalid):
1607 lzc.lzc_send_space(snap1, snap2)
1608 with self.assertRaises(lzc_exc.NameInvalid):
1609 lzc.lzc_send_space(snap2, snap1)
1610 with self.assertRaises(lzc_exc.NameInvalid):
1611 lzc.lzc_send_space(snap2)
1612
1613 def test_send_space_not_snap_2(self):
4b1c4062
BB
1614 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
1615 snap2 = ZFSTest.pool.makeName(b"fs1#bmark")
6abf9225
AG
1616
1617 lzc.lzc_snapshot([snap1])
1618
1619 with self.assertRaises(lzc_exc.NameInvalid):
1620 lzc.lzc_send_space(snap2, snap1)
1621 with self.assertRaises(lzc_exc.NameInvalid):
1622 lzc.lzc_send_space(snap2)
1623
1624 def test_send_full(self):
4b1c4062 1625 snap = ZFSTest.pool.makeName(b"fs1@snap")
6abf9225 1626
4b1c4062 1627 with zfs_mount(ZFSTest.pool.makeName(b"fs1")) as mntdir:
6abf9225
AG
1628 with tempfile.NamedTemporaryFile(dir=mntdir) as f:
1629 for i in range(1024):
4b1c4062 1630 f.write(b'x' * 1024)
6abf9225
AG
1631 f.flush()
1632 lzc.lzc_snapshot([snap])
1633
d8d418ff 1634 with tempfile.TemporaryFile(suffix='.zstream') as output:
6abf9225
AG
1635 estimate = lzc.lzc_send_space(snap)
1636
1637 fd = output.fileno()
1638 lzc.lzc_send(snap, None, fd)
1639 st = os.fstat(fd)
1640 # 5%, arbitrary.
9de8c0cd 1641 self.assertAlmostEqual(st.st_size, estimate, delta=estimate // 20)
6abf9225
AG
1642
1643 def test_send_incremental(self):
4b1c4062
BB
1644 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
1645 snap2 = ZFSTest.pool.makeName(b"fs1@snap2")
6abf9225
AG
1646
1647 lzc.lzc_snapshot([snap1])
4b1c4062 1648 with zfs_mount(ZFSTest.pool.makeName(b"fs1")) as mntdir:
6abf9225
AG
1649 with tempfile.NamedTemporaryFile(dir=mntdir) as f:
1650 for i in range(1024):
4b1c4062 1651 f.write(b'x' * 1024)
6abf9225
AG
1652 f.flush()
1653 lzc.lzc_snapshot([snap2])
1654
d8d418ff 1655 with tempfile.TemporaryFile(suffix='.zstream') as output:
6abf9225
AG
1656 estimate = lzc.lzc_send_space(snap2, snap1)
1657
1658 fd = output.fileno()
1659 lzc.lzc_send(snap2, snap1, fd)
1660 st = os.fstat(fd)
1661 # 5%, arbitrary.
9de8c0cd 1662 self.assertAlmostEqual(st.st_size, estimate, delta=estimate // 20)
6abf9225
AG
1663
1664 def test_send_flags(self):
85ce3f4f 1665 flags = ['embedded_data', 'large_blocks', 'compress', 'raw']
4b1c4062 1666 snap = ZFSTest.pool.makeName(b"fs1@snap")
6abf9225 1667 lzc.lzc_snapshot([snap])
85ce3f4f 1668
1669 for c in range(len(flags)):
1670 for flag in itertools.permutations(flags, c + 1):
1671 with dev_null() as fd:
1672 lzc.lzc_send(snap, None, fd, list(flag))
6abf9225
AG
1673
1674 def test_send_unknown_flags(self):
4b1c4062 1675 snap = ZFSTest.pool.makeName(b"fs1@snap")
6abf9225
AG
1676 lzc.lzc_snapshot([snap])
1677 with dev_null() as fd:
1678 with self.assertRaises(lzc_exc.UnknownStreamFeature):
1679 lzc.lzc_send(snap, None, fd, ['embedded_data', 'UNKNOWN'])
1680
1681 def test_send_same_snap(self):
4b1c4062 1682 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
6abf9225 1683 lzc.lzc_snapshot([snap1])
d8d418ff 1684 with tempfile.TemporaryFile(suffix='.zstream') as output:
6abf9225
AG
1685 fd = output.fileno()
1686 with self.assertRaises(lzc_exc.SnapshotMismatch):
1687 lzc.lzc_send(snap1, snap1, fd)
1688
1689 def test_send_wrong_order(self):
4b1c4062
BB
1690 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
1691 snap2 = ZFSTest.pool.makeName(b"fs1@snap2")
6abf9225
AG
1692
1693 lzc.lzc_snapshot([snap1])
1694 lzc.lzc_snapshot([snap2])
1695
d8d418ff 1696 with tempfile.TemporaryFile(suffix='.zstream') as output:
6abf9225
AG
1697 fd = output.fileno()
1698 with self.assertRaises(lzc_exc.SnapshotMismatch):
1699 lzc.lzc_send(snap1, snap2, fd)
1700
1701 def test_send_unrelated(self):
4b1c4062
BB
1702 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
1703 snap2 = ZFSTest.pool.makeName(b"fs2@snap2")
6abf9225
AG
1704
1705 lzc.lzc_snapshot([snap1])
1706 lzc.lzc_snapshot([snap2])
1707
d8d418ff 1708 with tempfile.TemporaryFile(suffix='.zstream') as output:
6abf9225
AG
1709 fd = output.fileno()
1710 with self.assertRaises(lzc_exc.SnapshotMismatch):
1711 lzc.lzc_send(snap1, snap2, fd)
1712
1713 def test_send_across_pools(self):
4b1c4062
BB
1714 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
1715 snap2 = ZFSTest.misc_pool.makeName(b"@snap2")
6abf9225
AG
1716
1717 lzc.lzc_snapshot([snap1])
1718 lzc.lzc_snapshot([snap2])
1719
d8d418ff 1720 with tempfile.TemporaryFile(suffix='.zstream') as output:
6abf9225
AG
1721 fd = output.fileno()
1722 with self.assertRaises(lzc_exc.PoolsDiffer):
1723 lzc.lzc_send(snap1, snap2, fd)
1724
1725 def test_send_nonexistent(self):
4b1c4062
BB
1726 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
1727 snap2 = ZFSTest.pool.makeName(b"fs1@snap2")
6abf9225
AG
1728
1729 lzc.lzc_snapshot([snap1])
1730
d8d418ff 1731 with tempfile.TemporaryFile(suffix='.zstream') as output:
6abf9225
AG
1732 fd = output.fileno()
1733 with self.assertRaises(lzc_exc.SnapshotNotFound) as ctx:
1734 lzc.lzc_send(snap1, snap2, fd)
9de8c0cd 1735 self.assertEqual(ctx.exception.name, snap1)
6abf9225
AG
1736
1737 with self.assertRaises(lzc_exc.SnapshotNotFound) as ctx:
1738 lzc.lzc_send(snap2, snap1, fd)
9de8c0cd 1739 self.assertEqual(ctx.exception.name, snap2)
6abf9225
AG
1740
1741 with self.assertRaises(lzc_exc.SnapshotNotFound) as ctx:
1742 lzc.lzc_send(snap2, None, fd)
9de8c0cd 1743 self.assertEqual(ctx.exception.name, snap2)
6abf9225
AG
1744
1745 def test_send_invalid_name(self):
4b1c4062
BB
1746 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
1747 snap2 = ZFSTest.pool.makeName(b"fs1@sn!p")
6abf9225
AG
1748
1749 lzc.lzc_snapshot([snap1])
1750
d8d418ff 1751 with tempfile.TemporaryFile(suffix='.zstream') as output:
6abf9225
AG
1752 fd = output.fileno()
1753 with self.assertRaises(lzc_exc.NameInvalid) as ctx:
1754 lzc.lzc_send(snap2, snap1, fd)
9de8c0cd 1755 self.assertEqual(ctx.exception.name, snap2)
6abf9225
AG
1756 with self.assertRaises(lzc_exc.NameInvalid) as ctx:
1757 lzc.lzc_send(snap2, None, fd)
9de8c0cd 1758 self.assertEqual(ctx.exception.name, snap2)
6abf9225
AG
1759 with self.assertRaises(lzc_exc.NameInvalid) as ctx:
1760 lzc.lzc_send(snap1, snap2, fd)
9de8c0cd 1761 self.assertEqual(ctx.exception.name, snap2)
6abf9225
AG
1762
1763 # XXX Although undocumented the API allows to create an incremental
1764 # or full stream for a filesystem as if a temporary unnamed snapshot
1765 # is taken at some time after the call is made and before the stream
1766 # starts being produced.
1767 def test_send_filesystem(self):
4b1c4062
BB
1768 snap = ZFSTest.pool.makeName(b"fs1@snap1")
1769 fs = ZFSTest.pool.makeName(b"fs1")
6abf9225
AG
1770
1771 lzc.lzc_snapshot([snap])
1772
d8d418ff 1773 with tempfile.TemporaryFile(suffix='.zstream') as output:
6abf9225
AG
1774 fd = output.fileno()
1775 lzc.lzc_send(fs, snap, fd)
1776 lzc.lzc_send(fs, None, fd)
1777
1778 def test_send_from_filesystem(self):
4b1c4062
BB
1779 snap = ZFSTest.pool.makeName(b"fs1@snap1")
1780 fs = ZFSTest.pool.makeName(b"fs1")
6abf9225
AG
1781
1782 lzc.lzc_snapshot([snap])
1783
d8d418ff 1784 with tempfile.TemporaryFile(suffix='.zstream') as output:
6abf9225
AG
1785 fd = output.fileno()
1786 with self.assertRaises(lzc_exc.NameInvalid):
1787 lzc.lzc_send(snap, fs, fd)
1788
1789 @skipUnlessBookmarksSupported
1790 def test_send_bookmark(self):
4b1c4062
BB
1791 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
1792 snap2 = ZFSTest.pool.makeName(b"fs1@snap2")
1793 bmark = ZFSTest.pool.makeName(b"fs1#bmark")
6abf9225
AG
1794
1795 lzc.lzc_snapshot([snap1])
1796 lzc.lzc_snapshot([snap2])
1797 lzc.lzc_bookmark({bmark: snap2})
1798 lzc.lzc_destroy_snaps([snap2], defer=False)
1799
d8d418ff 1800 with tempfile.TemporaryFile(suffix='.zstream') as output:
6abf9225
AG
1801 fd = output.fileno()
1802 with self.assertRaises(lzc_exc.NameInvalid):
1803 lzc.lzc_send(bmark, snap1, fd)
1804 with self.assertRaises(lzc_exc.NameInvalid):
1805 lzc.lzc_send(bmark, None, fd)
1806
1807 @skipUnlessBookmarksSupported
1808 def test_send_from_bookmark(self):
4b1c4062
BB
1809 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
1810 snap2 = ZFSTest.pool.makeName(b"fs1@snap2")
1811 bmark = ZFSTest.pool.makeName(b"fs1#bmark")
6abf9225
AG
1812
1813 lzc.lzc_snapshot([snap1])
1814 lzc.lzc_snapshot([snap2])
1815 lzc.lzc_bookmark({bmark: snap1})
1816 lzc.lzc_destroy_snaps([snap1], defer=False)
1817
d8d418ff 1818 with tempfile.TemporaryFile(suffix='.zstream') as output:
6abf9225
AG
1819 fd = output.fileno()
1820 lzc.lzc_send(snap2, bmark, fd)
1821
1822 def test_send_bad_fd(self):
4b1c4062 1823 snap = ZFSTest.pool.makeName(b"fs1@snap")
6abf9225
AG
1824 lzc.lzc_snapshot([snap])
1825
1826 with tempfile.TemporaryFile() as tmp:
1827 bad_fd = tmp.fileno()
1828
1829 with self.assertRaises(lzc_exc.StreamIOError) as ctx:
1830 lzc.lzc_send(snap, None, bad_fd)
9de8c0cd 1831 self.assertEqual(ctx.exception.errno, errno.EBADF)
6abf9225
AG
1832
1833 def test_send_bad_fd_2(self):
4b1c4062 1834 snap = ZFSTest.pool.makeName(b"fs1@snap")
6abf9225
AG
1835 lzc.lzc_snapshot([snap])
1836
1837 with self.assertRaises(lzc_exc.StreamIOError) as ctx:
1838 lzc.lzc_send(snap, None, -2)
9de8c0cd 1839 self.assertEqual(ctx.exception.errno, errno.EBADF)
6abf9225
AG
1840
1841 def test_send_bad_fd_3(self):
4b1c4062 1842 snap = ZFSTest.pool.makeName(b"fs1@snap")
6abf9225
AG
1843 lzc.lzc_snapshot([snap])
1844
1845 with tempfile.TemporaryFile() as tmp:
1846 bad_fd = tmp.fileno()
1847
1848 (soft, hard) = resource.getrlimit(resource.RLIMIT_NOFILE)
1849 bad_fd = hard + 1
1850 with self.assertRaises(lzc_exc.StreamIOError) as ctx:
1851 lzc.lzc_send(snap, None, bad_fd)
9de8c0cd 1852 self.assertEqual(ctx.exception.errno, errno.EBADF)
6abf9225
AG
1853
1854 def test_send_to_broken_pipe(self):
4b1c4062 1855 snap = ZFSTest.pool.makeName(b"fs1@snap")
6abf9225
AG
1856 lzc.lzc_snapshot([snap])
1857
4b1c4062
BB
1858 if sys.version_info < (3, 0):
1859 proc = subprocess.Popen(['true'], stdin=subprocess.PIPE)
1860 proc.wait()
1861 with self.assertRaises(lzc_exc.StreamIOError) as ctx:
1862 lzc.lzc_send(snap, None, proc.stdin.fileno())
1863 self.assertEqual(ctx.exception.errno, errno.EPIPE)
1864 else:
1865 with subprocess.Popen(['true'], stdin=subprocess.PIPE) as proc:
1866 proc.wait()
1867 with self.assertRaises(lzc_exc.StreamIOError) as ctx:
1868 lzc.lzc_send(snap, None, proc.stdin.fileno())
1869 self.assertEqual(ctx.exception.errno, errno.EPIPE)
6abf9225
AG
1870
1871 def test_send_to_broken_pipe_2(self):
4b1c4062
BB
1872 snap = ZFSTest.pool.makeName(b"fs1@snap")
1873 with zfs_mount(ZFSTest.pool.makeName(b"fs1")) as mntdir:
6abf9225
AG
1874 with tempfile.NamedTemporaryFile(dir=mntdir) as f:
1875 for i in range(1024):
4b1c4062 1876 f.write(b'x' * 1024)
6abf9225
AG
1877 f.flush()
1878 lzc.lzc_snapshot([snap])
1879
4b1c4062
BB
1880 if sys.version_info < (3, 0):
1881 p = subprocess.Popen(['sleep', '2'], stdin=subprocess.PIPE)
1882 with self.assertRaises(lzc_exc.StreamIOError) as ctx:
1883 lzc.lzc_send(snap, None, p.stdin.fileno())
1884 self.assertTrue(ctx.exception.errno == errno.EPIPE or
1885 ctx.exception.errno == errno.EINTR)
1886 else:
1887 with subprocess.Popen(['sleep', '2'], stdin=subprocess.PIPE) as p:
1888 with self.assertRaises(lzc_exc.StreamIOError) as ctx:
1889 lzc.lzc_send(snap, None, p.stdin.fileno())
1890 self.assertTrue(ctx.exception.errno == errno.EPIPE or
1891 ctx.exception.errno == errno.EINTR)
6abf9225
AG
1892
1893 def test_send_to_ro_file(self):
4b1c4062 1894 snap = ZFSTest.pool.makeName(b"fs1@snap")
6abf9225
AG
1895 lzc.lzc_snapshot([snap])
1896
85ce3f4f 1897 with tempfile.NamedTemporaryFile(
d8d418ff 1898 suffix='.zstream', delete=False) as output:
6abf9225
AG
1899 # tempfile always opens a temporary file in read-write mode
1900 # regardless of the specified mode, so we have to open it again.
1901 os.chmod(output.name, stat.S_IRUSR)
1902 fd = os.open(output.name, os.O_RDONLY)
1903 with self.assertRaises(lzc_exc.StreamIOError) as ctx:
1904 lzc.lzc_send(snap, None, fd)
1905 os.close(fd)
6ef2151c
AZ
1906 os.unlink(output.name)
1907
9de8c0cd 1908 self.assertEqual(ctx.exception.errno, errno.EBADF)
6abf9225
AG
1909
1910 def test_recv_full(self):
4b1c4062
BB
1911 src = ZFSTest.pool.makeName(b"fs1@snap")
1912 dst = ZFSTest.pool.makeName(b"fs2/received-1@snap")
6abf9225 1913
4b1c4062 1914 with temp_file_in_fs(ZFSTest.pool.makeName(b"fs1")) as name:
6abf9225
AG
1915 lzc.lzc_snapshot([src])
1916
d8d418ff 1917 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
1918 lzc.lzc_send(src, None, stream.fileno())
1919 stream.seek(0)
1920 lzc.lzc_receive(dst, stream.fileno())
1921
1922 name = os.path.basename(name)
1923 with zfs_mount(src) as mnt1, zfs_mount(dst) as mnt2:
1924 self.assertTrue(
85ce3f4f 1925 filecmp.cmp(
1926 os.path.join(mnt1, name), os.path.join(mnt2, name), False))
6abf9225
AG
1927
1928 def test_recv_incremental(self):
4b1c4062
BB
1929 src1 = ZFSTest.pool.makeName(b"fs1@snap1")
1930 src2 = ZFSTest.pool.makeName(b"fs1@snap2")
1931 dst1 = ZFSTest.pool.makeName(b"fs2/received-2@snap1")
1932 dst2 = ZFSTest.pool.makeName(b"fs2/received-2@snap2")
6abf9225
AG
1933
1934 lzc.lzc_snapshot([src1])
4b1c4062 1935 with temp_file_in_fs(ZFSTest.pool.makeName(b"fs1")) as name:
6abf9225
AG
1936 lzc.lzc_snapshot([src2])
1937
d8d418ff 1938 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
1939 lzc.lzc_send(src1, None, stream.fileno())
1940 stream.seek(0)
1941 lzc.lzc_receive(dst1, stream.fileno())
d8d418ff 1942 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
1943 lzc.lzc_send(src2, src1, stream.fileno())
1944 stream.seek(0)
1945 lzc.lzc_receive(dst2, stream.fileno())
1946
1947 name = os.path.basename(name)
1948 with zfs_mount(src2) as mnt1, zfs_mount(dst2) as mnt2:
1949 self.assertTrue(
85ce3f4f 1950 filecmp.cmp(
1951 os.path.join(mnt1, name), os.path.join(mnt2, name), False))
1952
cd6b910b 1953 # This test case fails unless a patch from
85ce3f4f 1954 # https://clusterhq.atlassian.net/browse/ZFS-20
1955 # is applied to libzfs_core, otherwise it succeeds.
1956 @unittest.skip("fails with unpatched libzfs_core")
1957 def test_recv_without_explicit_snap_name(self):
4b1c4062
BB
1958 srcfs = ZFSTest.pool.makeName(b"fs1")
1959 src1 = srcfs + b"@snap1"
1960 src2 = srcfs + b"@snap2"
1961 dstfs = ZFSTest.pool.makeName(b"fs2/received-100")
1962 dst1 = dstfs + b'@snap1'
1963 dst2 = dstfs + b'@snap2'
85ce3f4f 1964
1965 with streams(srcfs, src1, src2) as (_, (full, incr)):
1966 lzc.lzc_receive(dstfs, full.fileno())
1967 lzc.lzc_receive(dstfs, incr.fileno())
1968 self.assertExists(dst1)
1969 self.assertExists(dst2)
6abf9225
AG
1970
1971 def test_recv_clone(self):
4b1c4062
BB
1972 orig_src = ZFSTest.pool.makeName(b"fs2@send-origin")
1973 clone = ZFSTest.pool.makeName(b"fs1/fs/send-clone")
1974 clone_snap = clone + b"@snap"
1975 orig_dst = ZFSTest.pool.makeName(b"fs1/fs/recv-origin@snap")
1976 clone_dst = ZFSTest.pool.makeName(b"fs1/fs/recv-clone@snap")
6abf9225
AG
1977
1978 lzc.lzc_snapshot([orig_src])
d8d418ff 1979 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
1980 lzc.lzc_send(orig_src, None, stream.fileno())
1981 stream.seek(0)
1982 lzc.lzc_receive(orig_dst, stream.fileno())
1983
1984 lzc.lzc_clone(clone, orig_src)
1985 lzc.lzc_snapshot([clone_snap])
d8d418ff 1986 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
1987 lzc.lzc_send(clone_snap, orig_src, stream.fileno())
1988 stream.seek(0)
1989 lzc.lzc_receive(clone_dst, stream.fileno(), origin=orig_dst)
1990
1991 def test_recv_full_already_existing_empty_fs(self):
4b1c4062
BB
1992 src = ZFSTest.pool.makeName(b"fs1@snap")
1993 dstfs = ZFSTest.pool.makeName(b"fs2/received-3")
1994 dst = dstfs + b'@snap'
6abf9225 1995
4b1c4062 1996 with temp_file_in_fs(ZFSTest.pool.makeName(b"fs1")):
6abf9225
AG
1997 lzc.lzc_snapshot([src])
1998 lzc.lzc_create(dstfs)
d8d418ff 1999 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
2000 lzc.lzc_send(src, None, stream.fileno())
2001 stream.seek(0)
85ce3f4f 2002 with self.assertRaises((
2003 lzc_exc.DestinationModified, lzc_exc.DatasetExists)):
6abf9225
AG
2004 lzc.lzc_receive(dst, stream.fileno())
2005
2006 def test_recv_full_into_root_empty_pool(self):
2007 empty_pool = None
2008 try:
4b1c4062 2009 srcfs = ZFSTest.pool.makeName(b"fs1")
6abf9225 2010 empty_pool = _TempPool()
4b1c4062 2011 dst = empty_pool.makeName(b'@snap')
6abf9225 2012
4b1c4062 2013 with streams(srcfs, b"snap", None) as (_, (stream, _)):
85ce3f4f 2014 with self.assertRaises((
2015 lzc_exc.DestinationModified, lzc_exc.DatasetExists)):
6abf9225
AG
2016 lzc.lzc_receive(dst, stream.fileno())
2017 finally:
2018 if empty_pool is not None:
2019 empty_pool.cleanUp()
2020
2021 def test_recv_full_into_ro_pool(self):
4b1c4062
BB
2022 srcfs = ZFSTest.pool.makeName(b"fs1")
2023 dst = ZFSTest.readonly_pool.makeName(b'fs2/received@snap')
6abf9225 2024
4b1c4062 2025 with streams(srcfs, b"snap", None) as (_, (stream, _)):
6abf9225
AG
2026 with self.assertRaises(lzc_exc.ReadOnlyPool):
2027 lzc.lzc_receive(dst, stream.fileno())
2028
2029 def test_recv_full_already_existing_modified_fs(self):
4b1c4062
BB
2030 src = ZFSTest.pool.makeName(b"fs1@snap")
2031 dstfs = ZFSTest.pool.makeName(b"fs2/received-5")
2032 dst = dstfs + b'@snap'
6abf9225 2033
4b1c4062 2034 with temp_file_in_fs(ZFSTest.pool.makeName(b"fs1")):
6abf9225
AG
2035 lzc.lzc_snapshot([src])
2036 lzc.lzc_create(dstfs)
2037 with temp_file_in_fs(dstfs):
d8d418ff 2038 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
2039 lzc.lzc_send(src, None, stream.fileno())
2040 stream.seek(0)
85ce3f4f 2041 with self.assertRaises((
2042 lzc_exc.DestinationModified, lzc_exc.DatasetExists)):
6abf9225
AG
2043 lzc.lzc_receive(dst, stream.fileno())
2044
2045 def test_recv_full_already_existing_with_snapshots(self):
4b1c4062
BB
2046 src = ZFSTest.pool.makeName(b"fs1@snap")
2047 dstfs = ZFSTest.pool.makeName(b"fs2/received-4")
2048 dst = dstfs + b'@snap'
6abf9225 2049
4b1c4062 2050 with temp_file_in_fs(ZFSTest.pool.makeName(b"fs1")):
6abf9225
AG
2051 lzc.lzc_snapshot([src])
2052 lzc.lzc_create(dstfs)
4b1c4062 2053 lzc.lzc_snapshot([dstfs + b"@snap1"])
d8d418ff 2054 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
2055 lzc.lzc_send(src, None, stream.fileno())
2056 stream.seek(0)
85ce3f4f 2057 with self.assertRaises((
2058 lzc_exc.StreamMismatch, lzc_exc.DatasetExists)):
6abf9225
AG
2059 lzc.lzc_receive(dst, stream.fileno())
2060
2061 def test_recv_full_already_existing_snapshot(self):
4b1c4062
BB
2062 src = ZFSTest.pool.makeName(b"fs1@snap")
2063 dstfs = ZFSTest.pool.makeName(b"fs2/received-6")
2064 dst = dstfs + b'@snap'
6abf9225 2065
4b1c4062 2066 with temp_file_in_fs(ZFSTest.pool.makeName(b"fs1")):
6abf9225
AG
2067 lzc.lzc_snapshot([src])
2068 lzc.lzc_create(dstfs)
2069 lzc.lzc_snapshot([dst])
d8d418ff 2070 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
2071 lzc.lzc_send(src, None, stream.fileno())
2072 stream.seek(0)
2073 with self.assertRaises(lzc_exc.DatasetExists):
2074 lzc.lzc_receive(dst, stream.fileno())
2075
2076 def test_recv_full_missing_parent_fs(self):
4b1c4062
BB
2077 src = ZFSTest.pool.makeName(b"fs1@snap")
2078 dst = ZFSTest.pool.makeName(b"fs2/nonexistent/fs@snap")
6abf9225 2079
4b1c4062 2080 with temp_file_in_fs(ZFSTest.pool.makeName(b"fs1")):
6abf9225 2081 lzc.lzc_snapshot([src])
d8d418ff 2082 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
2083 lzc.lzc_send(src, None, stream.fileno())
2084 stream.seek(0)
2085 with self.assertRaises(lzc_exc.DatasetNotFound):
2086 lzc.lzc_receive(dst, stream.fileno())
2087
6abf9225 2088 def test_recv_full_but_specify_origin(self):
4b1c4062
BB
2089 srcfs = ZFSTest.pool.makeName(b"fs1")
2090 src = srcfs + b"@snap"
2091 dstfs = ZFSTest.pool.makeName(b"fs2/received-30")
2092 dst = dstfs + b'@snap'
2093 origin1 = ZFSTest.pool.makeName(b"fs2@snap1")
2094 origin2 = ZFSTest.pool.makeName(b"fs2@snap2")
6abf9225
AG
2095
2096 lzc.lzc_snapshot([origin1])
2097 with streams(srcfs, src, None) as (_, (stream, _)):
85ce3f4f 2098 lzc.lzc_receive(dst, stream.fileno(), origin=origin1)
4b1c4062
BB
2099 origin = ZFSTest.pool.getFilesystem(
2100 b"fs2/received-30").getProperty('origin')
9de8c0cd 2101 self.assertEqual(origin, origin1)
6abf9225 2102 stream.seek(0)
85ce3f4f 2103 # because origin snap does not exist can't receive as a clone of it
2104 with self.assertRaises((
2105 lzc_exc.DatasetNotFound,
2106 lzc_exc.BadStream)):
6abf9225
AG
2107 lzc.lzc_receive(dst, stream.fileno(), origin=origin2)
2108
6abf9225 2109 def test_recv_full_existing_empty_fs_and_origin(self):
4b1c4062
BB
2110 srcfs = ZFSTest.pool.makeName(b"fs1")
2111 src = srcfs + b"@snap"
2112 dstfs = ZFSTest.pool.makeName(b"fs2/received-31")
2113 dst = dstfs + b'@snap'
2114 origin = dstfs + b'@dummy'
6abf9225
AG
2115
2116 lzc.lzc_create(dstfs)
2117 with streams(srcfs, src, None) as (_, (stream, _)):
2118 # because the destination fs already exists and has no snaps
85ce3f4f 2119 with self.assertRaises((
2120 lzc_exc.DestinationModified,
2121 lzc_exc.DatasetExists,
2122 lzc_exc.BadStream)):
6abf9225
AG
2123 lzc.lzc_receive(dst, stream.fileno(), origin=origin)
2124 lzc.lzc_snapshot([origin])
2125 stream.seek(0)
2126 # because the destination fs already exists and has the snap
85ce3f4f 2127 with self.assertRaises((
2128 lzc_exc.StreamMismatch,
2129 lzc_exc.DatasetExists,
2130 lzc_exc.BadStream)):
6abf9225
AG
2131 lzc.lzc_receive(dst, stream.fileno(), origin=origin)
2132
2133 def test_recv_incremental_mounted_fs(self):
4b1c4062
BB
2134 srcfs = ZFSTest.pool.makeName(b"fs1")
2135 src1 = srcfs + b"@snap1"
2136 src2 = srcfs + b"@snap2"
2137 dstfs = ZFSTest.pool.makeName(b"fs2/received-7")
2138 dst1 = dstfs + b'@snap1'
2139 dst2 = dstfs + b'@snap2'
6abf9225
AG
2140
2141 with streams(srcfs, src1, src2) as (_, (full, incr)):
2142 lzc.lzc_receive(dst1, full.fileno())
2143 with zfs_mount(dstfs):
2144 lzc.lzc_receive(dst2, incr.fileno())
2145
2146 def test_recv_incremental_modified_fs(self):
4b1c4062
BB
2147 srcfs = ZFSTest.pool.makeName(b"fs1")
2148 src1 = srcfs + b"@snap1"
2149 src2 = srcfs + b"@snap2"
2150 dstfs = ZFSTest.pool.makeName(b"fs2/received-15")
2151 dst1 = dstfs + b'@snap1'
2152 dst2 = dstfs + b'@snap2'
6abf9225
AG
2153
2154 with streams(srcfs, src1, src2) as (_, (full, incr)):
2155 lzc.lzc_receive(dst1, full.fileno())
2156 with temp_file_in_fs(dstfs):
2157 with self.assertRaises(lzc_exc.DestinationModified):
2158 lzc.lzc_receive(dst2, incr.fileno())
2159
2160 def test_recv_incremental_snapname_used(self):
4b1c4062
BB
2161 srcfs = ZFSTest.pool.makeName(b"fs1")
2162 src1 = srcfs + b"@snap1"
2163 src2 = srcfs + b"@snap2"
2164 dstfs = ZFSTest.pool.makeName(b"fs2/received-8")
2165 dst1 = dstfs + b'@snap1'
2166 dst2 = dstfs + b'@snap2'
6abf9225
AG
2167
2168 with streams(srcfs, src1, src2) as (_, (full, incr)):
2169 lzc.lzc_receive(dst1, full.fileno())
2170 lzc.lzc_snapshot([dst2])
2171 with self.assertRaises(lzc_exc.DatasetExists):
2172 lzc.lzc_receive(dst2, incr.fileno())
2173
2174 def test_recv_incremental_more_recent_snap_with_no_changes(self):
4b1c4062
BB
2175 srcfs = ZFSTest.pool.makeName(b"fs1")
2176 src1 = srcfs + b"@snap1"
2177 src2 = srcfs + b"@snap2"
2178 dstfs = ZFSTest.pool.makeName(b"fs2/received-9")
2179 dst1 = dstfs + b'@snap1'
2180 dst2 = dstfs + b'@snap2'
2181 dst_snap = dstfs + b'@snap'
6abf9225
AG
2182
2183 with streams(srcfs, src1, src2) as (_, (full, incr)):
2184 lzc.lzc_receive(dst1, full.fileno())
2185 lzc.lzc_snapshot([dst_snap])
2186 lzc.lzc_receive(dst2, incr.fileno())
2187
6abf9225 2188 def test_recv_incremental_non_clone_but_set_origin(self):
4b1c4062
BB
2189 srcfs = ZFSTest.pool.makeName(b"fs1")
2190 src1 = srcfs + b"@snap1"
2191 src2 = srcfs + b"@snap2"
2192 dstfs = ZFSTest.pool.makeName(b"fs2/received-20")
2193 dst1 = dstfs + b'@snap1'
2194 dst2 = dstfs + b'@snap2'
2195 dst_snap = dstfs + b'@snap'
6abf9225
AG
2196
2197 with streams(srcfs, src1, src2) as (_, (full, incr)):
2198 lzc.lzc_receive(dst1, full.fileno())
2199 lzc.lzc_snapshot([dst_snap])
cd6b910b 2200 # because cannot receive incremental and set origin on a non-clone
85ce3f4f 2201 with self.assertRaises(lzc_exc.BadStream):
2202 lzc.lzc_receive(dst2, incr.fileno(), origin=dst1)
6abf9225 2203
6abf9225 2204 def test_recv_incremental_non_clone_but_set_random_origin(self):
4b1c4062
BB
2205 srcfs = ZFSTest.pool.makeName(b"fs1")
2206 src1 = srcfs + b"@snap1"
2207 src2 = srcfs + b"@snap2"
2208 dstfs = ZFSTest.pool.makeName(b"fs2/received-21")
2209 dst1 = dstfs + b'@snap1'
2210 dst2 = dstfs + b'@snap2'
2211 dst_snap = dstfs + b'@snap'
6abf9225
AG
2212
2213 with streams(srcfs, src1, src2) as (_, (full, incr)):
2214 lzc.lzc_receive(dst1, full.fileno())
2215 lzc.lzc_snapshot([dst_snap])
85ce3f4f 2216 # because origin snap does not exist can't receive as a clone of it
2217 with self.assertRaises((
2218 lzc_exc.DatasetNotFound,
2219 lzc_exc.BadStream)):
2220 lzc.lzc_receive(
2221 dst2, incr.fileno(),
4b1c4062 2222 origin=ZFSTest.pool.makeName(b"fs2/fs@snap"))
6abf9225
AG
2223
2224 def test_recv_incremental_more_recent_snap(self):
4b1c4062
BB
2225 srcfs = ZFSTest.pool.makeName(b"fs1")
2226 src1 = srcfs + b"@snap1"
2227 src2 = srcfs + b"@snap2"
2228 dstfs = ZFSTest.pool.makeName(b"fs2/received-10")
2229 dst1 = dstfs + b'@snap1'
2230 dst2 = dstfs + b'@snap2'
2231 dst_snap = dstfs + b'@snap'
6abf9225
AG
2232
2233 with streams(srcfs, src1, src2) as (_, (full, incr)):
2234 lzc.lzc_receive(dst1, full.fileno())
2235 with temp_file_in_fs(dstfs):
2236 lzc.lzc_snapshot([dst_snap])
2237 with self.assertRaises(lzc_exc.DestinationModified):
2238 lzc.lzc_receive(dst2, incr.fileno())
2239
2240 def test_recv_incremental_duplicate(self):
4b1c4062
BB
2241 srcfs = ZFSTest.pool.makeName(b"fs1")
2242 src1 = srcfs + b"@snap1"
2243 src2 = srcfs + b"@snap2"
2244 dstfs = ZFSTest.pool.makeName(b"fs2/received-11")
2245 dst1 = dstfs + b'@snap1'
2246 dst2 = dstfs + b'@snap2'
2247 dst_snap = dstfs + b'@snap'
6abf9225
AG
2248
2249 with streams(srcfs, src1, src2) as (_, (full, incr)):
2250 lzc.lzc_receive(dst1, full.fileno())
2251 lzc.lzc_receive(dst2, incr.fileno())
2252 incr.seek(0)
2253 with self.assertRaises(lzc_exc.DestinationModified):
2254 lzc.lzc_receive(dst_snap, incr.fileno())
2255
2256 def test_recv_incremental_unrelated_fs(self):
4b1c4062
BB
2257 srcfs = ZFSTest.pool.makeName(b"fs1")
2258 src1 = srcfs + b"@snap1"
2259 src2 = srcfs + b"@snap2"
2260 dstfs = ZFSTest.pool.makeName(b"fs2/received-12")
2261 dst_snap = dstfs + b'@snap'
6abf9225
AG
2262
2263 with streams(srcfs, src1, src2) as (_, (_, incr)):
2264 lzc.lzc_create(dstfs)
2265 with self.assertRaises(lzc_exc.StreamMismatch):
2266 lzc.lzc_receive(dst_snap, incr.fileno())
2267
2268 def test_recv_incremental_nonexistent_fs(self):
4b1c4062
BB
2269 srcfs = ZFSTest.pool.makeName(b"fs1")
2270 src1 = srcfs + b"@snap1"
2271 src2 = srcfs + b"@snap2"
2272 dstfs = ZFSTest.pool.makeName(b"fs2/received-13")
2273 dst_snap = dstfs + b'@snap'
6abf9225
AG
2274
2275 with streams(srcfs, src1, src2) as (_, (_, incr)):
2276 with self.assertRaises(lzc_exc.DatasetNotFound):
2277 lzc.lzc_receive(dst_snap, incr.fileno())
2278
2279 def test_recv_incremental_same_fs(self):
4b1c4062
BB
2280 srcfs = ZFSTest.pool.makeName(b"fs1")
2281 src1 = srcfs + b"@snap1"
2282 src2 = srcfs + b"@snap2"
2283 src_snap = srcfs + b'@snap'
6abf9225
AG
2284
2285 with streams(srcfs, src1, src2) as (_, (_, incr)):
2286 with self.assertRaises(lzc_exc.DestinationModified):
2287 lzc.lzc_receive(src_snap, incr.fileno())
2288
2289 def test_recv_clone_without_specifying_origin(self):
4b1c4062
BB
2290 orig_src = ZFSTest.pool.makeName(b"fs2@send-origin-2")
2291 clone = ZFSTest.pool.makeName(b"fs1/fs/send-clone-2")
2292 clone_snap = clone + b"@snap"
2293 orig_dst = ZFSTest.pool.makeName(b"fs1/fs/recv-origin-2@snap")
2294 clone_dst = ZFSTest.pool.makeName(b"fs1/fs/recv-clone-2@snap")
6abf9225
AG
2295
2296 lzc.lzc_snapshot([orig_src])
d8d418ff 2297 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
2298 lzc.lzc_send(orig_src, None, stream.fileno())
2299 stream.seek(0)
2300 lzc.lzc_receive(orig_dst, stream.fileno())
2301
2302 lzc.lzc_clone(clone, orig_src)
2303 lzc.lzc_snapshot([clone_snap])
d8d418ff 2304 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
2305 lzc.lzc_send(clone_snap, orig_src, stream.fileno())
2306 stream.seek(0)
2307 with self.assertRaises(lzc_exc.BadStream):
2308 lzc.lzc_receive(clone_dst, stream.fileno())
2309
2310 def test_recv_clone_invalid_origin(self):
4b1c4062
BB
2311 orig_src = ZFSTest.pool.makeName(b"fs2@send-origin-3")
2312 clone = ZFSTest.pool.makeName(b"fs1/fs/send-clone-3")
2313 clone_snap = clone + b"@snap"
2314 orig_dst = ZFSTest.pool.makeName(b"fs1/fs/recv-origin-3@snap")
2315 clone_dst = ZFSTest.pool.makeName(b"fs1/fs/recv-clone-3@snap")
6abf9225
AG
2316
2317 lzc.lzc_snapshot([orig_src])
d8d418ff 2318 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
2319 lzc.lzc_send(orig_src, None, stream.fileno())
2320 stream.seek(0)
2321 lzc.lzc_receive(orig_dst, stream.fileno())
2322
2323 lzc.lzc_clone(clone, orig_src)
2324 lzc.lzc_snapshot([clone_snap])
d8d418ff 2325 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
2326 lzc.lzc_send(clone_snap, orig_src, stream.fileno())
2327 stream.seek(0)
2328 with self.assertRaises(lzc_exc.NameInvalid):
2329 lzc.lzc_receive(
85ce3f4f 2330 clone_dst, stream.fileno(),
4b1c4062 2331 origin=ZFSTest.pool.makeName(b"fs1/fs"))
6abf9225
AG
2332
2333 def test_recv_clone_wrong_origin(self):
4b1c4062
BB
2334 orig_src = ZFSTest.pool.makeName(b"fs2@send-origin-4")
2335 clone = ZFSTest.pool.makeName(b"fs1/fs/send-clone-4")
2336 clone_snap = clone + b"@snap"
2337 orig_dst = ZFSTest.pool.makeName(b"fs1/fs/recv-origin-4@snap")
2338 clone_dst = ZFSTest.pool.makeName(b"fs1/fs/recv-clone-4@snap")
2339 wrong_origin = ZFSTest.pool.makeName(b"fs1/fs@snap")
6abf9225
AG
2340
2341 lzc.lzc_snapshot([orig_src])
d8d418ff 2342 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
2343 lzc.lzc_send(orig_src, None, stream.fileno())
2344 stream.seek(0)
2345 lzc.lzc_receive(orig_dst, stream.fileno())
2346
2347 lzc.lzc_clone(clone, orig_src)
2348 lzc.lzc_snapshot([clone_snap])
2349 lzc.lzc_snapshot([wrong_origin])
d8d418ff 2350 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
2351 lzc.lzc_send(clone_snap, orig_src, stream.fileno())
2352 stream.seek(0)
2353 with self.assertRaises(lzc_exc.StreamMismatch):
2354 lzc.lzc_receive(
2355 clone_dst, stream.fileno(), origin=wrong_origin)
2356
2357 def test_recv_clone_nonexistent_origin(self):
4b1c4062
BB
2358 orig_src = ZFSTest.pool.makeName(b"fs2@send-origin-5")
2359 clone = ZFSTest.pool.makeName(b"fs1/fs/send-clone-5")
2360 clone_snap = clone + b"@snap"
2361 orig_dst = ZFSTest.pool.makeName(b"fs1/fs/recv-origin-5@snap")
2362 clone_dst = ZFSTest.pool.makeName(b"fs1/fs/recv-clone-5@snap")
2363 wrong_origin = ZFSTest.pool.makeName(b"fs1/fs@snap")
6abf9225
AG
2364
2365 lzc.lzc_snapshot([orig_src])
d8d418ff 2366 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
2367 lzc.lzc_send(orig_src, None, stream.fileno())
2368 stream.seek(0)
2369 lzc.lzc_receive(orig_dst, stream.fileno())
2370
2371 lzc.lzc_clone(clone, orig_src)
2372 lzc.lzc_snapshot([clone_snap])
d8d418ff 2373 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
2374 lzc.lzc_send(clone_snap, orig_src, stream.fileno())
2375 stream.seek(0)
2376 with self.assertRaises(lzc_exc.DatasetNotFound):
2377 lzc.lzc_receive(
2378 clone_dst, stream.fileno(), origin=wrong_origin)
2379
2380 def test_force_recv_full_existing_fs(self):
4b1c4062
BB
2381 src = ZFSTest.pool.makeName(b"fs1@snap")
2382 dstfs = ZFSTest.pool.makeName(b"fs2/received-50")
2383 dst = dstfs + b'@snap'
6abf9225 2384
4b1c4062 2385 with temp_file_in_fs(ZFSTest.pool.makeName(b"fs1")):
6abf9225
AG
2386 lzc.lzc_snapshot([src])
2387
2388 lzc.lzc_create(dstfs)
2389 with temp_file_in_fs(dstfs):
2390 pass # enough to taint the fs
2391
d8d418ff 2392 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
2393 lzc.lzc_send(src, None, stream.fileno())
2394 stream.seek(0)
2395 lzc.lzc_receive(dst, stream.fileno(), force=True)
2396
2397 def test_force_recv_full_existing_modified_mounted_fs(self):
4b1c4062
BB
2398 src = ZFSTest.pool.makeName(b"fs1@snap")
2399 dstfs = ZFSTest.pool.makeName(b"fs2/received-53")
2400 dst = dstfs + b'@snap'
6abf9225 2401
4b1c4062 2402 with temp_file_in_fs(ZFSTest.pool.makeName(b"fs1")):
6abf9225
AG
2403 lzc.lzc_snapshot([src])
2404
2405 lzc.lzc_create(dstfs)
2406
d8d418ff 2407 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
2408 lzc.lzc_send(src, None, stream.fileno())
2409 stream.seek(0)
2410 with zfs_mount(dstfs) as mntdir:
2411 f = tempfile.NamedTemporaryFile(dir=mntdir, delete=False)
2412 for i in range(1024):
4b1c4062 2413 f.write(b'x' * 1024)
6abf9225 2414 lzc.lzc_receive(dst, stream.fileno(), force=True)
cd6b910b 2415 # The temporary file disappears and any access, even close(),
6abf9225
AG
2416 # results in EIO.
2417 self.assertFalse(os.path.exists(f.name))
2418 with self.assertRaises(IOError):
2419 f.close()
2420
2421 # This test-case expects the behavior that should be there,
2422 # at the moment it may fail with DatasetExists or StreamMismatch
2423 # depending on the implementation.
2424 def test_force_recv_full_already_existing_with_snapshots(self):
4b1c4062
BB
2425 src = ZFSTest.pool.makeName(b"fs1@snap")
2426 dstfs = ZFSTest.pool.makeName(b"fs2/received-51")
2427 dst = dstfs + b'@snap'
6abf9225 2428
4b1c4062 2429 with temp_file_in_fs(ZFSTest.pool.makeName(b"fs1")):
6abf9225
AG
2430 lzc.lzc_snapshot([src])
2431
2432 lzc.lzc_create(dstfs)
2433 with temp_file_in_fs(dstfs):
2434 pass # enough to taint the fs
4b1c4062 2435 lzc.lzc_snapshot([dstfs + b"@snap1"])
6abf9225 2436
d8d418ff 2437 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
2438 lzc.lzc_send(src, None, stream.fileno())
2439 stream.seek(0)
2440 lzc.lzc_receive(dst, stream.fileno(), force=True)
2441
2442 def test_force_recv_full_already_existing_with_same_snap(self):
4b1c4062
BB
2443 src = ZFSTest.pool.makeName(b"fs1@snap")
2444 dstfs = ZFSTest.pool.makeName(b"fs2/received-52")
2445 dst = dstfs + b'@snap'
6abf9225 2446
4b1c4062 2447 with temp_file_in_fs(ZFSTest.pool.makeName(b"fs1")):
6abf9225
AG
2448 lzc.lzc_snapshot([src])
2449
2450 lzc.lzc_create(dstfs)
2451 with temp_file_in_fs(dstfs):
2452 pass # enough to taint the fs
2453 lzc.lzc_snapshot([dst])
2454
d8d418ff 2455 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
2456 lzc.lzc_send(src, None, stream.fileno())
2457 stream.seek(0)
2458 with self.assertRaises(lzc_exc.DatasetExists):
2459 lzc.lzc_receive(dst, stream.fileno(), force=True)
2460
2461 def test_force_recv_full_missing_parent_fs(self):
4b1c4062
BB
2462 src = ZFSTest.pool.makeName(b"fs1@snap")
2463 dst = ZFSTest.pool.makeName(b"fs2/nonexistent/fs@snap")
6abf9225 2464
4b1c4062 2465 with temp_file_in_fs(ZFSTest.pool.makeName(b"fs1")):
6abf9225 2466 lzc.lzc_snapshot([src])
d8d418ff 2467 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
2468 lzc.lzc_send(src, None, stream.fileno())
2469 stream.seek(0)
2470 with self.assertRaises(lzc_exc.DatasetNotFound):
2471 lzc.lzc_receive(dst, stream.fileno(), force=True)
2472
2473 def test_force_recv_incremental_modified_fs(self):
4b1c4062
BB
2474 srcfs = ZFSTest.pool.makeName(b"fs1")
2475 src1 = srcfs + b"@snap1"
2476 src2 = srcfs + b"@snap2"
2477 dstfs = ZFSTest.pool.makeName(b"fs2/received-60")
2478 dst1 = dstfs + b'@snap1'
2479 dst2 = dstfs + b'@snap2'
6abf9225
AG
2480
2481 with streams(srcfs, src1, src2) as (_, (full, incr)):
2482 lzc.lzc_receive(dst1, full.fileno())
2483 with temp_file_in_fs(dstfs):
2484 pass # enough to taint the fs
2485 lzc.lzc_receive(dst2, incr.fileno(), force=True)
2486
2487 def test_force_recv_incremental_modified_mounted_fs(self):
4b1c4062
BB
2488 srcfs = ZFSTest.pool.makeName(b"fs1")
2489 src1 = srcfs + b"@snap1"
2490 src2 = srcfs + b"@snap2"
2491 dstfs = ZFSTest.pool.makeName(b"fs2/received-64")
2492 dst1 = dstfs + b'@snap1'
2493 dst2 = dstfs + b'@snap2'
6abf9225
AG
2494
2495 with streams(srcfs, src1, src2) as (_, (full, incr)):
2496 lzc.lzc_receive(dst1, full.fileno())
2497 with zfs_mount(dstfs) as mntdir:
2498 f = tempfile.NamedTemporaryFile(dir=mntdir, delete=False)
2499 for i in range(1024):
4b1c4062 2500 f.write(b'x' * 1024)
6abf9225 2501 lzc.lzc_receive(dst2, incr.fileno(), force=True)
cd6b910b 2502 # The temporary file disappears and any access, even close(),
6abf9225
AG
2503 # results in EIO.
2504 self.assertFalse(os.path.exists(f.name))
2505 with self.assertRaises(IOError):
2506 f.close()
2507
2508 def test_force_recv_incremental_modified_fs_plus_later_snap(self):
4b1c4062
BB
2509 srcfs = ZFSTest.pool.makeName(b"fs1")
2510 src1 = srcfs + b"@snap1"
2511 src2 = srcfs + b"@snap2"
2512 dstfs = ZFSTest.pool.makeName(b"fs2/received-61")
2513 dst1 = dstfs + b'@snap1'
2514 dst2 = dstfs + b'@snap2'
2515 dst3 = dstfs + b'@snap'
6abf9225
AG
2516
2517 with streams(srcfs, src1, src2) as (_, (full, incr)):
2518 lzc.lzc_receive(dst1, full.fileno())
2519 with temp_file_in_fs(dstfs):
2520 pass # enough to taint the fs
2521 lzc.lzc_snapshot([dst3])
2522 lzc.lzc_receive(dst2, incr.fileno(), force=True)
2523 self.assertExists(dst1)
2524 self.assertExists(dst2)
2525 self.assertNotExists(dst3)
2526
2527 def test_force_recv_incremental_modified_fs_plus_same_name_snap(self):
4b1c4062
BB
2528 srcfs = ZFSTest.pool.makeName(b"fs1")
2529 src1 = srcfs + b"@snap1"
2530 src2 = srcfs + b"@snap2"
2531 dstfs = ZFSTest.pool.makeName(b"fs2/received-62")
2532 dst1 = dstfs + b'@snap1'
2533 dst2 = dstfs + b'@snap2'
6abf9225
AG
2534
2535 with streams(srcfs, src1, src2) as (_, (full, incr)):
2536 lzc.lzc_receive(dst1, full.fileno())
2537 with temp_file_in_fs(dstfs):
2538 pass # enough to taint the fs
2539 lzc.lzc_snapshot([dst2])
2540 with self.assertRaises(lzc_exc.DatasetExists):
2541 lzc.lzc_receive(dst2, incr.fileno(), force=True)
2542
2543 def test_force_recv_incremental_modified_fs_plus_held_snap(self):
4b1c4062
BB
2544 srcfs = ZFSTest.pool.makeName(b"fs1")
2545 src1 = srcfs + b"@snap1"
2546 src2 = srcfs + b"@snap2"
2547 dstfs = ZFSTest.pool.makeName(b"fs2/received-63")
2548 dst1 = dstfs + b'@snap1'
2549 dst2 = dstfs + b'@snap2'
2550 dst3 = dstfs + b'@snap'
6abf9225
AG
2551
2552 with streams(srcfs, src1, src2) as (_, (full, incr)):
2553 lzc.lzc_receive(dst1, full.fileno())
2554 with temp_file_in_fs(dstfs):
2555 pass # enough to taint the fs
2556 lzc.lzc_snapshot([dst3])
2557 with cleanup_fd() as cfd:
4b1c4062 2558 lzc.lzc_hold({dst3: b'tag'}, cfd)
6abf9225
AG
2559 with self.assertRaises(lzc_exc.DatasetBusy):
2560 lzc.lzc_receive(dst2, incr.fileno(), force=True)
2561 self.assertExists(dst1)
2562 self.assertNotExists(dst2)
2563 self.assertExists(dst3)
2564
2565 def test_force_recv_incremental_modified_fs_plus_cloned_snap(self):
4b1c4062
BB
2566 srcfs = ZFSTest.pool.makeName(b"fs1")
2567 src1 = srcfs + b"@snap1"
2568 src2 = srcfs + b"@snap2"
2569 dstfs = ZFSTest.pool.makeName(b"fs2/received-70")
2570 dst1 = dstfs + b'@snap1'
2571 dst2 = dstfs + b'@snap2'
2572 dst3 = dstfs + b'@snap'
2573 cloned = ZFSTest.pool.makeName(b"fs2/received-cloned-70")
6abf9225
AG
2574
2575 with streams(srcfs, src1, src2) as (_, (full, incr)):
2576 lzc.lzc_receive(dst1, full.fileno())
2577 with temp_file_in_fs(dstfs):
2578 pass # enough to taint the fs
2579 lzc.lzc_snapshot([dst3])
2580 lzc.lzc_clone(cloned, dst3)
2581 with self.assertRaises(lzc_exc.DatasetExists):
2582 lzc.lzc_receive(dst2, incr.fileno(), force=True)
2583 self.assertExists(dst1)
2584 self.assertNotExists(dst2)
2585 self.assertExists(dst3)
2586
6abf9225 2587 def test_recv_incremental_into_cloned_fs(self):
4b1c4062
BB
2588 srcfs = ZFSTest.pool.makeName(b"fs1")
2589 src1 = srcfs + b"@snap1"
2590 src2 = srcfs + b"@snap2"
2591 dstfs = ZFSTest.pool.makeName(b"fs2/received-71")
2592 dst1 = dstfs + b'@snap1'
2593 cloned = ZFSTest.pool.makeName(b"fs2/received-cloned-71")
2594 dst2 = cloned + b'@snap'
6abf9225
AG
2595
2596 with streams(srcfs, src1, src2) as (_, (full, incr)):
2597 lzc.lzc_receive(dst1, full.fileno())
2598 lzc.lzc_clone(cloned, dst1)
2599 # test both graceful and with-force attempts
2600 with self.assertRaises(lzc_exc.StreamMismatch):
2601 lzc.lzc_receive(dst2, incr.fileno())
2602 incr.seek(0)
2603 with self.assertRaises(lzc_exc.StreamMismatch):
2604 lzc.lzc_receive(dst2, incr.fileno(), force=True)
2605 self.assertExists(dst1)
2606 self.assertNotExists(dst2)
2607
85ce3f4f 2608 def test_recv_with_header_full(self):
4b1c4062
BB
2609 src = ZFSTest.pool.makeName(b"fs1@snap")
2610 dst = ZFSTest.pool.makeName(b"fs2/received")
85ce3f4f 2611
4b1c4062 2612 with temp_file_in_fs(ZFSTest.pool.makeName(b"fs1")) as name:
85ce3f4f 2613 lzc.lzc_snapshot([src])
2614
d8d418ff 2615 with tempfile.TemporaryFile(suffix='.zstream') as stream:
85ce3f4f 2616 lzc.lzc_send(src, None, stream.fileno())
2617 stream.seek(0)
2618
2619 (header, c_header) = lzc.receive_header(stream.fileno())
2620 self.assertEqual(src, header['drr_toname'])
4b1c4062 2621 snap = header['drr_toname'].split(b'@', 1)[1]
85ce3f4f 2622 lzc.lzc_receive_with_header(
4b1c4062 2623 dst + b'@' + snap, stream.fileno(), c_header)
85ce3f4f 2624
2625 name = os.path.basename(name)
2626 with zfs_mount(src) as mnt1, zfs_mount(dst) as mnt2:
2627 self.assertTrue(
2628 filecmp.cmp(
2629 os.path.join(mnt1, name), os.path.join(mnt2, name), False))
2630
d8d418ff 2631 def test_recv_fs_below_zvol(self):
2632 send = ZFSTest.pool.makeName(b"fs1@snap")
2633 zvol = ZFSTest.pool.makeName(b"fs1/zvol")
2634 dest = zvol + b"/fs@snap"
2635 props = {b"volsize": 1024 * 1024}
2636
2637 lzc.lzc_snapshot([send])
2638 lzc.lzc_create(zvol, ds_type='zvol', props=props)
2639 with tempfile.TemporaryFile(suffix='.zstream') as stream:
2640 lzc.lzc_send(send, None, stream.fileno())
2641 stream.seek(0)
2642 with self.assertRaises(lzc_exc.WrongParent):
2643 lzc.lzc_receive(dest, stream.fileno())
2644
2645 def test_recv_zvol_over_fs_with_children(self):
2646 parent = ZFSTest.pool.makeName(b"fs1")
2647 child = parent + b"subfs"
2648 zvol = ZFSTest.pool.makeName(b"fs1/zvol")
2649 send = zvol + b"@snap"
2650 props = {b"volsize": 1024 * 1024}
2651
2652 lzc.lzc_create(child)
2653 lzc.lzc_create(zvol, ds_type='zvol', props=props)
2654 lzc.lzc_snapshot([send])
2655 with tempfile.TemporaryFile(suffix='.zstream') as stream:
2656 lzc.lzc_send(send, None, stream.fileno())
2657 stream.seek(0)
2658 with self.assertRaises(lzc_exc.WrongParent):
2659 lzc.lzc_receive(parent + b"@snap", stream.fileno(), force=True)
2660
2661 def test_recv_zvol_overwrite_rootds(self):
2662 zvol = ZFSTest.pool.makeName(b"fs1/zvol")
2663 snap = zvol + b"@snap"
2664 rootds = ZFSTest.pool.getRoot().getName()
2665 props = {b"volsize": 1024 * 1024}
2666
2667 lzc.lzc_create(zvol, ds_type='zvol', props=props)
2668 lzc.lzc_snapshot([snap])
2669 with tempfile.TemporaryFile(suffix='.zstream') as stream:
2670 lzc.lzc_send(snap, None, stream.fileno())
2671 stream.seek(0)
2672 with self.assertRaises(lzc_exc.WrongParent):
2673 lzc.lzc_receive(rootds + b"@snap", stream.fileno(), force=True)
2674
6abf9225 2675 def test_send_full_across_clone_branch_point(self):
4b1c4062 2676 origfs = ZFSTest.pool.makeName(b"fs2")
6abf9225
AG
2677
2678 (_, (fromsnap, origsnap, _)) = make_snapshots(
4b1c4062 2679 origfs, b"snap1", b"send-origin-20", None)
6abf9225 2680
4b1c4062 2681 clonefs = ZFSTest.pool.makeName(b"fs1/fs/send-clone-20")
6abf9225
AG
2682 lzc.lzc_clone(clonefs, origsnap)
2683
4b1c4062 2684 (_, (_, tosnap, _)) = make_snapshots(clonefs, None, b"snap", None)
6abf9225 2685
d8d418ff 2686 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
2687 lzc.lzc_send(tosnap, None, stream.fileno())
2688
2689 def test_send_incr_across_clone_branch_point(self):
4b1c4062 2690 origfs = ZFSTest.pool.makeName(b"fs2")
6abf9225
AG
2691
2692 (_, (fromsnap, origsnap, _)) = make_snapshots(
4b1c4062 2693 origfs, b"snap1", b"send-origin-21", None)
6abf9225 2694
4b1c4062 2695 clonefs = ZFSTest.pool.makeName(b"fs1/fs/send-clone-21")
6abf9225
AG
2696 lzc.lzc_clone(clonefs, origsnap)
2697
4b1c4062 2698 (_, (_, tosnap, _)) = make_snapshots(clonefs, None, b"snap", None)
6abf9225 2699
d8d418ff 2700 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
2701 lzc.lzc_send(tosnap, fromsnap, stream.fileno())
2702
85ce3f4f 2703 def test_send_resume_token_full(self):
4b1c4062
BB
2704 src = ZFSTest.pool.makeName(b"fs1@snap")
2705 dstfs = ZFSTest.pool.getFilesystem(b"fs2/received")
85ce3f4f 2706 dst = dstfs.getSnap()
2707
4b1c4062 2708 with zfs_mount(ZFSTest.pool.makeName(b"fs1")) as mntdir:
85ce3f4f 2709 for i in range(1, 10):
2710 with tempfile.NamedTemporaryFile(dir=mntdir) as f:
4b1c4062 2711 f.write(b'x' * 1024 * i)
85ce3f4f 2712 f.flush()
2713 lzc.lzc_snapshot([src])
2714
d8d418ff 2715 with tempfile.NamedTemporaryFile(suffix='.zstream') as stream:
85ce3f4f 2716 lzc.lzc_send(src, None, stream.fileno())
2717 stream.seek(0)
2718 stream.truncate(1024 * 3)
7145123b 2719 with self.assertRaises(lzc_exc.StreamTruncated):
85ce3f4f 2720 lzc.lzc_receive_resumable(dst, stream.fileno())
2721 # Resume token code from zfs_send_resume_token_to_nvlist()
2722 # XXX: if used more than twice move this code into an external func
2723 # format: <version>-<cksum>-<packed-size>-<compressed-payload>
2724 token = dstfs.getProperty("receive_resume_token")
4b1c4062
BB
2725 self.assertNotEqual(token, b'-')
2726 tokens = token.split(b'-')
85ce3f4f 2727 self.assertEqual(len(tokens), 4)
2728 version = tokens[0]
2729 packed_size = int(tokens[2], 16)
2730 compressed_nvs = tokens[3]
2731 # Validate resume token
4b1c4062
BB
2732 self.assertEqual(version, b'1') # ZFS_SEND_RESUME_TOKEN_VERSION
2733 if sys.version_info < (3, 0):
2734 payload = (
2735 zlib.decompress(str(bytearray.fromhex(compressed_nvs)))
2736 )
2737 else:
2738 payload = (
2739 zlib.decompress(bytearray.fromhex(compressed_nvs.decode()))
2740 )
85ce3f4f 2741 self.assertEqual(len(payload), packed_size)
2742 # Unpack
2743 resume_values = packed_nvlist_out(payload, packed_size)
4b1c4062
BB
2744 resumeobj = resume_values.get(b'object')
2745 resumeoff = resume_values.get(b'offset')
d8d418ff 2746 with tempfile.NamedTemporaryFile(suffix='.zstream') as rstream:
85ce3f4f 2747 lzc.lzc_send_resume(
2748 src, None, rstream.fileno(), None, resumeobj, resumeoff)
2749 rstream.seek(0)
2750 lzc.lzc_receive_resumable(dst, rstream.fileno())
2751
2752 def test_send_resume_token_incremental(self):
4b1c4062
BB
2753 snap1 = ZFSTest.pool.makeName(b"fs1@snap1")
2754 snap2 = ZFSTest.pool.makeName(b"fs1@snap2")
2755 dstfs = ZFSTest.pool.getFilesystem(b"fs2/received")
85ce3f4f 2756 dst1 = dstfs.getSnap()
2757 dst2 = dstfs.getSnap()
2758
2759 lzc.lzc_snapshot([snap1])
d8d418ff 2760 with tempfile.NamedTemporaryFile(suffix='.zstream') as stream:
85ce3f4f 2761 lzc.lzc_send(snap1, None, stream.fileno())
2762 stream.seek(0)
2763 lzc.lzc_receive(dst1, stream.fileno())
2764
4b1c4062 2765 with zfs_mount(ZFSTest.pool.makeName(b"fs1")) as mntdir:
85ce3f4f 2766 for i in range(1, 10):
2767 with tempfile.NamedTemporaryFile(dir=mntdir) as f:
4b1c4062 2768 f.write(b'x' * 1024 * i)
85ce3f4f 2769 f.flush()
2770 lzc.lzc_snapshot([snap2])
2771
d8d418ff 2772 with tempfile.NamedTemporaryFile(suffix='.zstream') as stream:
85ce3f4f 2773 lzc.lzc_send(snap2, snap1, stream.fileno())
2774 stream.seek(0)
2775 stream.truncate(1024 * 3)
7145123b 2776 with self.assertRaises(lzc_exc.StreamTruncated):
85ce3f4f 2777 lzc.lzc_receive_resumable(dst2, stream.fileno())
2778 # Resume token code from zfs_send_resume_token_to_nvlist()
2779 # format: <version>-<cksum>-<packed-size>-<compressed-payload>
2780 token = dstfs.getProperty("receive_resume_token")
2781 self.assertNotEqual(token, '-')
4b1c4062 2782 tokens = token.split(b'-')
85ce3f4f 2783 self.assertEqual(len(tokens), 4)
2784 version = tokens[0]
2785 packed_size = int(tokens[2], 16)
2786 compressed_nvs = tokens[3]
2787 # Validate resume token
4b1c4062
BB
2788 self.assertEqual(version, b'1') # ZFS_SEND_RESUME_TOKEN_VERSION
2789 if sys.version_info < (3, 0):
2790 payload = (
2791 zlib.decompress(str(bytearray.fromhex(compressed_nvs)))
2792 )
2793 else:
2794 payload = (
2795 zlib.decompress(bytearray.fromhex(compressed_nvs.decode()))
2796 )
85ce3f4f 2797 self.assertEqual(len(payload), packed_size)
2798 # Unpack
2799 resume_values = packed_nvlist_out(payload, packed_size)
4b1c4062
BB
2800 resumeobj = resume_values.get(b'object')
2801 resumeoff = resume_values.get(b'offset')
d8d418ff 2802 with tempfile.NamedTemporaryFile(suffix='.zstream') as rstream:
85ce3f4f 2803 lzc.lzc_send_resume(
2804 snap2, snap1, rstream.fileno(), None, resumeobj, resumeoff)
2805 rstream.seek(0)
2806 lzc.lzc_receive_resumable(dst2, rstream.fileno())
2807
6abf9225 2808 def test_recv_full_across_clone_branch_point(self):
4b1c4062 2809 origfs = ZFSTest.pool.makeName(b"fs2")
6abf9225
AG
2810
2811 (_, (fromsnap, origsnap, _)) = make_snapshots(
4b1c4062 2812 origfs, b"snap1", b"send-origin-30", None)
6abf9225 2813
4b1c4062 2814 clonefs = ZFSTest.pool.makeName(b"fs1/fs/send-clone-30")
6abf9225
AG
2815 lzc.lzc_clone(clonefs, origsnap)
2816
4b1c4062 2817 (_, (_, tosnap, _)) = make_snapshots(clonefs, None, b"snap", None)
6abf9225 2818
4b1c4062
BB
2819 recvfs = ZFSTest.pool.makeName(b"fs1/recv-clone-30")
2820 recvsnap = recvfs + b"@snap"
d8d418ff 2821 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
2822 lzc.lzc_send(tosnap, None, stream.fileno())
2823 stream.seek(0)
2824 lzc.lzc_receive(recvsnap, stream.fileno())
2825
85ce3f4f 2826 def test_recv_one(self):
4b1c4062
BB
2827 fromsnap = ZFSTest.pool.makeName(b"fs1@snap1")
2828 tosnap = ZFSTest.pool.makeName(b"recv@snap1")
85ce3f4f 2829
2830 lzc.lzc_snapshot([fromsnap])
d8d418ff 2831 with tempfile.TemporaryFile(suffix='.zstream') as stream:
85ce3f4f 2832 lzc.lzc_send(fromsnap, None, stream.fileno())
2833 stream.seek(0)
2834 (header, c_header) = lzc.receive_header(stream.fileno())
2835 lzc.lzc_receive_one(tosnap, stream.fileno(), c_header)
2836
2837 def test_recv_one_size(self):
4b1c4062
BB
2838 fromsnap = ZFSTest.pool.makeName(b"fs1@snap1")
2839 tosnap = ZFSTest.pool.makeName(b"recv@snap1")
85ce3f4f 2840
2841 lzc.lzc_snapshot([fromsnap])
d8d418ff 2842 with tempfile.TemporaryFile(suffix='.zstream') as stream:
85ce3f4f 2843 lzc.lzc_send(fromsnap, None, stream.fileno())
2844 size = os.fstat(stream.fileno()).st_size
2845 stream.seek(0)
2846 (header, c_header) = lzc.receive_header(stream.fileno())
2847 (read, _) = lzc.lzc_receive_one(tosnap, stream.fileno(), c_header)
2848 self.assertAlmostEqual(read, size, delta=read * 0.05)
2849
2850 def test_recv_one_props(self):
4b1c4062
BB
2851 fromsnap = ZFSTest.pool.makeName(b"fs1@snap1")
2852 fs = ZFSTest.pool.getFilesystem(b"recv")
2853 tosnap = fs.getName() + b"@snap1"
85ce3f4f 2854 props = {
4b1c4062
BB
2855 b"compression": 0x01,
2856 b"ns:prop": b"val"
85ce3f4f 2857 }
2858
2859 lzc.lzc_snapshot([fromsnap])
d8d418ff 2860 with tempfile.TemporaryFile(suffix='.zstream') as stream:
85ce3f4f 2861 lzc.lzc_send(fromsnap, None, stream.fileno())
2862 stream.seek(0)
2863 (header, c_header) = lzc.receive_header(stream.fileno())
2864 lzc.lzc_receive_one(tosnap, stream.fileno(), c_header, props=props)
2865 self.assertExists(tosnap)
4b1c4062
BB
2866 self.assertEqual(fs.getProperty("compression", "received"), b"on")
2867 self.assertEqual(fs.getProperty("ns:prop", "received"), b"val")
85ce3f4f 2868
2869 def test_recv_one_invalid_prop(self):
4b1c4062
BB
2870 fromsnap = ZFSTest.pool.makeName(b"fs1@snap1")
2871 fs = ZFSTest.pool.getFilesystem(b"recv")
2872 tosnap = fs.getName() + b"@snap1"
85ce3f4f 2873 props = {
4b1c4062
BB
2874 b"exec": 0xff,
2875 b"atime": 0x00
85ce3f4f 2876 }
2877
2878 lzc.lzc_snapshot([fromsnap])
d8d418ff 2879 with tempfile.TemporaryFile(suffix='.zstream') as stream:
85ce3f4f 2880 lzc.lzc_send(fromsnap, None, stream.fileno())
2881 stream.seek(0)
2882 (header, c_header) = lzc.receive_header(stream.fileno())
2883 with self.assertRaises(lzc_exc.ReceivePropertyFailure) as ctx:
2884 lzc.lzc_receive_one(
2885 tosnap, stream.fileno(), c_header, props=props)
2886 self.assertExists(tosnap)
4b1c4062 2887 self.assertEqual(fs.getProperty("atime", "received"), b"off")
85ce3f4f 2888 for e in ctx.exception.errors:
2889 self.assertIsInstance(e, lzc_exc.PropertyInvalid)
4b1c4062 2890 self.assertEqual(e.name, b"exec")
85ce3f4f 2891
2892 def test_recv_with_cmdprops(self):
4b1c4062
BB
2893 fromsnap = ZFSTest.pool.makeName(b"fs1@snap1")
2894 fs = ZFSTest.pool.getFilesystem(b"recv")
2895 tosnap = fs.getName() + b"@snap1"
85ce3f4f 2896 props = {}
2897 cmdprops = {
4b1c4062
BB
2898 b"compression": 0x01,
2899 b"ns:prop": b"val"
85ce3f4f 2900 }
2901
2902 lzc.lzc_snapshot([fromsnap])
d8d418ff 2903 with tempfile.TemporaryFile(suffix='.zstream') as stream:
85ce3f4f 2904 lzc.lzc_send(fromsnap, None, stream.fileno())
2905 stream.seek(0)
2906 (header, c_header) = lzc.receive_header(stream.fileno())
2907 lzc.lzc_receive_with_cmdprops(
2908 tosnap, stream.fileno(), c_header, props=props,
2909 cmdprops=cmdprops)
2910 self.assertExists(tosnap)
4b1c4062
BB
2911 self.assertEqual(fs.getProperty("compression"), b"on")
2912 self.assertEqual(fs.getProperty("ns:prop"), b"val")
85ce3f4f 2913
e8cf3a4f
AP
2914 def test_recv_with_heal(self):
2915 snap = ZFSTest.pool.makeName(b"fs1@snap1")
2916 fs = ZFSTest.pool.getFilesystem(b"fs1")
2917 props = {}
2918 cmdprops = {
2919 b"compression": 0x01,
2920 b"ns:prop": b"val"
2921 }
2922
2923 lzc.lzc_snapshot([snap])
2924 with tempfile.TemporaryFile(suffix='.zstream') as stream:
2925 lzc.lzc_send(snap, None, stream.fileno())
2926 stream.seek(0)
2927 (header, c_header) = lzc.receive_header(stream.fileno())
2928 lzc.lzc_receive_with_heal(
2929 snap, stream.fileno(), c_header, props=props,
2930 cmdprops=cmdprops)
2931 self.assertExists(snap)
2932 self.assertEqual(fs.getProperty("compression"), b"on")
2933 self.assertEqual(fs.getProperty("ns:prop"), b"val")
2934
85ce3f4f 2935 def test_recv_with_cmdprops_and_recvprops(self):
4b1c4062
BB
2936 fromsnap = ZFSTest.pool.makeName(b"fs1@snap1")
2937 fs = ZFSTest.pool.getFilesystem(b"recv")
2938 tosnap = fs.getName() + b"@snap1"
85ce3f4f 2939 props = {
4b1c4062
BB
2940 b"atime": 0x01,
2941 b"exec": 0x00,
2942 b"ns:prop": b"abc"
85ce3f4f 2943 }
2944 cmdprops = {
4b1c4062
BB
2945 b"compression": 0x01,
2946 b"ns:prop": b"def",
2947 b"exec": None,
85ce3f4f 2948 }
2949
2950 lzc.lzc_snapshot([fromsnap])
d8d418ff 2951 with tempfile.TemporaryFile(suffix='.zstream') as stream:
85ce3f4f 2952 lzc.lzc_send(fromsnap, None, stream.fileno())
2953 stream.seek(0)
2954 (header, c_header) = lzc.receive_header(stream.fileno())
2955 lzc.lzc_receive_with_cmdprops(
2956 tosnap, stream.fileno(), c_header, props=props,
2957 cmdprops=cmdprops)
2958 self.assertExists(tosnap)
4b1c4062
BB
2959 self.assertEqual(fs.getProperty("atime", True), b"on")
2960 self.assertEqual(fs.getProperty("exec", True), b"off")
2961 self.assertEqual(fs.getProperty("ns:prop", True), b"abc")
2962 self.assertEqual(fs.getProperty("compression"), b"on")
2963 self.assertEqual(fs.getProperty("ns:prop"), b"def")
2964 self.assertEqual(fs.getProperty("exec"), b"on")
85ce3f4f 2965
2966 def test_recv_incr_across_clone_branch_point_no_origin(self):
4b1c4062 2967 origfs = ZFSTest.pool.makeName(b"fs2")
6abf9225
AG
2968
2969 (_, (fromsnap, origsnap, _)) = make_snapshots(
4b1c4062 2970 origfs, b"snap1", b"send-origin-32", None)
6abf9225 2971
4b1c4062 2972 clonefs = ZFSTest.pool.makeName(b"fs1/fs/send-clone-32")
6abf9225
AG
2973 lzc.lzc_clone(clonefs, origsnap)
2974
4b1c4062 2975 (_, (_, tosnap, _)) = make_snapshots(clonefs, None, b"snap", None)
6abf9225 2976
4b1c4062
BB
2977 recvfs = ZFSTest.pool.makeName(b"fs1/recv-clone-32")
2978 recvsnap1 = recvfs + b"@snap1"
2979 recvsnap2 = recvfs + b"@snap2"
d8d418ff 2980 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
2981 lzc.lzc_send(fromsnap, None, stream.fileno())
2982 stream.seek(0)
2983 lzc.lzc_receive(recvsnap1, stream.fileno())
d8d418ff 2984 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
2985 lzc.lzc_send(tosnap, fromsnap, stream.fileno())
2986 stream.seek(0)
2987 with self.assertRaises(lzc_exc.BadStream):
2988 lzc.lzc_receive(recvsnap2, stream.fileno())
2989
2990 def test_recv_incr_across_clone_branch_point(self):
4b1c4062 2991 origfs = ZFSTest.pool.makeName(b"fs2")
6abf9225
AG
2992
2993 (_, (fromsnap, origsnap, _)) = make_snapshots(
4b1c4062 2994 origfs, b"snap1", b"send-origin-31", None)
6abf9225 2995
4b1c4062 2996 clonefs = ZFSTest.pool.makeName(b"fs1/fs/send-clone-31")
6abf9225
AG
2997 lzc.lzc_clone(clonefs, origsnap)
2998
4b1c4062 2999 (_, (_, tosnap, _)) = make_snapshots(clonefs, None, b"snap", None)
6abf9225 3000
4b1c4062
BB
3001 recvfs = ZFSTest.pool.makeName(b"fs1/recv-clone-31")
3002 recvsnap1 = recvfs + b"@snap1"
3003 recvsnap2 = recvfs + b"@snap2"
d8d418ff 3004 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
3005 lzc.lzc_send(fromsnap, None, stream.fileno())
3006 stream.seek(0)
3007 lzc.lzc_receive(recvsnap1, stream.fileno())
d8d418ff 3008 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
3009 lzc.lzc_send(tosnap, fromsnap, stream.fileno())
3010 stream.seek(0)
3011 with self.assertRaises(lzc_exc.BadStream):
3012 lzc.lzc_receive(recvsnap2, stream.fileno(), origin=recvsnap1)
3013
85ce3f4f 3014 def test_recv_incr_across_clone_branch_point_new_fs(self):
4b1c4062 3015 origfs = ZFSTest.pool.makeName(b"fs2")
6abf9225
AG
3016
3017 (_, (fromsnap, origsnap, _)) = make_snapshots(
4b1c4062 3018 origfs, b"snap1", b"send-origin-33", None)
6abf9225 3019
4b1c4062 3020 clonefs = ZFSTest.pool.makeName(b"fs1/fs/send-clone-33")
6abf9225
AG
3021 lzc.lzc_clone(clonefs, origsnap)
3022
4b1c4062 3023 (_, (_, tosnap, _)) = make_snapshots(clonefs, None, b"snap", None)
6abf9225 3024
4b1c4062
BB
3025 recvfs1 = ZFSTest.pool.makeName(b"fs1/recv-clone-33")
3026 recvsnap1 = recvfs1 + b"@snap"
3027 recvfs2 = ZFSTest.pool.makeName(b"fs1/recv-clone-33_2")
3028 recvsnap2 = recvfs2 + b"@snap"
d8d418ff 3029 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
3030 lzc.lzc_send(fromsnap, None, stream.fileno())
3031 stream.seek(0)
3032 lzc.lzc_receive(recvsnap1, stream.fileno())
d8d418ff 3033 with tempfile.TemporaryFile(suffix='.zstream') as stream:
6abf9225
AG
3034 lzc.lzc_send(tosnap, fromsnap, stream.fileno())
3035 stream.seek(0)
3036 lzc.lzc_receive(recvsnap2, stream.fileno(), origin=recvsnap1)
3037
3038 def test_recv_bad_stream(self):
4b1c4062
BB
3039 dstfs = ZFSTest.pool.makeName(b"fs2/received")
3040 dst_snap = dstfs + b'@snap'
6abf9225
AG
3041
3042 with dev_zero() as fd:
3043 with self.assertRaises(lzc_exc.BadStream):
3044 lzc.lzc_receive(dst_snap, fd)
3045
3046 @needs_support(lzc.lzc_promote)
3047 def test_promote(self):
4b1c4062
BB
3048 origfs = ZFSTest.pool.makeName(b"fs2")
3049 snap = b"@promote-snap-1"
6abf9225
AG
3050 origsnap = origfs + snap
3051 lzc.lzc_snap([origsnap])
3052
4b1c4062 3053 clonefs = ZFSTest.pool.makeName(b"fs1/fs/promote-clone-1")
6abf9225
AG
3054 lzc.lzc_clone(clonefs, origsnap)
3055
3056 lzc.lzc_promote(clonefs)
3057 # the snapshot now should belong to the promoted fs
3058 self.assertExists(clonefs + snap)
3059
3060 @needs_support(lzc.lzc_promote)
3061 def test_promote_too_long_snapname(self):
3062 # origfs name must be shorter than clonefs name
4b1c4062
BB
3063 origfs = ZFSTest.pool.makeName(b"fs2")
3064 clonefs = ZFSTest.pool.makeName(b"fs1/fs/promote-clone-2")
3065 snapprefix = b"@promote-snap-2-"
6abf9225 3066 pad_len = 1 + lzc.MAXNAMELEN - len(clonefs) - len(snapprefix)
4b1c4062 3067 snap = snapprefix + b'x' * pad_len
6abf9225
AG
3068 origsnap = origfs + snap
3069
3070 lzc.lzc_snap([origsnap])
3071 lzc.lzc_clone(clonefs, origsnap)
3072
3073 # This may fail on older buggy systems.
3074 # See: https://www.illumos.org/issues/5909
3075 with self.assertRaises(lzc_exc.NameTooLong):
3076 lzc.lzc_promote(clonefs)
3077
3078 @needs_support(lzc.lzc_promote)
3079 def test_promote_not_cloned(self):
4b1c4062 3080 fs = ZFSTest.pool.makeName(b"fs2")
6abf9225
AG
3081 with self.assertRaises(lzc_exc.NotClone):
3082 lzc.lzc_promote(fs)
3083
3084 @unittest.skipIf(*illumos_bug_6379())
3085 def test_hold_bad_fd(self):
3086 snap = ZFSTest.pool.getRoot().getSnap()
3087 lzc.lzc_snapshot([snap])
3088
3089 with tempfile.TemporaryFile() as tmp:
3090 bad_fd = tmp.fileno()
3091
3092 with self.assertRaises(lzc_exc.BadHoldCleanupFD):
4b1c4062 3093 lzc.lzc_hold({snap: b'tag'}, bad_fd)
6abf9225
AG
3094
3095 @unittest.skipIf(*illumos_bug_6379())
3096 def test_hold_bad_fd_2(self):
3097 snap = ZFSTest.pool.getRoot().getSnap()
3098 lzc.lzc_snapshot([snap])
3099
3100 with self.assertRaises(lzc_exc.BadHoldCleanupFD):
4b1c4062 3101 lzc.lzc_hold({snap: b'tag'}, -2)
6abf9225
AG
3102
3103 @unittest.skipIf(*illumos_bug_6379())
3104 def test_hold_bad_fd_3(self):
3105 snap = ZFSTest.pool.getRoot().getSnap()
3106 lzc.lzc_snapshot([snap])
3107
3108 (soft, hard) = resource.getrlimit(resource.RLIMIT_NOFILE)
3109 bad_fd = hard + 1
3110 with self.assertRaises(lzc_exc.BadHoldCleanupFD):
4b1c4062 3111 lzc.lzc_hold({snap: b'tag'}, bad_fd)
6abf9225
AG
3112
3113 @unittest.skipIf(*illumos_bug_6379())
3114 def test_hold_wrong_fd(self):
3115 snap = ZFSTest.pool.getRoot().getSnap()
3116 lzc.lzc_snapshot([snap])
3117
3118 with tempfile.TemporaryFile() as tmp:
3119 fd = tmp.fileno()
3120 with self.assertRaises(lzc_exc.BadHoldCleanupFD):
4b1c4062 3121 lzc.lzc_hold({snap: b'tag'}, fd)
6abf9225
AG
3122
3123 def test_hold_fd(self):
3124 snap = ZFSTest.pool.getRoot().getSnap()
3125 lzc.lzc_snapshot([snap])
3126
3127 with cleanup_fd() as fd:
4b1c4062 3128 lzc.lzc_hold({snap: b'tag'}, fd)
6abf9225
AG
3129
3130 def test_hold_empty(self):
3131 with cleanup_fd() as fd:
3132 lzc.lzc_hold({}, fd)
3133
3134 def test_hold_empty_2(self):
3135 lzc.lzc_hold({})
3136
3137 def test_hold_vs_snap_destroy(self):
3138 snap = ZFSTest.pool.getRoot().getSnap()
3139 lzc.lzc_snapshot([snap])
3140
3141 with cleanup_fd() as fd:
4b1c4062 3142 lzc.lzc_hold({snap: b'tag'}, fd)
6abf9225
AG
3143
3144 with self.assertRaises(lzc_exc.SnapshotDestructionFailure) as ctx:
3145 lzc.lzc_destroy_snaps([snap], defer=False)
3146 for e in ctx.exception.errors:
3147 self.assertIsInstance(e, lzc_exc.SnapshotIsHeld)
3148
3149 lzc.lzc_destroy_snaps([snap], defer=True)
3150 self.assertExists(snap)
3151
3152 # after automatic hold cleanup and deferred destruction
3153 self.assertNotExists(snap)
3154
3155 def test_hold_many_tags(self):
3156 snap = ZFSTest.pool.getRoot().getSnap()
3157 lzc.lzc_snapshot([snap])
3158
3159 with cleanup_fd() as fd:
4b1c4062
BB
3160 lzc.lzc_hold({snap: b'tag1'}, fd)
3161 lzc.lzc_hold({snap: b'tag2'}, fd)
6abf9225
AG
3162
3163 def test_hold_many_snaps(self):
3164 snap1 = ZFSTest.pool.getRoot().getSnap()
3165 snap2 = ZFSTest.pool.getRoot().getSnap()
3166 lzc.lzc_snapshot([snap1])
3167 lzc.lzc_snapshot([snap2])
3168
3169 with cleanup_fd() as fd:
4b1c4062 3170 lzc.lzc_hold({snap1: b'tag', snap2: b'tag'}, fd)
6abf9225
AG
3171
3172 def test_hold_many_with_one_missing(self):
3173 snap1 = ZFSTest.pool.getRoot().getSnap()
3174 snap2 = ZFSTest.pool.getRoot().getSnap()
3175 lzc.lzc_snapshot([snap1])
3176
3177 with cleanup_fd() as fd:
4b1c4062 3178 missing = lzc.lzc_hold({snap1: b'tag', snap2: b'tag'}, fd)
6abf9225
AG
3179 self.assertEqual(len(missing), 1)
3180 self.assertEqual(missing[0], snap2)
3181
3182 def test_hold_many_with_all_missing(self):
3183 snap1 = ZFSTest.pool.getRoot().getSnap()
3184 snap2 = ZFSTest.pool.getRoot().getSnap()
3185
3186 with cleanup_fd() as fd:
4b1c4062 3187 missing = lzc.lzc_hold({snap1: b'tag', snap2: b'tag'}, fd)
6abf9225
AG
3188 self.assertEqual(len(missing), 2)
3189 self.assertEqual(sorted(missing), sorted([snap1, snap2]))
3190
6abf9225
AG
3191 def test_hold_missing_fs(self):
3192 # XXX skip pre-created filesystems
3193 ZFSTest.pool.getRoot().getFilesystem()
3194 ZFSTest.pool.getRoot().getFilesystem()
3195 ZFSTest.pool.getRoot().getFilesystem()
3196 ZFSTest.pool.getRoot().getFilesystem()
3197 ZFSTest.pool.getRoot().getFilesystem()
3198 snap = ZFSTest.pool.getRoot().getFilesystem().getSnap()
3199
4b1c4062 3200 snaps = lzc.lzc_hold({snap: b'tag'})
9de8c0cd 3201 self.assertEqual([snap], snaps)
6abf9225 3202
6abf9225
AG
3203 def test_hold_missing_fs_auto_cleanup(self):
3204 # XXX skip pre-created filesystems
3205 ZFSTest.pool.getRoot().getFilesystem()
3206 ZFSTest.pool.getRoot().getFilesystem()
3207 ZFSTest.pool.getRoot().getFilesystem()
3208 ZFSTest.pool.getRoot().getFilesystem()
3209 ZFSTest.pool.getRoot().getFilesystem()
3210 snap = ZFSTest.pool.getRoot().getFilesystem().getSnap()
3211
3212 with cleanup_fd() as fd:
4b1c4062 3213 snaps = lzc.lzc_hold({snap: b'tag'}, fd)
9de8c0cd 3214 self.assertEqual([snap], snaps)
6abf9225
AG
3215
3216 def test_hold_duplicate(self):
3217 snap = ZFSTest.pool.getRoot().getSnap()
3218 lzc.lzc_snapshot([snap])
3219
3220 with cleanup_fd() as fd:
4b1c4062 3221 lzc.lzc_hold({snap: b'tag'}, fd)
6abf9225 3222 with self.assertRaises(lzc_exc.HoldFailure) as ctx:
4b1c4062 3223 lzc.lzc_hold({snap: b'tag'}, fd)
6abf9225
AG
3224 for e in ctx.exception.errors:
3225 self.assertIsInstance(e, lzc_exc.HoldExists)
3226
3227 def test_hold_across_pools(self):
3228 snap1 = ZFSTest.pool.getRoot().getSnap()
3229 snap2 = ZFSTest.misc_pool.getRoot().getSnap()
3230 lzc.lzc_snapshot([snap1])
3231 lzc.lzc_snapshot([snap2])
3232
3233 with cleanup_fd() as fd:
3234 with self.assertRaises(lzc_exc.HoldFailure) as ctx:
4b1c4062 3235 lzc.lzc_hold({snap1: b'tag', snap2: b'tag'}, fd)
6abf9225
AG
3236 for e in ctx.exception.errors:
3237 self.assertIsInstance(e, lzc_exc.PoolsDiffer)
3238
3239 def test_hold_too_long_tag(self):
3240 snap = ZFSTest.pool.getRoot().getSnap()
4b1c4062 3241 tag = b't' * 256
6abf9225
AG
3242 lzc.lzc_snapshot([snap])
3243
3244 with cleanup_fd() as fd:
3245 with self.assertRaises(lzc_exc.HoldFailure) as ctx:
3246 lzc.lzc_hold({snap: tag}, fd)
3247 for e in ctx.exception.errors:
3248 self.assertIsInstance(e, lzc_exc.NameTooLong)
9de8c0cd 3249 self.assertEqual(e.name, tag)
6abf9225
AG
3250
3251 # Apparently the full snapshot name is not checked for length
3252 # and this snapshot is treated as simply missing.
3253 @unittest.expectedFailure
3254 def test_hold_too_long_snap_name(self):
3255 snap = ZFSTest.pool.getRoot().getTooLongSnap(False)
3256 with cleanup_fd() as fd:
3257 with self.assertRaises(lzc_exc.HoldFailure) as ctx:
4b1c4062 3258 lzc.lzc_hold({snap: b'tag'}, fd)
6abf9225
AG
3259 for e in ctx.exception.errors:
3260 self.assertIsInstance(e, lzc_exc.NameTooLong)
9de8c0cd 3261 self.assertEqual(e.name, snap)
6abf9225
AG
3262
3263 def test_hold_too_long_snap_name_2(self):
3264 snap = ZFSTest.pool.getRoot().getTooLongSnap(True)
3265 with cleanup_fd() as fd:
3266 with self.assertRaises(lzc_exc.HoldFailure) as ctx:
4b1c4062 3267 lzc.lzc_hold({snap: b'tag'}, fd)
6abf9225
AG
3268 for e in ctx.exception.errors:
3269 self.assertIsInstance(e, lzc_exc.NameTooLong)
9de8c0cd 3270 self.assertEqual(e.name, snap)
6abf9225
AG
3271
3272 def test_hold_invalid_snap_name(self):
4b1c4062 3273 snap = ZFSTest.pool.getRoot().getSnap() + b'@bad'
6abf9225
AG
3274 with cleanup_fd() as fd:
3275 with self.assertRaises(lzc_exc.HoldFailure) as ctx:
4b1c4062 3276 lzc.lzc_hold({snap: b'tag'}, fd)
6abf9225
AG
3277 for e in ctx.exception.errors:
3278 self.assertIsInstance(e, lzc_exc.NameInvalid)
9de8c0cd 3279 self.assertEqual(e.name, snap)
6abf9225
AG
3280
3281 def test_hold_invalid_snap_name_2(self):
3282 snap = ZFSTest.pool.getRoot().getFilesystem().getName()
3283 with cleanup_fd() as fd:
3284 with self.assertRaises(lzc_exc.HoldFailure) as ctx:
4b1c4062 3285 lzc.lzc_hold({snap: b'tag'}, fd)
6abf9225
AG
3286 for e in ctx.exception.errors:
3287 self.assertIsInstance(e, lzc_exc.NameInvalid)
9de8c0cd 3288 self.assertEqual(e.name, snap)
6abf9225
AG
3289
3290 def test_get_holds(self):
3291 snap = ZFSTest.pool.getRoot().getSnap()
3292 lzc.lzc_snapshot([snap])
3293
3294 with cleanup_fd() as fd:
4b1c4062
BB
3295 lzc.lzc_hold({snap: b'tag1'}, fd)
3296 lzc.lzc_hold({snap: b'tag2'}, fd)
6abf9225
AG
3297
3298 holds = lzc.lzc_get_holds(snap)
9de8c0cd 3299 self.assertEqual(len(holds), 2)
4b1c4062
BB
3300 self.assertIn(b'tag1', holds)
3301 self.assertIn(b'tag2', holds)
3302 self.assertIsInstance(holds[b'tag1'], (int, int))
6abf9225
AG
3303
3304 def test_get_holds_after_auto_cleanup(self):
3305 snap = ZFSTest.pool.getRoot().getSnap()
3306 lzc.lzc_snapshot([snap])
3307
3308 with cleanup_fd() as fd:
4b1c4062
BB
3309 lzc.lzc_hold({snap: b'tag1'}, fd)
3310 lzc.lzc_hold({snap: b'tag2'}, fd)
6abf9225
AG
3311
3312 holds = lzc.lzc_get_holds(snap)
9de8c0cd 3313 self.assertEqual(len(holds), 0)
6abf9225
AG
3314 self.assertIsInstance(holds, dict)
3315
3316 def test_get_holds_nonexistent_snap(self):
3317 snap = ZFSTest.pool.getRoot().getSnap()
3318 with self.assertRaises(lzc_exc.SnapshotNotFound):
3319 lzc.lzc_get_holds(snap)
3320
3321 def test_get_holds_too_long_snap_name(self):
3322 snap = ZFSTest.pool.getRoot().getTooLongSnap(False)
3323 with self.assertRaises(lzc_exc.NameTooLong):
3324 lzc.lzc_get_holds(snap)
3325
3326 def test_get_holds_too_long_snap_name_2(self):
3327 snap = ZFSTest.pool.getRoot().getTooLongSnap(True)
3328 with self.assertRaises(lzc_exc.NameTooLong):
3329 lzc.lzc_get_holds(snap)
3330
3331 def test_get_holds_invalid_snap_name(self):
4b1c4062 3332 snap = ZFSTest.pool.getRoot().getSnap() + b'@bad'
6abf9225
AG
3333 with self.assertRaises(lzc_exc.NameInvalid):
3334 lzc.lzc_get_holds(snap)
3335
3336 # A filesystem-like snapshot name is not recognized as
3337 # an invalid name.
3338 @unittest.expectedFailure
3339 def test_get_holds_invalid_snap_name_2(self):
3340 snap = ZFSTest.pool.getRoot().getFilesystem().getName()
3341 with self.assertRaises(lzc_exc.NameInvalid):
3342 lzc.lzc_get_holds(snap)
3343
3344 def test_release_hold(self):
3345 snap = ZFSTest.pool.getRoot().getSnap()
3346 lzc.lzc_snapshot([snap])
3347
4b1c4062
BB
3348 lzc.lzc_hold({snap: b'tag'})
3349 ret = lzc.lzc_release({snap: [b'tag']})
9de8c0cd 3350 self.assertEqual(len(ret), 0)
6abf9225
AG
3351
3352 def test_release_hold_empty(self):
3353 ret = lzc.lzc_release({})
9de8c0cd 3354 self.assertEqual(len(ret), 0)
6abf9225
AG
3355
3356 def test_release_hold_complex(self):
3357 snap1 = ZFSTest.pool.getRoot().getSnap()
3358 snap2 = ZFSTest.pool.getRoot().getSnap()
3359 snap3 = ZFSTest.pool.getRoot().getFilesystem().getSnap()
3360 lzc.lzc_snapshot([snap1])
3361 lzc.lzc_snapshot([snap2, snap3])
3362
4b1c4062
BB
3363 lzc.lzc_hold({snap1: b'tag1'})
3364 lzc.lzc_hold({snap1: b'tag2'})
3365 lzc.lzc_hold({snap2: b'tag'})
3366 lzc.lzc_hold({snap3: b'tag1'})
3367 lzc.lzc_hold({snap3: b'tag2'})
6abf9225
AG
3368
3369 holds = lzc.lzc_get_holds(snap1)
9de8c0cd 3370 self.assertEqual(len(holds), 2)
6abf9225 3371 holds = lzc.lzc_get_holds(snap2)
9de8c0cd 3372 self.assertEqual(len(holds), 1)
6abf9225 3373 holds = lzc.lzc_get_holds(snap3)
9de8c0cd 3374 self.assertEqual(len(holds), 2)
6abf9225
AG
3375
3376 release = {
4b1c4062
BB
3377 snap1: [b'tag1', b'tag2'],
3378 snap2: [b'tag'],
3379 snap3: [b'tag2'],
6abf9225
AG
3380 }
3381 ret = lzc.lzc_release(release)
9de8c0cd 3382 self.assertEqual(len(ret), 0)
6abf9225
AG
3383
3384 holds = lzc.lzc_get_holds(snap1)
9de8c0cd 3385 self.assertEqual(len(holds), 0)
6abf9225 3386 holds = lzc.lzc_get_holds(snap2)
9de8c0cd 3387 self.assertEqual(len(holds), 0)
6abf9225 3388 holds = lzc.lzc_get_holds(snap3)
9de8c0cd 3389 self.assertEqual(len(holds), 1)
6abf9225 3390
4b1c4062 3391 ret = lzc.lzc_release({snap3: [b'tag1']})
9de8c0cd 3392 self.assertEqual(len(ret), 0)
6abf9225 3393 holds = lzc.lzc_get_holds(snap3)
9de8c0cd 3394 self.assertEqual(len(holds), 0)
6abf9225
AG
3395
3396 def test_release_hold_before_auto_cleanup(self):
3397 snap = ZFSTest.pool.getRoot().getSnap()
3398 lzc.lzc_snapshot([snap])
3399
3400 with cleanup_fd() as fd:
4b1c4062
BB
3401 lzc.lzc_hold({snap: b'tag'}, fd)
3402 ret = lzc.lzc_release({snap: [b'tag']})
9de8c0cd 3403 self.assertEqual(len(ret), 0)
6abf9225
AG
3404
3405 def test_release_hold_and_snap_destruction(self):
3406 snap = ZFSTest.pool.getRoot().getSnap()
3407 lzc.lzc_snapshot([snap])
3408
3409 with cleanup_fd() as fd:
4b1c4062
BB
3410 lzc.lzc_hold({snap: b'tag1'}, fd)
3411 lzc.lzc_hold({snap: b'tag2'}, fd)
6abf9225
AG
3412
3413 lzc.lzc_destroy_snaps([snap], defer=True)
3414 self.assertExists(snap)
3415
4b1c4062 3416 lzc.lzc_release({snap: [b'tag1']})
6abf9225
AG
3417 self.assertExists(snap)
3418
4b1c4062 3419 lzc.lzc_release({snap: [b'tag2']})
6abf9225
AG
3420 self.assertNotExists(snap)
3421
3422 def test_release_hold_and_multiple_snap_destruction(self):
3423 snap = ZFSTest.pool.getRoot().getSnap()
3424 lzc.lzc_snapshot([snap])
3425
3426 with cleanup_fd() as fd:
4b1c4062 3427 lzc.lzc_hold({snap: b'tag'}, fd)
6abf9225
AG
3428
3429 lzc.lzc_destroy_snaps([snap], defer=True)
3430 self.assertExists(snap)
3431
3432 lzc.lzc_destroy_snaps([snap], defer=True)
3433 self.assertExists(snap)
3434
4b1c4062 3435 lzc.lzc_release({snap: [b'tag']})
6abf9225
AG
3436 self.assertNotExists(snap)
3437
3438 def test_release_hold_missing_tag(self):
3439 snap = ZFSTest.pool.getRoot().getSnap()
3440 lzc.lzc_snapshot([snap])
3441
4b1c4062 3442 ret = lzc.lzc_release({snap: [b'tag']})
9de8c0cd 3443 self.assertEqual(len(ret), 1)
4b1c4062 3444 self.assertEqual(ret[0], snap + b'#tag')
6abf9225
AG
3445
3446 def test_release_hold_missing_snap(self):
3447 snap = ZFSTest.pool.getRoot().getSnap()
3448
4b1c4062 3449 ret = lzc.lzc_release({snap: [b'tag']})
9de8c0cd
AR
3450 self.assertEqual(len(ret), 1)
3451 self.assertEqual(ret[0], snap)
6abf9225
AG
3452
3453 def test_release_hold_missing_snap_2(self):
3454 snap = ZFSTest.pool.getRoot().getSnap()
3455
4b1c4062 3456 ret = lzc.lzc_release({snap: [b'tag', b'another']})
9de8c0cd
AR
3457 self.assertEqual(len(ret), 1)
3458 self.assertEqual(ret[0], snap)
6abf9225
AG
3459
3460 def test_release_hold_across_pools(self):
3461 snap1 = ZFSTest.pool.getRoot().getSnap()
3462 snap2 = ZFSTest.misc_pool.getRoot().getSnap()
3463 lzc.lzc_snapshot([snap1])
3464 lzc.lzc_snapshot([snap2])
3465
3466 with cleanup_fd() as fd:
4b1c4062
BB
3467 lzc.lzc_hold({snap1: b'tag'}, fd)
3468 lzc.lzc_hold({snap2: b'tag'}, fd)
6abf9225 3469 with self.assertRaises(lzc_exc.HoldReleaseFailure) as ctx:
4b1c4062 3470 lzc.lzc_release({snap1: [b'tag'], snap2: [b'tag']})
6abf9225
AG
3471 for e in ctx.exception.errors:
3472 self.assertIsInstance(e, lzc_exc.PoolsDiffer)
3473
3474 # Apparently the tag name is not verified,
3475 # only its existence is checked.
3476 @unittest.expectedFailure
3477 def test_release_hold_too_long_tag(self):
3478 snap = ZFSTest.pool.getRoot().getSnap()
4b1c4062 3479 tag = b't' * 256
6abf9225
AG
3480 lzc.lzc_snapshot([snap])
3481
3482 with self.assertRaises(lzc_exc.HoldReleaseFailure):
3483 lzc.lzc_release({snap: [tag]})
3484
3485 # Apparently the full snapshot name is not checked for length
3486 # and this snapshot is treated as simply missing.
3487 @unittest.expectedFailure
3488 def test_release_hold_too_long_snap_name(self):
3489 snap = ZFSTest.pool.getRoot().getTooLongSnap(False)
3490
3491 with self.assertRaises(lzc_exc.HoldReleaseFailure):
4b1c4062 3492 lzc.lzc_release({snap: [b'tag']})
6abf9225
AG
3493
3494 def test_release_hold_too_long_snap_name_2(self):
3495 snap = ZFSTest.pool.getRoot().getTooLongSnap(True)
3496 with self.assertRaises(lzc_exc.HoldReleaseFailure) as ctx:
4b1c4062 3497 lzc.lzc_release({snap: [b'tag']})
6abf9225
AG
3498 for e in ctx.exception.errors:
3499 self.assertIsInstance(e, lzc_exc.NameTooLong)
9de8c0cd 3500 self.assertEqual(e.name, snap)
6abf9225
AG
3501
3502 def test_release_hold_invalid_snap_name(self):
4b1c4062 3503 snap = ZFSTest.pool.getRoot().getSnap() + b'@bad'
6abf9225 3504 with self.assertRaises(lzc_exc.HoldReleaseFailure) as ctx:
4b1c4062 3505 lzc.lzc_release({snap: [b'tag']})
6abf9225
AG
3506 for e in ctx.exception.errors:
3507 self.assertIsInstance(e, lzc_exc.NameInvalid)
9de8c0cd 3508 self.assertEqual(e.name, snap)
6abf9225
AG
3509
3510 def test_release_hold_invalid_snap_name_2(self):
3511 snap = ZFSTest.pool.getRoot().getFilesystem().getName()
3512 with self.assertRaises(lzc_exc.HoldReleaseFailure) as ctx:
4b1c4062 3513 lzc.lzc_release({snap: [b'tag']})
6abf9225
AG
3514 for e in ctx.exception.errors:
3515 self.assertIsInstance(e, lzc_exc.NameInvalid)
9de8c0cd 3516 self.assertEqual(e.name, snap)
6abf9225 3517
85ce3f4f 3518 def test_sync_missing_pool(self):
4b1c4062 3519 pool = b"nonexistent"
85ce3f4f 3520 with self.assertRaises(lzc_exc.PoolNotFound):
3521 lzc.lzc_sync(pool)
3522
3523 def test_sync_pool_forced(self):
3524 pool = ZFSTest.pool.getRoot().getName()
3525 lzc.lzc_sync(pool, True)
3526
3527 def test_reopen_missing_pool(self):
4b1c4062 3528 pool = b"nonexistent"
85ce3f4f 3529 with self.assertRaises(lzc_exc.PoolNotFound):
3530 lzc.lzc_reopen(pool)
3531
3532 def test_reopen_pool_no_restart(self):
3533 pool = ZFSTest.pool.getRoot().getName()
3534 lzc.lzc_reopen(pool, False)
3535
3536 def test_channel_program_missing_pool(self):
4b1c4062 3537 pool = b"nonexistent"
85ce3f4f 3538 with self.assertRaises(lzc_exc.PoolNotFound):
4b1c4062 3539 lzc.lzc_channel_program(pool, b"return {}")
85ce3f4f 3540
3541 def test_channel_program_timeout(self):
3542 pool = ZFSTest.pool.getRoot().getName()
4b1c4062 3543 zcp = b"""
85ce3f4f 3544for i = 1,10000 do
4b1c4062 3545 zfs.sync.snapshot('""" + pool + b"""@zcp' .. i)
85ce3f4f 3546end
3547"""
3548 with self.assertRaises(lzc_exc.ZCPTimeout):
3549 lzc.lzc_channel_program(pool, zcp, instrlimit=1)
3550
3551 def test_channel_program_memory_limit(self):
3552 pool = ZFSTest.pool.getRoot().getName()
4b1c4062 3553 zcp = b"""
85ce3f4f 3554for i = 1,10000 do
4b1c4062 3555 zfs.sync.snapshot('""" + pool + b"""@zcp' .. i)
85ce3f4f 3556end
3557"""
3558 with self.assertRaises(lzc_exc.ZCPSpaceError):
3559 lzc.lzc_channel_program(pool, zcp, memlimit=1)
3560
3561 def test_channel_program_invalid_limits(self):
3562 pool = ZFSTest.pool.getRoot().getName()
4b1c4062 3563 zcp = b"""
85ce3f4f 3564return {}
3565"""
3566 with self.assertRaises(lzc_exc.ZCPLimitInvalid):
3567 lzc.lzc_channel_program(pool, zcp, instrlimit=0)
3568 with self.assertRaises(lzc_exc.ZCPLimitInvalid):
3569 lzc.lzc_channel_program(pool, zcp, memlimit=0)
3570
3571 def test_channel_program_syntax_error(self):
3572 pool = ZFSTest.pool.getRoot().getName()
4b1c4062 3573 zcp = b"""
85ce3f4f 3574inv+val:id
3575"""
3576 with self.assertRaises(lzc_exc.ZCPSyntaxError) as ctx:
3577 lzc.lzc_channel_program(pool, zcp)
4b1c4062 3578 self.assertTrue(b"syntax error" in ctx.exception.details)
85ce3f4f 3579
3580 def test_channel_program_sync_snapshot(self):
3581 pool = ZFSTest.pool.getRoot().getName()
4b1c4062
BB
3582 snapname = ZFSTest.pool.makeName(b"@zcp")
3583 zcp = b"""
3584zfs.sync.snapshot('""" + snapname + b"""')
85ce3f4f 3585"""
3586 lzc.lzc_channel_program(pool, zcp)
3587 self.assertExists(snapname)
3588
3589 def test_channel_program_runtime_error(self):
3590 pool = ZFSTest.pool.getRoot().getName()
3591
3592 # failing an assertion raises a runtime error
3593 with self.assertRaises(lzc_exc.ZCPRuntimeError) as ctx:
4b1c4062 3594 lzc.lzc_channel_program(pool, b"assert(1 == 2)")
85ce3f4f 3595 self.assertTrue(
4b1c4062 3596 b"assertion failed" in ctx.exception.details)
85ce3f4f 3597 # invoking the error() function raises a runtime error
3598 with self.assertRaises(lzc_exc.ZCPRuntimeError) as ctx:
4b1c4062 3599 lzc.lzc_channel_program(pool, b"error()")
85ce3f4f 3600
3601 def test_channel_program_nosync_runtime_error(self):
3602 pool = ZFSTest.pool.getRoot().getName()
4b1c4062
BB
3603 zcp = b"""
3604zfs.sync.snapshot('""" + pool + b"""@zcp')
85ce3f4f 3605"""
3606 # lzc_channel_program_nosync() allows only "read-only" operations
3607 with self.assertRaises(lzc_exc.ZCPRuntimeError) as ctx:
3608 lzc.lzc_channel_program_nosync(pool, zcp)
3609 self.assertTrue(
4b1c4062 3610 b"running functions from the zfs.sync" in ctx.exception.details)
85ce3f4f 3611
3612 def test_change_key_new(self):
3613 with encrypted_filesystem() as (fs, _):
3614 lzc.lzc_change_key(
3615 fs, 'new_key',
4b1c4062 3616 props={b"keyformat": lzc.zfs_keyformat.ZFS_KEYFORMAT_RAW},
85ce3f4f 3617 key=os.urandom(lzc.WRAPPING_KEY_LEN))
3618
3619 def test_change_key_missing_fs(self):
4b1c4062 3620 name = b"nonexistent"
85ce3f4f 3621
3622 with self.assertRaises(lzc_exc.FilesystemNotFound):
3623 lzc.lzc_change_key(
3624 name, 'new_key',
4b1c4062 3625 props={b"keyformat": lzc.zfs_keyformat.ZFS_KEYFORMAT_RAW},
85ce3f4f 3626 key=os.urandom(lzc.WRAPPING_KEY_LEN))
3627
3628 def test_change_key_not_loaded(self):
3629 with encrypted_filesystem() as (fs, _):
3630 lzc.lzc_unload_key(fs)
3631 with self.assertRaises(lzc_exc.EncryptionKeyNotLoaded):
3632 lzc.lzc_change_key(
3633 fs, 'new_key',
4b1c4062 3634 props={b"keyformat": lzc.zfs_keyformat.ZFS_KEYFORMAT_RAW},
85ce3f4f 3635 key=os.urandom(lzc.WRAPPING_KEY_LEN))
3636
3637 def test_change_key_invalid_property(self):
3638 with encrypted_filesystem() as (fs, _):
3639 with self.assertRaises(lzc_exc.PropertyInvalid):
4b1c4062 3640 lzc.lzc_change_key(fs, 'new_key', props={b"invalid": b"prop"})
85ce3f4f 3641
3642 def test_change_key_invalid_crypt_command(self):
3643 with encrypted_filesystem() as (fs, _):
3644 with self.assertRaises(lzc_exc.UnknownCryptCommand):
3645 lzc.lzc_change_key(fs, 'duplicate_key')
3646
3647 def test_load_key(self):
3648 with encrypted_filesystem() as (fs, key):
3649 lzc.lzc_unload_key(fs)
3650 lzc.lzc_load_key(fs, False, key)
3651
3652 def test_load_key_invalid(self):
3653 with encrypted_filesystem() as (fs, key):
3654 lzc.lzc_unload_key(fs)
3655 with self.assertRaises(lzc_exc.EncryptionKeyInvalid):
3656 lzc.lzc_load_key(fs, False, os.urandom(lzc.WRAPPING_KEY_LEN))
3657
3658 def test_load_key_already_loaded(self):
3659 with encrypted_filesystem() as (fs, key):
3660 lzc.lzc_unload_key(fs)
3661 lzc.lzc_load_key(fs, False, key)
3662 with self.assertRaises(lzc_exc.EncryptionKeyAlreadyLoaded):
3663 lzc.lzc_load_key(fs, False, key)
3664
3665 def test_load_key_missing_fs(self):
4b1c4062 3666 name = b"nonexistent"
85ce3f4f 3667
3668 with self.assertRaises(lzc_exc.FilesystemNotFound):
3669 lzc.lzc_load_key(name, False, key=os.urandom(lzc.WRAPPING_KEY_LEN))
3670
3671 def test_unload_key(self):
3672 with encrypted_filesystem() as (fs, _):
3673 lzc.lzc_unload_key(fs)
3674
3675 def test_unload_key_missing_fs(self):
4b1c4062 3676 name = b"nonexistent"
85ce3f4f 3677
3678 with self.assertRaises(lzc_exc.FilesystemNotFound):
3679 lzc.lzc_unload_key(name)
3680
3681 def test_unload_key_busy(self):
3682 with encrypted_filesystem() as (fs, _):
3683 with zfs_mount(fs):
3684 with self.assertRaises(lzc_exc.DatasetBusy):
3685 lzc.lzc_unload_key(fs)
3686
3687 def test_unload_key_not_loaded(self):
3688 with encrypted_filesystem() as (fs, _):
3689 lzc.lzc_unload_key(fs)
3690 with self.assertRaises(lzc_exc.EncryptionKeyNotLoaded):
3691 lzc.lzc_unload_key(fs)
3692
c962fd6c 3693 def test_checkpoint(self):
3694 pool = ZFSTest.pool.getRoot().getName()
3695
3696 lzc.lzc_pool_checkpoint(pool)
3697
3698 def test_checkpoint_missing_pool(self):
4b1c4062 3699 pool = b"nonexistent"
c962fd6c 3700
3701 with self.assertRaises(lzc_exc.PoolNotFound):
3702 lzc.lzc_pool_checkpoint(pool)
3703
3704 def test_checkpoint_already_exists(self):
3705 pool = ZFSTest.pool.getRoot().getName()
3706
3707 lzc.lzc_pool_checkpoint(pool)
3708 with self.assertRaises(lzc_exc.CheckpointExists):
3709 lzc.lzc_pool_checkpoint(pool)
3710
3711 def test_checkpoint_discard(self):
3712 pool = ZFSTest.pool.getRoot().getName()
3713
3714 lzc.lzc_pool_checkpoint(pool)
3715 lzc.lzc_pool_checkpoint_discard(pool)
3716
3717 def test_checkpoint_discard_missing_pool(self):
4b1c4062 3718 pool = b"nonexistent"
c962fd6c 3719
3720 with self.assertRaises(lzc_exc.PoolNotFound):
3721 lzc.lzc_pool_checkpoint_discard(pool)
3722
3723 def test_checkpoint_discard_missing_checkpoint(self):
3724 pool = ZFSTest.pool.getRoot().getName()
3725
3726 with self.assertRaises(lzc_exc.CheckpointNotFound):
3727 lzc.lzc_pool_checkpoint_discard(pool)
3728
6abf9225
AG
3729 @needs_support(lzc.lzc_list_children)
3730 def test_list_children(self):
4b1c4062
BB
3731 name = ZFSTest.pool.makeName(b"fs1/fs")
3732 names = [ZFSTest.pool.makeName(b"fs1/fs/test1"),
3733 ZFSTest.pool.makeName(b"fs1/fs/test2"),
3734 ZFSTest.pool.makeName(b"fs1/fs/test3"), ]
6abf9225 3735 # and one snap to see that it is not listed
4b1c4062 3736 snap = ZFSTest.pool.makeName(b"fs1/fs@test")
6abf9225
AG
3737
3738 for fs in names:
3739 lzc.lzc_create(fs)
3740 lzc.lzc_snapshot([snap])
3741
3742 children = list(lzc.lzc_list_children(name))
3743 self.assertItemsEqual(children, names)
3744
3745 @needs_support(lzc.lzc_list_children)
3746 def test_list_children_nonexistent(self):
4b1c4062 3747 fs = ZFSTest.pool.makeName(b"nonexistent")
6abf9225
AG
3748
3749 with self.assertRaises(lzc_exc.DatasetNotFound):
3750 list(lzc.lzc_list_children(fs))
3751
3752 @needs_support(lzc.lzc_list_children)
3753 def test_list_children_of_snap(self):
4b1c4062 3754 snap = ZFSTest.pool.makeName(b"@newsnap")
6abf9225
AG
3755
3756 lzc.lzc_snapshot([snap])
3757 children = list(lzc.lzc_list_children(snap))
3758 self.assertEqual(children, [])
3759
3760 @needs_support(lzc.lzc_list_snaps)
3761 def test_list_snaps(self):
4b1c4062
BB
3762 name = ZFSTest.pool.makeName(b"fs1/fs")
3763 names = [ZFSTest.pool.makeName(b"fs1/fs@test1"),
3764 ZFSTest.pool.makeName(b"fs1/fs@test2"),
3765 ZFSTest.pool.makeName(b"fs1/fs@test3"), ]
6abf9225 3766 # and one filesystem to see that it is not listed
4b1c4062 3767 fs = ZFSTest.pool.makeName(b"fs1/fs/test")
6abf9225
AG
3768
3769 for snap in names:
3770 lzc.lzc_snapshot([snap])
3771 lzc.lzc_create(fs)
3772
3773 snaps = list(lzc.lzc_list_snaps(name))
3774 self.assertItemsEqual(snaps, names)
3775
3776 @needs_support(lzc.lzc_list_snaps)
3777 def test_list_snaps_nonexistent(self):
4b1c4062 3778 fs = ZFSTest.pool.makeName(b"nonexistent")
6abf9225
AG
3779
3780 with self.assertRaises(lzc_exc.DatasetNotFound):
3781 list(lzc.lzc_list_snaps(fs))
3782
3783 @needs_support(lzc.lzc_list_snaps)
3784 def test_list_snaps_of_snap(self):
4b1c4062 3785 snap = ZFSTest.pool.makeName(b"@newsnap")
6abf9225
AG
3786
3787 lzc.lzc_snapshot([snap])
3788 snaps = list(lzc.lzc_list_snaps(snap))
3789 self.assertEqual(snaps, [])
3790
3791 @needs_support(lzc.lzc_get_props)
3792 def test_get_fs_props(self):
4b1c4062
BB
3793 fs = ZFSTest.pool.makeName(b"new")
3794 props = {b"user:foo": b"bar"}
6abf9225
AG
3795
3796 lzc.lzc_create(fs, props=props)
3797 actual_props = lzc.lzc_get_props(fs)
3798 self.assertDictContainsSubset(props, actual_props)
3799
3800 @needs_support(lzc.lzc_get_props)
3801 def test_get_fs_props_with_child(self):
4b1c4062
BB
3802 parent = ZFSTest.pool.makeName(b"parent")
3803 child = ZFSTest.pool.makeName(b"parent/child")
3804 parent_props = {b"user:foo": b"parent"}
3805 child_props = {b"user:foo": b"child"}
6abf9225
AG
3806
3807 lzc.lzc_create(parent, props=parent_props)
3808 lzc.lzc_create(child, props=child_props)
3809 actual_parent_props = lzc.lzc_get_props(parent)
3810 actual_child_props = lzc.lzc_get_props(child)
3811 self.assertDictContainsSubset(parent_props, actual_parent_props)
3812 self.assertDictContainsSubset(child_props, actual_child_props)
3813
3814 @needs_support(lzc.lzc_get_props)
3815 def test_get_snap_props(self):
4b1c4062 3816 snapname = ZFSTest.pool.makeName(b"@snap")
6abf9225 3817 snaps = [snapname]
4b1c4062 3818 props = {b"user:foo": b"bar"}
6abf9225
AG
3819
3820 lzc.lzc_snapshot(snaps, props)
3821 actual_props = lzc.lzc_get_props(snapname)
3822 self.assertDictContainsSubset(props, actual_props)
3823
3824 @needs_support(lzc.lzc_get_props)
3825 def test_get_props_nonexistent(self):
4b1c4062 3826 fs = ZFSTest.pool.makeName(b"nonexistent")
6abf9225
AG
3827
3828 with self.assertRaises(lzc_exc.DatasetNotFound):
3829 lzc.lzc_get_props(fs)
3830
3831 @needs_support(lzc.lzc_get_props)
3832 def test_get_mountpoint_none(self):
3833 '''
3834 If the *mountpoint* property is set to none, then its
3835 value is returned as `bytes` "none".
3836 Also, a child filesystem inherits that value.
3837 '''
4b1c4062
BB
3838 fs = ZFSTest.pool.makeName(b"new")
3839 child = ZFSTest.pool.makeName(b"new/child")
3840 props = {b"mountpoint": b"none"}
6abf9225
AG
3841
3842 lzc.lzc_create(fs, props=props)
3843 lzc.lzc_create(child)
3844 actual_props = lzc.lzc_get_props(fs)
3845 self.assertDictContainsSubset(props, actual_props)
3846 # check that mountpoint value is correctly inherited
3847 child_props = lzc.lzc_get_props(child)
3848 self.assertDictContainsSubset(props, child_props)
3849
3850 @needs_support(lzc.lzc_get_props)
3851 def test_get_mountpoint_legacy(self):
3852 '''
3853 If the *mountpoint* property is set to legacy, then its
3854 value is returned as `bytes` "legacy".
3855 Also, a child filesystem inherits that value.
3856 '''
4b1c4062
BB
3857 fs = ZFSTest.pool.makeName(b"new")
3858 child = ZFSTest.pool.makeName(b"new/child")
3859 props = {b"mountpoint": b"legacy"}
6abf9225
AG
3860
3861 lzc.lzc_create(fs, props=props)
3862 lzc.lzc_create(child)
3863 actual_props = lzc.lzc_get_props(fs)
3864 self.assertDictContainsSubset(props, actual_props)
3865 # check that mountpoint value is correctly inherited
3866 child_props = lzc.lzc_get_props(child)
3867 self.assertDictContainsSubset(props, child_props)
3868
3869 @needs_support(lzc.lzc_get_props)
3870 def test_get_mountpoint_path(self):
3871 '''
3872 If the *mountpoint* property is set to a path and the property
3873 is not explicitly set on a child filesystem, then its
3874 value is that of the parent filesystem with the child's
3875 name appended using the '/' separator.
3876 '''
4b1c4062
BB
3877 fs = ZFSTest.pool.makeName(b"new")
3878 child = ZFSTest.pool.makeName(b"new/child")
3879 props = {b"mountpoint": b"/mnt"}
6abf9225
AG
3880
3881 lzc.lzc_create(fs, props=props)
3882 lzc.lzc_create(child)
3883 actual_props = lzc.lzc_get_props(fs)
3884 self.assertDictContainsSubset(props, actual_props)
3885 # check that mountpoint value is correctly inherited
3886 child_props = lzc.lzc_get_props(child)
3887 self.assertDictContainsSubset(
4b1c4062 3888 {b"mountpoint": b"/mnt/child"}, child_props)
6abf9225
AG
3889
3890 @needs_support(lzc.lzc_get_props)
3891 def test_get_snap_clones(self):
4b1c4062
BB
3892 fs = ZFSTest.pool.makeName(b"new")
3893 snap = ZFSTest.pool.makeName(b"@snap")
3894 clone1 = ZFSTest.pool.makeName(b"clone1")
3895 clone2 = ZFSTest.pool.makeName(b"clone2")
6abf9225
AG
3896
3897 lzc.lzc_create(fs)
3898 lzc.lzc_snapshot([snap])
3899 lzc.lzc_clone(clone1, snap)
3900 lzc.lzc_clone(clone2, snap)
3901
3902 clones_prop = lzc.lzc_get_props(snap)["clones"]
3903 self.assertItemsEqual(clones_prop, [clone1, clone2])
3904
3905 @needs_support(lzc.lzc_rename)
3906 def test_rename(self):
4b1c4062
BB
3907 src = ZFSTest.pool.makeName(b"source")
3908 tgt = ZFSTest.pool.makeName(b"target")
6abf9225
AG
3909
3910 lzc.lzc_create(src)
3911 lzc.lzc_rename(src, tgt)
3912 self.assertNotExists(src)
3913 self.assertExists(tgt)
3914
3915 @needs_support(lzc.lzc_rename)
3916 def test_rename_nonexistent(self):
4b1c4062
BB
3917 src = ZFSTest.pool.makeName(b"source")
3918 tgt = ZFSTest.pool.makeName(b"target")
6abf9225
AG
3919
3920 with self.assertRaises(lzc_exc.FilesystemNotFound):
3921 lzc.lzc_rename(src, tgt)
3922
3923 @needs_support(lzc.lzc_rename)
3924 def test_rename_existing_target(self):
4b1c4062
BB
3925 src = ZFSTest.pool.makeName(b"source")
3926 tgt = ZFSTest.pool.makeName(b"target")
6abf9225
AG
3927
3928 lzc.lzc_create(src)
3929 lzc.lzc_create(tgt)
3930 with self.assertRaises(lzc_exc.FilesystemExists):
3931 lzc.lzc_rename(src, tgt)
3932
3933 @needs_support(lzc.lzc_rename)
3934 def test_rename_nonexistent_target_parent(self):
4b1c4062
BB
3935 src = ZFSTest.pool.makeName(b"source")
3936 tgt = ZFSTest.pool.makeName(b"parent/target")
6abf9225
AG
3937
3938 lzc.lzc_create(src)
3939 with self.assertRaises(lzc_exc.FilesystemNotFound):
3940 lzc.lzc_rename(src, tgt)
3941
d8d418ff 3942 @needs_support(lzc.lzc_rename)
3943 def test_rename_parent_is_zvol(self):
3944 src = ZFSTest.pool.makeName(b"source")
3945 zvol = ZFSTest.pool.makeName(b"parent")
3946 tgt = zvol + b"/target"
3947 props = {b"volsize": 1024 * 1024}
3948
3949 lzc.lzc_create(src)
3950 lzc.lzc_create(zvol, ds_type='zvol', props=props)
3951 with self.assertRaises(lzc_exc.WrongParent):
3952 lzc.lzc_rename(src, tgt)
3953
6abf9225
AG
3954 @needs_support(lzc.lzc_destroy)
3955 def test_destroy(self):
4b1c4062 3956 fs = ZFSTest.pool.makeName(b"test-fs")
6abf9225
AG
3957
3958 lzc.lzc_create(fs)
3959 lzc.lzc_destroy(fs)
3960 self.assertNotExists(fs)
3961
3962 @needs_support(lzc.lzc_destroy)
3963 def test_destroy_nonexistent(self):
4b1c4062 3964 fs = ZFSTest.pool.makeName(b"test-fs")
6abf9225
AG
3965
3966 with self.assertRaises(lzc_exc.FilesystemNotFound):
3967 lzc.lzc_destroy(fs)
3968
3969 @needs_support(lzc.lzc_inherit_prop)
3970 def test_inherit_prop(self):
4b1c4062
BB
3971 parent = ZFSTest.pool.makeName(b"parent")
3972 child = ZFSTest.pool.makeName(b"parent/child")
3973 the_prop = b"user:foo"
3974 parent_props = {the_prop: b"parent"}
3975 child_props = {the_prop: b"child"}
6abf9225
AG
3976
3977 lzc.lzc_create(parent, props=parent_props)
3978 lzc.lzc_create(child, props=child_props)
3979 lzc.lzc_inherit_prop(child, the_prop)
3980 actual_props = lzc.lzc_get_props(child)
3981 self.assertDictContainsSubset(parent_props, actual_props)
3982
3983 @needs_support(lzc.lzc_inherit_prop)
3984 def test_inherit_missing_prop(self):
4b1c4062
BB
3985 parent = ZFSTest.pool.makeName(b"parent")
3986 child = ZFSTest.pool.makeName(b"parent/child")
6abf9225
AG
3987 the_prop = "user:foo"
3988 child_props = {the_prop: "child"}
3989
3990 lzc.lzc_create(parent)
3991 lzc.lzc_create(child, props=child_props)
3992 lzc.lzc_inherit_prop(child, the_prop)
3993 actual_props = lzc.lzc_get_props(child)
3994 self.assertNotIn(the_prop, actual_props)
3995
3996 @needs_support(lzc.lzc_inherit_prop)
3997 def test_inherit_readonly_prop(self):
4b1c4062
BB
3998 parent = ZFSTest.pool.makeName(b"parent")
3999 child = ZFSTest.pool.makeName(b"parent/child")
4000 the_prop = b"createtxg"
6abf9225
AG
4001
4002 lzc.lzc_create(parent)
4003 lzc.lzc_create(child)
4004 with self.assertRaises(lzc_exc.PropertyInvalid):
4005 lzc.lzc_inherit_prop(child, the_prop)
4006
4007 @needs_support(lzc.lzc_inherit_prop)
4008 def test_inherit_unknown_prop(self):
4b1c4062
BB
4009 parent = ZFSTest.pool.makeName(b"parent")
4010 child = ZFSTest.pool.makeName(b"parent/child")
4011 the_prop = b"nosuchprop"
6abf9225
AG
4012
4013 lzc.lzc_create(parent)
4014 lzc.lzc_create(child)
4015 with self.assertRaises(lzc_exc.PropertyInvalid):
4016 lzc.lzc_inherit_prop(child, the_prop)
4017
4018 @needs_support(lzc.lzc_inherit_prop)
4019 def test_inherit_prop_on_snap(self):
4b1c4062
BB
4020 fs = ZFSTest.pool.makeName(b"new")
4021 snapname = ZFSTest.pool.makeName(b"new@snap")
4022 prop = b"user:foo"
4023 fs_val = b"fs"
4024 snap_val = b"snap"
6abf9225
AG
4025
4026 lzc.lzc_create(fs, props={prop: fs_val})
4027 lzc.lzc_snapshot([snapname], props={prop: snap_val})
4028
4029 actual_props = lzc.lzc_get_props(snapname)
4030 self.assertDictContainsSubset({prop: snap_val}, actual_props)
4031
4032 lzc.lzc_inherit_prop(snapname, prop)
4033 actual_props = lzc.lzc_get_props(snapname)
4034 self.assertDictContainsSubset({prop: fs_val}, actual_props)
4035
4036 @needs_support(lzc.lzc_set_prop)
4037 def test_set_fs_prop(self):
4b1c4062
BB
4038 fs = ZFSTest.pool.makeName(b"new")
4039 prop = b"user:foo"
4040 val = b"bar"
6abf9225
AG
4041
4042 lzc.lzc_create(fs)
4043 lzc.lzc_set_prop(fs, prop, val)
4044 actual_props = lzc.lzc_get_props(fs)
4045 self.assertDictContainsSubset({prop: val}, actual_props)
4046
4047 @needs_support(lzc.lzc_set_prop)
4048 def test_set_snap_prop(self):
4b1c4062
BB
4049 snapname = ZFSTest.pool.makeName(b"@snap")
4050 prop = b"user:foo"
4051 val = b"bar"
6abf9225
AG
4052
4053 lzc.lzc_snapshot([snapname])
4054 lzc.lzc_set_prop(snapname, prop, val)
4055 actual_props = lzc.lzc_get_props(snapname)
4056 self.assertDictContainsSubset({prop: val}, actual_props)
4057
4058 @needs_support(lzc.lzc_set_prop)
4059 def test_set_prop_nonexistent(self):
4b1c4062
BB
4060 fs = ZFSTest.pool.makeName(b"nonexistent")
4061 prop = b"user:foo"
4062 val = b"bar"
6abf9225
AG
4063
4064 with self.assertRaises(lzc_exc.DatasetNotFound):
4065 lzc.lzc_set_prop(fs, prop, val)
4066
4067 @needs_support(lzc.lzc_set_prop)
4068 def test_set_sys_prop(self):
4b1c4062
BB
4069 fs = ZFSTest.pool.makeName(b"new")
4070 prop = b"recordsize"
6abf9225
AG
4071 val = 4096
4072
4073 lzc.lzc_create(fs)
4074 lzc.lzc_set_prop(fs, prop, val)
4075 actual_props = lzc.lzc_get_props(fs)
4076 self.assertDictContainsSubset({prop: val}, actual_props)
4077
4078 @needs_support(lzc.lzc_set_prop)
4079 def test_set_invalid_prop(self):
4b1c4062
BB
4080 fs = ZFSTest.pool.makeName(b"new")
4081 prop = b"nosuchprop"
6abf9225
AG
4082 val = 0
4083
4084 lzc.lzc_create(fs)
4085 with self.assertRaises(lzc_exc.PropertyInvalid):
4086 lzc.lzc_set_prop(fs, prop, val)
4087
4088 @needs_support(lzc.lzc_set_prop)
4089 def test_set_invalid_value_prop(self):
4b1c4062
BB
4090 fs = ZFSTest.pool.makeName(b"new")
4091 prop = b"atime"
6abf9225
AG
4092 val = 100
4093
4094 lzc.lzc_create(fs)
4095 with self.assertRaises(lzc_exc.PropertyInvalid):
4096 lzc.lzc_set_prop(fs, prop, val)
4097
4098 @needs_support(lzc.lzc_set_prop)
4099 def test_set_invalid_value_prop_2(self):
4b1c4062
BB
4100 fs = ZFSTest.pool.makeName(b"new")
4101 prop = b"readonly"
6abf9225
AG
4102 val = 100
4103
4104 lzc.lzc_create(fs)
4105 with self.assertRaises(lzc_exc.PropertyInvalid):
4106 lzc.lzc_set_prop(fs, prop, val)
4107
4108 @needs_support(lzc.lzc_set_prop)
4109 def test_set_prop_too_small_quota(self):
4b1c4062
BB
4110 fs = ZFSTest.pool.makeName(b"new")
4111 prop = b"refquota"
6abf9225
AG
4112 val = 1
4113
4114 lzc.lzc_create(fs)
4115 with self.assertRaises(lzc_exc.NoSpace):
4116 lzc.lzc_set_prop(fs, prop, val)
4117
4118 @needs_support(lzc.lzc_set_prop)
4119 def test_set_readonly_prop(self):
4b1c4062
BB
4120 fs = ZFSTest.pool.makeName(b"new")
4121 prop = b"creation"
6abf9225
AG
4122 val = 0
4123
4124 lzc.lzc_create(fs)
4125 lzc.lzc_set_prop(fs, prop, val)
4126 actual_props = lzc.lzc_get_props(fs)
4127 # the change is silently ignored
4128 self.assertTrue(actual_props[prop] != val)
4129
4130
4131class _TempPool(object):
4b1c4062
BB
4132 SNAPSHOTS = [b'snap', b'snap1', b'snap2']
4133 BOOKMARKS = [b'bmark', b'bmark1', b'bmark2']
6abf9225
AG
4134
4135 _cachefile_suffix = ".cachefile"
4136
4137 # XXX Whether to do a sloppy but much faster cleanup
4138 # or a proper but slower one.
4139 _recreate_pools = True
4140
4141 def __init__(self, size=128 * 1024 * 1024, readonly=False, filesystems=[]):
4142 self._filesystems = filesystems
4143 self._readonly = readonly
4b1c4062
BB
4144 if sys.version_info < (3, 0):
4145 self._pool_name = b'pool.' + bytes(uuid.uuid4())
4146 else:
4147 self._pool_name = b'pool.' + bytes(str(uuid.uuid4()),
4148 encoding='utf-8')
6abf9225
AG
4149 self._root = _Filesystem(self._pool_name)
4150 (fd, self._pool_file_path) = tempfile.mkstemp(
4151 suffix='.zpool', prefix='tmp-')
4152 if readonly:
4153 cachefile = self._pool_file_path + _TempPool._cachefile_suffix
4154 else:
4155 cachefile = 'none'
85ce3f4f 4156 self._zpool_create = [
4157 'zpool', 'create', '-o', 'cachefile=' + cachefile,
56fa4aa9
RE
4158 '-O', 'mountpoint=legacy', '-O', 'compression=off',
4159 self._pool_name, self._pool_file_path]
6abf9225
AG
4160 try:
4161 os.ftruncate(fd, size)
4162 os.close(fd)
4163
4164 subprocess.check_output(
4165 self._zpool_create, stderr=subprocess.STDOUT)
4166
4167 for fs in filesystems:
4168 lzc.lzc_create(self.makeName(fs))
4169
4170 self._bmarks_supported = self.isPoolFeatureEnabled('bookmarks')
4171
4172 if readonly:
85ce3f4f 4173 # To make a pool read-only it must exported and re-imported
4174 # with readonly option.
4175 # The most deterministic way to re-import the pool is by using
4176 # a cache file.
4177 # But the cache file has to be stashed away before the pool is
4178 # exported, because otherwise the pool is removed from the
4179 # cache.
6abf9225
AG
4180 shutil.copyfile(cachefile, cachefile + '.tmp')
4181 subprocess.check_output(
85ce3f4f 4182 ['zpool', 'export', '-f', self._pool_name],
4183 stderr=subprocess.STDOUT)
6abf9225 4184 os.rename(cachefile + '.tmp', cachefile)
85ce3f4f 4185 subprocess.check_output(
4186 ['zpool', 'import', '-f', '-N', '-c', cachefile,
4187 '-o', 'readonly=on', self._pool_name],
4188 stderr=subprocess.STDOUT)
6abf9225
AG
4189 os.remove(cachefile)
4190
4191 except subprocess.CalledProcessError as e:
4192 self.cleanUp()
4b1c4062 4193 if b'permission denied' in e.output:
6abf9225
AG
4194 raise unittest.SkipTest(
4195 'insufficient privileges to run libzfs_core tests')
9de8c0cd 4196 print('command failed: ', e.output)
6abf9225
AG
4197 raise
4198 except Exception:
4199 self.cleanUp()
4200 raise
4201
4202 def reset(self):
4203 if self._readonly:
4204 return
4205
4206 if not self.__class__._recreate_pools:
4207 snaps = []
4208 for fs in [''] + self._filesystems:
4209 for snap in self.__class__.SNAPSHOTS:
4210 snaps.append(self.makeName(fs + '@' + snap))
4211 self.getRoot().visitSnaps(lambda snap: snaps.append(snap))
4212 lzc.lzc_destroy_snaps(snaps, defer=False)
4213
4214 if self._bmarks_supported:
4215 bmarks = []
4216 for fs in [''] + self._filesystems:
4217 for bmark in self.__class__.BOOKMARKS:
4218 bmarks.append(self.makeName(fs + '#' + bmark))
4219 self.getRoot().visitBookmarks(
4220 lambda bmark: bmarks.append(bmark))
4221 lzc.lzc_destroy_bookmarks(bmarks)
4222 self.getRoot().reset()
4223 return
4224
85ce3f4f 4225 # On the Buildbot builders this may fail with "pool is busy"
4226 # Retry 5 times before raising an error
4227 retry = 0
4228 while True:
4229 try:
4230 subprocess.check_output(
4231 ['zpool', 'destroy', '-f', self._pool_name],
4232 stderr=subprocess.STDOUT)
4233 subprocess.check_output(
4234 self._zpool_create, stderr=subprocess.STDOUT)
4235 break
4236 except subprocess.CalledProcessError as e:
4b1c4062 4237 if b'pool is busy' in e.output and retry < 5:
85ce3f4f 4238 retry += 1
4239 time.sleep(1)
4240 continue
4241 else:
9de8c0cd 4242 print('command failed: ', e.output)
85ce3f4f 4243 raise
6abf9225
AG
4244 for fs in self._filesystems:
4245 lzc.lzc_create(self.makeName(fs))
4246 self.getRoot().reset()
4247
4248 def cleanUp(self):
4249 try:
4250 subprocess.check_output(
85ce3f4f 4251 ['zpool', 'destroy', '-f', self._pool_name],
4252 stderr=subprocess.STDOUT)
6abf9225
AG
4253 except Exception:
4254 pass
4255 try:
4256 os.remove(self._pool_file_path)
4257 except Exception:
4258 pass
4259 try:
4260 os.remove(self._pool_file_path + _TempPool._cachefile_suffix)
4261 except Exception:
4262 pass
4263 try:
4264 os.remove(
4265 self._pool_file_path + _TempPool._cachefile_suffix + '.tmp')
4266 except Exception:
4267 pass
4268
4269 def makeName(self, relative=None):
4270 if not relative:
4271 return self._pool_name
4b1c4062 4272 if relative.startswith((b'@', b'#')):
6abf9225 4273 return self._pool_name + relative
4b1c4062 4274 return self._pool_name + b'/' + relative
6abf9225
AG
4275
4276 def makeTooLongName(self, prefix=None):
4277 if not prefix:
4b1c4062 4278 prefix = b'x'
6abf9225
AG
4279 prefix = self.makeName(prefix)
4280 pad_len = lzc.MAXNAMELEN + 1 - len(prefix)
4281 if pad_len > 0:
4b1c4062 4282 return prefix + b'x' * pad_len
6abf9225
AG
4283 else:
4284 return prefix
4285
4286 def makeTooLongComponent(self, prefix=None):
4b1c4062 4287 padding = b'x' * (lzc.MAXNAMELEN + 1)
6abf9225
AG
4288 if not prefix:
4289 prefix = padding
4290 else:
4291 prefix = prefix + padding
4292 return self.makeName(prefix)
4293
4294 def getRoot(self):
4295 return self._root
4296
85ce3f4f 4297 def getFilesystem(self, fsname):
4b1c4062 4298 return _Filesystem(self._pool_name + b'/' + fsname)
85ce3f4f 4299
6abf9225
AG
4300 def isPoolFeatureAvailable(self, feature):
4301 output = subprocess.check_output(
4302 ['zpool', 'get', '-H', 'feature@' + feature, self._pool_name])
4303 output = output.strip()
4304 return output != ''
4305
4306 def isPoolFeatureEnabled(self, feature):
4307 output = subprocess.check_output(
4308 ['zpool', 'get', '-H', 'feature@' + feature, self._pool_name])
4309 output = output.split()[2]
4b1c4062 4310 return output in [b'active', b'enabled']
6abf9225
AG
4311
4312
4313class _Filesystem(object):
4314
4315 def __init__(self, name):
4316 self._name = name
4317 self.reset()
4318
4319 def getName(self):
4320 return self._name
4321
4322 def reset(self):
4323 self._children = []
4324 self._fs_id = 0
4325 self._snap_id = 0
4326 self._bmark_id = 0
4327
4328 def getFilesystem(self):
4329 self._fs_id += 1
4b1c4062 4330 fsname = self._name + b'/fs' + str(self._fs_id).encode()
6abf9225
AG
4331 fs = _Filesystem(fsname)
4332 self._children.append(fs)
4333 return fs
4334
85ce3f4f 4335 def getProperty(self, propname, received=False):
4336 if received:
4337 output = subprocess.check_output(
4338 ['zfs', 'get', '-pH', '-o', 'received', propname, self._name])
4339 else:
4340 output = subprocess.check_output(
4341 ['zfs', 'get', '-pH', '-o', 'value', propname, self._name])
4342 return output.strip()
4343
6abf9225 4344 def _makeSnapName(self, i):
4b1c4062 4345 return self._name + b'@snap' + str(i).encode()
6abf9225
AG
4346
4347 def getSnap(self):
4348 self._snap_id += 1
4349 return self._makeSnapName(self._snap_id)
4350
4351 def _makeBookmarkName(self, i):
4b1c4062 4352 return self._name + b'#bmark' + bytes(i)
6abf9225
AG
4353
4354 def getBookmark(self):
4355 self._bmark_id += 1
4356 return self._makeBookmarkName(self._bmark_id)
4357
4358 def _makeTooLongName(self, too_long_component):
4359 if too_long_component:
4b1c4062 4360 return b'x' * (lzc.MAXNAMELEN + 1)
6abf9225
AG
4361
4362 # Note that another character is used for one of '/', '@', '#'.
4363 comp_len = lzc.MAXNAMELEN - len(self._name)
4364 if comp_len > 0:
4b1c4062 4365 return b'x' * comp_len
6abf9225 4366 else:
4b1c4062 4367 return b'x'
6abf9225
AG
4368
4369 def getTooLongFilesystemName(self, too_long_component):
4b1c4062 4370 return self._name + b'/' + self._makeTooLongName(too_long_component)
6abf9225
AG
4371
4372 def getTooLongSnap(self, too_long_component):
4b1c4062 4373 return self._name + b'@' + self._makeTooLongName(too_long_component)
6abf9225
AG
4374
4375 def getTooLongBookmark(self, too_long_component):
4b1c4062 4376 return self._name + b'#' + self._makeTooLongName(too_long_component)
6abf9225
AG
4377
4378 def _visitFilesystems(self, visitor):
4379 for child in self._children:
4380 child._visitFilesystems(visitor)
4381 visitor(self)
4382
4383 def visitFilesystems(self, visitor):
4384 def _fsVisitor(fs):
4385 visitor(fs._name)
4386
4387 self._visitFilesystems(_fsVisitor)
4388
4389 def visitSnaps(self, visitor):
4390 def _snapVisitor(fs):
4391 for i in range(1, fs._snap_id + 1):
4392 visitor(fs._makeSnapName(i))
4393
4394 self._visitFilesystems(_snapVisitor)
4395
4396 def visitBookmarks(self, visitor):
4397 def _bmarkVisitor(fs):
4398 for i in range(1, fs._bmark_id + 1):
4399 visitor(fs._makeBookmarkName(i))
4400
4401 self._visitFilesystems(_bmarkVisitor)
4402
4403
4404# vim: softtabstop=4 tabstop=4 expandtab shiftwidth=4