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