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