2 # Copyright 2015 ClusterHQ
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
8 # http://www.apache.org/licenses/LICENSE-2.0
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.
18 Tests for `libzfs_core` operations.
20 These are mostly functional and conformance tests that validate
21 that the operations produce expected effects or fail with expected
24 from __future__
import absolute_import
, division
, print_function
42 from .. import _libzfs_core
as lzc
43 from .. import exceptions
as lzc_exc
44 from .._nvlist
import packed_nvlist_out
53 @contextlib.contextmanager
54 def suppress(exceptions
=None):
57 except BaseException
as e
:
58 if exceptions
is None or isinstance(e
, exceptions
):
64 @contextlib.contextmanager
66 mntdir
= tempfile
.mkdtemp()
67 if platform
.system() == 'SunOS':
68 mount_cmd
= ['mount', '-F', 'zfs', fs
, mntdir
]
70 mount_cmd
= ['mount', '-t', 'zfs', fs
, mntdir
]
71 unmount_cmd
= ['umount', '-f', mntdir
]
74 subprocess
.check_output(mount_cmd
, stderr
=subprocess
.STDOUT
)
79 subprocess
.check_output(unmount_cmd
, stderr
=subprocess
.STDOUT
)
80 except subprocess
.CalledProcessError
as e
:
81 print('failed to mount %s @ %s : %s' % (fs
, mntdir
, e
.output
))
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
91 # At the moment the former approach is implemented.
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.
101 @contextlib.contextmanager
102 def _illumos_mount_fs(fs
):
106 with
_zfs_mount(fs
) as mntdir
:
111 _mnttab
.pop(fs
, None)
114 @contextlib.contextmanager
115 def _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
)
121 @contextlib.contextmanager
122 def _zfs_mount_illumos(fs
):
124 with
_illumos_mount_fs(fs
) as mntdir
:
127 with
_illumos_mount_snap(fs
) as mntdir
:
131 if platform
.system() == 'SunOS':
132 zfs_mount
= _zfs_mount_illumos
134 zfs_mount
= _zfs_mount
137 @contextlib.contextmanager
139 fd
= os
.open('/dev/zfs', os
.O_EXCL
)
146 @contextlib.contextmanager
147 def os_open(name
, mode
):
148 fd
= os
.open(name
, mode
)
155 @contextlib.contextmanager
157 with
os_open('/dev/null', os
.O_WRONLY
) as fd
:
161 @contextlib.contextmanager
163 with
os_open('/dev/zero', os
.O_RDONLY
) as fd
:
167 @contextlib.contextmanager
168 def 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):
177 def make_snapshots(fs
, before
, modified
, after
):
178 def _maybe_snap(snap
):
180 if not snap
.startswith(fs
):
181 snap
= fs
+ b
'@' + snap
182 lzc
.lzc_snapshot([snap
])
185 before
= _maybe_snap(before
)
186 with
temp_file_in_fs(fs
) as name
:
187 modified
= _maybe_snap(modified
)
188 after
= _maybe_snap(after
)
190 return (name
, (before
, modified
, after
))
193 @contextlib.contextmanager
194 def streams(fs
, first
, second
):
195 (filename
, snaps
) = make_snapshots(fs
, None, first
, second
)
196 with tempfile
.TemporaryFile(suffix
='.zstream') as full
:
197 lzc
.lzc_send(snaps
[1], None, full
.fileno())
199 if snaps
[2] is not None:
200 with tempfile
.TemporaryFile(suffix
='.zstream') as incremental
:
201 lzc
.lzc_send(snaps
[2], snaps
[1], incremental
.fileno())
203 yield (filename
, (full
, incremental
))
205 yield (filename
, (full
, None))
208 @contextlib.contextmanager
209 def encrypted_filesystem():
210 fs
= ZFSTest
.pool
.getFilesystem(b
"encrypted")
213 key
= os
.urandom(lzc
.WRAPPING_KEY_LEN
)
214 with tempfile
.NamedTemporaryFile() as f
:
215 filename
= "file://" + f
.name
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
,
221 lzc
.lzc_create(name
, 'zfs', props
=props
, key
=key
)
225 def runtimeSkipIf(check_method
, message
):
227 def _f(_self
, *args
, **kwargs
):
228 if check_method(_self
):
229 return _self
.skipTest(message
)
231 return f(_self
, *args
, **kwargs
)
232 _f
.__name
__ = f
.__name
__
237 def skipIfFeatureAvailable(feature
, message
):
238 return runtimeSkipIf(
239 lambda _self
: _self
.__class
__.pool
.isPoolFeatureAvailable(feature
),
243 def skipUnlessFeatureEnabled(feature
, message
):
244 return runtimeSkipIf(
245 lambda _self
: not _self
.__class
__.pool
.isPoolFeatureEnabled(feature
),
249 def skipUnlessBookmarksSupported(f
):
250 return skipUnlessFeatureEnabled(
251 'bookmarks', 'bookmarks are not enabled')(f
)
254 def snap_always_unmounted_before_destruction():
255 # Apparently ZoL automatically unmounts the snapshot
256 # only if it is mounted at its default .zfs/snapshot
259 platform
.system() != 'Linux', 'snapshot is not auto-unmounted')
262 def illumos_bug_6379():
263 # zfs_ioc_hold() panics on a bad cleanup fd
265 platform
.system() == 'SunOS',
266 'see https://www.illumos.org/issues/6379')
269 def needs_support(function
):
270 return unittest
.skipUnless(
271 lzc
.is_supported(function
),
272 '{} not available'.format(function
.__name
__))
275 class ZFSTest(unittest
.TestCase
):
276 POOL_FILE_SIZE
= 128 * 1024 * 1024
277 FILESYSTEMS
= [b
'fs1', b
'fs2', b
'fs1/fs']
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
]
296 def tearDownClass(cls
):
301 for pool
in [cls
.pool
, cls
.misc_pool
, cls
.readonly_pool
]:
309 for pool
in ZFSTest
.pools
:
312 def assertExists(self
, name
):
314 lzc
.lzc_exists(name
), 'ZFS dataset %s does not exist' % (name
, ))
316 def assertNotExists(self
, name
):
318 lzc
.lzc_exists(name
), 'ZFS dataset %s exists' % (name
, ))
320 def test_exists(self
):
321 self
.assertExists(ZFSTest
.pool
.makeName())
323 def test_exists_in_ro_pool(self
):
324 self
.assertExists(ZFSTest
.readonly_pool
.makeName())
326 def test_exists_failure(self
):
327 self
.assertNotExists(ZFSTest
.pool
.makeName(b
'nonexistent'))
329 def test_create_fs(self
):
330 name
= ZFSTest
.pool
.makeName(b
"fs1/fs/test1")
333 self
.assertExists(name
)
335 def test_create_zvol(self
):
336 name
= ZFSTest
.pool
.makeName(b
"fs1/fs/zvol")
337 props
= {b
"volsize": 1024 * 1024}
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.
347 def test_create_fs_with_prop(self
):
348 name
= ZFSTest
.pool
.makeName(b
"fs1/fs/test2")
349 props
= {b
"atime": 0}
351 lzc
.lzc_create(name
, props
=props
)
352 self
.assertExists(name
)
354 def test_create_fs_wrong_ds_type(self
):
355 name
= ZFSTest
.pool
.makeName(b
"fs1/fs/test1")
357 with self
.assertRaises(lzc_exc
.DatasetTypeInvalid
):
358 lzc
.lzc_create(name
, ds_type
='wrong')
360 def test_create_fs_below_zvol(self
):
361 name
= ZFSTest
.pool
.makeName(b
"fs1/fs/zvol")
362 props
= {b
"volsize": 1024 * 1024}
364 lzc
.lzc_create(name
, ds_type
='zvol', props
=props
)
365 with self
.assertRaises(lzc_exc
.WrongParent
):
366 lzc
.lzc_create(name
+ b
'/fs')
368 def test_create_zvol_below_zvol(self
):
369 name
= ZFSTest
.pool
.makeName(b
"fs1/fs/zvol")
370 props
= {b
"volsize": 1024 * 1024}
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
)
376 def test_create_fs_duplicate(self
):
377 name
= ZFSTest
.pool
.makeName(b
"fs1/fs/test6")
381 with self
.assertRaises(lzc_exc
.FilesystemExists
):
384 def test_create_fs_in_ro_pool(self
):
385 name
= ZFSTest
.readonly_pool
.makeName(b
"fs")
387 with self
.assertRaises(lzc_exc
.ReadOnlyPool
):
390 def test_create_fs_without_parent(self
):
391 name
= ZFSTest
.pool
.makeName(b
"fs1/nonexistent/test")
393 with self
.assertRaises(lzc_exc
.ParentNotFound
):
395 self
.assertNotExists(name
)
397 def test_create_fs_in_nonexistent_pool(self
):
398 name
= b
"no-such-pool/fs"
400 with self
.assertRaises(lzc_exc
.ParentNotFound
):
402 self
.assertNotExists(name
)
404 def test_create_fs_with_invalid_prop(self
):
405 name
= ZFSTest
.pool
.makeName(b
"fs1/fs/test3")
406 props
= {b
"BOGUS": 0}
408 with self
.assertRaises(lzc_exc
.PropertyInvalid
):
409 lzc
.lzc_create(name
, 'zfs', props
)
410 self
.assertNotExists(name
)
412 def test_create_fs_with_invalid_prop_type(self
):
413 name
= ZFSTest
.pool
.makeName(b
"fs1/fs/test4")
414 props
= {b
"recordsize": b
"128k"}
416 with self
.assertRaises(lzc_exc
.PropertyInvalid
):
417 lzc
.lzc_create(name
, 'zfs', props
)
418 self
.assertNotExists(name
)
420 def test_create_fs_with_invalid_prop_val(self
):
421 name
= ZFSTest
.pool
.makeName(b
"fs1/fs/test5")
422 props
= {b
"atime": 20}
424 with self
.assertRaises(lzc_exc
.PropertyInvalid
):
425 lzc
.lzc_create(name
, 'zfs', props
)
426 self
.assertNotExists(name
)
428 def test_create_fs_with_invalid_name(self
):
429 name
= ZFSTest
.pool
.makeName(b
"@badname")
431 with self
.assertRaises(lzc_exc
.NameInvalid
):
433 self
.assertNotExists(name
)
435 def test_create_fs_with_invalid_pool_name(self
):
436 name
= b
"bad!pool/fs"
438 with self
.assertRaises(lzc_exc
.NameInvalid
):
440 self
.assertNotExists(name
)
442 def test_create_encrypted_fs(self
):
443 fs
= ZFSTest
.pool
.getFilesystem(b
"encrypted")
446 with tempfile
.NamedTemporaryFile() as f
:
447 filename
= "file://" + f
.name
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
,
453 key
= os
.urandom(lzc
.WRAPPING_KEY_LEN
)
454 lzc
.lzc_create(name
, 'zfs', props
=props
, key
=key
)
455 self
.assertEqual(fs
.getProperty("encryption"), b
"aes-256-ccm")
456 self
.assertEqual(fs
.getProperty("encryptionroot"), name
)
457 self
.assertEqual(fs
.getProperty("keylocation"), filename
.encode())
458 self
.assertEqual(fs
.getProperty("keyformat"), b
"raw")
460 def test_snapshot(self
):
461 snapname
= ZFSTest
.pool
.makeName(b
"@snap")
464 lzc
.lzc_snapshot(snaps
)
465 self
.assertExists(snapname
)
467 def test_snapshot_empty_list(self
):
470 def test_snapshot_user_props(self
):
471 snapname
= ZFSTest
.pool
.makeName(b
"@snap")
473 props
= {b
"user:foo": b
"bar"}
475 lzc
.lzc_snapshot(snaps
, props
)
476 self
.assertExists(snapname
)
478 def test_snapshot_invalid_props(self
):
479 snapname
= ZFSTest
.pool
.makeName(b
"@snap")
481 props
= {b
"foo": b
"bar"}
483 with self
.assertRaises(lzc_exc
.SnapshotFailure
) as ctx
:
484 lzc
.lzc_snapshot(snaps
, props
)
486 self
.assertEqual(len(ctx
.exception
.errors
), len(snaps
))
487 for e
in ctx
.exception
.errors
:
488 self
.assertIsInstance(e
, lzc_exc
.PropertyInvalid
)
489 self
.assertNotExists(snapname
)
491 def test_snapshot_ro_pool(self
):
492 snapname1
= ZFSTest
.readonly_pool
.makeName(b
"@snap")
493 snapname2
= ZFSTest
.readonly_pool
.makeName(b
"fs1@snap")
494 snaps
= [snapname1
, snapname2
]
496 with self
.assertRaises(lzc_exc
.SnapshotFailure
) as ctx
:
497 lzc
.lzc_snapshot(snaps
)
499 # NB: one common error is reported.
500 self
.assertEqual(len(ctx
.exception
.errors
), 1)
501 for e
in ctx
.exception
.errors
:
502 self
.assertIsInstance(e
, lzc_exc
.ReadOnlyPool
)
503 self
.assertNotExists(snapname1
)
504 self
.assertNotExists(snapname2
)
506 def test_snapshot_nonexistent_pool(self
):
507 snapname
= b
"no-such-pool@snap"
510 with self
.assertRaises(lzc_exc
.SnapshotFailure
) as ctx
:
511 lzc
.lzc_snapshot(snaps
)
513 self
.assertEqual(len(ctx
.exception
.errors
), 1)
514 for e
in ctx
.exception
.errors
:
515 self
.assertIsInstance(e
, lzc_exc
.FilesystemNotFound
)
517 def test_snapshot_nonexistent_fs(self
):
518 snapname
= ZFSTest
.pool
.makeName(b
"nonexistent@snap")
521 with self
.assertRaises(lzc_exc
.SnapshotFailure
) as ctx
:
522 lzc
.lzc_snapshot(snaps
)
524 self
.assertEqual(len(ctx
.exception
.errors
), 1)
525 for e
in ctx
.exception
.errors
:
526 self
.assertIsInstance(e
, lzc_exc
.FilesystemNotFound
)
528 def test_snapshot_nonexistent_and_existent_fs(self
):
529 snapname1
= ZFSTest
.pool
.makeName(b
"@snap")
530 snapname2
= ZFSTest
.pool
.makeName(b
"nonexistent@snap")
531 snaps
= [snapname1
, snapname2
]
533 with self
.assertRaises(lzc_exc
.SnapshotFailure
) as ctx
:
534 lzc
.lzc_snapshot(snaps
)
536 self
.assertEqual(len(ctx
.exception
.errors
), 1)
537 for e
in ctx
.exception
.errors
:
538 self
.assertIsInstance(e
, lzc_exc
.FilesystemNotFound
)
539 self
.assertNotExists(snapname1
)
540 self
.assertNotExists(snapname2
)
542 def test_multiple_snapshots_nonexistent_fs(self
):
543 snapname1
= ZFSTest
.pool
.makeName(b
"nonexistent@snap1")
544 snapname2
= ZFSTest
.pool
.makeName(b
"nonexistent@snap2")
545 snaps
= [snapname1
, snapname2
]
547 with self
.assertRaises(lzc_exc
.SnapshotFailure
) as ctx
:
548 lzc
.lzc_snapshot(snaps
)
550 # XXX two errors should be reported but alas
551 self
.assertEqual(len(ctx
.exception
.errors
), 1)
552 for e
in ctx
.exception
.errors
:
553 self
.assertIsInstance(e
, lzc_exc
.DuplicateSnapshots
)
554 self
.assertNotExists(snapname1
)
555 self
.assertNotExists(snapname2
)
557 def test_multiple_snapshots_multiple_nonexistent_fs(self
):
558 snapname1
= ZFSTest
.pool
.makeName(b
"nonexistent1@snap")
559 snapname2
= ZFSTest
.pool
.makeName(b
"nonexistent2@snap")
560 snaps
= [snapname1
, snapname2
]
562 with self
.assertRaises(lzc_exc
.SnapshotFailure
) as ctx
:
563 lzc
.lzc_snapshot(snaps
)
565 self
.assertEqual(len(ctx
.exception
.errors
), 2)
566 for e
in ctx
.exception
.errors
:
567 self
.assertIsInstance(e
, lzc_exc
.FilesystemNotFound
)
568 self
.assertNotExists(snapname1
)
569 self
.assertNotExists(snapname2
)
571 def test_snapshot_already_exists(self
):
572 snapname
= ZFSTest
.pool
.makeName(b
"@snap")
575 lzc
.lzc_snapshot(snaps
)
577 with self
.assertRaises(lzc_exc
.SnapshotFailure
) as ctx
:
578 lzc
.lzc_snapshot(snaps
)
580 self
.assertEqual(len(ctx
.exception
.errors
), 1)
581 for e
in ctx
.exception
.errors
:
582 self
.assertIsInstance(e
, lzc_exc
.SnapshotExists
)
584 def test_multiple_snapshots_for_same_fs(self
):
585 snapname1
= ZFSTest
.pool
.makeName(b
"@snap1")
586 snapname2
= ZFSTest
.pool
.makeName(b
"@snap2")
587 snaps
= [snapname1
, snapname2
]
589 with self
.assertRaises(lzc_exc
.SnapshotFailure
) as ctx
:
590 lzc
.lzc_snapshot(snaps
)
592 self
.assertEqual(len(ctx
.exception
.errors
), 1)
593 for e
in ctx
.exception
.errors
:
594 self
.assertIsInstance(e
, lzc_exc
.DuplicateSnapshots
)
595 self
.assertNotExists(snapname1
)
596 self
.assertNotExists(snapname2
)
598 def test_multiple_snapshots(self
):
599 snapname1
= ZFSTest
.pool
.makeName(b
"@snap")
600 snapname2
= ZFSTest
.pool
.makeName(b
"fs1@snap")
601 snaps
= [snapname1
, snapname2
]
603 lzc
.lzc_snapshot(snaps
)
604 self
.assertExists(snapname1
)
605 self
.assertExists(snapname2
)
607 def test_multiple_existing_snapshots(self
):
608 snapname1
= ZFSTest
.pool
.makeName(b
"@snap")
609 snapname2
= ZFSTest
.pool
.makeName(b
"fs1@snap")
610 snaps
= [snapname1
, snapname2
]
612 lzc
.lzc_snapshot(snaps
)
614 with self
.assertRaises(lzc_exc
.SnapshotFailure
) as ctx
:
615 lzc
.lzc_snapshot(snaps
)
617 self
.assertEqual(len(ctx
.exception
.errors
), 2)
618 for e
in ctx
.exception
.errors
:
619 self
.assertIsInstance(e
, lzc_exc
.SnapshotExists
)
621 def test_multiple_new_and_existing_snapshots(self
):
622 snapname1
= ZFSTest
.pool
.makeName(b
"@snap")
623 snapname2
= ZFSTest
.pool
.makeName(b
"fs1@snap")
624 snapname3
= ZFSTest
.pool
.makeName(b
"fs2@snap")
625 snaps
= [snapname1
, snapname2
]
626 more_snaps
= snaps
+ [snapname3
]
628 lzc
.lzc_snapshot(snaps
)
630 with self
.assertRaises(lzc_exc
.SnapshotFailure
) as ctx
:
631 lzc
.lzc_snapshot(more_snaps
)
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
)
638 def test_snapshot_multiple_errors(self
):
639 snapname1
= ZFSTest
.pool
.makeName(b
"@snap")
640 snapname2
= ZFSTest
.pool
.makeName(b
"nonexistent@snap")
641 snapname3
= ZFSTest
.pool
.makeName(b
"fs1@snap")
643 more_snaps
= [snapname1
, snapname2
, snapname3
]
645 # create 'snapname1' snapshot
646 lzc
.lzc_snapshot(snaps
)
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
)
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
:
659 self
.assertIsInstance(
660 e
, (lzc_exc
.SnapshotExists
, lzc_exc
.FilesystemNotFound
))
661 self
.assertNotExists(snapname2
)
662 self
.assertNotExists(snapname3
)
664 def test_snapshot_different_pools(self
):
665 snapname1
= ZFSTest
.pool
.makeName(b
"@snap")
666 snapname2
= ZFSTest
.misc_pool
.makeName(b
"@snap")
667 snaps
= [snapname1
, snapname2
]
669 with self
.assertRaises(lzc_exc
.SnapshotFailure
) as ctx
:
670 lzc
.lzc_snapshot(snaps
)
672 # NB: one common error is reported.
673 self
.assertEqual(len(ctx
.exception
.errors
), 1)
674 for e
in ctx
.exception
.errors
:
675 self
.assertIsInstance(e
, lzc_exc
.PoolsDiffer
)
676 self
.assertNotExists(snapname1
)
677 self
.assertNotExists(snapname2
)
679 def test_snapshot_different_pools_ro_pool(self
):
680 snapname1
= ZFSTest
.pool
.makeName(b
"@snap")
681 snapname2
= ZFSTest
.readonly_pool
.makeName(b
"@snap")
682 snaps
= [snapname1
, snapname2
]
684 with self
.assertRaises(lzc_exc
.SnapshotFailure
) as ctx
:
685 lzc
.lzc_snapshot(snaps
)
687 # NB: one common error is reported.
688 self
.assertEqual(len(ctx
.exception
.errors
), 1)
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
)
697 def test_snapshot_invalid_name(self
):
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")
701 snaps
= [snapname1
, snapname2
, snapname3
]
703 with self
.assertRaises(lzc_exc
.SnapshotFailure
) as ctx
:
704 lzc
.lzc_snapshot(snaps
)
706 # NB: one common error is reported.
707 self
.assertEqual(len(ctx
.exception
.errors
), 1)
708 for e
in ctx
.exception
.errors
:
709 self
.assertIsInstance(e
, lzc_exc
.NameInvalid
)
710 self
.assertIsNone(e
.name
)
712 def test_snapshot_too_long_complete_name(self
):
713 snapname1
= ZFSTest
.pool
.makeTooLongName(b
"fs1@")
714 snapname2
= ZFSTest
.pool
.makeTooLongName(b
"fs2@")
715 snapname3
= ZFSTest
.pool
.makeName(b
"@snap")
716 snaps
= [snapname1
, snapname2
, snapname3
]
718 with self
.assertRaises(lzc_exc
.SnapshotFailure
) as ctx
:
719 lzc
.lzc_snapshot(snaps
)
721 self
.assertEqual(len(ctx
.exception
.errors
), 2)
722 for e
in ctx
.exception
.errors
:
723 self
.assertIsInstance(e
, lzc_exc
.NameTooLong
)
724 self
.assertIsNotNone(e
.name
)
726 def test_snapshot_too_long_snap_name(self
):
727 snapname1
= ZFSTest
.pool
.makeTooLongComponent(b
"fs1@")
728 snapname2
= ZFSTest
.pool
.makeTooLongComponent(b
"fs2@")
729 snapname3
= ZFSTest
.pool
.makeName(b
"@snap")
730 snaps
= [snapname1
, snapname2
, snapname3
]
732 with self
.assertRaises(lzc_exc
.SnapshotFailure
) as ctx
:
733 lzc
.lzc_snapshot(snaps
)
735 # NB: one common error is reported.
736 self
.assertEqual(len(ctx
.exception
.errors
), 1)
737 for e
in ctx
.exception
.errors
:
738 self
.assertIsInstance(e
, lzc_exc
.NameTooLong
)
739 self
.assertIsNone(e
.name
)
741 def test_destroy_nonexistent_snapshot(self
):
742 lzc
.lzc_destroy_snaps([ZFSTest
.pool
.makeName(b
"@nonexistent")], False)
743 lzc
.lzc_destroy_snaps([ZFSTest
.pool
.makeName(b
"@nonexistent")], True)
745 def test_destroy_snapshot_of_nonexistent_pool(self
):
746 with self
.assertRaises(lzc_exc
.SnapshotDestructionFailure
) as ctx
:
747 lzc
.lzc_destroy_snaps([b
"no-such-pool@snap"], False)
749 for e
in ctx
.exception
.errors
:
750 self
.assertIsInstance(e
, lzc_exc
.PoolNotFound
)
752 with self
.assertRaises(lzc_exc
.SnapshotDestructionFailure
) as ctx
:
753 lzc
.lzc_destroy_snaps([b
"no-such-pool@snap"], True)
755 for e
in ctx
.exception
.errors
:
756 self
.assertIsInstance(e
, lzc_exc
.PoolNotFound
)
758 # NB: note the difference from the nonexistent pool test.
759 def test_destroy_snapshot_of_nonexistent_fs(self
):
760 lzc
.lzc_destroy_snaps(
761 [ZFSTest
.pool
.makeName(b
"nonexistent@snap")], False)
762 lzc
.lzc_destroy_snaps(
763 [ZFSTest
.pool
.makeName(b
"nonexistent@snap")], True)
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(
770 [ZFSTest
.pool
.makeName(b
"@non$&*existent")], False)
771 with self
.assertRaises(lzc_exc
.SnapshotDestructionFailure
):
772 lzc
.lzc_destroy_snaps(
773 [ZFSTest
.pool
.makeName(b
"@non$&*existent")], True)
775 # Apparently the full name is not checked for length.
776 @unittest.expectedFailure
777 def test_destroy_too_long_full_snap_name(self
):
778 snapname1
= ZFSTest
.pool
.makeTooLongName(b
"fs1@")
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)
786 def test_destroy_too_long_short_snap_name(self
):
787 snapname1
= ZFSTest
.pool
.makeTooLongComponent(b
"fs1@")
788 snapname2
= ZFSTest
.pool
.makeTooLongComponent(b
"fs2@")
789 snapname3
= ZFSTest
.pool
.makeName(b
"@snap")
790 snaps
= [snapname1
, snapname2
, snapname3
]
792 with self
.assertRaises(lzc_exc
.SnapshotDestructionFailure
) as ctx
:
793 lzc
.lzc_destroy_snaps(snaps
, False)
795 for e
in ctx
.exception
.errors
:
796 self
.assertIsInstance(e
, lzc_exc
.NameTooLong
)
798 @unittest.skipUnless(*snap_always_unmounted_before_destruction())
799 def test_destroy_mounted_snap(self
):
800 snap
= ZFSTest
.pool
.getRoot().getSnap()
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
)
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.
813 snapname
= ZFSTest
.pool
.makeName(b
"fs2@origin1")
814 name
= ZFSTest
.pool
.makeName(b
"fs1/fs/clone1")
816 lzc
.lzc_snapshot([snapname
])
818 lzc
.lzc_clone(name
, snapname
)
819 self
.assertExists(name
)
821 def test_clone_nonexistent_snapshot(self
):
822 snapname
= ZFSTest
.pool
.makeName(b
"fs2@nonexistent")
823 name
= ZFSTest
.pool
.makeName(b
"fs1/fs/clone2")
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
)
832 def test_clone_nonexistent_parent_fs(self
):
833 snapname
= ZFSTest
.pool
.makeName(b
"fs2@origin3")
834 name
= ZFSTest
.pool
.makeName(b
"fs1/nonexistent/clone3")
836 lzc
.lzc_snapshot([snapname
])
838 with self
.assertRaises(lzc_exc
.DatasetNotFound
):
839 lzc
.lzc_clone(name
, snapname
)
840 self
.assertNotExists(name
)
842 def test_clone_to_nonexistent_pool(self
):
843 snapname
= ZFSTest
.pool
.makeName(b
"fs2@snap")
844 name
= b
"no-such-pool/fs"
846 lzc
.lzc_snapshot([snapname
])
848 with self
.assertRaises(lzc_exc
.DatasetNotFound
):
849 lzc
.lzc_clone(name
, snapname
)
850 self
.assertNotExists(name
)
852 def test_clone_invalid_snap_name(self
):
853 # Use a valid filesystem name of filesystem that
854 # exists as a snapshot name
855 snapname
= ZFSTest
.pool
.makeName(b
"fs1/fs")
856 name
= ZFSTest
.pool
.makeName(b
"fs2/clone")
858 with self
.assertRaises(lzc_exc
.SnapshotNameInvalid
):
859 lzc
.lzc_clone(name
, snapname
)
860 self
.assertNotExists(name
)
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
865 snapname
= ZFSTest
.pool
.makeName(b
"fs1/nonexistent")
866 name
= ZFSTest
.pool
.makeName(b
"fs2/clone")
868 with self
.assertRaises(lzc_exc
.SnapshotNameInvalid
):
869 lzc
.lzc_clone(name
, snapname
)
870 self
.assertNotExists(name
)
872 def test_clone_invalid_name(self
):
873 snapname
= ZFSTest
.pool
.makeName(b
"fs2@snap")
874 name
= ZFSTest
.pool
.makeName(b
"fs1/bad#name")
876 lzc
.lzc_snapshot([snapname
])
878 with self
.assertRaises(lzc_exc
.FilesystemNameInvalid
):
879 lzc
.lzc_clone(name
, snapname
)
880 self
.assertNotExists(name
)
882 def test_clone_invalid_pool_name(self
):
883 snapname
= ZFSTest
.pool
.makeName(b
"fs2@snap")
884 name
= b
"bad!pool/fs1"
886 lzc
.lzc_snapshot([snapname
])
888 with self
.assertRaises(lzc_exc
.FilesystemNameInvalid
):
889 lzc
.lzc_clone(name
, snapname
)
890 self
.assertNotExists(name
)
892 def test_clone_across_pools(self
):
893 snapname
= ZFSTest
.pool
.makeName(b
"fs2@snap")
894 name
= ZFSTest
.misc_pool
.makeName(b
"clone1")
896 lzc
.lzc_snapshot([snapname
])
898 with self
.assertRaises(lzc_exc
.PoolsDiffer
):
899 lzc
.lzc_clone(name
, snapname
)
900 self
.assertNotExists(name
)
902 def test_clone_across_pools_to_ro_pool(self
):
903 snapname
= ZFSTest
.pool
.makeName(b
"fs2@snap")
904 name
= ZFSTest
.readonly_pool
.makeName(b
"fs1/clone1")
906 lzc
.lzc_snapshot([snapname
])
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
)
913 def test_destroy_cloned_fs(self
):
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")
917 snaps
= [snapname1
, snapname2
]
919 lzc
.lzc_snapshot(snaps
)
920 lzc
.lzc_clone(clonename
, snapname1
)
922 with self
.assertRaises(lzc_exc
.SnapshotDestructionFailure
) as ctx
:
923 lzc
.lzc_destroy_snaps(snaps
, False)
925 self
.assertEqual(len(ctx
.exception
.errors
), 1)
926 for e
in ctx
.exception
.errors
:
927 self
.assertIsInstance(e
, lzc_exc
.SnapshotIsCloned
)
929 self
.assertExists(snap
)
931 def test_deferred_destroy_cloned_fs(self
):
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")
935 snaps
= [snapname1
, snapname2
]
937 lzc
.lzc_snapshot(snaps
)
938 lzc
.lzc_clone(clonename
, snapname1
)
940 lzc
.lzc_destroy_snaps(snaps
, defer
=True)
942 self
.assertExists(snapname1
)
943 self
.assertNotExists(snapname2
)
945 def test_rollback(self
):
946 name
= ZFSTest
.pool
.makeName(b
"fs1")
947 snapname
= name
+ b
"@snap"
949 lzc
.lzc_snapshot([snapname
])
950 ret
= lzc
.lzc_rollback(name
)
951 self
.assertEqual(ret
, snapname
)
953 def test_rollback_2(self
):
954 name
= ZFSTest
.pool
.makeName(b
"fs1")
955 snapname1
= name
+ b
"@snap1"
956 snapname2
= name
+ b
"@snap2"
958 lzc
.lzc_snapshot([snapname1
])
959 lzc
.lzc_snapshot([snapname2
])
960 ret
= lzc
.lzc_rollback(name
)
961 self
.assertEqual(ret
, snapname2
)
963 def test_rollback_no_snaps(self
):
964 name
= ZFSTest
.pool
.makeName(b
"fs1")
966 with self
.assertRaises(lzc_exc
.SnapshotNotFound
):
967 lzc
.lzc_rollback(name
)
969 def test_rollback_non_existent_fs(self
):
970 name
= ZFSTest
.pool
.makeName(b
"nonexistent")
972 with self
.assertRaises(lzc_exc
.FilesystemNotFound
):
973 lzc
.lzc_rollback(name
)
975 def test_rollback_invalid_fs_name(self
):
976 name
= ZFSTest
.pool
.makeName(b
"bad~name")
978 with self
.assertRaises(lzc_exc
.NameInvalid
):
979 lzc
.lzc_rollback(name
)
981 def test_rollback_snap_name(self
):
982 name
= ZFSTest
.pool
.makeName(b
"fs1@snap")
984 with self
.assertRaises(lzc_exc
.NameInvalid
):
985 lzc
.lzc_rollback(name
)
987 def test_rollback_snap_name_2(self
):
988 name
= ZFSTest
.pool
.makeName(b
"fs1@snap")
990 lzc
.lzc_snapshot([name
])
991 with self
.assertRaises(lzc_exc
.NameInvalid
):
992 lzc
.lzc_rollback(name
)
994 def test_rollback_too_long_fs_name(self
):
995 name
= ZFSTest
.pool
.makeTooLongName()
997 with self
.assertRaises(lzc_exc
.NameTooLong
):
998 lzc
.lzc_rollback(name
)
1000 def test_rollback_to_snap_name(self
):
1001 name
= ZFSTest
.pool
.makeName(b
"fs1")
1002 snap
= name
+ b
"@snap"
1004 lzc
.lzc_snapshot([snap
])
1005 lzc
.lzc_rollback_to(name
, snap
)
1007 def test_rollback_to_not_latest(self
):
1008 fsname
= ZFSTest
.pool
.makeName(b
'fs1')
1009 snap1
= fsname
+ b
"@snap1"
1010 snap2
= fsname
+ b
"@snap2"
1012 lzc
.lzc_snapshot([snap1
])
1013 lzc
.lzc_snapshot([snap2
])
1014 with self
.assertRaises(lzc_exc
.SnapshotNotLatest
):
1015 lzc
.lzc_rollback_to(fsname
, fsname
+ b
"@snap1")
1017 @skipUnlessBookmarksSupported
1018 def test_bookmarks(self
):
1019 snaps
= [ZFSTest
.pool
.makeName(
1020 b
'fs1@snap1'), ZFSTest
.pool
.makeName(b
'fs2@snap1')]
1021 bmarks
= [ZFSTest
.pool
.makeName(
1022 b
'fs1#bmark1'), ZFSTest
.pool
.makeName(b
'fs2#bmark1')]
1023 bmark_dict
= {x
: y
for x
, y
in zip(bmarks
, snaps
)}
1025 lzc
.lzc_snapshot(snaps
)
1026 lzc
.lzc_bookmark(bmark_dict
)
1028 @skipUnlessBookmarksSupported
1029 def test_bookmarks_2(self
):
1030 snaps
= [ZFSTest
.pool
.makeName(
1031 b
'fs1@snap1'), ZFSTest
.pool
.makeName(b
'fs2@snap1')]
1032 bmarks
= [ZFSTest
.pool
.makeName(
1033 b
'fs1#bmark1'), ZFSTest
.pool
.makeName(b
'fs2#bmark1')]
1034 bmark_dict
= {x
: y
for x
, y
in zip(bmarks
, snaps
)}
1036 lzc
.lzc_snapshot(snaps
)
1037 lzc
.lzc_bookmark(bmark_dict
)
1038 lzc
.lzc_destroy_snaps(snaps
, defer
=False)
1040 @skipUnlessBookmarksSupported
1041 def test_bookmarks_empty(self
):
1042 lzc
.lzc_bookmark({})
1044 @skipUnlessBookmarksSupported
1045 def test_bookmarks_mismatching_name(self
):
1046 snaps
= [ZFSTest
.pool
.makeName(b
'fs1@snap1')]
1047 bmarks
= [ZFSTest
.pool
.makeName(b
'fs2#bmark1')]
1048 bmark_dict
= {x
: y
for x
, y
in zip(bmarks
, snaps
)}
1050 lzc
.lzc_snapshot(snaps
)
1051 with self
.assertRaises(lzc_exc
.BookmarkFailure
) as ctx
:
1052 lzc
.lzc_bookmark(bmark_dict
)
1054 for e
in ctx
.exception
.errors
:
1055 self
.assertIsInstance(e
, lzc_exc
.BookmarkMismatch
)
1057 @skipUnlessBookmarksSupported
1058 def test_bookmarks_invalid_name(self
):
1059 snaps
= [ZFSTest
.pool
.makeName(b
'fs1@snap1')]
1060 bmarks
= [ZFSTest
.pool
.makeName(b
'fs1#bmark!')]
1061 bmark_dict
= {x
: y
for x
, y
in zip(bmarks
, snaps
)}
1063 lzc
.lzc_snapshot(snaps
)
1064 with self
.assertRaises(lzc_exc
.BookmarkFailure
) as ctx
:
1065 lzc
.lzc_bookmark(bmark_dict
)
1067 for e
in ctx
.exception
.errors
:
1068 self
.assertIsInstance(e
, lzc_exc
.NameInvalid
)
1070 @skipUnlessBookmarksSupported
1071 def test_bookmarks_invalid_name_2(self
):
1072 snaps
= [ZFSTest
.pool
.makeName(b
'fs1@snap1')]
1073 bmarks
= [ZFSTest
.pool
.makeName(b
'fs1@bmark')]
1074 bmark_dict
= {x
: y
for x
, y
in zip(bmarks
, snaps
)}
1076 lzc
.lzc_snapshot(snaps
)
1077 with self
.assertRaises(lzc_exc
.BookmarkFailure
) as ctx
:
1078 lzc
.lzc_bookmark(bmark_dict
)
1080 for e
in ctx
.exception
.errors
:
1081 self
.assertIsInstance(e
, lzc_exc
.NameInvalid
)
1083 @skipUnlessBookmarksSupported
1084 def test_bookmarks_too_long_name(self
):
1085 snaps
= [ZFSTest
.pool
.makeName(b
'fs1@snap1')]
1086 bmarks
= [ZFSTest
.pool
.makeTooLongName(b
'fs1#')]
1087 bmark_dict
= {x
: y
for x
, y
in zip(bmarks
, snaps
)}
1089 lzc
.lzc_snapshot(snaps
)
1090 with self
.assertRaises(lzc_exc
.BookmarkFailure
) as ctx
:
1091 lzc
.lzc_bookmark(bmark_dict
)
1093 for e
in ctx
.exception
.errors
:
1094 self
.assertIsInstance(e
, lzc_exc
.NameTooLong
)
1096 @skipUnlessBookmarksSupported
1097 def test_bookmarks_too_long_name_2(self
):
1098 snaps
= [ZFSTest
.pool
.makeName(b
'fs1@snap1')]
1099 bmarks
= [ZFSTest
.pool
.makeTooLongComponent(b
'fs1#')]
1100 bmark_dict
= {x
: y
for x
, y
in zip(bmarks
, snaps
)}
1102 lzc
.lzc_snapshot(snaps
)
1103 with self
.assertRaises(lzc_exc
.BookmarkFailure
) as ctx
:
1104 lzc
.lzc_bookmark(bmark_dict
)
1106 for e
in ctx
.exception
.errors
:
1107 self
.assertIsInstance(e
, lzc_exc
.NameTooLong
)
1109 @skipUnlessBookmarksSupported
1110 def test_bookmarks_mismatching_names(self
):
1111 snaps
= [ZFSTest
.pool
.makeName(
1112 b
'fs1@snap1'), ZFSTest
.pool
.makeName(b
'fs2@snap1')]
1113 bmarks
= [ZFSTest
.pool
.makeName(
1114 b
'fs2#bmark1'), ZFSTest
.pool
.makeName(b
'fs1#bmark1')]
1115 bmark_dict
= {x
: y
for x
, y
in zip(bmarks
, snaps
)}
1117 lzc
.lzc_snapshot(snaps
)
1118 with self
.assertRaises(lzc_exc
.BookmarkFailure
) as ctx
:
1119 lzc
.lzc_bookmark(bmark_dict
)
1121 for e
in ctx
.exception
.errors
:
1122 self
.assertIsInstance(e
, lzc_exc
.BookmarkMismatch
)
1124 @skipUnlessBookmarksSupported
1125 def test_bookmarks_partially_mismatching_names(self
):
1126 snaps
= [ZFSTest
.pool
.makeName(
1127 b
'fs1@snap1'), ZFSTest
.pool
.makeName(b
'fs2@snap1')]
1128 bmarks
= [ZFSTest
.pool
.makeName(
1129 b
'fs2#bmark'), ZFSTest
.pool
.makeName(b
'fs2#bmark1')]
1130 bmark_dict
= {x
: y
for x
, y
in zip(bmarks
, snaps
)}
1132 lzc
.lzc_snapshot(snaps
)
1133 with self
.assertRaises(lzc_exc
.BookmarkFailure
) as ctx
:
1134 lzc
.lzc_bookmark(bmark_dict
)
1136 for e
in ctx
.exception
.errors
:
1137 self
.assertIsInstance(e
, lzc_exc
.BookmarkMismatch
)
1139 @skipUnlessBookmarksSupported
1140 def test_bookmarks_cross_pool(self
):
1141 snaps
= [ZFSTest
.pool
.makeName(
1142 b
'fs1@snap1'), ZFSTest
.misc_pool
.makeName(b
'@snap1')]
1143 bmarks
= [ZFSTest
.pool
.makeName(
1144 b
'fs1#bmark1'), ZFSTest
.misc_pool
.makeName(b
'#bmark1')]
1145 bmark_dict
= {x
: y
for x
, y
in zip(bmarks
, snaps
)}
1147 lzc
.lzc_snapshot(snaps
[0:1])
1148 lzc
.lzc_snapshot(snaps
[1:2])
1149 with self
.assertRaises(lzc_exc
.BookmarkFailure
) as ctx
:
1150 lzc
.lzc_bookmark(bmark_dict
)
1152 for e
in ctx
.exception
.errors
:
1153 self
.assertIsInstance(e
, lzc_exc
.PoolsDiffer
)
1155 @skipUnlessBookmarksSupported
1156 def test_bookmarks_missing_snap(self
):
1157 snaps
= [ZFSTest
.pool
.makeName(
1158 b
'fs1@snap1'), ZFSTest
.pool
.makeName(b
'fs2@snap1')]
1159 bmarks
= [ZFSTest
.pool
.makeName(
1160 b
'fs1#bmark1'), ZFSTest
.pool
.makeName(b
'fs2#bmark1')]
1161 bmark_dict
= {x
: y
for x
, y
in zip(bmarks
, snaps
)}
1163 lzc
.lzc_snapshot(snaps
[0:1])
1164 with self
.assertRaises(lzc_exc
.BookmarkFailure
) as ctx
:
1165 lzc
.lzc_bookmark(bmark_dict
)
1167 for e
in ctx
.exception
.errors
:
1168 self
.assertIsInstance(e
, lzc_exc
.SnapshotNotFound
)
1170 @skipUnlessBookmarksSupported
1171 def test_bookmarks_missing_snaps(self
):
1172 snaps
= [ZFSTest
.pool
.makeName(
1173 b
'fs1@snap1'), ZFSTest
.pool
.makeName(b
'fs2@snap1')]
1174 bmarks
= [ZFSTest
.pool
.makeName(
1175 b
'fs1#bmark1'), ZFSTest
.pool
.makeName(b
'fs2#bmark1')]
1176 bmark_dict
= {x
: y
for x
, y
in zip(bmarks
, snaps
)}
1178 with self
.assertRaises(lzc_exc
.BookmarkFailure
) as ctx
:
1179 lzc
.lzc_bookmark(bmark_dict
)
1181 for e
in ctx
.exception
.errors
:
1182 self
.assertIsInstance(e
, lzc_exc
.SnapshotNotFound
)
1184 @skipUnlessBookmarksSupported
1185 def test_bookmarks_for_the_same_snap(self
):
1186 snap
= ZFSTest
.pool
.makeName(b
'fs1@snap1')
1187 bmark1
= ZFSTest
.pool
.makeName(b
'fs1#bmark1')
1188 bmark2
= ZFSTest
.pool
.makeName(b
'fs1#bmark2')
1189 bmark_dict
= {bmark1
: snap
, bmark2
: snap
}
1191 lzc
.lzc_snapshot([snap
])
1192 lzc
.lzc_bookmark(bmark_dict
)
1194 @skipUnlessBookmarksSupported
1195 def test_bookmarks_for_the_same_snap_2(self
):
1196 snap
= ZFSTest
.pool
.makeName(b
'fs1@snap1')
1197 bmark1
= ZFSTest
.pool
.makeName(b
'fs1#bmark1')
1198 bmark2
= ZFSTest
.pool
.makeName(b
'fs1#bmark2')
1199 bmark_dict1
= {bmark1
: snap
}
1200 bmark_dict2
= {bmark2
: snap
}
1202 lzc
.lzc_snapshot([snap
])
1203 lzc
.lzc_bookmark(bmark_dict1
)
1204 lzc
.lzc_bookmark(bmark_dict2
)
1206 @skipUnlessBookmarksSupported
1207 def test_bookmarks_duplicate_name(self
):
1208 snap1
= ZFSTest
.pool
.makeName(b
'fs1@snap1')
1209 snap2
= ZFSTest
.pool
.makeName(b
'fs1@snap2')
1210 bmark
= ZFSTest
.pool
.makeName(b
'fs1#bmark')
1211 bmark_dict1
= {bmark
: snap1
}
1212 bmark_dict2
= {bmark
: snap2
}
1214 lzc
.lzc_snapshot([snap1
])
1215 lzc
.lzc_snapshot([snap2
])
1216 lzc
.lzc_bookmark(bmark_dict1
)
1217 with self
.assertRaises(lzc_exc
.BookmarkFailure
) as ctx
:
1218 lzc
.lzc_bookmark(bmark_dict2
)
1220 for e
in ctx
.exception
.errors
:
1221 self
.assertIsInstance(e
, lzc_exc
.BookmarkExists
)
1223 @skipUnlessBookmarksSupported
1224 def test_get_bookmarks(self
):
1225 snap1
= ZFSTest
.pool
.makeName(b
'fs1@snap1')
1226 snap2
= ZFSTest
.pool
.makeName(b
'fs1@snap2')
1227 bmark
= ZFSTest
.pool
.makeName(b
'fs1#bmark')
1228 bmark1
= ZFSTest
.pool
.makeName(b
'fs1#bmark1')
1229 bmark2
= ZFSTest
.pool
.makeName(b
'fs1#bmark2')
1230 bmark_dict1
= {bmark1
: snap1
, bmark2
: snap2
}
1231 bmark_dict2
= {bmark
: snap2
}
1233 lzc
.lzc_snapshot([snap1
])
1234 lzc
.lzc_snapshot([snap2
])
1235 lzc
.lzc_bookmark(bmark_dict1
)
1236 lzc
.lzc_bookmark(bmark_dict2
)
1237 lzc
.lzc_destroy_snaps([snap1
, snap2
], defer
=False)
1239 bmarks
= lzc
.lzc_get_bookmarks(ZFSTest
.pool
.makeName(b
'fs1'))
1240 self
.assertEqual(len(bmarks
), 3)
1241 for b
in b
'bmark', b
'bmark1', b
'bmark2':
1242 self
.assertIn(b
, bmarks
)
1243 self
.assertIsInstance(bmarks
[b
], dict)
1244 self
.assertEqual(len(bmarks
[b
]), 0)
1246 bmarks
= lzc
.lzc_get_bookmarks(ZFSTest
.pool
.makeName(b
'fs1'),
1247 [b
'guid', b
'createtxg', b
'creation'])
1248 self
.assertEqual(len(bmarks
), 3)
1249 for b
in b
'bmark', b
'bmark1', b
'bmark2':
1250 self
.assertIn(b
, bmarks
)
1251 self
.assertIsInstance(bmarks
[b
], dict)
1252 self
.assertEqual(len(bmarks
[b
]), 3)
1254 @skipUnlessBookmarksSupported
1255 def test_get_bookmarks_invalid_property(self
):
1256 snap
= ZFSTest
.pool
.makeName(b
'fs1@snap')
1257 bmark
= ZFSTest
.pool
.makeName(b
'fs1#bmark')
1258 bmark_dict
= {bmark
: snap
}
1260 lzc
.lzc_snapshot([snap
])
1261 lzc
.lzc_bookmark(bmark_dict
)
1263 bmarks
= lzc
.lzc_get_bookmarks(
1264 ZFSTest
.pool
.makeName(b
'fs1'), [b
'badprop'])
1265 self
.assertEqual(len(bmarks
), 1)
1266 for b
in (b
'bmark', ):
1267 self
.assertIn(b
, bmarks
)
1268 self
.assertIsInstance(bmarks
[b
], dict)
1269 self
.assertEqual(len(bmarks
[b
]), 0)
1271 @skipUnlessBookmarksSupported
1272 def test_get_bookmarks_nonexistent_fs(self
):
1273 with self
.assertRaises(lzc_exc
.FilesystemNotFound
):
1274 lzc
.lzc_get_bookmarks(ZFSTest
.pool
.makeName(b
'nonexistent'))
1276 @skipUnlessBookmarksSupported
1277 def test_destroy_bookmarks(self
):
1278 snap
= ZFSTest
.pool
.makeName(b
'fs1@snap')
1279 bmark
= ZFSTest
.pool
.makeName(b
'fs1#bmark')
1280 bmark_dict
= {bmark
: snap
}
1282 lzc
.lzc_snapshot([snap
])
1283 lzc
.lzc_bookmark(bmark_dict
)
1285 lzc
.lzc_destroy_bookmarks(
1286 [bmark
, ZFSTest
.pool
.makeName(b
'fs1#nonexistent')])
1287 bmarks
= lzc
.lzc_get_bookmarks(ZFSTest
.pool
.makeName(b
'fs1'))
1288 self
.assertEqual(len(bmarks
), 0)
1290 @skipUnlessBookmarksSupported
1291 def test_destroy_bookmarks_invalid_name(self
):
1292 snap
= ZFSTest
.pool
.makeName(b
'fs1@snap')
1293 bmark
= ZFSTest
.pool
.makeName(b
'fs1#bmark')
1294 bmark_dict
= {bmark
: snap
}
1296 lzc
.lzc_snapshot([snap
])
1297 lzc
.lzc_bookmark(bmark_dict
)
1299 with self
.assertRaises(lzc_exc
.BookmarkDestructionFailure
) as ctx
:
1300 lzc
.lzc_destroy_bookmarks(
1301 [bmark
, ZFSTest
.pool
.makeName(b
'fs1/nonexistent')])
1302 for e
in ctx
.exception
.errors
:
1303 self
.assertIsInstance(e
, lzc_exc
.NameInvalid
)
1305 bmarks
= lzc
.lzc_get_bookmarks(ZFSTest
.pool
.makeName(b
'fs1'))
1306 self
.assertEqual(len(bmarks
), 1)
1307 self
.assertIn(b
'bmark', bmarks
)
1309 @skipUnlessBookmarksSupported
1310 def test_destroy_bookmark_nonexistent_fs(self
):
1311 lzc
.lzc_destroy_bookmarks(
1312 [ZFSTest
.pool
.makeName(b
'nonexistent#bmark')])
1314 @skipUnlessBookmarksSupported
1315 def test_destroy_bookmarks_empty(self
):
1316 lzc
.lzc_bookmark({})
1318 def test_snaprange_space(self
):
1319 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1320 snap2
= ZFSTest
.pool
.makeName(b
"fs1@snap2")
1321 snap3
= ZFSTest
.pool
.makeName(b
"fs1@snap")
1323 lzc
.lzc_snapshot([snap1
])
1324 lzc
.lzc_snapshot([snap2
])
1325 lzc
.lzc_snapshot([snap3
])
1327 space
= lzc
.lzc_snaprange_space(snap1
, snap2
)
1328 self
.assertIsInstance(space
, (int, int))
1329 space
= lzc
.lzc_snaprange_space(snap2
, snap3
)
1330 self
.assertIsInstance(space
, (int, int))
1331 space
= lzc
.lzc_snaprange_space(snap1
, snap3
)
1332 self
.assertIsInstance(space
, (int, int))
1334 def test_snaprange_space_2(self
):
1335 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1336 snap2
= ZFSTest
.pool
.makeName(b
"fs1@snap2")
1337 snap3
= ZFSTest
.pool
.makeName(b
"fs1@snap")
1339 lzc
.lzc_snapshot([snap1
])
1340 with
zfs_mount(ZFSTest
.pool
.makeName(b
"fs1")) as mntdir
:
1341 with tempfile
.NamedTemporaryFile(dir=mntdir
) as f
:
1342 for i
in range(1024):
1343 f
.write(b
'x' * 1024)
1345 lzc
.lzc_snapshot([snap2
])
1346 lzc
.lzc_snapshot([snap3
])
1348 space
= lzc
.lzc_snaprange_space(snap1
, snap2
)
1349 self
.assertGreater(space
, 1024 * 1024)
1350 space
= lzc
.lzc_snaprange_space(snap2
, snap3
)
1351 self
.assertGreater(space
, 1024 * 1024)
1352 space
= lzc
.lzc_snaprange_space(snap1
, snap3
)
1353 self
.assertGreater(space
, 1024 * 1024)
1355 def test_snaprange_space_same_snap(self
):
1356 snap
= ZFSTest
.pool
.makeName(b
"fs1@snap")
1358 with
zfs_mount(ZFSTest
.pool
.makeName(b
"fs1")) as mntdir
:
1359 with tempfile
.NamedTemporaryFile(dir=mntdir
) as f
:
1360 for i
in range(1024):
1361 f
.write(b
'x' * 1024)
1363 lzc
.lzc_snapshot([snap
])
1365 space
= lzc
.lzc_snaprange_space(snap
, snap
)
1366 self
.assertGreater(space
, 1024 * 1024)
1367 self
.assertAlmostEqual(space
, 1024 * 1024, delta
=1024 * 1024 // 20)
1369 def test_snaprange_space_wrong_order(self
):
1370 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1371 snap2
= ZFSTest
.pool
.makeName(b
"fs1@snap2")
1373 lzc
.lzc_snapshot([snap1
])
1374 lzc
.lzc_snapshot([snap2
])
1376 with self
.assertRaises(lzc_exc
.SnapshotMismatch
):
1377 lzc
.lzc_snaprange_space(snap2
, snap1
)
1379 def test_snaprange_space_unrelated(self
):
1380 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1381 snap2
= ZFSTest
.pool
.makeName(b
"fs2@snap2")
1383 lzc
.lzc_snapshot([snap1
])
1384 lzc
.lzc_snapshot([snap2
])
1386 with self
.assertRaises(lzc_exc
.SnapshotMismatch
):
1387 lzc
.lzc_snaprange_space(snap1
, snap2
)
1389 def test_snaprange_space_across_pools(self
):
1390 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1391 snap2
= ZFSTest
.misc_pool
.makeName(b
"@snap2")
1393 lzc
.lzc_snapshot([snap1
])
1394 lzc
.lzc_snapshot([snap2
])
1396 with self
.assertRaises(lzc_exc
.PoolsDiffer
):
1397 lzc
.lzc_snaprange_space(snap1
, snap2
)
1399 def test_snaprange_space_nonexistent(self
):
1400 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1401 snap2
= ZFSTest
.pool
.makeName(b
"fs1@snap2")
1403 lzc
.lzc_snapshot([snap1
])
1405 with self
.assertRaises(lzc_exc
.SnapshotNotFound
) as ctx
:
1406 lzc
.lzc_snaprange_space(snap1
, snap2
)
1407 self
.assertEqual(ctx
.exception
.name
, snap2
)
1409 with self
.assertRaises(lzc_exc
.SnapshotNotFound
) as ctx
:
1410 lzc
.lzc_snaprange_space(snap2
, snap1
)
1411 self
.assertEqual(ctx
.exception
.name
, snap1
)
1413 def test_snaprange_space_invalid_name(self
):
1414 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1415 snap2
= ZFSTest
.pool
.makeName(b
"fs1@sn#p")
1417 lzc
.lzc_snapshot([snap1
])
1419 with self
.assertRaises(lzc_exc
.NameInvalid
):
1420 lzc
.lzc_snaprange_space(snap1
, snap2
)
1422 def test_snaprange_space_not_snap(self
):
1423 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1424 snap2
= ZFSTest
.pool
.makeName(b
"fs1")
1426 lzc
.lzc_snapshot([snap1
])
1428 with self
.assertRaises(lzc_exc
.NameInvalid
):
1429 lzc
.lzc_snaprange_space(snap1
, snap2
)
1430 with self
.assertRaises(lzc_exc
.NameInvalid
):
1431 lzc
.lzc_snaprange_space(snap2
, snap1
)
1433 def test_snaprange_space_not_snap_2(self
):
1434 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1435 snap2
= ZFSTest
.pool
.makeName(b
"fs1#bmark")
1437 lzc
.lzc_snapshot([snap1
])
1439 with self
.assertRaises(lzc_exc
.NameInvalid
):
1440 lzc
.lzc_snaprange_space(snap1
, snap2
)
1441 with self
.assertRaises(lzc_exc
.NameInvalid
):
1442 lzc
.lzc_snaprange_space(snap2
, snap1
)
1444 def test_send_space(self
):
1445 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1446 snap2
= ZFSTest
.pool
.makeName(b
"fs1@snap2")
1447 snap3
= ZFSTest
.pool
.makeName(b
"fs1@snap")
1449 lzc
.lzc_snapshot([snap1
])
1450 lzc
.lzc_snapshot([snap2
])
1451 lzc
.lzc_snapshot([snap3
])
1453 space
= lzc
.lzc_send_space(snap2
, snap1
)
1454 self
.assertIsInstance(space
, (int, int))
1455 space
= lzc
.lzc_send_space(snap3
, snap2
)
1456 self
.assertIsInstance(space
, (int, int))
1457 space
= lzc
.lzc_send_space(snap3
, snap1
)
1458 self
.assertIsInstance(space
, (int, int))
1459 space
= lzc
.lzc_send_space(snap1
)
1460 self
.assertIsInstance(space
, (int, int))
1461 space
= lzc
.lzc_send_space(snap2
)
1462 self
.assertIsInstance(space
, (int, int))
1463 space
= lzc
.lzc_send_space(snap3
)
1464 self
.assertIsInstance(space
, (int, int))
1466 def test_send_space_2(self
):
1467 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1468 snap2
= ZFSTest
.pool
.makeName(b
"fs1@snap2")
1469 snap3
= ZFSTest
.pool
.makeName(b
"fs1@snap")
1471 lzc
.lzc_snapshot([snap1
])
1472 with
zfs_mount(ZFSTest
.pool
.makeName(b
"fs1")) as mntdir
:
1473 with tempfile
.NamedTemporaryFile(dir=mntdir
) as f
:
1474 for i
in range(1024):
1475 f
.write(b
'x' * 1024)
1477 lzc
.lzc_snapshot([snap2
])
1478 lzc
.lzc_snapshot([snap3
])
1480 space
= lzc
.lzc_send_space(snap2
, snap1
)
1481 self
.assertGreater(space
, 1024 * 1024)
1483 space
= lzc
.lzc_send_space(snap3
, snap2
)
1485 space
= lzc
.lzc_send_space(snap3
, snap1
)
1487 space_empty
= lzc
.lzc_send_space(snap1
)
1489 space
= lzc
.lzc_send_space(snap2
)
1490 self
.assertGreater(space
, 1024 * 1024)
1492 space
= lzc
.lzc_send_space(snap3
)
1493 self
.assertEqual(space
, space_empty
)
1495 def test_send_space_same_snap(self
):
1496 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1497 lzc
.lzc_snapshot([snap1
])
1498 with self
.assertRaises(lzc_exc
.SnapshotMismatch
):
1499 lzc
.lzc_send_space(snap1
, snap1
)
1501 def test_send_space_wrong_order(self
):
1502 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1503 snap2
= ZFSTest
.pool
.makeName(b
"fs1@snap2")
1505 lzc
.lzc_snapshot([snap1
])
1506 lzc
.lzc_snapshot([snap2
])
1508 with self
.assertRaises(lzc_exc
.SnapshotMismatch
):
1509 lzc
.lzc_send_space(snap1
, snap2
)
1511 def test_send_space_unrelated(self
):
1512 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1513 snap2
= ZFSTest
.pool
.makeName(b
"fs2@snap2")
1515 lzc
.lzc_snapshot([snap1
])
1516 lzc
.lzc_snapshot([snap2
])
1518 with self
.assertRaises(lzc_exc
.SnapshotMismatch
):
1519 lzc
.lzc_send_space(snap1
, snap2
)
1521 def test_send_space_across_pools(self
):
1522 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1523 snap2
= ZFSTest
.misc_pool
.makeName(b
"@snap2")
1525 lzc
.lzc_snapshot([snap1
])
1526 lzc
.lzc_snapshot([snap2
])
1528 with self
.assertRaises(lzc_exc
.PoolsDiffer
):
1529 lzc
.lzc_send_space(snap1
, snap2
)
1531 def test_send_space_nonexistent(self
):
1532 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1533 snap2
= ZFSTest
.pool
.makeName(b
"fs2@snap2")
1535 lzc
.lzc_snapshot([snap1
])
1537 with self
.assertRaises(lzc_exc
.SnapshotNotFound
) as ctx
:
1538 lzc
.lzc_send_space(snap1
, snap2
)
1539 self
.assertEqual(ctx
.exception
.name
, snap1
)
1541 with self
.assertRaises(lzc_exc
.SnapshotNotFound
) as ctx
:
1542 lzc
.lzc_send_space(snap2
, snap1
)
1543 self
.assertEqual(ctx
.exception
.name
, snap2
)
1545 with self
.assertRaises(lzc_exc
.SnapshotNotFound
) as ctx
:
1546 lzc
.lzc_send_space(snap2
)
1547 self
.assertEqual(ctx
.exception
.name
, snap2
)
1549 def test_send_space_invalid_name(self
):
1550 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1551 snap2
= ZFSTest
.pool
.makeName(b
"fs1@sn!p")
1553 lzc
.lzc_snapshot([snap1
])
1555 with self
.assertRaises(lzc_exc
.NameInvalid
) as ctx
:
1556 lzc
.lzc_send_space(snap2
, snap1
)
1557 self
.assertEqual(ctx
.exception
.name
, snap2
)
1558 with self
.assertRaises(lzc_exc
.NameInvalid
) as ctx
:
1559 lzc
.lzc_send_space(snap2
)
1560 self
.assertEqual(ctx
.exception
.name
, snap2
)
1561 with self
.assertRaises(lzc_exc
.NameInvalid
) as ctx
:
1562 lzc
.lzc_send_space(snap1
, snap2
)
1563 self
.assertEqual(ctx
.exception
.name
, snap2
)
1565 def test_send_space_not_snap(self
):
1566 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1567 snap2
= ZFSTest
.pool
.makeName(b
"fs1")
1569 lzc
.lzc_snapshot([snap1
])
1571 with self
.assertRaises(lzc_exc
.NameInvalid
):
1572 lzc
.lzc_send_space(snap1
, snap2
)
1573 with self
.assertRaises(lzc_exc
.NameInvalid
):
1574 lzc
.lzc_send_space(snap2
, snap1
)
1575 with self
.assertRaises(lzc_exc
.NameInvalid
):
1576 lzc
.lzc_send_space(snap2
)
1578 def test_send_space_not_snap_2(self
):
1579 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1580 snap2
= ZFSTest
.pool
.makeName(b
"fs1#bmark")
1582 lzc
.lzc_snapshot([snap1
])
1584 with self
.assertRaises(lzc_exc
.NameInvalid
):
1585 lzc
.lzc_send_space(snap2
, snap1
)
1586 with self
.assertRaises(lzc_exc
.NameInvalid
):
1587 lzc
.lzc_send_space(snap2
)
1589 def test_send_full(self
):
1590 snap
= ZFSTest
.pool
.makeName(b
"fs1@snap")
1592 with
zfs_mount(ZFSTest
.pool
.makeName(b
"fs1")) as mntdir
:
1593 with tempfile
.NamedTemporaryFile(dir=mntdir
) as f
:
1594 for i
in range(1024):
1595 f
.write(b
'x' * 1024)
1597 lzc
.lzc_snapshot([snap
])
1599 with tempfile
.TemporaryFile(suffix
='.zstream') as output
:
1600 estimate
= lzc
.lzc_send_space(snap
)
1602 fd
= output
.fileno()
1603 lzc
.lzc_send(snap
, None, fd
)
1606 self
.assertAlmostEqual(st
.st_size
, estimate
, delta
=estimate
// 20)
1608 def test_send_incremental(self
):
1609 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1610 snap2
= ZFSTest
.pool
.makeName(b
"fs1@snap2")
1612 lzc
.lzc_snapshot([snap1
])
1613 with
zfs_mount(ZFSTest
.pool
.makeName(b
"fs1")) as mntdir
:
1614 with tempfile
.NamedTemporaryFile(dir=mntdir
) as f
:
1615 for i
in range(1024):
1616 f
.write(b
'x' * 1024)
1618 lzc
.lzc_snapshot([snap2
])
1620 with tempfile
.TemporaryFile(suffix
='.zstream') as output
:
1621 estimate
= lzc
.lzc_send_space(snap2
, snap1
)
1623 fd
= output
.fileno()
1624 lzc
.lzc_send(snap2
, snap1
, fd
)
1627 self
.assertAlmostEqual(st
.st_size
, estimate
, delta
=estimate
// 20)
1629 def test_send_flags(self
):
1630 flags
= ['embedded_data', 'large_blocks', 'compress', 'raw']
1631 snap
= ZFSTest
.pool
.makeName(b
"fs1@snap")
1632 lzc
.lzc_snapshot([snap
])
1634 for c
in range(len(flags
)):
1635 for flag
in itertools
.permutations(flags
, c
+ 1):
1636 with
dev_null() as fd
:
1637 lzc
.lzc_send(snap
, None, fd
, list(flag
))
1639 def test_send_unknown_flags(self
):
1640 snap
= ZFSTest
.pool
.makeName(b
"fs1@snap")
1641 lzc
.lzc_snapshot([snap
])
1642 with
dev_null() as fd
:
1643 with self
.assertRaises(lzc_exc
.UnknownStreamFeature
):
1644 lzc
.lzc_send(snap
, None, fd
, ['embedded_data', 'UNKNOWN'])
1646 def test_send_same_snap(self
):
1647 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1648 lzc
.lzc_snapshot([snap1
])
1649 with tempfile
.TemporaryFile(suffix
='.zstream') as output
:
1650 fd
= output
.fileno()
1651 with self
.assertRaises(lzc_exc
.SnapshotMismatch
):
1652 lzc
.lzc_send(snap1
, snap1
, fd
)
1654 def test_send_wrong_order(self
):
1655 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1656 snap2
= ZFSTest
.pool
.makeName(b
"fs1@snap2")
1658 lzc
.lzc_snapshot([snap1
])
1659 lzc
.lzc_snapshot([snap2
])
1661 with tempfile
.TemporaryFile(suffix
='.zstream') as output
:
1662 fd
= output
.fileno()
1663 with self
.assertRaises(lzc_exc
.SnapshotMismatch
):
1664 lzc
.lzc_send(snap1
, snap2
, fd
)
1666 def test_send_unrelated(self
):
1667 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1668 snap2
= ZFSTest
.pool
.makeName(b
"fs2@snap2")
1670 lzc
.lzc_snapshot([snap1
])
1671 lzc
.lzc_snapshot([snap2
])
1673 with tempfile
.TemporaryFile(suffix
='.zstream') as output
:
1674 fd
= output
.fileno()
1675 with self
.assertRaises(lzc_exc
.SnapshotMismatch
):
1676 lzc
.lzc_send(snap1
, snap2
, fd
)
1678 def test_send_across_pools(self
):
1679 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1680 snap2
= ZFSTest
.misc_pool
.makeName(b
"@snap2")
1682 lzc
.lzc_snapshot([snap1
])
1683 lzc
.lzc_snapshot([snap2
])
1685 with tempfile
.TemporaryFile(suffix
='.zstream') as output
:
1686 fd
= output
.fileno()
1687 with self
.assertRaises(lzc_exc
.PoolsDiffer
):
1688 lzc
.lzc_send(snap1
, snap2
, fd
)
1690 def test_send_nonexistent(self
):
1691 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1692 snap2
= ZFSTest
.pool
.makeName(b
"fs1@snap2")
1694 lzc
.lzc_snapshot([snap1
])
1696 with tempfile
.TemporaryFile(suffix
='.zstream') as output
:
1697 fd
= output
.fileno()
1698 with self
.assertRaises(lzc_exc
.SnapshotNotFound
) as ctx
:
1699 lzc
.lzc_send(snap1
, snap2
, fd
)
1700 self
.assertEqual(ctx
.exception
.name
, snap1
)
1702 with self
.assertRaises(lzc_exc
.SnapshotNotFound
) as ctx
:
1703 lzc
.lzc_send(snap2
, snap1
, fd
)
1704 self
.assertEqual(ctx
.exception
.name
, snap2
)
1706 with self
.assertRaises(lzc_exc
.SnapshotNotFound
) as ctx
:
1707 lzc
.lzc_send(snap2
, None, fd
)
1708 self
.assertEqual(ctx
.exception
.name
, snap2
)
1710 def test_send_invalid_name(self
):
1711 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1712 snap2
= ZFSTest
.pool
.makeName(b
"fs1@sn!p")
1714 lzc
.lzc_snapshot([snap1
])
1716 with tempfile
.TemporaryFile(suffix
='.zstream') as output
:
1717 fd
= output
.fileno()
1718 with self
.assertRaises(lzc_exc
.NameInvalid
) as ctx
:
1719 lzc
.lzc_send(snap2
, snap1
, fd
)
1720 self
.assertEqual(ctx
.exception
.name
, snap2
)
1721 with self
.assertRaises(lzc_exc
.NameInvalid
) as ctx
:
1722 lzc
.lzc_send(snap2
, None, fd
)
1723 self
.assertEqual(ctx
.exception
.name
, snap2
)
1724 with self
.assertRaises(lzc_exc
.NameInvalid
) as ctx
:
1725 lzc
.lzc_send(snap1
, snap2
, fd
)
1726 self
.assertEqual(ctx
.exception
.name
, snap2
)
1728 # XXX Although undocumented the API allows to create an incremental
1729 # or full stream for a filesystem as if a temporary unnamed snapshot
1730 # is taken at some time after the call is made and before the stream
1731 # starts being produced.
1732 def test_send_filesystem(self
):
1733 snap
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1734 fs
= ZFSTest
.pool
.makeName(b
"fs1")
1736 lzc
.lzc_snapshot([snap
])
1738 with tempfile
.TemporaryFile(suffix
='.zstream') as output
:
1739 fd
= output
.fileno()
1740 lzc
.lzc_send(fs
, snap
, fd
)
1741 lzc
.lzc_send(fs
, None, fd
)
1743 def test_send_from_filesystem(self
):
1744 snap
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1745 fs
= ZFSTest
.pool
.makeName(b
"fs1")
1747 lzc
.lzc_snapshot([snap
])
1749 with tempfile
.TemporaryFile(suffix
='.zstream') as output
:
1750 fd
= output
.fileno()
1751 with self
.assertRaises(lzc_exc
.NameInvalid
):
1752 lzc
.lzc_send(snap
, fs
, fd
)
1754 @skipUnlessBookmarksSupported
1755 def test_send_bookmark(self
):
1756 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1757 snap2
= ZFSTest
.pool
.makeName(b
"fs1@snap2")
1758 bmark
= ZFSTest
.pool
.makeName(b
"fs1#bmark")
1760 lzc
.lzc_snapshot([snap1
])
1761 lzc
.lzc_snapshot([snap2
])
1762 lzc
.lzc_bookmark({bmark
: snap2
})
1763 lzc
.lzc_destroy_snaps([snap2
], defer
=False)
1765 with tempfile
.TemporaryFile(suffix
='.zstream') as output
:
1766 fd
= output
.fileno()
1767 with self
.assertRaises(lzc_exc
.NameInvalid
):
1768 lzc
.lzc_send(bmark
, snap1
, fd
)
1769 with self
.assertRaises(lzc_exc
.NameInvalid
):
1770 lzc
.lzc_send(bmark
, None, fd
)
1772 @skipUnlessBookmarksSupported
1773 def test_send_from_bookmark(self
):
1774 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1775 snap2
= ZFSTest
.pool
.makeName(b
"fs1@snap2")
1776 bmark
= ZFSTest
.pool
.makeName(b
"fs1#bmark")
1778 lzc
.lzc_snapshot([snap1
])
1779 lzc
.lzc_snapshot([snap2
])
1780 lzc
.lzc_bookmark({bmark
: snap1
})
1781 lzc
.lzc_destroy_snaps([snap1
], defer
=False)
1783 with tempfile
.TemporaryFile(suffix
='.zstream') as output
:
1784 fd
= output
.fileno()
1785 lzc
.lzc_send(snap2
, bmark
, fd
)
1787 def test_send_bad_fd(self
):
1788 snap
= ZFSTest
.pool
.makeName(b
"fs1@snap")
1789 lzc
.lzc_snapshot([snap
])
1791 with tempfile
.TemporaryFile() as tmp
:
1792 bad_fd
= tmp
.fileno()
1794 with self
.assertRaises(lzc_exc
.StreamIOError
) as ctx
:
1795 lzc
.lzc_send(snap
, None, bad_fd
)
1796 self
.assertEqual(ctx
.exception
.errno
, errno
.EBADF
)
1798 def test_send_bad_fd_2(self
):
1799 snap
= ZFSTest
.pool
.makeName(b
"fs1@snap")
1800 lzc
.lzc_snapshot([snap
])
1802 with self
.assertRaises(lzc_exc
.StreamIOError
) as ctx
:
1803 lzc
.lzc_send(snap
, None, -2)
1804 self
.assertEqual(ctx
.exception
.errno
, errno
.EBADF
)
1806 def test_send_bad_fd_3(self
):
1807 snap
= ZFSTest
.pool
.makeName(b
"fs1@snap")
1808 lzc
.lzc_snapshot([snap
])
1810 with tempfile
.TemporaryFile() as tmp
:
1811 bad_fd
= tmp
.fileno()
1813 (soft
, hard
) = resource
.getrlimit(resource
.RLIMIT_NOFILE
)
1815 with self
.assertRaises(lzc_exc
.StreamIOError
) as ctx
:
1816 lzc
.lzc_send(snap
, None, bad_fd
)
1817 self
.assertEqual(ctx
.exception
.errno
, errno
.EBADF
)
1819 def test_send_to_broken_pipe(self
):
1820 snap
= ZFSTest
.pool
.makeName(b
"fs1@snap")
1821 lzc
.lzc_snapshot([snap
])
1823 if sys
.version_info
< (3, 0):
1824 proc
= subprocess
.Popen(['true'], stdin
=subprocess
.PIPE
)
1826 with self
.assertRaises(lzc_exc
.StreamIOError
) as ctx
:
1827 lzc
.lzc_send(snap
, None, proc
.stdin
.fileno())
1828 self
.assertEqual(ctx
.exception
.errno
, errno
.EPIPE
)
1830 with subprocess
.Popen(['true'], stdin
=subprocess
.PIPE
) as proc
:
1832 with self
.assertRaises(lzc_exc
.StreamIOError
) as ctx
:
1833 lzc
.lzc_send(snap
, None, proc
.stdin
.fileno())
1834 self
.assertEqual(ctx
.exception
.errno
, errno
.EPIPE
)
1836 def test_send_to_broken_pipe_2(self
):
1837 snap
= ZFSTest
.pool
.makeName(b
"fs1@snap")
1838 with
zfs_mount(ZFSTest
.pool
.makeName(b
"fs1")) as mntdir
:
1839 with tempfile
.NamedTemporaryFile(dir=mntdir
) as f
:
1840 for i
in range(1024):
1841 f
.write(b
'x' * 1024)
1843 lzc
.lzc_snapshot([snap
])
1845 if sys
.version_info
< (3, 0):
1846 p
= subprocess
.Popen(['sleep', '2'], stdin
=subprocess
.PIPE
)
1847 with self
.assertRaises(lzc_exc
.StreamIOError
) as ctx
:
1848 lzc
.lzc_send(snap
, None, p
.stdin
.fileno())
1849 self
.assertTrue(ctx
.exception
.errno
== errno
.EPIPE
or
1850 ctx
.exception
.errno
== errno
.EINTR
)
1852 with subprocess
.Popen(['sleep', '2'], stdin
=subprocess
.PIPE
) as p
:
1853 with self
.assertRaises(lzc_exc
.StreamIOError
) as ctx
:
1854 lzc
.lzc_send(snap
, None, p
.stdin
.fileno())
1855 self
.assertTrue(ctx
.exception
.errno
== errno
.EPIPE
or
1856 ctx
.exception
.errno
== errno
.EINTR
)
1858 def test_send_to_ro_file(self
):
1859 snap
= ZFSTest
.pool
.makeName(b
"fs1@snap")
1860 lzc
.lzc_snapshot([snap
])
1862 with tempfile
.NamedTemporaryFile(
1863 suffix
='.zstream', delete
=False) as output
:
1864 # tempfile always opens a temporary file in read-write mode
1865 # regardless of the specified mode, so we have to open it again.
1866 os
.chmod(output
.name
, stat
.S_IRUSR
)
1867 fd
= os
.open(output
.name
, os
.O_RDONLY
)
1868 with self
.assertRaises(lzc_exc
.StreamIOError
) as ctx
:
1869 lzc
.lzc_send(snap
, None, fd
)
1871 self
.assertEqual(ctx
.exception
.errno
, errno
.EBADF
)
1873 def test_recv_full(self
):
1874 src
= ZFSTest
.pool
.makeName(b
"fs1@snap")
1875 dst
= ZFSTest
.pool
.makeName(b
"fs2/received-1@snap")
1877 with
temp_file_in_fs(ZFSTest
.pool
.makeName(b
"fs1")) as name
:
1878 lzc
.lzc_snapshot([src
])
1880 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
1881 lzc
.lzc_send(src
, None, stream
.fileno())
1883 lzc
.lzc_receive(dst
, stream
.fileno())
1885 name
= os
.path
.basename(name
)
1886 with
zfs_mount(src
) as mnt1
, zfs_mount(dst
) as mnt2
:
1889 os
.path
.join(mnt1
, name
), os
.path
.join(mnt2
, name
), False))
1891 def test_recv_incremental(self
):
1892 src1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
1893 src2
= ZFSTest
.pool
.makeName(b
"fs1@snap2")
1894 dst1
= ZFSTest
.pool
.makeName(b
"fs2/received-2@snap1")
1895 dst2
= ZFSTest
.pool
.makeName(b
"fs2/received-2@snap2")
1897 lzc
.lzc_snapshot([src1
])
1898 with
temp_file_in_fs(ZFSTest
.pool
.makeName(b
"fs1")) as name
:
1899 lzc
.lzc_snapshot([src2
])
1901 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
1902 lzc
.lzc_send(src1
, None, stream
.fileno())
1904 lzc
.lzc_receive(dst1
, stream
.fileno())
1905 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
1906 lzc
.lzc_send(src2
, src1
, stream
.fileno())
1908 lzc
.lzc_receive(dst2
, stream
.fileno())
1910 name
= os
.path
.basename(name
)
1911 with
zfs_mount(src2
) as mnt1
, zfs_mount(dst2
) as mnt2
:
1914 os
.path
.join(mnt1
, name
), os
.path
.join(mnt2
, name
), False))
1916 # This test case fails unless unless a patch from
1917 # https://clusterhq.atlassian.net/browse/ZFS-20
1918 # is applied to libzfs_core, otherwise it succeeds.
1919 @unittest.skip("fails with unpatched libzfs_core")
1920 def test_recv_without_explicit_snap_name(self
):
1921 srcfs
= ZFSTest
.pool
.makeName(b
"fs1")
1922 src1
= srcfs
+ b
"@snap1"
1923 src2
= srcfs
+ b
"@snap2"
1924 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-100")
1925 dst1
= dstfs
+ b
'@snap1'
1926 dst2
= dstfs
+ b
'@snap2'
1928 with
streams(srcfs
, src1
, src2
) as (_
, (full
, incr
)):
1929 lzc
.lzc_receive(dstfs
, full
.fileno())
1930 lzc
.lzc_receive(dstfs
, incr
.fileno())
1931 self
.assertExists(dst1
)
1932 self
.assertExists(dst2
)
1934 def test_recv_clone(self
):
1935 orig_src
= ZFSTest
.pool
.makeName(b
"fs2@send-origin")
1936 clone
= ZFSTest
.pool
.makeName(b
"fs1/fs/send-clone")
1937 clone_snap
= clone
+ b
"@snap"
1938 orig_dst
= ZFSTest
.pool
.makeName(b
"fs1/fs/recv-origin@snap")
1939 clone_dst
= ZFSTest
.pool
.makeName(b
"fs1/fs/recv-clone@snap")
1941 lzc
.lzc_snapshot([orig_src
])
1942 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
1943 lzc
.lzc_send(orig_src
, None, stream
.fileno())
1945 lzc
.lzc_receive(orig_dst
, stream
.fileno())
1947 lzc
.lzc_clone(clone
, orig_src
)
1948 lzc
.lzc_snapshot([clone_snap
])
1949 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
1950 lzc
.lzc_send(clone_snap
, orig_src
, stream
.fileno())
1952 lzc
.lzc_receive(clone_dst
, stream
.fileno(), origin
=orig_dst
)
1954 def test_recv_full_already_existing_empty_fs(self
):
1955 src
= ZFSTest
.pool
.makeName(b
"fs1@snap")
1956 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-3")
1957 dst
= dstfs
+ b
'@snap'
1959 with
temp_file_in_fs(ZFSTest
.pool
.makeName(b
"fs1")):
1960 lzc
.lzc_snapshot([src
])
1961 lzc
.lzc_create(dstfs
)
1962 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
1963 lzc
.lzc_send(src
, None, stream
.fileno())
1965 with self
.assertRaises((
1966 lzc_exc
.DestinationModified
, lzc_exc
.DatasetExists
)):
1967 lzc
.lzc_receive(dst
, stream
.fileno())
1969 def test_recv_full_into_root_empty_pool(self
):
1972 srcfs
= ZFSTest
.pool
.makeName(b
"fs1")
1973 empty_pool
= _TempPool()
1974 dst
= empty_pool
.makeName(b
'@snap')
1976 with
streams(srcfs
, b
"snap", None) as (_
, (stream
, _
)):
1977 with self
.assertRaises((
1978 lzc_exc
.DestinationModified
, lzc_exc
.DatasetExists
)):
1979 lzc
.lzc_receive(dst
, stream
.fileno())
1981 if empty_pool
is not None:
1982 empty_pool
.cleanUp()
1984 def test_recv_full_into_ro_pool(self
):
1985 srcfs
= ZFSTest
.pool
.makeName(b
"fs1")
1986 dst
= ZFSTest
.readonly_pool
.makeName(b
'fs2/received@snap')
1988 with
streams(srcfs
, b
"snap", None) as (_
, (stream
, _
)):
1989 with self
.assertRaises(lzc_exc
.ReadOnlyPool
):
1990 lzc
.lzc_receive(dst
, stream
.fileno())
1992 def test_recv_full_already_existing_modified_fs(self
):
1993 src
= ZFSTest
.pool
.makeName(b
"fs1@snap")
1994 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-5")
1995 dst
= dstfs
+ b
'@snap'
1997 with
temp_file_in_fs(ZFSTest
.pool
.makeName(b
"fs1")):
1998 lzc
.lzc_snapshot([src
])
1999 lzc
.lzc_create(dstfs
)
2000 with
temp_file_in_fs(dstfs
):
2001 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2002 lzc
.lzc_send(src
, None, stream
.fileno())
2004 with self
.assertRaises((
2005 lzc_exc
.DestinationModified
, lzc_exc
.DatasetExists
)):
2006 lzc
.lzc_receive(dst
, stream
.fileno())
2008 def test_recv_full_already_existing_with_snapshots(self
):
2009 src
= ZFSTest
.pool
.makeName(b
"fs1@snap")
2010 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-4")
2011 dst
= dstfs
+ b
'@snap'
2013 with
temp_file_in_fs(ZFSTest
.pool
.makeName(b
"fs1")):
2014 lzc
.lzc_snapshot([src
])
2015 lzc
.lzc_create(dstfs
)
2016 lzc
.lzc_snapshot([dstfs
+ b
"@snap1"])
2017 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2018 lzc
.lzc_send(src
, None, stream
.fileno())
2020 with self
.assertRaises((
2021 lzc_exc
.StreamMismatch
, lzc_exc
.DatasetExists
)):
2022 lzc
.lzc_receive(dst
, stream
.fileno())
2024 def test_recv_full_already_existing_snapshot(self
):
2025 src
= ZFSTest
.pool
.makeName(b
"fs1@snap")
2026 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-6")
2027 dst
= dstfs
+ b
'@snap'
2029 with
temp_file_in_fs(ZFSTest
.pool
.makeName(b
"fs1")):
2030 lzc
.lzc_snapshot([src
])
2031 lzc
.lzc_create(dstfs
)
2032 lzc
.lzc_snapshot([dst
])
2033 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2034 lzc
.lzc_send(src
, None, stream
.fileno())
2036 with self
.assertRaises(lzc_exc
.DatasetExists
):
2037 lzc
.lzc_receive(dst
, stream
.fileno())
2039 def test_recv_full_missing_parent_fs(self
):
2040 src
= ZFSTest
.pool
.makeName(b
"fs1@snap")
2041 dst
= ZFSTest
.pool
.makeName(b
"fs2/nonexistent/fs@snap")
2043 with
temp_file_in_fs(ZFSTest
.pool
.makeName(b
"fs1")):
2044 lzc
.lzc_snapshot([src
])
2045 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2046 lzc
.lzc_send(src
, None, stream
.fileno())
2048 with self
.assertRaises(lzc_exc
.DatasetNotFound
):
2049 lzc
.lzc_receive(dst
, stream
.fileno())
2051 def test_recv_full_but_specify_origin(self
):
2052 srcfs
= ZFSTest
.pool
.makeName(b
"fs1")
2053 src
= srcfs
+ b
"@snap"
2054 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-30")
2055 dst
= dstfs
+ b
'@snap'
2056 origin1
= ZFSTest
.pool
.makeName(b
"fs2@snap1")
2057 origin2
= ZFSTest
.pool
.makeName(b
"fs2@snap2")
2059 lzc
.lzc_snapshot([origin1
])
2060 with
streams(srcfs
, src
, None) as (_
, (stream
, _
)):
2061 lzc
.lzc_receive(dst
, stream
.fileno(), origin
=origin1
)
2062 origin
= ZFSTest
.pool
.getFilesystem(
2063 b
"fs2/received-30").getProperty('origin')
2064 self
.assertEqual(origin
, origin1
)
2066 # because origin snap does not exist can't receive as a clone of it
2067 with self
.assertRaises((
2068 lzc_exc
.DatasetNotFound
,
2069 lzc_exc
.BadStream
)):
2070 lzc
.lzc_receive(dst
, stream
.fileno(), origin
=origin2
)
2072 def test_recv_full_existing_empty_fs_and_origin(self
):
2073 srcfs
= ZFSTest
.pool
.makeName(b
"fs1")
2074 src
= srcfs
+ b
"@snap"
2075 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-31")
2076 dst
= dstfs
+ b
'@snap'
2077 origin
= dstfs
+ b
'@dummy'
2079 lzc
.lzc_create(dstfs
)
2080 with
streams(srcfs
, src
, None) as (_
, (stream
, _
)):
2081 # because the destination fs already exists and has no snaps
2082 with self
.assertRaises((
2083 lzc_exc
.DestinationModified
,
2084 lzc_exc
.DatasetExists
,
2085 lzc_exc
.BadStream
)):
2086 lzc
.lzc_receive(dst
, stream
.fileno(), origin
=origin
)
2087 lzc
.lzc_snapshot([origin
])
2089 # because the destination fs already exists and has the snap
2090 with self
.assertRaises((
2091 lzc_exc
.StreamMismatch
,
2092 lzc_exc
.DatasetExists
,
2093 lzc_exc
.BadStream
)):
2094 lzc
.lzc_receive(dst
, stream
.fileno(), origin
=origin
)
2096 def test_recv_incremental_mounted_fs(self
):
2097 srcfs
= ZFSTest
.pool
.makeName(b
"fs1")
2098 src1
= srcfs
+ b
"@snap1"
2099 src2
= srcfs
+ b
"@snap2"
2100 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-7")
2101 dst1
= dstfs
+ b
'@snap1'
2102 dst2
= dstfs
+ b
'@snap2'
2104 with
streams(srcfs
, src1
, src2
) as (_
, (full
, incr
)):
2105 lzc
.lzc_receive(dst1
, full
.fileno())
2106 with
zfs_mount(dstfs
):
2107 lzc
.lzc_receive(dst2
, incr
.fileno())
2109 def test_recv_incremental_modified_fs(self
):
2110 srcfs
= ZFSTest
.pool
.makeName(b
"fs1")
2111 src1
= srcfs
+ b
"@snap1"
2112 src2
= srcfs
+ b
"@snap2"
2113 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-15")
2114 dst1
= dstfs
+ b
'@snap1'
2115 dst2
= dstfs
+ b
'@snap2'
2117 with
streams(srcfs
, src1
, src2
) as (_
, (full
, incr
)):
2118 lzc
.lzc_receive(dst1
, full
.fileno())
2119 with
temp_file_in_fs(dstfs
):
2120 with self
.assertRaises(lzc_exc
.DestinationModified
):
2121 lzc
.lzc_receive(dst2
, incr
.fileno())
2123 def test_recv_incremental_snapname_used(self
):
2124 srcfs
= ZFSTest
.pool
.makeName(b
"fs1")
2125 src1
= srcfs
+ b
"@snap1"
2126 src2
= srcfs
+ b
"@snap2"
2127 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-8")
2128 dst1
= dstfs
+ b
'@snap1'
2129 dst2
= dstfs
+ b
'@snap2'
2131 with
streams(srcfs
, src1
, src2
) as (_
, (full
, incr
)):
2132 lzc
.lzc_receive(dst1
, full
.fileno())
2133 lzc
.lzc_snapshot([dst2
])
2134 with self
.assertRaises(lzc_exc
.DatasetExists
):
2135 lzc
.lzc_receive(dst2
, incr
.fileno())
2137 def test_recv_incremental_more_recent_snap_with_no_changes(self
):
2138 srcfs
= ZFSTest
.pool
.makeName(b
"fs1")
2139 src1
= srcfs
+ b
"@snap1"
2140 src2
= srcfs
+ b
"@snap2"
2141 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-9")
2142 dst1
= dstfs
+ b
'@snap1'
2143 dst2
= dstfs
+ b
'@snap2'
2144 dst_snap
= dstfs
+ b
'@snap'
2146 with
streams(srcfs
, src1
, src2
) as (_
, (full
, incr
)):
2147 lzc
.lzc_receive(dst1
, full
.fileno())
2148 lzc
.lzc_snapshot([dst_snap
])
2149 lzc
.lzc_receive(dst2
, incr
.fileno())
2151 def test_recv_incremental_non_clone_but_set_origin(self
):
2152 srcfs
= ZFSTest
.pool
.makeName(b
"fs1")
2153 src1
= srcfs
+ b
"@snap1"
2154 src2
= srcfs
+ b
"@snap2"
2155 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-20")
2156 dst1
= dstfs
+ b
'@snap1'
2157 dst2
= dstfs
+ b
'@snap2'
2158 dst_snap
= dstfs
+ b
'@snap'
2160 with
streams(srcfs
, src1
, src2
) as (_
, (full
, incr
)):
2161 lzc
.lzc_receive(dst1
, full
.fileno())
2162 lzc
.lzc_snapshot([dst_snap
])
2163 # becase cannot receive incremental and set origin on a non-clone
2164 with self
.assertRaises(lzc_exc
.BadStream
):
2165 lzc
.lzc_receive(dst2
, incr
.fileno(), origin
=dst1
)
2167 def test_recv_incremental_non_clone_but_set_random_origin(self
):
2168 srcfs
= ZFSTest
.pool
.makeName(b
"fs1")
2169 src1
= srcfs
+ b
"@snap1"
2170 src2
= srcfs
+ b
"@snap2"
2171 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-21")
2172 dst1
= dstfs
+ b
'@snap1'
2173 dst2
= dstfs
+ b
'@snap2'
2174 dst_snap
= dstfs
+ b
'@snap'
2176 with
streams(srcfs
, src1
, src2
) as (_
, (full
, incr
)):
2177 lzc
.lzc_receive(dst1
, full
.fileno())
2178 lzc
.lzc_snapshot([dst_snap
])
2179 # because origin snap does not exist can't receive as a clone of it
2180 with self
.assertRaises((
2181 lzc_exc
.DatasetNotFound
,
2182 lzc_exc
.BadStream
)):
2184 dst2
, incr
.fileno(),
2185 origin
=ZFSTest
.pool
.makeName(b
"fs2/fs@snap"))
2187 def test_recv_incremental_more_recent_snap(self
):
2188 srcfs
= ZFSTest
.pool
.makeName(b
"fs1")
2189 src1
= srcfs
+ b
"@snap1"
2190 src2
= srcfs
+ b
"@snap2"
2191 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-10")
2192 dst1
= dstfs
+ b
'@snap1'
2193 dst2
= dstfs
+ b
'@snap2'
2194 dst_snap
= dstfs
+ b
'@snap'
2196 with
streams(srcfs
, src1
, src2
) as (_
, (full
, incr
)):
2197 lzc
.lzc_receive(dst1
, full
.fileno())
2198 with
temp_file_in_fs(dstfs
):
2199 lzc
.lzc_snapshot([dst_snap
])
2200 with self
.assertRaises(lzc_exc
.DestinationModified
):
2201 lzc
.lzc_receive(dst2
, incr
.fileno())
2203 def test_recv_incremental_duplicate(self
):
2204 srcfs
= ZFSTest
.pool
.makeName(b
"fs1")
2205 src1
= srcfs
+ b
"@snap1"
2206 src2
= srcfs
+ b
"@snap2"
2207 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-11")
2208 dst1
= dstfs
+ b
'@snap1'
2209 dst2
= dstfs
+ b
'@snap2'
2210 dst_snap
= dstfs
+ b
'@snap'
2212 with
streams(srcfs
, src1
, src2
) as (_
, (full
, incr
)):
2213 lzc
.lzc_receive(dst1
, full
.fileno())
2214 lzc
.lzc_receive(dst2
, incr
.fileno())
2216 with self
.assertRaises(lzc_exc
.DestinationModified
):
2217 lzc
.lzc_receive(dst_snap
, incr
.fileno())
2219 def test_recv_incremental_unrelated_fs(self
):
2220 srcfs
= ZFSTest
.pool
.makeName(b
"fs1")
2221 src1
= srcfs
+ b
"@snap1"
2222 src2
= srcfs
+ b
"@snap2"
2223 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-12")
2224 dst_snap
= dstfs
+ b
'@snap'
2226 with
streams(srcfs
, src1
, src2
) as (_
, (_
, incr
)):
2227 lzc
.lzc_create(dstfs
)
2228 with self
.assertRaises(lzc_exc
.StreamMismatch
):
2229 lzc
.lzc_receive(dst_snap
, incr
.fileno())
2231 def test_recv_incremental_nonexistent_fs(self
):
2232 srcfs
= ZFSTest
.pool
.makeName(b
"fs1")
2233 src1
= srcfs
+ b
"@snap1"
2234 src2
= srcfs
+ b
"@snap2"
2235 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-13")
2236 dst_snap
= dstfs
+ b
'@snap'
2238 with
streams(srcfs
, src1
, src2
) as (_
, (_
, incr
)):
2239 with self
.assertRaises(lzc_exc
.DatasetNotFound
):
2240 lzc
.lzc_receive(dst_snap
, incr
.fileno())
2242 def test_recv_incremental_same_fs(self
):
2243 srcfs
= ZFSTest
.pool
.makeName(b
"fs1")
2244 src1
= srcfs
+ b
"@snap1"
2245 src2
= srcfs
+ b
"@snap2"
2246 src_snap
= srcfs
+ b
'@snap'
2248 with
streams(srcfs
, src1
, src2
) as (_
, (_
, incr
)):
2249 with self
.assertRaises(lzc_exc
.DestinationModified
):
2250 lzc
.lzc_receive(src_snap
, incr
.fileno())
2252 def test_recv_clone_without_specifying_origin(self
):
2253 orig_src
= ZFSTest
.pool
.makeName(b
"fs2@send-origin-2")
2254 clone
= ZFSTest
.pool
.makeName(b
"fs1/fs/send-clone-2")
2255 clone_snap
= clone
+ b
"@snap"
2256 orig_dst
= ZFSTest
.pool
.makeName(b
"fs1/fs/recv-origin-2@snap")
2257 clone_dst
= ZFSTest
.pool
.makeName(b
"fs1/fs/recv-clone-2@snap")
2259 lzc
.lzc_snapshot([orig_src
])
2260 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2261 lzc
.lzc_send(orig_src
, None, stream
.fileno())
2263 lzc
.lzc_receive(orig_dst
, stream
.fileno())
2265 lzc
.lzc_clone(clone
, orig_src
)
2266 lzc
.lzc_snapshot([clone_snap
])
2267 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2268 lzc
.lzc_send(clone_snap
, orig_src
, stream
.fileno())
2270 with self
.assertRaises(lzc_exc
.BadStream
):
2271 lzc
.lzc_receive(clone_dst
, stream
.fileno())
2273 def test_recv_clone_invalid_origin(self
):
2274 orig_src
= ZFSTest
.pool
.makeName(b
"fs2@send-origin-3")
2275 clone
= ZFSTest
.pool
.makeName(b
"fs1/fs/send-clone-3")
2276 clone_snap
= clone
+ b
"@snap"
2277 orig_dst
= ZFSTest
.pool
.makeName(b
"fs1/fs/recv-origin-3@snap")
2278 clone_dst
= ZFSTest
.pool
.makeName(b
"fs1/fs/recv-clone-3@snap")
2280 lzc
.lzc_snapshot([orig_src
])
2281 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2282 lzc
.lzc_send(orig_src
, None, stream
.fileno())
2284 lzc
.lzc_receive(orig_dst
, stream
.fileno())
2286 lzc
.lzc_clone(clone
, orig_src
)
2287 lzc
.lzc_snapshot([clone_snap
])
2288 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2289 lzc
.lzc_send(clone_snap
, orig_src
, stream
.fileno())
2291 with self
.assertRaises(lzc_exc
.NameInvalid
):
2293 clone_dst
, stream
.fileno(),
2294 origin
=ZFSTest
.pool
.makeName(b
"fs1/fs"))
2296 def test_recv_clone_wrong_origin(self
):
2297 orig_src
= ZFSTest
.pool
.makeName(b
"fs2@send-origin-4")
2298 clone
= ZFSTest
.pool
.makeName(b
"fs1/fs/send-clone-4")
2299 clone_snap
= clone
+ b
"@snap"
2300 orig_dst
= ZFSTest
.pool
.makeName(b
"fs1/fs/recv-origin-4@snap")
2301 clone_dst
= ZFSTest
.pool
.makeName(b
"fs1/fs/recv-clone-4@snap")
2302 wrong_origin
= ZFSTest
.pool
.makeName(b
"fs1/fs@snap")
2304 lzc
.lzc_snapshot([orig_src
])
2305 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2306 lzc
.lzc_send(orig_src
, None, stream
.fileno())
2308 lzc
.lzc_receive(orig_dst
, stream
.fileno())
2310 lzc
.lzc_clone(clone
, orig_src
)
2311 lzc
.lzc_snapshot([clone_snap
])
2312 lzc
.lzc_snapshot([wrong_origin
])
2313 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2314 lzc
.lzc_send(clone_snap
, orig_src
, stream
.fileno())
2316 with self
.assertRaises(lzc_exc
.StreamMismatch
):
2318 clone_dst
, stream
.fileno(), origin
=wrong_origin
)
2320 def test_recv_clone_nonexistent_origin(self
):
2321 orig_src
= ZFSTest
.pool
.makeName(b
"fs2@send-origin-5")
2322 clone
= ZFSTest
.pool
.makeName(b
"fs1/fs/send-clone-5")
2323 clone_snap
= clone
+ b
"@snap"
2324 orig_dst
= ZFSTest
.pool
.makeName(b
"fs1/fs/recv-origin-5@snap")
2325 clone_dst
= ZFSTest
.pool
.makeName(b
"fs1/fs/recv-clone-5@snap")
2326 wrong_origin
= ZFSTest
.pool
.makeName(b
"fs1/fs@snap")
2328 lzc
.lzc_snapshot([orig_src
])
2329 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2330 lzc
.lzc_send(orig_src
, None, stream
.fileno())
2332 lzc
.lzc_receive(orig_dst
, stream
.fileno())
2334 lzc
.lzc_clone(clone
, orig_src
)
2335 lzc
.lzc_snapshot([clone_snap
])
2336 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2337 lzc
.lzc_send(clone_snap
, orig_src
, stream
.fileno())
2339 with self
.assertRaises(lzc_exc
.DatasetNotFound
):
2341 clone_dst
, stream
.fileno(), origin
=wrong_origin
)
2343 def test_force_recv_full_existing_fs(self
):
2344 src
= ZFSTest
.pool
.makeName(b
"fs1@snap")
2345 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-50")
2346 dst
= dstfs
+ b
'@snap'
2348 with
temp_file_in_fs(ZFSTest
.pool
.makeName(b
"fs1")):
2349 lzc
.lzc_snapshot([src
])
2351 lzc
.lzc_create(dstfs
)
2352 with
temp_file_in_fs(dstfs
):
2353 pass # enough to taint the fs
2355 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2356 lzc
.lzc_send(src
, None, stream
.fileno())
2358 lzc
.lzc_receive(dst
, stream
.fileno(), force
=True)
2360 def test_force_recv_full_existing_modified_mounted_fs(self
):
2361 src
= ZFSTest
.pool
.makeName(b
"fs1@snap")
2362 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-53")
2363 dst
= dstfs
+ b
'@snap'
2365 with
temp_file_in_fs(ZFSTest
.pool
.makeName(b
"fs1")):
2366 lzc
.lzc_snapshot([src
])
2368 lzc
.lzc_create(dstfs
)
2370 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2371 lzc
.lzc_send(src
, None, stream
.fileno())
2373 with
zfs_mount(dstfs
) as mntdir
:
2374 f
= tempfile
.NamedTemporaryFile(dir=mntdir
, delete
=False)
2375 for i
in range(1024):
2376 f
.write(b
'x' * 1024)
2377 lzc
.lzc_receive(dst
, stream
.fileno(), force
=True)
2378 # The temporary file dissappears and any access, even close(),
2380 self
.assertFalse(os
.path
.exists(f
.name
))
2381 with self
.assertRaises(IOError):
2384 # This test-case expects the behavior that should be there,
2385 # at the moment it may fail with DatasetExists or StreamMismatch
2386 # depending on the implementation.
2387 def test_force_recv_full_already_existing_with_snapshots(self
):
2388 src
= ZFSTest
.pool
.makeName(b
"fs1@snap")
2389 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-51")
2390 dst
= dstfs
+ b
'@snap'
2392 with
temp_file_in_fs(ZFSTest
.pool
.makeName(b
"fs1")):
2393 lzc
.lzc_snapshot([src
])
2395 lzc
.lzc_create(dstfs
)
2396 with
temp_file_in_fs(dstfs
):
2397 pass # enough to taint the fs
2398 lzc
.lzc_snapshot([dstfs
+ b
"@snap1"])
2400 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2401 lzc
.lzc_send(src
, None, stream
.fileno())
2403 lzc
.lzc_receive(dst
, stream
.fileno(), force
=True)
2405 def test_force_recv_full_already_existing_with_same_snap(self
):
2406 src
= ZFSTest
.pool
.makeName(b
"fs1@snap")
2407 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-52")
2408 dst
= dstfs
+ b
'@snap'
2410 with
temp_file_in_fs(ZFSTest
.pool
.makeName(b
"fs1")):
2411 lzc
.lzc_snapshot([src
])
2413 lzc
.lzc_create(dstfs
)
2414 with
temp_file_in_fs(dstfs
):
2415 pass # enough to taint the fs
2416 lzc
.lzc_snapshot([dst
])
2418 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2419 lzc
.lzc_send(src
, None, stream
.fileno())
2421 with self
.assertRaises(lzc_exc
.DatasetExists
):
2422 lzc
.lzc_receive(dst
, stream
.fileno(), force
=True)
2424 def test_force_recv_full_missing_parent_fs(self
):
2425 src
= ZFSTest
.pool
.makeName(b
"fs1@snap")
2426 dst
= ZFSTest
.pool
.makeName(b
"fs2/nonexistent/fs@snap")
2428 with
temp_file_in_fs(ZFSTest
.pool
.makeName(b
"fs1")):
2429 lzc
.lzc_snapshot([src
])
2430 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2431 lzc
.lzc_send(src
, None, stream
.fileno())
2433 with self
.assertRaises(lzc_exc
.DatasetNotFound
):
2434 lzc
.lzc_receive(dst
, stream
.fileno(), force
=True)
2436 def test_force_recv_incremental_modified_fs(self
):
2437 srcfs
= ZFSTest
.pool
.makeName(b
"fs1")
2438 src1
= srcfs
+ b
"@snap1"
2439 src2
= srcfs
+ b
"@snap2"
2440 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-60")
2441 dst1
= dstfs
+ b
'@snap1'
2442 dst2
= dstfs
+ b
'@snap2'
2444 with
streams(srcfs
, src1
, src2
) as (_
, (full
, incr
)):
2445 lzc
.lzc_receive(dst1
, full
.fileno())
2446 with
temp_file_in_fs(dstfs
):
2447 pass # enough to taint the fs
2448 lzc
.lzc_receive(dst2
, incr
.fileno(), force
=True)
2450 def test_force_recv_incremental_modified_mounted_fs(self
):
2451 srcfs
= ZFSTest
.pool
.makeName(b
"fs1")
2452 src1
= srcfs
+ b
"@snap1"
2453 src2
= srcfs
+ b
"@snap2"
2454 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-64")
2455 dst1
= dstfs
+ b
'@snap1'
2456 dst2
= dstfs
+ b
'@snap2'
2458 with
streams(srcfs
, src1
, src2
) as (_
, (full
, incr
)):
2459 lzc
.lzc_receive(dst1
, full
.fileno())
2460 with
zfs_mount(dstfs
) as mntdir
:
2461 f
= tempfile
.NamedTemporaryFile(dir=mntdir
, delete
=False)
2462 for i
in range(1024):
2463 f
.write(b
'x' * 1024)
2464 lzc
.lzc_receive(dst2
, incr
.fileno(), force
=True)
2465 # The temporary file dissappears and any access, even close(),
2467 self
.assertFalse(os
.path
.exists(f
.name
))
2468 with self
.assertRaises(IOError):
2471 def test_force_recv_incremental_modified_fs_plus_later_snap(self
):
2472 srcfs
= ZFSTest
.pool
.makeName(b
"fs1")
2473 src1
= srcfs
+ b
"@snap1"
2474 src2
= srcfs
+ b
"@snap2"
2475 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-61")
2476 dst1
= dstfs
+ b
'@snap1'
2477 dst2
= dstfs
+ b
'@snap2'
2478 dst3
= dstfs
+ b
'@snap'
2480 with
streams(srcfs
, src1
, src2
) as (_
, (full
, incr
)):
2481 lzc
.lzc_receive(dst1
, full
.fileno())
2482 with
temp_file_in_fs(dstfs
):
2483 pass # enough to taint the fs
2484 lzc
.lzc_snapshot([dst3
])
2485 lzc
.lzc_receive(dst2
, incr
.fileno(), force
=True)
2486 self
.assertExists(dst1
)
2487 self
.assertExists(dst2
)
2488 self
.assertNotExists(dst3
)
2490 def test_force_recv_incremental_modified_fs_plus_same_name_snap(self
):
2491 srcfs
= ZFSTest
.pool
.makeName(b
"fs1")
2492 src1
= srcfs
+ b
"@snap1"
2493 src2
= srcfs
+ b
"@snap2"
2494 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-62")
2495 dst1
= dstfs
+ b
'@snap1'
2496 dst2
= dstfs
+ b
'@snap2'
2498 with
streams(srcfs
, src1
, src2
) as (_
, (full
, incr
)):
2499 lzc
.lzc_receive(dst1
, full
.fileno())
2500 with
temp_file_in_fs(dstfs
):
2501 pass # enough to taint the fs
2502 lzc
.lzc_snapshot([dst2
])
2503 with self
.assertRaises(lzc_exc
.DatasetExists
):
2504 lzc
.lzc_receive(dst2
, incr
.fileno(), force
=True)
2506 def test_force_recv_incremental_modified_fs_plus_held_snap(self
):
2507 srcfs
= ZFSTest
.pool
.makeName(b
"fs1")
2508 src1
= srcfs
+ b
"@snap1"
2509 src2
= srcfs
+ b
"@snap2"
2510 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-63")
2511 dst1
= dstfs
+ b
'@snap1'
2512 dst2
= dstfs
+ b
'@snap2'
2513 dst3
= dstfs
+ b
'@snap'
2515 with
streams(srcfs
, src1
, src2
) as (_
, (full
, incr
)):
2516 lzc
.lzc_receive(dst1
, full
.fileno())
2517 with
temp_file_in_fs(dstfs
):
2518 pass # enough to taint the fs
2519 lzc
.lzc_snapshot([dst3
])
2520 with
cleanup_fd() as cfd
:
2521 lzc
.lzc_hold({dst3
: b
'tag'}, cfd
)
2522 with self
.assertRaises(lzc_exc
.DatasetBusy
):
2523 lzc
.lzc_receive(dst2
, incr
.fileno(), force
=True)
2524 self
.assertExists(dst1
)
2525 self
.assertNotExists(dst2
)
2526 self
.assertExists(dst3
)
2528 def test_force_recv_incremental_modified_fs_plus_cloned_snap(self
):
2529 srcfs
= ZFSTest
.pool
.makeName(b
"fs1")
2530 src1
= srcfs
+ b
"@snap1"
2531 src2
= srcfs
+ b
"@snap2"
2532 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-70")
2533 dst1
= dstfs
+ b
'@snap1'
2534 dst2
= dstfs
+ b
'@snap2'
2535 dst3
= dstfs
+ b
'@snap'
2536 cloned
= ZFSTest
.pool
.makeName(b
"fs2/received-cloned-70")
2538 with
streams(srcfs
, src1
, src2
) as (_
, (full
, incr
)):
2539 lzc
.lzc_receive(dst1
, full
.fileno())
2540 with
temp_file_in_fs(dstfs
):
2541 pass # enough to taint the fs
2542 lzc
.lzc_snapshot([dst3
])
2543 lzc
.lzc_clone(cloned
, dst3
)
2544 with self
.assertRaises(lzc_exc
.DatasetExists
):
2545 lzc
.lzc_receive(dst2
, incr
.fileno(), force
=True)
2546 self
.assertExists(dst1
)
2547 self
.assertNotExists(dst2
)
2548 self
.assertExists(dst3
)
2550 def test_recv_incremental_into_cloned_fs(self
):
2551 srcfs
= ZFSTest
.pool
.makeName(b
"fs1")
2552 src1
= srcfs
+ b
"@snap1"
2553 src2
= srcfs
+ b
"@snap2"
2554 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received-71")
2555 dst1
= dstfs
+ b
'@snap1'
2556 cloned
= ZFSTest
.pool
.makeName(b
"fs2/received-cloned-71")
2557 dst2
= cloned
+ b
'@snap'
2559 with
streams(srcfs
, src1
, src2
) as (_
, (full
, incr
)):
2560 lzc
.lzc_receive(dst1
, full
.fileno())
2561 lzc
.lzc_clone(cloned
, dst1
)
2562 # test both graceful and with-force attempts
2563 with self
.assertRaises(lzc_exc
.StreamMismatch
):
2564 lzc
.lzc_receive(dst2
, incr
.fileno())
2566 with self
.assertRaises(lzc_exc
.StreamMismatch
):
2567 lzc
.lzc_receive(dst2
, incr
.fileno(), force
=True)
2568 self
.assertExists(dst1
)
2569 self
.assertNotExists(dst2
)
2571 def test_recv_with_header_full(self
):
2572 src
= ZFSTest
.pool
.makeName(b
"fs1@snap")
2573 dst
= ZFSTest
.pool
.makeName(b
"fs2/received")
2575 with
temp_file_in_fs(ZFSTest
.pool
.makeName(b
"fs1")) as name
:
2576 lzc
.lzc_snapshot([src
])
2578 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2579 lzc
.lzc_send(src
, None, stream
.fileno())
2582 (header
, c_header
) = lzc
.receive_header(stream
.fileno())
2583 self
.assertEqual(src
, header
['drr_toname'])
2584 snap
= header
['drr_toname'].split(b
'@', 1)[1]
2585 lzc
.lzc_receive_with_header(
2586 dst
+ b
'@' + snap
, stream
.fileno(), c_header
)
2588 name
= os
.path
.basename(name
)
2589 with
zfs_mount(src
) as mnt1
, zfs_mount(dst
) as mnt2
:
2592 os
.path
.join(mnt1
, name
), os
.path
.join(mnt2
, name
), False))
2594 def test_recv_fs_below_zvol(self
):
2595 send
= ZFSTest
.pool
.makeName(b
"fs1@snap")
2596 zvol
= ZFSTest
.pool
.makeName(b
"fs1/zvol")
2597 dest
= zvol
+ b
"/fs@snap"
2598 props
= {b
"volsize": 1024 * 1024}
2600 lzc
.lzc_snapshot([send
])
2601 lzc
.lzc_create(zvol
, ds_type
='zvol', props
=props
)
2602 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2603 lzc
.lzc_send(send
, None, stream
.fileno())
2605 with self
.assertRaises(lzc_exc
.WrongParent
):
2606 lzc
.lzc_receive(dest
, stream
.fileno())
2608 def test_recv_zvol_over_fs_with_children(self
):
2609 parent
= ZFSTest
.pool
.makeName(b
"fs1")
2610 child
= parent
+ b
"subfs"
2611 zvol
= ZFSTest
.pool
.makeName(b
"fs1/zvol")
2612 send
= zvol
+ b
"@snap"
2613 props
= {b
"volsize": 1024 * 1024}
2615 lzc
.lzc_create(child
)
2616 lzc
.lzc_create(zvol
, ds_type
='zvol', props
=props
)
2617 lzc
.lzc_snapshot([send
])
2618 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2619 lzc
.lzc_send(send
, None, stream
.fileno())
2621 with self
.assertRaises(lzc_exc
.WrongParent
):
2622 lzc
.lzc_receive(parent
+ b
"@snap", stream
.fileno(), force
=True)
2624 def test_recv_zvol_overwrite_rootds(self
):
2625 zvol
= ZFSTest
.pool
.makeName(b
"fs1/zvol")
2626 snap
= zvol
+ b
"@snap"
2627 rootds
= ZFSTest
.pool
.getRoot().getName()
2628 props
= {b
"volsize": 1024 * 1024}
2630 lzc
.lzc_create(zvol
, ds_type
='zvol', props
=props
)
2631 lzc
.lzc_snapshot([snap
])
2632 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2633 lzc
.lzc_send(snap
, None, stream
.fileno())
2635 with self
.assertRaises(lzc_exc
.WrongParent
):
2636 lzc
.lzc_receive(rootds
+ b
"@snap", stream
.fileno(), force
=True)
2638 def test_send_full_across_clone_branch_point(self
):
2639 origfs
= ZFSTest
.pool
.makeName(b
"fs2")
2641 (_
, (fromsnap
, origsnap
, _
)) = make_snapshots(
2642 origfs
, b
"snap1", b
"send-origin-20", None)
2644 clonefs
= ZFSTest
.pool
.makeName(b
"fs1/fs/send-clone-20")
2645 lzc
.lzc_clone(clonefs
, origsnap
)
2647 (_
, (_
, tosnap
, _
)) = make_snapshots(clonefs
, None, b
"snap", None)
2649 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2650 lzc
.lzc_send(tosnap
, None, stream
.fileno())
2652 def test_send_incr_across_clone_branch_point(self
):
2653 origfs
= ZFSTest
.pool
.makeName(b
"fs2")
2655 (_
, (fromsnap
, origsnap
, _
)) = make_snapshots(
2656 origfs
, b
"snap1", b
"send-origin-21", None)
2658 clonefs
= ZFSTest
.pool
.makeName(b
"fs1/fs/send-clone-21")
2659 lzc
.lzc_clone(clonefs
, origsnap
)
2661 (_
, (_
, tosnap
, _
)) = make_snapshots(clonefs
, None, b
"snap", None)
2663 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2664 lzc
.lzc_send(tosnap
, fromsnap
, stream
.fileno())
2666 def test_send_resume_token_full(self
):
2667 src
= ZFSTest
.pool
.makeName(b
"fs1@snap")
2668 dstfs
= ZFSTest
.pool
.getFilesystem(b
"fs2/received")
2669 dst
= dstfs
.getSnap()
2671 with
zfs_mount(ZFSTest
.pool
.makeName(b
"fs1")) as mntdir
:
2672 for i
in range(1, 10):
2673 with tempfile
.NamedTemporaryFile(dir=mntdir
) as f
:
2674 f
.write(b
'x' * 1024 * i
)
2676 lzc
.lzc_snapshot([src
])
2678 with tempfile
.NamedTemporaryFile(suffix
='.zstream') as stream
:
2679 lzc
.lzc_send(src
, None, stream
.fileno())
2681 stream
.truncate(1024 * 3)
2682 with self
.assertRaises(lzc_exc
.BadStream
):
2683 lzc
.lzc_receive_resumable(dst
, stream
.fileno())
2684 # Resume token code from zfs_send_resume_token_to_nvlist()
2685 # XXX: if used more than twice move this code into an external func
2686 # format: <version>-<cksum>-<packed-size>-<compressed-payload>
2687 token
= dstfs
.getProperty("receive_resume_token")
2688 self
.assertNotEqual(token
, b
'-')
2689 tokens
= token
.split(b
'-')
2690 self
.assertEqual(len(tokens
), 4)
2692 packed_size
= int(tokens
[2], 16)
2693 compressed_nvs
= tokens
[3]
2694 # Validate resume token
2695 self
.assertEqual(version
, b
'1') # ZFS_SEND_RESUME_TOKEN_VERSION
2696 if sys
.version_info
< (3, 0):
2698 zlib
.decompress(str(bytearray
.fromhex(compressed_nvs
)))
2702 zlib
.decompress(bytearray
.fromhex(compressed_nvs
.decode()))
2704 self
.assertEqual(len(payload
), packed_size
)
2706 resume_values
= packed_nvlist_out(payload
, packed_size
)
2707 resumeobj
= resume_values
.get(b
'object')
2708 resumeoff
= resume_values
.get(b
'offset')
2709 with tempfile
.NamedTemporaryFile(suffix
='.zstream') as rstream
:
2710 lzc
.lzc_send_resume(
2711 src
, None, rstream
.fileno(), None, resumeobj
, resumeoff
)
2713 lzc
.lzc_receive_resumable(dst
, rstream
.fileno())
2715 def test_send_resume_token_incremental(self
):
2716 snap1
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
2717 snap2
= ZFSTest
.pool
.makeName(b
"fs1@snap2")
2718 dstfs
= ZFSTest
.pool
.getFilesystem(b
"fs2/received")
2719 dst1
= dstfs
.getSnap()
2720 dst2
= dstfs
.getSnap()
2722 lzc
.lzc_snapshot([snap1
])
2723 with tempfile
.NamedTemporaryFile(suffix
='.zstream') as stream
:
2724 lzc
.lzc_send(snap1
, None, stream
.fileno())
2726 lzc
.lzc_receive(dst1
, stream
.fileno())
2728 with
zfs_mount(ZFSTest
.pool
.makeName(b
"fs1")) as mntdir
:
2729 for i
in range(1, 10):
2730 with tempfile
.NamedTemporaryFile(dir=mntdir
) as f
:
2731 f
.write(b
'x' * 1024 * i
)
2733 lzc
.lzc_snapshot([snap2
])
2735 with tempfile
.NamedTemporaryFile(suffix
='.zstream') as stream
:
2736 lzc
.lzc_send(snap2
, snap1
, stream
.fileno())
2738 stream
.truncate(1024 * 3)
2739 with self
.assertRaises(lzc_exc
.BadStream
):
2740 lzc
.lzc_receive_resumable(dst2
, stream
.fileno())
2741 # Resume token code from zfs_send_resume_token_to_nvlist()
2742 # format: <version>-<cksum>-<packed-size>-<compressed-payload>
2743 token
= dstfs
.getProperty("receive_resume_token")
2744 self
.assertNotEqual(token
, '-')
2745 tokens
= token
.split(b
'-')
2746 self
.assertEqual(len(tokens
), 4)
2748 packed_size
= int(tokens
[2], 16)
2749 compressed_nvs
= tokens
[3]
2750 # Validate resume token
2751 self
.assertEqual(version
, b
'1') # ZFS_SEND_RESUME_TOKEN_VERSION
2752 if sys
.version_info
< (3, 0):
2754 zlib
.decompress(str(bytearray
.fromhex(compressed_nvs
)))
2758 zlib
.decompress(bytearray
.fromhex(compressed_nvs
.decode()))
2760 self
.assertEqual(len(payload
), packed_size
)
2762 resume_values
= packed_nvlist_out(payload
, packed_size
)
2763 resumeobj
= resume_values
.get(b
'object')
2764 resumeoff
= resume_values
.get(b
'offset')
2765 with tempfile
.NamedTemporaryFile(suffix
='.zstream') as rstream
:
2766 lzc
.lzc_send_resume(
2767 snap2
, snap1
, rstream
.fileno(), None, resumeobj
, resumeoff
)
2769 lzc
.lzc_receive_resumable(dst2
, rstream
.fileno())
2771 def test_recv_full_across_clone_branch_point(self
):
2772 origfs
= ZFSTest
.pool
.makeName(b
"fs2")
2774 (_
, (fromsnap
, origsnap
, _
)) = make_snapshots(
2775 origfs
, b
"snap1", b
"send-origin-30", None)
2777 clonefs
= ZFSTest
.pool
.makeName(b
"fs1/fs/send-clone-30")
2778 lzc
.lzc_clone(clonefs
, origsnap
)
2780 (_
, (_
, tosnap
, _
)) = make_snapshots(clonefs
, None, b
"snap", None)
2782 recvfs
= ZFSTest
.pool
.makeName(b
"fs1/recv-clone-30")
2783 recvsnap
= recvfs
+ b
"@snap"
2784 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2785 lzc
.lzc_send(tosnap
, None, stream
.fileno())
2787 lzc
.lzc_receive(recvsnap
, stream
.fileno())
2789 def test_recv_one(self
):
2790 fromsnap
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
2791 tosnap
= ZFSTest
.pool
.makeName(b
"recv@snap1")
2793 lzc
.lzc_snapshot([fromsnap
])
2794 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2795 lzc
.lzc_send(fromsnap
, None, stream
.fileno())
2797 (header
, c_header
) = lzc
.receive_header(stream
.fileno())
2798 lzc
.lzc_receive_one(tosnap
, stream
.fileno(), c_header
)
2800 def test_recv_one_size(self
):
2801 fromsnap
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
2802 tosnap
= ZFSTest
.pool
.makeName(b
"recv@snap1")
2804 lzc
.lzc_snapshot([fromsnap
])
2805 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2806 lzc
.lzc_send(fromsnap
, None, stream
.fileno())
2807 size
= os
.fstat(stream
.fileno()).st_size
2809 (header
, c_header
) = lzc
.receive_header(stream
.fileno())
2810 (read
, _
) = lzc
.lzc_receive_one(tosnap
, stream
.fileno(), c_header
)
2811 self
.assertAlmostEqual(read
, size
, delta
=read
* 0.05)
2813 def test_recv_one_props(self
):
2814 fromsnap
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
2815 fs
= ZFSTest
.pool
.getFilesystem(b
"recv")
2816 tosnap
= fs
.getName() + b
"@snap1"
2818 b
"compression": 0x01,
2822 lzc
.lzc_snapshot([fromsnap
])
2823 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2824 lzc
.lzc_send(fromsnap
, None, stream
.fileno())
2826 (header
, c_header
) = lzc
.receive_header(stream
.fileno())
2827 lzc
.lzc_receive_one(tosnap
, stream
.fileno(), c_header
, props
=props
)
2828 self
.assertExists(tosnap
)
2829 self
.assertEqual(fs
.getProperty("compression", "received"), b
"on")
2830 self
.assertEqual(fs
.getProperty("ns:prop", "received"), b
"val")
2832 def test_recv_one_invalid_prop(self
):
2833 fromsnap
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
2834 fs
= ZFSTest
.pool
.getFilesystem(b
"recv")
2835 tosnap
= fs
.getName() + b
"@snap1"
2841 lzc
.lzc_snapshot([fromsnap
])
2842 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2843 lzc
.lzc_send(fromsnap
, None, stream
.fileno())
2845 (header
, c_header
) = lzc
.receive_header(stream
.fileno())
2846 with self
.assertRaises(lzc_exc
.ReceivePropertyFailure
) as ctx
:
2847 lzc
.lzc_receive_one(
2848 tosnap
, stream
.fileno(), c_header
, props
=props
)
2849 self
.assertExists(tosnap
)
2850 self
.assertEqual(fs
.getProperty("atime", "received"), b
"off")
2851 for e
in ctx
.exception
.errors
:
2852 self
.assertIsInstance(e
, lzc_exc
.PropertyInvalid
)
2853 self
.assertEqual(e
.name
, b
"exec")
2855 def test_recv_with_cmdprops(self
):
2856 fromsnap
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
2857 fs
= ZFSTest
.pool
.getFilesystem(b
"recv")
2858 tosnap
= fs
.getName() + b
"@snap1"
2861 b
"compression": 0x01,
2865 lzc
.lzc_snapshot([fromsnap
])
2866 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2867 lzc
.lzc_send(fromsnap
, None, stream
.fileno())
2869 (header
, c_header
) = lzc
.receive_header(stream
.fileno())
2870 lzc
.lzc_receive_with_cmdprops(
2871 tosnap
, stream
.fileno(), c_header
, props
=props
,
2873 self
.assertExists(tosnap
)
2874 self
.assertEqual(fs
.getProperty("compression"), b
"on")
2875 self
.assertEqual(fs
.getProperty("ns:prop"), b
"val")
2877 def test_recv_with_cmdprops_and_recvprops(self
):
2878 fromsnap
= ZFSTest
.pool
.makeName(b
"fs1@snap1")
2879 fs
= ZFSTest
.pool
.getFilesystem(b
"recv")
2880 tosnap
= fs
.getName() + b
"@snap1"
2887 b
"compression": 0x01,
2892 lzc
.lzc_snapshot([fromsnap
])
2893 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2894 lzc
.lzc_send(fromsnap
, None, stream
.fileno())
2896 (header
, c_header
) = lzc
.receive_header(stream
.fileno())
2897 lzc
.lzc_receive_with_cmdprops(
2898 tosnap
, stream
.fileno(), c_header
, props
=props
,
2900 self
.assertExists(tosnap
)
2901 self
.assertEqual(fs
.getProperty("atime", True), b
"on")
2902 self
.assertEqual(fs
.getProperty("exec", True), b
"off")
2903 self
.assertEqual(fs
.getProperty("ns:prop", True), b
"abc")
2904 self
.assertEqual(fs
.getProperty("compression"), b
"on")
2905 self
.assertEqual(fs
.getProperty("ns:prop"), b
"def")
2906 self
.assertEqual(fs
.getProperty("exec"), b
"on")
2908 def test_recv_incr_across_clone_branch_point_no_origin(self
):
2909 origfs
= ZFSTest
.pool
.makeName(b
"fs2")
2911 (_
, (fromsnap
, origsnap
, _
)) = make_snapshots(
2912 origfs
, b
"snap1", b
"send-origin-32", None)
2914 clonefs
= ZFSTest
.pool
.makeName(b
"fs1/fs/send-clone-32")
2915 lzc
.lzc_clone(clonefs
, origsnap
)
2917 (_
, (_
, tosnap
, _
)) = make_snapshots(clonefs
, None, b
"snap", None)
2919 recvfs
= ZFSTest
.pool
.makeName(b
"fs1/recv-clone-32")
2920 recvsnap1
= recvfs
+ b
"@snap1"
2921 recvsnap2
= recvfs
+ b
"@snap2"
2922 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2923 lzc
.lzc_send(fromsnap
, None, stream
.fileno())
2925 lzc
.lzc_receive(recvsnap1
, stream
.fileno())
2926 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2927 lzc
.lzc_send(tosnap
, fromsnap
, stream
.fileno())
2929 with self
.assertRaises(lzc_exc
.BadStream
):
2930 lzc
.lzc_receive(recvsnap2
, stream
.fileno())
2932 def test_recv_incr_across_clone_branch_point(self
):
2933 origfs
= ZFSTest
.pool
.makeName(b
"fs2")
2935 (_
, (fromsnap
, origsnap
, _
)) = make_snapshots(
2936 origfs
, b
"snap1", b
"send-origin-31", None)
2938 clonefs
= ZFSTest
.pool
.makeName(b
"fs1/fs/send-clone-31")
2939 lzc
.lzc_clone(clonefs
, origsnap
)
2941 (_
, (_
, tosnap
, _
)) = make_snapshots(clonefs
, None, b
"snap", None)
2943 recvfs
= ZFSTest
.pool
.makeName(b
"fs1/recv-clone-31")
2944 recvsnap1
= recvfs
+ b
"@snap1"
2945 recvsnap2
= recvfs
+ b
"@snap2"
2946 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2947 lzc
.lzc_send(fromsnap
, None, stream
.fileno())
2949 lzc
.lzc_receive(recvsnap1
, stream
.fileno())
2950 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2951 lzc
.lzc_send(tosnap
, fromsnap
, stream
.fileno())
2953 with self
.assertRaises(lzc_exc
.BadStream
):
2954 lzc
.lzc_receive(recvsnap2
, stream
.fileno(), origin
=recvsnap1
)
2956 def test_recv_incr_across_clone_branch_point_new_fs(self
):
2957 origfs
= ZFSTest
.pool
.makeName(b
"fs2")
2959 (_
, (fromsnap
, origsnap
, _
)) = make_snapshots(
2960 origfs
, b
"snap1", b
"send-origin-33", None)
2962 clonefs
= ZFSTest
.pool
.makeName(b
"fs1/fs/send-clone-33")
2963 lzc
.lzc_clone(clonefs
, origsnap
)
2965 (_
, (_
, tosnap
, _
)) = make_snapshots(clonefs
, None, b
"snap", None)
2967 recvfs1
= ZFSTest
.pool
.makeName(b
"fs1/recv-clone-33")
2968 recvsnap1
= recvfs1
+ b
"@snap"
2969 recvfs2
= ZFSTest
.pool
.makeName(b
"fs1/recv-clone-33_2")
2970 recvsnap2
= recvfs2
+ b
"@snap"
2971 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2972 lzc
.lzc_send(fromsnap
, None, stream
.fileno())
2974 lzc
.lzc_receive(recvsnap1
, stream
.fileno())
2975 with tempfile
.TemporaryFile(suffix
='.zstream') as stream
:
2976 lzc
.lzc_send(tosnap
, fromsnap
, stream
.fileno())
2978 lzc
.lzc_receive(recvsnap2
, stream
.fileno(), origin
=recvsnap1
)
2980 def test_recv_bad_stream(self
):
2981 dstfs
= ZFSTest
.pool
.makeName(b
"fs2/received")
2982 dst_snap
= dstfs
+ b
'@snap'
2984 with
dev_zero() as fd
:
2985 with self
.assertRaises(lzc_exc
.BadStream
):
2986 lzc
.lzc_receive(dst_snap
, fd
)
2988 @needs_support(lzc
.lzc_promote
)
2989 def test_promote(self
):
2990 origfs
= ZFSTest
.pool
.makeName(b
"fs2")
2991 snap
= b
"@promote-snap-1"
2992 origsnap
= origfs
+ snap
2993 lzc
.lzc_snap([origsnap
])
2995 clonefs
= ZFSTest
.pool
.makeName(b
"fs1/fs/promote-clone-1")
2996 lzc
.lzc_clone(clonefs
, origsnap
)
2998 lzc
.lzc_promote(clonefs
)
2999 # the snapshot now should belong to the promoted fs
3000 self
.assertExists(clonefs
+ snap
)
3002 @needs_support(lzc
.lzc_promote
)
3003 def test_promote_too_long_snapname(self
):
3004 # origfs name must be shorter than clonefs name
3005 origfs
= ZFSTest
.pool
.makeName(b
"fs2")
3006 clonefs
= ZFSTest
.pool
.makeName(b
"fs1/fs/promote-clone-2")
3007 snapprefix
= b
"@promote-snap-2-"
3008 pad_len
= 1 + lzc
.MAXNAMELEN
- len(clonefs
) - len(snapprefix
)
3009 snap
= snapprefix
+ b
'x' * pad_len
3010 origsnap
= origfs
+ snap
3012 lzc
.lzc_snap([origsnap
])
3013 lzc
.lzc_clone(clonefs
, origsnap
)
3015 # This may fail on older buggy systems.
3016 # See: https://www.illumos.org/issues/5909
3017 with self
.assertRaises(lzc_exc
.NameTooLong
):
3018 lzc
.lzc_promote(clonefs
)
3020 @needs_support(lzc
.lzc_promote
)
3021 def test_promote_not_cloned(self
):
3022 fs
= ZFSTest
.pool
.makeName(b
"fs2")
3023 with self
.assertRaises(lzc_exc
.NotClone
):
3026 @unittest.skipIf(*illumos_bug_6379())
3027 def test_hold_bad_fd(self
):
3028 snap
= ZFSTest
.pool
.getRoot().getSnap()
3029 lzc
.lzc_snapshot([snap
])
3031 with tempfile
.TemporaryFile() as tmp
:
3032 bad_fd
= tmp
.fileno()
3034 with self
.assertRaises(lzc_exc
.BadHoldCleanupFD
):
3035 lzc
.lzc_hold({snap
: b
'tag'}, bad_fd
)
3037 @unittest.skipIf(*illumos_bug_6379())
3038 def test_hold_bad_fd_2(self
):
3039 snap
= ZFSTest
.pool
.getRoot().getSnap()
3040 lzc
.lzc_snapshot([snap
])
3042 with self
.assertRaises(lzc_exc
.BadHoldCleanupFD
):
3043 lzc
.lzc_hold({snap
: b
'tag'}, -2)
3045 @unittest.skipIf(*illumos_bug_6379())
3046 def test_hold_bad_fd_3(self
):
3047 snap
= ZFSTest
.pool
.getRoot().getSnap()
3048 lzc
.lzc_snapshot([snap
])
3050 (soft
, hard
) = resource
.getrlimit(resource
.RLIMIT_NOFILE
)
3052 with self
.assertRaises(lzc_exc
.BadHoldCleanupFD
):
3053 lzc
.lzc_hold({snap
: b
'tag'}, bad_fd
)
3055 @unittest.skipIf(*illumos_bug_6379())
3056 def test_hold_wrong_fd(self
):
3057 snap
= ZFSTest
.pool
.getRoot().getSnap()
3058 lzc
.lzc_snapshot([snap
])
3060 with tempfile
.TemporaryFile() as tmp
:
3062 with self
.assertRaises(lzc_exc
.BadHoldCleanupFD
):
3063 lzc
.lzc_hold({snap
: b
'tag'}, fd
)
3065 def test_hold_fd(self
):
3066 snap
= ZFSTest
.pool
.getRoot().getSnap()
3067 lzc
.lzc_snapshot([snap
])
3069 with
cleanup_fd() as fd
:
3070 lzc
.lzc_hold({snap
: b
'tag'}, fd
)
3072 def test_hold_empty(self
):
3073 with
cleanup_fd() as fd
:
3074 lzc
.lzc_hold({}, fd
)
3076 def test_hold_empty_2(self
):
3079 def test_hold_vs_snap_destroy(self
):
3080 snap
= ZFSTest
.pool
.getRoot().getSnap()
3081 lzc
.lzc_snapshot([snap
])
3083 with
cleanup_fd() as fd
:
3084 lzc
.lzc_hold({snap
: b
'tag'}, fd
)
3086 with self
.assertRaises(lzc_exc
.SnapshotDestructionFailure
) as ctx
:
3087 lzc
.lzc_destroy_snaps([snap
], defer
=False)
3088 for e
in ctx
.exception
.errors
:
3089 self
.assertIsInstance(e
, lzc_exc
.SnapshotIsHeld
)
3091 lzc
.lzc_destroy_snaps([snap
], defer
=True)
3092 self
.assertExists(snap
)
3094 # after automatic hold cleanup and deferred destruction
3095 self
.assertNotExists(snap
)
3097 def test_hold_many_tags(self
):
3098 snap
= ZFSTest
.pool
.getRoot().getSnap()
3099 lzc
.lzc_snapshot([snap
])
3101 with
cleanup_fd() as fd
:
3102 lzc
.lzc_hold({snap
: b
'tag1'}, fd
)
3103 lzc
.lzc_hold({snap
: b
'tag2'}, fd
)
3105 def test_hold_many_snaps(self
):
3106 snap1
= ZFSTest
.pool
.getRoot().getSnap()
3107 snap2
= ZFSTest
.pool
.getRoot().getSnap()
3108 lzc
.lzc_snapshot([snap1
])
3109 lzc
.lzc_snapshot([snap2
])
3111 with
cleanup_fd() as fd
:
3112 lzc
.lzc_hold({snap1
: b
'tag', snap2
: b
'tag'}, fd
)
3114 def test_hold_many_with_one_missing(self
):
3115 snap1
= ZFSTest
.pool
.getRoot().getSnap()
3116 snap2
= ZFSTest
.pool
.getRoot().getSnap()
3117 lzc
.lzc_snapshot([snap1
])
3119 with
cleanup_fd() as fd
:
3120 missing
= lzc
.lzc_hold({snap1
: b
'tag', snap2
: b
'tag'}, fd
)
3121 self
.assertEqual(len(missing
), 1)
3122 self
.assertEqual(missing
[0], snap2
)
3124 def test_hold_many_with_all_missing(self
):
3125 snap1
= ZFSTest
.pool
.getRoot().getSnap()
3126 snap2
= ZFSTest
.pool
.getRoot().getSnap()
3128 with
cleanup_fd() as fd
:
3129 missing
= lzc
.lzc_hold({snap1
: b
'tag', snap2
: b
'tag'}, fd
)
3130 self
.assertEqual(len(missing
), 2)
3131 self
.assertEqual(sorted(missing
), sorted([snap1
, snap2
]))
3133 def test_hold_missing_fs(self
):
3134 # XXX skip pre-created filesystems
3135 ZFSTest
.pool
.getRoot().getFilesystem()
3136 ZFSTest
.pool
.getRoot().getFilesystem()
3137 ZFSTest
.pool
.getRoot().getFilesystem()
3138 ZFSTest
.pool
.getRoot().getFilesystem()
3139 ZFSTest
.pool
.getRoot().getFilesystem()
3140 snap
= ZFSTest
.pool
.getRoot().getFilesystem().getSnap()
3142 snaps
= lzc
.lzc_hold({snap
: b
'tag'})
3143 self
.assertEqual([snap
], snaps
)
3145 def test_hold_missing_fs_auto_cleanup(self
):
3146 # XXX skip pre-created filesystems
3147 ZFSTest
.pool
.getRoot().getFilesystem()
3148 ZFSTest
.pool
.getRoot().getFilesystem()
3149 ZFSTest
.pool
.getRoot().getFilesystem()
3150 ZFSTest
.pool
.getRoot().getFilesystem()
3151 ZFSTest
.pool
.getRoot().getFilesystem()
3152 snap
= ZFSTest
.pool
.getRoot().getFilesystem().getSnap()
3154 with
cleanup_fd() as fd
:
3155 snaps
= lzc
.lzc_hold({snap
: b
'tag'}, fd
)
3156 self
.assertEqual([snap
], snaps
)
3158 def test_hold_duplicate(self
):
3159 snap
= ZFSTest
.pool
.getRoot().getSnap()
3160 lzc
.lzc_snapshot([snap
])
3162 with
cleanup_fd() as fd
:
3163 lzc
.lzc_hold({snap
: b
'tag'}, fd
)
3164 with self
.assertRaises(lzc_exc
.HoldFailure
) as ctx
:
3165 lzc
.lzc_hold({snap
: b
'tag'}, fd
)
3166 for e
in ctx
.exception
.errors
:
3167 self
.assertIsInstance(e
, lzc_exc
.HoldExists
)
3169 def test_hold_across_pools(self
):
3170 snap1
= ZFSTest
.pool
.getRoot().getSnap()
3171 snap2
= ZFSTest
.misc_pool
.getRoot().getSnap()
3172 lzc
.lzc_snapshot([snap1
])
3173 lzc
.lzc_snapshot([snap2
])
3175 with
cleanup_fd() as fd
:
3176 with self
.assertRaises(lzc_exc
.HoldFailure
) as ctx
:
3177 lzc
.lzc_hold({snap1
: b
'tag', snap2
: b
'tag'}, fd
)
3178 for e
in ctx
.exception
.errors
:
3179 self
.assertIsInstance(e
, lzc_exc
.PoolsDiffer
)
3181 def test_hold_too_long_tag(self
):
3182 snap
= ZFSTest
.pool
.getRoot().getSnap()
3184 lzc
.lzc_snapshot([snap
])
3186 with
cleanup_fd() as fd
:
3187 with self
.assertRaises(lzc_exc
.HoldFailure
) as ctx
:
3188 lzc
.lzc_hold({snap
: tag
}, fd
)
3189 for e
in ctx
.exception
.errors
:
3190 self
.assertIsInstance(e
, lzc_exc
.NameTooLong
)
3191 self
.assertEqual(e
.name
, tag
)
3193 # Apparently the full snapshot name is not checked for length
3194 # and this snapshot is treated as simply missing.
3195 @unittest.expectedFailure
3196 def test_hold_too_long_snap_name(self
):
3197 snap
= ZFSTest
.pool
.getRoot().getTooLongSnap(False)
3198 with
cleanup_fd() as fd
:
3199 with self
.assertRaises(lzc_exc
.HoldFailure
) as ctx
:
3200 lzc
.lzc_hold({snap
: b
'tag'}, fd
)
3201 for e
in ctx
.exception
.errors
:
3202 self
.assertIsInstance(e
, lzc_exc
.NameTooLong
)
3203 self
.assertEqual(e
.name
, snap
)
3205 def test_hold_too_long_snap_name_2(self
):
3206 snap
= ZFSTest
.pool
.getRoot().getTooLongSnap(True)
3207 with
cleanup_fd() as fd
:
3208 with self
.assertRaises(lzc_exc
.HoldFailure
) as ctx
:
3209 lzc
.lzc_hold({snap
: b
'tag'}, fd
)
3210 for e
in ctx
.exception
.errors
:
3211 self
.assertIsInstance(e
, lzc_exc
.NameTooLong
)
3212 self
.assertEqual(e
.name
, snap
)
3214 def test_hold_invalid_snap_name(self
):
3215 snap
= ZFSTest
.pool
.getRoot().getSnap() + b
'@bad'
3216 with
cleanup_fd() as fd
:
3217 with self
.assertRaises(lzc_exc
.HoldFailure
) as ctx
:
3218 lzc
.lzc_hold({snap
: b
'tag'}, fd
)
3219 for e
in ctx
.exception
.errors
:
3220 self
.assertIsInstance(e
, lzc_exc
.NameInvalid
)
3221 self
.assertEqual(e
.name
, snap
)
3223 def test_hold_invalid_snap_name_2(self
):
3224 snap
= ZFSTest
.pool
.getRoot().getFilesystem().getName()
3225 with
cleanup_fd() as fd
:
3226 with self
.assertRaises(lzc_exc
.HoldFailure
) as ctx
:
3227 lzc
.lzc_hold({snap
: b
'tag'}, fd
)
3228 for e
in ctx
.exception
.errors
:
3229 self
.assertIsInstance(e
, lzc_exc
.NameInvalid
)
3230 self
.assertEqual(e
.name
, snap
)
3232 def test_get_holds(self
):
3233 snap
= ZFSTest
.pool
.getRoot().getSnap()
3234 lzc
.lzc_snapshot([snap
])
3236 with
cleanup_fd() as fd
:
3237 lzc
.lzc_hold({snap
: b
'tag1'}, fd
)
3238 lzc
.lzc_hold({snap
: b
'tag2'}, fd
)
3240 holds
= lzc
.lzc_get_holds(snap
)
3241 self
.assertEqual(len(holds
), 2)
3242 self
.assertIn(b
'tag1', holds
)
3243 self
.assertIn(b
'tag2', holds
)
3244 self
.assertIsInstance(holds
[b
'tag1'], (int, int))
3246 def test_get_holds_after_auto_cleanup(self
):
3247 snap
= ZFSTest
.pool
.getRoot().getSnap()
3248 lzc
.lzc_snapshot([snap
])
3250 with
cleanup_fd() as fd
:
3251 lzc
.lzc_hold({snap
: b
'tag1'}, fd
)
3252 lzc
.lzc_hold({snap
: b
'tag2'}, fd
)
3254 holds
= lzc
.lzc_get_holds(snap
)
3255 self
.assertEqual(len(holds
), 0)
3256 self
.assertIsInstance(holds
, dict)
3258 def test_get_holds_nonexistent_snap(self
):
3259 snap
= ZFSTest
.pool
.getRoot().getSnap()
3260 with self
.assertRaises(lzc_exc
.SnapshotNotFound
):
3261 lzc
.lzc_get_holds(snap
)
3263 def test_get_holds_too_long_snap_name(self
):
3264 snap
= ZFSTest
.pool
.getRoot().getTooLongSnap(False)
3265 with self
.assertRaises(lzc_exc
.NameTooLong
):
3266 lzc
.lzc_get_holds(snap
)
3268 def test_get_holds_too_long_snap_name_2(self
):
3269 snap
= ZFSTest
.pool
.getRoot().getTooLongSnap(True)
3270 with self
.assertRaises(lzc_exc
.NameTooLong
):
3271 lzc
.lzc_get_holds(snap
)
3273 def test_get_holds_invalid_snap_name(self
):
3274 snap
= ZFSTest
.pool
.getRoot().getSnap() + b
'@bad'
3275 with self
.assertRaises(lzc_exc
.NameInvalid
):
3276 lzc
.lzc_get_holds(snap
)
3278 # A filesystem-like snapshot name is not recognized as
3280 @unittest.expectedFailure
3281 def test_get_holds_invalid_snap_name_2(self
):
3282 snap
= ZFSTest
.pool
.getRoot().getFilesystem().getName()
3283 with self
.assertRaises(lzc_exc
.NameInvalid
):
3284 lzc
.lzc_get_holds(snap
)
3286 def test_release_hold(self
):
3287 snap
= ZFSTest
.pool
.getRoot().getSnap()
3288 lzc
.lzc_snapshot([snap
])
3290 lzc
.lzc_hold({snap
: b
'tag'})
3291 ret
= lzc
.lzc_release({snap
: [b
'tag']})
3292 self
.assertEqual(len(ret
), 0)
3294 def test_release_hold_empty(self
):
3295 ret
= lzc
.lzc_release({})
3296 self
.assertEqual(len(ret
), 0)
3298 def test_release_hold_complex(self
):
3299 snap1
= ZFSTest
.pool
.getRoot().getSnap()
3300 snap2
= ZFSTest
.pool
.getRoot().getSnap()
3301 snap3
= ZFSTest
.pool
.getRoot().getFilesystem().getSnap()
3302 lzc
.lzc_snapshot([snap1
])
3303 lzc
.lzc_snapshot([snap2
, snap3
])
3305 lzc
.lzc_hold({snap1
: b
'tag1'})
3306 lzc
.lzc_hold({snap1
: b
'tag2'})
3307 lzc
.lzc_hold({snap2
: b
'tag'})
3308 lzc
.lzc_hold({snap3
: b
'tag1'})
3309 lzc
.lzc_hold({snap3
: b
'tag2'})
3311 holds
= lzc
.lzc_get_holds(snap1
)
3312 self
.assertEqual(len(holds
), 2)
3313 holds
= lzc
.lzc_get_holds(snap2
)
3314 self
.assertEqual(len(holds
), 1)
3315 holds
= lzc
.lzc_get_holds(snap3
)
3316 self
.assertEqual(len(holds
), 2)
3319 snap1
: [b
'tag1', b
'tag2'],
3323 ret
= lzc
.lzc_release(release
)
3324 self
.assertEqual(len(ret
), 0)
3326 holds
= lzc
.lzc_get_holds(snap1
)
3327 self
.assertEqual(len(holds
), 0)
3328 holds
= lzc
.lzc_get_holds(snap2
)
3329 self
.assertEqual(len(holds
), 0)
3330 holds
= lzc
.lzc_get_holds(snap3
)
3331 self
.assertEqual(len(holds
), 1)
3333 ret
= lzc
.lzc_release({snap3
: [b
'tag1']})
3334 self
.assertEqual(len(ret
), 0)
3335 holds
= lzc
.lzc_get_holds(snap3
)
3336 self
.assertEqual(len(holds
), 0)
3338 def test_release_hold_before_auto_cleanup(self
):
3339 snap
= ZFSTest
.pool
.getRoot().getSnap()
3340 lzc
.lzc_snapshot([snap
])
3342 with
cleanup_fd() as fd
:
3343 lzc
.lzc_hold({snap
: b
'tag'}, fd
)
3344 ret
= lzc
.lzc_release({snap
: [b
'tag']})
3345 self
.assertEqual(len(ret
), 0)
3347 def test_release_hold_and_snap_destruction(self
):
3348 snap
= ZFSTest
.pool
.getRoot().getSnap()
3349 lzc
.lzc_snapshot([snap
])
3351 with
cleanup_fd() as fd
:
3352 lzc
.lzc_hold({snap
: b
'tag1'}, fd
)
3353 lzc
.lzc_hold({snap
: b
'tag2'}, fd
)
3355 lzc
.lzc_destroy_snaps([snap
], defer
=True)
3356 self
.assertExists(snap
)
3358 lzc
.lzc_release({snap
: [b
'tag1']})
3359 self
.assertExists(snap
)
3361 lzc
.lzc_release({snap
: [b
'tag2']})
3362 self
.assertNotExists(snap
)
3364 def test_release_hold_and_multiple_snap_destruction(self
):
3365 snap
= ZFSTest
.pool
.getRoot().getSnap()
3366 lzc
.lzc_snapshot([snap
])
3368 with
cleanup_fd() as fd
:
3369 lzc
.lzc_hold({snap
: b
'tag'}, fd
)
3371 lzc
.lzc_destroy_snaps([snap
], defer
=True)
3372 self
.assertExists(snap
)
3374 lzc
.lzc_destroy_snaps([snap
], defer
=True)
3375 self
.assertExists(snap
)
3377 lzc
.lzc_release({snap
: [b
'tag']})
3378 self
.assertNotExists(snap
)
3380 def test_release_hold_missing_tag(self
):
3381 snap
= ZFSTest
.pool
.getRoot().getSnap()
3382 lzc
.lzc_snapshot([snap
])
3384 ret
= lzc
.lzc_release({snap
: [b
'tag']})
3385 self
.assertEqual(len(ret
), 1)
3386 self
.assertEqual(ret
[0], snap
+ b
'#tag')
3388 def test_release_hold_missing_snap(self
):
3389 snap
= ZFSTest
.pool
.getRoot().getSnap()
3391 ret
= lzc
.lzc_release({snap
: [b
'tag']})
3392 self
.assertEqual(len(ret
), 1)
3393 self
.assertEqual(ret
[0], snap
)
3395 def test_release_hold_missing_snap_2(self
):
3396 snap
= ZFSTest
.pool
.getRoot().getSnap()
3398 ret
= lzc
.lzc_release({snap
: [b
'tag', b
'another']})
3399 self
.assertEqual(len(ret
), 1)
3400 self
.assertEqual(ret
[0], snap
)
3402 def test_release_hold_across_pools(self
):
3403 snap1
= ZFSTest
.pool
.getRoot().getSnap()
3404 snap2
= ZFSTest
.misc_pool
.getRoot().getSnap()
3405 lzc
.lzc_snapshot([snap1
])
3406 lzc
.lzc_snapshot([snap2
])
3408 with
cleanup_fd() as fd
:
3409 lzc
.lzc_hold({snap1
: b
'tag'}, fd
)
3410 lzc
.lzc_hold({snap2
: b
'tag'}, fd
)
3411 with self
.assertRaises(lzc_exc
.HoldReleaseFailure
) as ctx
:
3412 lzc
.lzc_release({snap1
: [b
'tag'], snap2
: [b
'tag']})
3413 for e
in ctx
.exception
.errors
:
3414 self
.assertIsInstance(e
, lzc_exc
.PoolsDiffer
)
3416 # Apparently the tag name is not verified,
3417 # only its existence is checked.
3418 @unittest.expectedFailure
3419 def test_release_hold_too_long_tag(self
):
3420 snap
= ZFSTest
.pool
.getRoot().getSnap()
3422 lzc
.lzc_snapshot([snap
])
3424 with self
.assertRaises(lzc_exc
.HoldReleaseFailure
):
3425 lzc
.lzc_release({snap
: [tag
]})
3427 # Apparently the full snapshot name is not checked for length
3428 # and this snapshot is treated as simply missing.
3429 @unittest.expectedFailure
3430 def test_release_hold_too_long_snap_name(self
):
3431 snap
= ZFSTest
.pool
.getRoot().getTooLongSnap(False)
3433 with self
.assertRaises(lzc_exc
.HoldReleaseFailure
):
3434 lzc
.lzc_release({snap
: [b
'tag']})
3436 def test_release_hold_too_long_snap_name_2(self
):
3437 snap
= ZFSTest
.pool
.getRoot().getTooLongSnap(True)
3438 with self
.assertRaises(lzc_exc
.HoldReleaseFailure
) as ctx
:
3439 lzc
.lzc_release({snap
: [b
'tag']})
3440 for e
in ctx
.exception
.errors
:
3441 self
.assertIsInstance(e
, lzc_exc
.NameTooLong
)
3442 self
.assertEqual(e
.name
, snap
)
3444 def test_release_hold_invalid_snap_name(self
):
3445 snap
= ZFSTest
.pool
.getRoot().getSnap() + b
'@bad'
3446 with self
.assertRaises(lzc_exc
.HoldReleaseFailure
) as ctx
:
3447 lzc
.lzc_release({snap
: [b
'tag']})
3448 for e
in ctx
.exception
.errors
:
3449 self
.assertIsInstance(e
, lzc_exc
.NameInvalid
)
3450 self
.assertEqual(e
.name
, snap
)
3452 def test_release_hold_invalid_snap_name_2(self
):
3453 snap
= ZFSTest
.pool
.getRoot().getFilesystem().getName()
3454 with self
.assertRaises(lzc_exc
.HoldReleaseFailure
) as ctx
:
3455 lzc
.lzc_release({snap
: [b
'tag']})
3456 for e
in ctx
.exception
.errors
:
3457 self
.assertIsInstance(e
, lzc_exc
.NameInvalid
)
3458 self
.assertEqual(e
.name
, snap
)
3460 def test_sync_missing_pool(self
):
3461 pool
= b
"nonexistent"
3462 with self
.assertRaises(lzc_exc
.PoolNotFound
):
3465 def test_sync_pool_forced(self
):
3466 pool
= ZFSTest
.pool
.getRoot().getName()
3467 lzc
.lzc_sync(pool
, True)
3469 def test_reopen_missing_pool(self
):
3470 pool
= b
"nonexistent"
3471 with self
.assertRaises(lzc_exc
.PoolNotFound
):
3472 lzc
.lzc_reopen(pool
)
3474 def test_reopen_pool_no_restart(self
):
3475 pool
= ZFSTest
.pool
.getRoot().getName()
3476 lzc
.lzc_reopen(pool
, False)
3478 def test_channel_program_missing_pool(self
):
3479 pool
= b
"nonexistent"
3480 with self
.assertRaises(lzc_exc
.PoolNotFound
):
3481 lzc
.lzc_channel_program(pool
, b
"return {}")
3483 def test_channel_program_timeout(self
):
3484 pool
= ZFSTest
.pool
.getRoot().getName()
3487 zfs.sync.snapshot('""" + pool
+ b
"""@zcp' .. i)
3490 with self
.assertRaises(lzc_exc
.ZCPTimeout
):
3491 lzc
.lzc_channel_program(pool
, zcp
, instrlimit
=1)
3493 def test_channel_program_memory_limit(self
):
3494 pool
= ZFSTest
.pool
.getRoot().getName()
3497 zfs.sync.snapshot('""" + pool
+ b
"""@zcp' .. i)
3500 with self
.assertRaises(lzc_exc
.ZCPSpaceError
):
3501 lzc
.lzc_channel_program(pool
, zcp
, memlimit
=1)
3503 def test_channel_program_invalid_limits(self
):
3504 pool
= ZFSTest
.pool
.getRoot().getName()
3508 with self
.assertRaises(lzc_exc
.ZCPLimitInvalid
):
3509 lzc
.lzc_channel_program(pool
, zcp
, instrlimit
=0)
3510 with self
.assertRaises(lzc_exc
.ZCPLimitInvalid
):
3511 lzc
.lzc_channel_program(pool
, zcp
, memlimit
=0)
3513 def test_channel_program_syntax_error(self
):
3514 pool
= ZFSTest
.pool
.getRoot().getName()
3518 with self
.assertRaises(lzc_exc
.ZCPSyntaxError
) as ctx
:
3519 lzc
.lzc_channel_program(pool
, zcp
)
3520 self
.assertTrue(b
"syntax error" in ctx
.exception
.details
)
3522 def test_channel_program_sync_snapshot(self
):
3523 pool
= ZFSTest
.pool
.getRoot().getName()
3524 snapname
= ZFSTest
.pool
.makeName(b
"@zcp")
3526 zfs.sync.snapshot('""" + snapname
+ b
"""')
3528 lzc
.lzc_channel_program(pool
, zcp
)
3529 self
.assertExists(snapname
)
3531 def test_channel_program_runtime_error(self
):
3532 pool
= ZFSTest
.pool
.getRoot().getName()
3534 # failing an assertion raises a runtime error
3535 with self
.assertRaises(lzc_exc
.ZCPRuntimeError
) as ctx
:
3536 lzc
.lzc_channel_program(pool
, b
"assert(1 == 2)")
3538 b
"assertion failed" in ctx
.exception
.details
)
3539 # invoking the error() function raises a runtime error
3540 with self
.assertRaises(lzc_exc
.ZCPRuntimeError
) as ctx
:
3541 lzc
.lzc_channel_program(pool
, b
"error()")
3543 def test_channel_program_nosync_runtime_error(self
):
3544 pool
= ZFSTest
.pool
.getRoot().getName()
3546 zfs.sync.snapshot('""" + pool
+ b
"""@zcp')
3548 # lzc_channel_program_nosync() allows only "read-only" operations
3549 with self
.assertRaises(lzc_exc
.ZCPRuntimeError
) as ctx
:
3550 lzc
.lzc_channel_program_nosync(pool
, zcp
)
3552 b
"running functions from the zfs.sync" in ctx
.exception
.details
)
3554 def test_change_key_new(self
):
3555 with
encrypted_filesystem() as (fs
, _
):
3558 props
={b
"keyformat": lzc
.zfs_keyformat
.ZFS_KEYFORMAT_RAW
},
3559 key
=os
.urandom(lzc
.WRAPPING_KEY_LEN
))
3561 def test_change_key_missing_fs(self
):
3562 name
= b
"nonexistent"
3564 with self
.assertRaises(lzc_exc
.FilesystemNotFound
):
3567 props
={b
"keyformat": lzc
.zfs_keyformat
.ZFS_KEYFORMAT_RAW
},
3568 key
=os
.urandom(lzc
.WRAPPING_KEY_LEN
))
3570 def test_change_key_not_loaded(self
):
3571 with
encrypted_filesystem() as (fs
, _
):
3572 lzc
.lzc_unload_key(fs
)
3573 with self
.assertRaises(lzc_exc
.EncryptionKeyNotLoaded
):
3576 props
={b
"keyformat": lzc
.zfs_keyformat
.ZFS_KEYFORMAT_RAW
},
3577 key
=os
.urandom(lzc
.WRAPPING_KEY_LEN
))
3579 def test_change_key_invalid_property(self
):
3580 with
encrypted_filesystem() as (fs
, _
):
3581 with self
.assertRaises(lzc_exc
.PropertyInvalid
):
3582 lzc
.lzc_change_key(fs
, 'new_key', props
={b
"invalid": b
"prop"})
3584 def test_change_key_invalid_crypt_command(self
):
3585 with
encrypted_filesystem() as (fs
, _
):
3586 with self
.assertRaises(lzc_exc
.UnknownCryptCommand
):
3587 lzc
.lzc_change_key(fs
, 'duplicate_key')
3589 def test_load_key(self
):
3590 with
encrypted_filesystem() as (fs
, key
):
3591 lzc
.lzc_unload_key(fs
)
3592 lzc
.lzc_load_key(fs
, False, key
)
3594 def test_load_key_invalid(self
):
3595 with
encrypted_filesystem() as (fs
, key
):
3596 lzc
.lzc_unload_key(fs
)
3597 with self
.assertRaises(lzc_exc
.EncryptionKeyInvalid
):
3598 lzc
.lzc_load_key(fs
, False, os
.urandom(lzc
.WRAPPING_KEY_LEN
))
3600 def test_load_key_already_loaded(self
):
3601 with
encrypted_filesystem() as (fs
, key
):
3602 lzc
.lzc_unload_key(fs
)
3603 lzc
.lzc_load_key(fs
, False, key
)
3604 with self
.assertRaises(lzc_exc
.EncryptionKeyAlreadyLoaded
):
3605 lzc
.lzc_load_key(fs
, False, key
)
3607 def test_load_key_missing_fs(self
):
3608 name
= b
"nonexistent"
3610 with self
.assertRaises(lzc_exc
.FilesystemNotFound
):
3611 lzc
.lzc_load_key(name
, False, key
=os
.urandom(lzc
.WRAPPING_KEY_LEN
))
3613 def test_unload_key(self
):
3614 with
encrypted_filesystem() as (fs
, _
):
3615 lzc
.lzc_unload_key(fs
)
3617 def test_unload_key_missing_fs(self
):
3618 name
= b
"nonexistent"
3620 with self
.assertRaises(lzc_exc
.FilesystemNotFound
):
3621 lzc
.lzc_unload_key(name
)
3623 def test_unload_key_busy(self
):
3624 with
encrypted_filesystem() as (fs
, _
):
3626 with self
.assertRaises(lzc_exc
.DatasetBusy
):
3627 lzc
.lzc_unload_key(fs
)
3629 def test_unload_key_not_loaded(self
):
3630 with
encrypted_filesystem() as (fs
, _
):
3631 lzc
.lzc_unload_key(fs
)
3632 with self
.assertRaises(lzc_exc
.EncryptionKeyNotLoaded
):
3633 lzc
.lzc_unload_key(fs
)
3635 def test_checkpoint(self
):
3636 pool
= ZFSTest
.pool
.getRoot().getName()
3638 lzc
.lzc_pool_checkpoint(pool
)
3640 def test_checkpoint_missing_pool(self
):
3641 pool
= b
"nonexistent"
3643 with self
.assertRaises(lzc_exc
.PoolNotFound
):
3644 lzc
.lzc_pool_checkpoint(pool
)
3646 def test_checkpoint_already_exists(self
):
3647 pool
= ZFSTest
.pool
.getRoot().getName()
3649 lzc
.lzc_pool_checkpoint(pool
)
3650 with self
.assertRaises(lzc_exc
.CheckpointExists
):
3651 lzc
.lzc_pool_checkpoint(pool
)
3653 def test_checkpoint_discard(self
):
3654 pool
= ZFSTest
.pool
.getRoot().getName()
3656 lzc
.lzc_pool_checkpoint(pool
)
3657 lzc
.lzc_pool_checkpoint_discard(pool
)
3659 def test_checkpoint_discard_missing_pool(self
):
3660 pool
= b
"nonexistent"
3662 with self
.assertRaises(lzc_exc
.PoolNotFound
):
3663 lzc
.lzc_pool_checkpoint_discard(pool
)
3665 def test_checkpoint_discard_missing_checkpoint(self
):
3666 pool
= ZFSTest
.pool
.getRoot().getName()
3668 with self
.assertRaises(lzc_exc
.CheckpointNotFound
):
3669 lzc
.lzc_pool_checkpoint_discard(pool
)
3671 @needs_support(lzc
.lzc_list_children
)
3672 def test_list_children(self
):
3673 name
= ZFSTest
.pool
.makeName(b
"fs1/fs")
3674 names
= [ZFSTest
.pool
.makeName(b
"fs1/fs/test1"),
3675 ZFSTest
.pool
.makeName(b
"fs1/fs/test2"),
3676 ZFSTest
.pool
.makeName(b
"fs1/fs/test3"), ]
3677 # and one snap to see that it is not listed
3678 snap
= ZFSTest
.pool
.makeName(b
"fs1/fs@test")
3682 lzc
.lzc_snapshot([snap
])
3684 children
= list(lzc
.lzc_list_children(name
))
3685 self
.assertItemsEqual(children
, names
)
3687 @needs_support(lzc
.lzc_list_children
)
3688 def test_list_children_nonexistent(self
):
3689 fs
= ZFSTest
.pool
.makeName(b
"nonexistent")
3691 with self
.assertRaises(lzc_exc
.DatasetNotFound
):
3692 list(lzc
.lzc_list_children(fs
))
3694 @needs_support(lzc
.lzc_list_children
)
3695 def test_list_children_of_snap(self
):
3696 snap
= ZFSTest
.pool
.makeName(b
"@newsnap")
3698 lzc
.lzc_snapshot([snap
])
3699 children
= list(lzc
.lzc_list_children(snap
))
3700 self
.assertEqual(children
, [])
3702 @needs_support(lzc
.lzc_list_snaps
)
3703 def test_list_snaps(self
):
3704 name
= ZFSTest
.pool
.makeName(b
"fs1/fs")
3705 names
= [ZFSTest
.pool
.makeName(b
"fs1/fs@test1"),
3706 ZFSTest
.pool
.makeName(b
"fs1/fs@test2"),
3707 ZFSTest
.pool
.makeName(b
"fs1/fs@test3"), ]
3708 # and one filesystem to see that it is not listed
3709 fs
= ZFSTest
.pool
.makeName(b
"fs1/fs/test")
3712 lzc
.lzc_snapshot([snap
])
3715 snaps
= list(lzc
.lzc_list_snaps(name
))
3716 self
.assertItemsEqual(snaps
, names
)
3718 @needs_support(lzc
.lzc_list_snaps
)
3719 def test_list_snaps_nonexistent(self
):
3720 fs
= ZFSTest
.pool
.makeName(b
"nonexistent")
3722 with self
.assertRaises(lzc_exc
.DatasetNotFound
):
3723 list(lzc
.lzc_list_snaps(fs
))
3725 @needs_support(lzc
.lzc_list_snaps
)
3726 def test_list_snaps_of_snap(self
):
3727 snap
= ZFSTest
.pool
.makeName(b
"@newsnap")
3729 lzc
.lzc_snapshot([snap
])
3730 snaps
= list(lzc
.lzc_list_snaps(snap
))
3731 self
.assertEqual(snaps
, [])
3733 @needs_support(lzc
.lzc_get_props
)
3734 def test_get_fs_props(self
):
3735 fs
= ZFSTest
.pool
.makeName(b
"new")
3736 props
= {b
"user:foo": b
"bar"}
3738 lzc
.lzc_create(fs
, props
=props
)
3739 actual_props
= lzc
.lzc_get_props(fs
)
3740 self
.assertDictContainsSubset(props
, actual_props
)
3742 @needs_support(lzc
.lzc_get_props
)
3743 def test_get_fs_props_with_child(self
):
3744 parent
= ZFSTest
.pool
.makeName(b
"parent")
3745 child
= ZFSTest
.pool
.makeName(b
"parent/child")
3746 parent_props
= {b
"user:foo": b
"parent"}
3747 child_props
= {b
"user:foo": b
"child"}
3749 lzc
.lzc_create(parent
, props
=parent_props
)
3750 lzc
.lzc_create(child
, props
=child_props
)
3751 actual_parent_props
= lzc
.lzc_get_props(parent
)
3752 actual_child_props
= lzc
.lzc_get_props(child
)
3753 self
.assertDictContainsSubset(parent_props
, actual_parent_props
)
3754 self
.assertDictContainsSubset(child_props
, actual_child_props
)
3756 @needs_support(lzc
.lzc_get_props
)
3757 def test_get_snap_props(self
):
3758 snapname
= ZFSTest
.pool
.makeName(b
"@snap")
3760 props
= {b
"user:foo": b
"bar"}
3762 lzc
.lzc_snapshot(snaps
, props
)
3763 actual_props
= lzc
.lzc_get_props(snapname
)
3764 self
.assertDictContainsSubset(props
, actual_props
)
3766 @needs_support(lzc
.lzc_get_props
)
3767 def test_get_props_nonexistent(self
):
3768 fs
= ZFSTest
.pool
.makeName(b
"nonexistent")
3770 with self
.assertRaises(lzc_exc
.DatasetNotFound
):
3771 lzc
.lzc_get_props(fs
)
3773 @needs_support(lzc
.lzc_get_props
)
3774 def test_get_mountpoint_none(self
):
3776 If the *mountpoint* property is set to none, then its
3777 value is returned as `bytes` "none".
3778 Also, a child filesystem inherits that value.
3780 fs
= ZFSTest
.pool
.makeName(b
"new")
3781 child
= ZFSTest
.pool
.makeName(b
"new/child")
3782 props
= {b
"mountpoint": b
"none"}
3784 lzc
.lzc_create(fs
, props
=props
)
3785 lzc
.lzc_create(child
)
3786 actual_props
= lzc
.lzc_get_props(fs
)
3787 self
.assertDictContainsSubset(props
, actual_props
)
3788 # check that mountpoint value is correctly inherited
3789 child_props
= lzc
.lzc_get_props(child
)
3790 self
.assertDictContainsSubset(props
, child_props
)
3792 @needs_support(lzc
.lzc_get_props
)
3793 def test_get_mountpoint_legacy(self
):
3795 If the *mountpoint* property is set to legacy, then its
3796 value is returned as `bytes` "legacy".
3797 Also, a child filesystem inherits that value.
3799 fs
= ZFSTest
.pool
.makeName(b
"new")
3800 child
= ZFSTest
.pool
.makeName(b
"new/child")
3801 props
= {b
"mountpoint": b
"legacy"}
3803 lzc
.lzc_create(fs
, props
=props
)
3804 lzc
.lzc_create(child
)
3805 actual_props
= lzc
.lzc_get_props(fs
)
3806 self
.assertDictContainsSubset(props
, actual_props
)
3807 # check that mountpoint value is correctly inherited
3808 child_props
= lzc
.lzc_get_props(child
)
3809 self
.assertDictContainsSubset(props
, child_props
)
3811 @needs_support(lzc
.lzc_get_props
)
3812 def test_get_mountpoint_path(self
):
3814 If the *mountpoint* property is set to a path and the property
3815 is not explicitly set on a child filesystem, then its
3816 value is that of the parent filesystem with the child's
3817 name appended using the '/' separator.
3819 fs
= ZFSTest
.pool
.makeName(b
"new")
3820 child
= ZFSTest
.pool
.makeName(b
"new/child")
3821 props
= {b
"mountpoint": b
"/mnt"}
3823 lzc
.lzc_create(fs
, props
=props
)
3824 lzc
.lzc_create(child
)
3825 actual_props
= lzc
.lzc_get_props(fs
)
3826 self
.assertDictContainsSubset(props
, actual_props
)
3827 # check that mountpoint value is correctly inherited
3828 child_props
= lzc
.lzc_get_props(child
)
3829 self
.assertDictContainsSubset(
3830 {b
"mountpoint": b
"/mnt/child"}, child_props
)
3832 @needs_support(lzc
.lzc_get_props
)
3833 def test_get_snap_clones(self
):
3834 fs
= ZFSTest
.pool
.makeName(b
"new")
3835 snap
= ZFSTest
.pool
.makeName(b
"@snap")
3836 clone1
= ZFSTest
.pool
.makeName(b
"clone1")
3837 clone2
= ZFSTest
.pool
.makeName(b
"clone2")
3840 lzc
.lzc_snapshot([snap
])
3841 lzc
.lzc_clone(clone1
, snap
)
3842 lzc
.lzc_clone(clone2
, snap
)
3844 clones_prop
= lzc
.lzc_get_props(snap
)["clones"]
3845 self
.assertItemsEqual(clones_prop
, [clone1
, clone2
])
3847 @needs_support(lzc
.lzc_rename
)
3848 def test_rename(self
):
3849 src
= ZFSTest
.pool
.makeName(b
"source")
3850 tgt
= ZFSTest
.pool
.makeName(b
"target")
3853 lzc
.lzc_rename(src
, tgt
)
3854 self
.assertNotExists(src
)
3855 self
.assertExists(tgt
)
3857 @needs_support(lzc
.lzc_rename
)
3858 def test_rename_nonexistent(self
):
3859 src
= ZFSTest
.pool
.makeName(b
"source")
3860 tgt
= ZFSTest
.pool
.makeName(b
"target")
3862 with self
.assertRaises(lzc_exc
.FilesystemNotFound
):
3863 lzc
.lzc_rename(src
, tgt
)
3865 @needs_support(lzc
.lzc_rename
)
3866 def test_rename_existing_target(self
):
3867 src
= ZFSTest
.pool
.makeName(b
"source")
3868 tgt
= ZFSTest
.pool
.makeName(b
"target")
3872 with self
.assertRaises(lzc_exc
.FilesystemExists
):
3873 lzc
.lzc_rename(src
, tgt
)
3875 @needs_support(lzc
.lzc_rename
)
3876 def test_rename_nonexistent_target_parent(self
):
3877 src
= ZFSTest
.pool
.makeName(b
"source")
3878 tgt
= ZFSTest
.pool
.makeName(b
"parent/target")
3881 with self
.assertRaises(lzc_exc
.FilesystemNotFound
):
3882 lzc
.lzc_rename(src
, tgt
)
3884 @needs_support(lzc
.lzc_rename
)
3885 def test_rename_parent_is_zvol(self
):
3886 src
= ZFSTest
.pool
.makeName(b
"source")
3887 zvol
= ZFSTest
.pool
.makeName(b
"parent")
3888 tgt
= zvol
+ b
"/target"
3889 props
= {b
"volsize": 1024 * 1024}
3892 lzc
.lzc_create(zvol
, ds_type
='zvol', props
=props
)
3893 with self
.assertRaises(lzc_exc
.WrongParent
):
3894 lzc
.lzc_rename(src
, tgt
)
3896 @needs_support(lzc
.lzc_destroy
)
3897 def test_destroy(self
):
3898 fs
= ZFSTest
.pool
.makeName(b
"test-fs")
3902 self
.assertNotExists(fs
)
3904 @needs_support(lzc
.lzc_destroy
)
3905 def test_destroy_nonexistent(self
):
3906 fs
= ZFSTest
.pool
.makeName(b
"test-fs")
3908 with self
.assertRaises(lzc_exc
.FilesystemNotFound
):
3911 @needs_support(lzc
.lzc_inherit_prop
)
3912 def test_inherit_prop(self
):
3913 parent
= ZFSTest
.pool
.makeName(b
"parent")
3914 child
= ZFSTest
.pool
.makeName(b
"parent/child")
3915 the_prop
= b
"user:foo"
3916 parent_props
= {the_prop
: b
"parent"}
3917 child_props
= {the_prop
: b
"child"}
3919 lzc
.lzc_create(parent
, props
=parent_props
)
3920 lzc
.lzc_create(child
, props
=child_props
)
3921 lzc
.lzc_inherit_prop(child
, the_prop
)
3922 actual_props
= lzc
.lzc_get_props(child
)
3923 self
.assertDictContainsSubset(parent_props
, actual_props
)
3925 @needs_support(lzc
.lzc_inherit_prop
)
3926 def test_inherit_missing_prop(self
):
3927 parent
= ZFSTest
.pool
.makeName(b
"parent")
3928 child
= ZFSTest
.pool
.makeName(b
"parent/child")
3929 the_prop
= "user:foo"
3930 child_props
= {the_prop
: "child"}
3932 lzc
.lzc_create(parent
)
3933 lzc
.lzc_create(child
, props
=child_props
)
3934 lzc
.lzc_inherit_prop(child
, the_prop
)
3935 actual_props
= lzc
.lzc_get_props(child
)
3936 self
.assertNotIn(the_prop
, actual_props
)
3938 @needs_support(lzc
.lzc_inherit_prop
)
3939 def test_inherit_readonly_prop(self
):
3940 parent
= ZFSTest
.pool
.makeName(b
"parent")
3941 child
= ZFSTest
.pool
.makeName(b
"parent/child")
3942 the_prop
= b
"createtxg"
3944 lzc
.lzc_create(parent
)
3945 lzc
.lzc_create(child
)
3946 with self
.assertRaises(lzc_exc
.PropertyInvalid
):
3947 lzc
.lzc_inherit_prop(child
, the_prop
)
3949 @needs_support(lzc
.lzc_inherit_prop
)
3950 def test_inherit_unknown_prop(self
):
3951 parent
= ZFSTest
.pool
.makeName(b
"parent")
3952 child
= ZFSTest
.pool
.makeName(b
"parent/child")
3953 the_prop
= b
"nosuchprop"
3955 lzc
.lzc_create(parent
)
3956 lzc
.lzc_create(child
)
3957 with self
.assertRaises(lzc_exc
.PropertyInvalid
):
3958 lzc
.lzc_inherit_prop(child
, the_prop
)
3960 @needs_support(lzc
.lzc_inherit_prop
)
3961 def test_inherit_prop_on_snap(self
):
3962 fs
= ZFSTest
.pool
.makeName(b
"new")
3963 snapname
= ZFSTest
.pool
.makeName(b
"new@snap")
3968 lzc
.lzc_create(fs
, props
={prop
: fs_val
})
3969 lzc
.lzc_snapshot([snapname
], props
={prop
: snap_val
})
3971 actual_props
= lzc
.lzc_get_props(snapname
)
3972 self
.assertDictContainsSubset({prop
: snap_val
}, actual_props
)
3974 lzc
.lzc_inherit_prop(snapname
, prop
)
3975 actual_props
= lzc
.lzc_get_props(snapname
)
3976 self
.assertDictContainsSubset({prop
: fs_val
}, actual_props
)
3978 @needs_support(lzc
.lzc_set_prop
)
3979 def test_set_fs_prop(self
):
3980 fs
= ZFSTest
.pool
.makeName(b
"new")
3985 lzc
.lzc_set_prop(fs
, prop
, val
)
3986 actual_props
= lzc
.lzc_get_props(fs
)
3987 self
.assertDictContainsSubset({prop
: val
}, actual_props
)
3989 @needs_support(lzc
.lzc_set_prop
)
3990 def test_set_snap_prop(self
):
3991 snapname
= ZFSTest
.pool
.makeName(b
"@snap")
3995 lzc
.lzc_snapshot([snapname
])
3996 lzc
.lzc_set_prop(snapname
, prop
, val
)
3997 actual_props
= lzc
.lzc_get_props(snapname
)
3998 self
.assertDictContainsSubset({prop
: val
}, actual_props
)
4000 @needs_support(lzc
.lzc_set_prop
)
4001 def test_set_prop_nonexistent(self
):
4002 fs
= ZFSTest
.pool
.makeName(b
"nonexistent")
4006 with self
.assertRaises(lzc_exc
.DatasetNotFound
):
4007 lzc
.lzc_set_prop(fs
, prop
, val
)
4009 @needs_support(lzc
.lzc_set_prop
)
4010 def test_set_sys_prop(self
):
4011 fs
= ZFSTest
.pool
.makeName(b
"new")
4012 prop
= b
"recordsize"
4016 lzc
.lzc_set_prop(fs
, prop
, val
)
4017 actual_props
= lzc
.lzc_get_props(fs
)
4018 self
.assertDictContainsSubset({prop
: val
}, actual_props
)
4020 @needs_support(lzc
.lzc_set_prop
)
4021 def test_set_invalid_prop(self
):
4022 fs
= ZFSTest
.pool
.makeName(b
"new")
4023 prop
= b
"nosuchprop"
4027 with self
.assertRaises(lzc_exc
.PropertyInvalid
):
4028 lzc
.lzc_set_prop(fs
, prop
, val
)
4030 @needs_support(lzc
.lzc_set_prop
)
4031 def test_set_invalid_value_prop(self
):
4032 fs
= ZFSTest
.pool
.makeName(b
"new")
4037 with self
.assertRaises(lzc_exc
.PropertyInvalid
):
4038 lzc
.lzc_set_prop(fs
, prop
, val
)
4040 @needs_support(lzc
.lzc_set_prop
)
4041 def test_set_invalid_value_prop_2(self
):
4042 fs
= ZFSTest
.pool
.makeName(b
"new")
4047 with self
.assertRaises(lzc_exc
.PropertyInvalid
):
4048 lzc
.lzc_set_prop(fs
, prop
, val
)
4050 @needs_support(lzc
.lzc_set_prop
)
4051 def test_set_prop_too_small_quota(self
):
4052 fs
= ZFSTest
.pool
.makeName(b
"new")
4057 with self
.assertRaises(lzc_exc
.NoSpace
):
4058 lzc
.lzc_set_prop(fs
, prop
, val
)
4060 @needs_support(lzc
.lzc_set_prop
)
4061 def test_set_readonly_prop(self
):
4062 fs
= ZFSTest
.pool
.makeName(b
"new")
4067 lzc
.lzc_set_prop(fs
, prop
, val
)
4068 actual_props
= lzc
.lzc_get_props(fs
)
4069 # the change is silently ignored
4070 self
.assertTrue(actual_props
[prop
] != val
)
4073 class _TempPool(object):
4074 SNAPSHOTS
= [b
'snap', b
'snap1', b
'snap2']
4075 BOOKMARKS
= [b
'bmark', b
'bmark1', b
'bmark2']
4077 _cachefile_suffix
= ".cachefile"
4079 # XXX Whether to do a sloppy but much faster cleanup
4080 # or a proper but slower one.
4081 _recreate_pools
= True
4083 def __init__(self
, size
=128 * 1024 * 1024, readonly
=False, filesystems
=[]):
4084 self
._filesystems
= filesystems
4085 self
._readonly
= readonly
4086 if sys
.version_info
< (3, 0):
4087 self
._pool
_name
= b
'pool.' + bytes(uuid
.uuid4())
4089 self
._pool
_name
= b
'pool.' + bytes(str(uuid
.uuid4()),
4091 self
._root
= _Filesystem(self
._pool
_name
)
4092 (fd
, self
._pool
_file
_path
) = tempfile
.mkstemp(
4093 suffix
='.zpool', prefix
='tmp-')
4095 cachefile
= self
._pool
_file
_path
+ _TempPool
._cachefile
_suffix
4098 self
._zpool
_create
= [
4099 'zpool', 'create', '-o', 'cachefile=' + cachefile
,
4100 '-O', 'mountpoint=legacy', self
._pool
_name
, self
._pool
_file
_path
]
4102 os
.ftruncate(fd
, size
)
4105 subprocess
.check_output(
4106 self
._zpool
_create
, stderr
=subprocess
.STDOUT
)
4108 for fs
in filesystems
:
4109 lzc
.lzc_create(self
.makeName(fs
))
4111 self
._bmarks
_supported
= self
.isPoolFeatureEnabled('bookmarks')
4114 # To make a pool read-only it must exported and re-imported
4115 # with readonly option.
4116 # The most deterministic way to re-import the pool is by using
4118 # But the cache file has to be stashed away before the pool is
4119 # exported, because otherwise the pool is removed from the
4121 shutil
.copyfile(cachefile
, cachefile
+ '.tmp')
4122 subprocess
.check_output(
4123 ['zpool', 'export', '-f', self
._pool
_name
],
4124 stderr
=subprocess
.STDOUT
)
4125 os
.rename(cachefile
+ '.tmp', cachefile
)
4126 subprocess
.check_output(
4127 ['zpool', 'import', '-f', '-N', '-c', cachefile
,
4128 '-o', 'readonly=on', self
._pool
_name
],
4129 stderr
=subprocess
.STDOUT
)
4130 os
.remove(cachefile
)
4132 except subprocess
.CalledProcessError
as e
:
4134 if b
'permission denied' in e
.output
:
4135 raise unittest
.SkipTest(
4136 'insufficient privileges to run libzfs_core tests')
4137 print('command failed: ', e
.output
)
4147 if not self
.__class
__._recreate
_pools
:
4149 for fs
in [''] + self
._filesystems
:
4150 for snap
in self
.__class
__.SNAPSHOTS
:
4151 snaps
.append(self
.makeName(fs
+ '@' + snap
))
4152 self
.getRoot().visitSnaps(lambda snap
: snaps
.append(snap
))
4153 lzc
.lzc_destroy_snaps(snaps
, defer
=False)
4155 if self
._bmarks
_supported
:
4157 for fs
in [''] + self
._filesystems
:
4158 for bmark
in self
.__class
__.BOOKMARKS
:
4159 bmarks
.append(self
.makeName(fs
+ '#' + bmark
))
4160 self
.getRoot().visitBookmarks(
4161 lambda bmark
: bmarks
.append(bmark
))
4162 lzc
.lzc_destroy_bookmarks(bmarks
)
4163 self
.getRoot().reset()
4166 # On the Buildbot builders this may fail with "pool is busy"
4167 # Retry 5 times before raising an error
4171 subprocess
.check_output(
4172 ['zpool', 'destroy', '-f', self
._pool
_name
],
4173 stderr
=subprocess
.STDOUT
)
4174 subprocess
.check_output(
4175 self
._zpool
_create
, stderr
=subprocess
.STDOUT
)
4177 except subprocess
.CalledProcessError
as e
:
4178 if b
'pool is busy' in e
.output
and retry
< 5:
4183 print('command failed: ', e
.output
)
4185 for fs
in self
._filesystems
:
4186 lzc
.lzc_create(self
.makeName(fs
))
4187 self
.getRoot().reset()
4191 subprocess
.check_output(
4192 ['zpool', 'destroy', '-f', self
._pool
_name
],
4193 stderr
=subprocess
.STDOUT
)
4197 os
.remove(self
._pool
_file
_path
)
4201 os
.remove(self
._pool
_file
_path
+ _TempPool
._cachefile
_suffix
)
4206 self
._pool
_file
_path
+ _TempPool
._cachefile
_suffix
+ '.tmp')
4210 def makeName(self
, relative
=None):
4212 return self
._pool
_name
4213 if relative
.startswith((b
'@', b
'#')):
4214 return self
._pool
_name
+ relative
4215 return self
._pool
_name
+ b
'/' + relative
4217 def makeTooLongName(self
, prefix
=None):
4220 prefix
= self
.makeName(prefix
)
4221 pad_len
= lzc
.MAXNAMELEN
+ 1 - len(prefix
)
4223 return prefix
+ b
'x' * pad_len
4227 def makeTooLongComponent(self
, prefix
=None):
4228 padding
= b
'x' * (lzc
.MAXNAMELEN
+ 1)
4232 prefix
= prefix
+ padding
4233 return self
.makeName(prefix
)
4238 def getFilesystem(self
, fsname
):
4239 return _Filesystem(self
._pool
_name
+ b
'/' + fsname
)
4241 def isPoolFeatureAvailable(self
, feature
):
4242 output
= subprocess
.check_output(
4243 ['zpool', 'get', '-H', 'feature@' + feature
, self
._pool
_name
])
4244 output
= output
.strip()
4247 def isPoolFeatureEnabled(self
, feature
):
4248 output
= subprocess
.check_output(
4249 ['zpool', 'get', '-H', 'feature@' + feature
, self
._pool
_name
])
4250 output
= output
.split()[2]
4251 return output
in [b
'active', b
'enabled']
4254 class _Filesystem(object):
4256 def __init__(self
, name
):
4269 def getFilesystem(self
):
4271 fsname
= self
._name
+ b
'/fs' + str(self
._fs
_id
).encode()
4272 fs
= _Filesystem(fsname
)
4273 self
._children
.append(fs
)
4276 def getProperty(self
, propname
, received
=False):
4278 output
= subprocess
.check_output(
4279 ['zfs', 'get', '-pH', '-o', 'received', propname
, self
._name
])
4281 output
= subprocess
.check_output(
4282 ['zfs', 'get', '-pH', '-o', 'value', propname
, self
._name
])
4283 return output
.strip()
4285 def _makeSnapName(self
, i
):
4286 return self
._name
+ b
'@snap' + str(i
).encode()
4290 return self
._makeSnapName
(self
._snap
_id
)
4292 def _makeBookmarkName(self
, i
):
4293 return self
._name
+ b
'#bmark' + bytes(i
)
4295 def getBookmark(self
):
4297 return self
._makeBookmarkName
(self
._bmark
_id
)
4299 def _makeTooLongName(self
, too_long_component
):
4300 if too_long_component
:
4301 return b
'x' * (lzc
.MAXNAMELEN
+ 1)
4303 # Note that another character is used for one of '/', '@', '#'.
4304 comp_len
= lzc
.MAXNAMELEN
- len(self
._name
)
4306 return b
'x' * comp_len
4310 def getTooLongFilesystemName(self
, too_long_component
):
4311 return self
._name
+ b
'/' + self
._makeTooLongName
(too_long_component
)
4313 def getTooLongSnap(self
, too_long_component
):
4314 return self
._name
+ b
'@' + self
._makeTooLongName
(too_long_component
)
4316 def getTooLongBookmark(self
, too_long_component
):
4317 return self
._name
+ b
'#' + self
._makeTooLongName
(too_long_component
)
4319 def _visitFilesystems(self
, visitor
):
4320 for child
in self
._children
:
4321 child
._visitFilesystems
(visitor
)
4324 def visitFilesystems(self
, visitor
):
4328 self
._visitFilesystems
(_fsVisitor
)
4330 def visitSnaps(self
, visitor
):
4331 def _snapVisitor(fs
):
4332 for i
in range(1, fs
._snap
_id
+ 1):
4333 visitor(fs
._makeSnapName
(i
))
4335 self
._visitFilesystems
(_snapVisitor
)
4337 def visitBookmarks(self
, visitor
):
4338 def _bmarkVisitor(fs
):
4339 for i
in range(1, fs
._bmark
_id
+ 1):
4340 visitor(fs
._makeBookmarkName
(i
))
4342 self
._visitFilesystems
(_bmarkVisitor
)
4345 # vim: softtabstop=4 tabstop=4 expandtab shiftwidth=4