from basetest import * class TestZfsNode(unittest2.TestCase): def setUp(self): prepare_zpools() self.longMessage = True def test_destroymissing(self): # initial backup with mocktime("19101111000000"): # 1000 years in past self.assertFalse(ZfsAutobackup("test test_target1 --no-progress --verbose --no-holds".split(" ")).run()) with mocktime("20101111000000"): # far in past self.assertFalse( ZfsAutobackup("test test_target1 --no-progress --verbose --no-holds --allow-empty".split(" ")).run()) with self.subTest("Should do nothing yet"): with OutputIO() as buf: with redirect_stdout(buf): self.assertFalse(ZfsAutobackup( "test test_target1 --no-progress --verbose --no-snapshot --destroy-missing 0s".split( " ")).run()) print(buf.getvalue()) self.assertNotIn(": Destroy missing", buf.getvalue()) with self.subTest("missing dataset of us that still has children"): # just deselect it so it counts as 'missing' shelltest("zfs set autobackup:test=child test_source1/fs1") with OutputIO() as buf: with redirect_stdout(buf), redirect_stderr(buf): self.assertFalse(ZfsAutobackup( "test test_target1 --no-progress --verbose --no-snapshot --destroy-missing 0s".split( " ")).run()) print(buf.getvalue()) # should have done the snapshot cleanup for destoy missing: self.assertIn("fs1@test-19101111000000: Destroying", buf.getvalue()) self.assertIn("fs1: Destroy missing: Still has children here.", buf.getvalue()) shelltest("zfs inherit autobackup:test test_source1/fs1") with self.subTest("Normal destroyed leaf"): shelltest("zfs destroy -r test_source1/fs1/sub") # wait for deadline of last snapshot with OutputIO() as buf: with redirect_stdout(buf): # 100y: lastest should not be old enough, while second to latest snapshot IS old enough: self.assertFalse(ZfsAutobackup( "test test_target1 --no-progress --verbose --no-snapshot --destroy-missing 100y".split( " ")).run()) print(buf.getvalue()) self.assertIn(": Waiting for deadline", buf.getvalue()) # past deadline, destroy with OutputIO() as buf: with redirect_stdout(buf): self.assertFalse(ZfsAutobackup( "test test_target1 --no-progress --verbose --no-snapshot --destroy-missing 1y".split( " ")).run()) print(buf.getvalue()) self.assertIn("sub: Destroying", buf.getvalue()) with self.subTest("Leaf with other snapshot still using it"): shelltest("zfs destroy -r test_source1/fs1") shelltest("zfs snapshot -r test_target1/test_source1/fs1@other1") with OutputIO() as buf: with redirect_stdout(buf): self.assertFalse(ZfsAutobackup( "test test_target1 --no-progress --verbose --no-snapshot --destroy-missing 0s".split( " ")).run()) print(buf.getvalue()) # cant finish because still in use: self.assertIn("fs1: Destroy missing: Still in use", buf.getvalue()) shelltest("zfs destroy test_target1/test_source1/fs1@other1") with self.subTest("In use by clone"): shelltest("zfs clone test_target1/test_source1/fs1@test-20101111000000 test_target1/clone1") with OutputIO() as buf: with redirect_stdout(buf), redirect_stderr(buf): self.assertFalse(ZfsAutobackup( "test test_target1 --no-progress --verbose --no-snapshot --destroy-missing 0s".split( " ")).run()) print(buf.getvalue()) # now tries to destroy our own last snapshot (before the final destroy of the dataset) self.assertIn("fs1@test-20101111000000: Destroying", buf.getvalue()) # but cant finish because still in use: self.assertIn("fs1: Error during --destroy-missing", buf.getvalue()) shelltest("zfs destroy test_target1/clone1") with self.subTest("Should leave test_source1 parent"): with OutputIO() as buf: with redirect_stdout(buf), redirect_stderr(buf): self.assertFalse(ZfsAutobackup( "test test_target1 --no-progress --verbose --no-snapshot --destroy-missing 0s".split( " ")).run()) print(buf.getvalue()) # should have done the snapshot cleanup for destoy missing: self.assertIn("fs1: Destroying", buf.getvalue()) with OutputIO() as buf: with redirect_stdout(buf), redirect_stderr(buf): self.assertFalse(ZfsAutobackup( "test test_target1 --no-progress --verbose --no-snapshot --destroy-missing 0s".split( " ")).run()) print(buf.getvalue()) # on second run it sees the dangling ex-parent but doesnt know what to do with it (since it has no own snapshot) self.assertIn("test_source1: Destroy missing: has no snapshots made by us", buf.getvalue()) # end result r = shelltest("zfs list -H -o name -r -t snapshot,filesystem test_target1") self.assertMultiLineEqual(r, """ test_target1 test_target1/test_source1 test_target1/test_source2 test_target1/test_source2/fs2 test_target1/test_source2/fs2/sub test_target1/test_source2/fs2/sub@test-19101111000000 test_target1/test_source2/fs2/sub@test-20101111000000 """)