Compare commits

...

67 Commits

Author SHA1 Message Date
Aaron Whitehouse accd8ccbac
Merge cd0b9f362b into b31ed6e325 2024-04-22 20:09:31 +02:00
Jim Salter b31ed6e325
Merge pull request #916 from 0xFelix/zstdmt
syncoid: Add zstdmt compress options
2024-04-22 12:14:40 -04:00
Jim Salter fa2c16d65a
Merge pull request #905 from phreaker0/findoid-relative-path
[findoid] support relative paths
2024-04-22 12:13:43 -04:00
Jim Salter 1207ea0062
Merge pull request #904 from phreaker0/tests-restructure
test adaptions
2024-04-22 12:13:28 -04:00
Jim Salter d800e5e17d
Merge pull request #903 from spicyFajitas/regather_snapshots--delete-target-snaps_task
fix(syncoid): regather $snaps on --delete-target-snapshots flag
2024-04-22 12:12:58 -04:00
Jim Salter 1ee6815e5e
Merge pull request #910 from phreaker0/improve-output
added missing status information about what is done and provide more details
2024-04-22 12:12:28 -04:00
0xFelix 8b7d29d5a0 syncoid: Add zstdmt compress options
Add the zstdmt-fast and zstdmt-slow compress options to allow use of
multithreading when using zstd compression.

Signed-off-by: 0xFelix <felix@matouschek.org>
2024-04-20 18:41:43 +02:00
Christoph Klaffl b4c8e4b499
Merge branch 'master' into improve-output 2024-04-18 14:30:04 +02:00
Jim Salter 45b1ce9e5d
Merge pull request #911 from phreaker0/fix-error-handling
handle error output for filtered replications
2024-04-18 08:25:30 -04:00
Christoph Klaffl 6c1e31e551
handle error output for filtered replications 2024-04-18 08:22:37 +02:00
Christoph Klaffl eb4fe8a01c
added missing status information about what is done and provide more details 2024-04-18 07:42:47 +02:00
Christoph Klaffl d7ed4bdf54
support relative paths 2024-04-05 15:24:42 +02:00
Christoph Klaffl 4e86733c1a
missed debug statement 2024-04-05 15:22:13 +02:00
Christoph Klaffl 7c8a34eceb
* proper order of tests
* timing fixes for fast NVME pools
* skip invasive tests by default
2024-04-05 15:20:28 +02:00
Adam Fulton d08b2882b7 finish rebase to master 2024-04-01 13:16:16 -05:00
Adam Fulton f89372967f fix(syncoid): regather $snaps on --delete-target-snapshots flag 2024-04-01 13:12:59 -05:00
Aaron Whitehouse cd0b9f362b Add tests with monitor_dont_crit set but
without monitor_dont_warn
2022-04-02 21:37:54 +01:00
Aaron Whitehouse 135f310881 Add copy of monitor snapshots test with
monitor_dont_warn and monitor_dont_crit set
2022-04-02 21:23:34 +01:00
Aaron Whitehouse fec7cf9e18 Add newline 2022-03-27 22:23:03 +01:00
Aaron Whitehouse b17a0fe104 Add newline at end of sanoid.conf 2022-03-27 22:13:49 +01:00
Aaron Whitehouse 9759fa45c4 Ready to merge 2022-03-27 22:10:03 +01:00
Aaron Whitehouse 9cc6b7f12b Delete redundant set of tests from rename/merge 2022-03-27 21:36:19 +01:00
Aaron Whitehouse 3a4e043c96 Merge branch 'add_vm_tests' of https://github.com/Hooloovoo/sanoid into add_vm_tests 2022-03-27 21:32:37 +01:00
Aaron Whitehouse cdbe07e4ec Create a new set of tests for --monitor-snapshots
these create pools in a number of states and check the output text
and return code
2022-03-27 21:28:21 +01:00
Aaron Whitehouse 5015aecd7e change name of test_two_warnings_daily
to be more accurate
2022-03-27 20:35:24 +01:00
Aaron Whitehouse c7e57b7c74 Fix test_two_warnings 2022-03-23 22:11:45 +00:00
Aaron Whitehouse 81529523fd Fix return code 2022-03-23 22:10:52 +00:00
Aaron Whitehouse c28f1c30dc Fix test_two_warnings_daily text test 2022-03-23 22:09:29 +00:00
Aaron Whitehouse ae4c0c6fa2 Start test_two_warnings_daily 2022-03-23 21:53:39 +00:00
Aaron Whitehouse 38ed37c96d Fix test_two_criticals returncode 2022-03-23 21:45:44 +00:00
Aaron Whitehouse f0fd435fa6 Fix test_two_criticals output test 2022-03-23 21:44:20 +00:00
Aaron Whitehouse a7fd743228 Add test details for two criticals 2022-03-23 21:42:00 +00:00
Aaron Whitehouse 7462a1a7fe Adjust time slightly 2022-03-23 21:29:18 +00:00
Aaron Whitehouse adddd20672 Add initial test for two critical monitoring
errors
2022-03-23 21:27:08 +00:00
Aaron Whitehouse 4c9a9e2eb8 Use sanoid --force-update instead of
manually deleting snapshot cache
2022-03-23 21:23:11 +00:00
Aaron Whitehouse d9da30dadd Fix test for one monitoring warning. 2022-03-23 21:20:18 +00:00
Aaron Whitehouse f870d27e9f Test warning string 2022-03-23 21:16:31 +00:00
Aaron Whitehouse a2fc4b30ac Add print for debugging 2022-03-23 21:03:36 +00:00
Aaron Whitehouse 2561a5ed5d Add more info for debugging 2022-03-23 21:03:11 +00:00
Aaron Whitehouse 0b7c05f4c7 First time-based test (one warning) 2022-03-23 20:55:44 +00:00
Aaron Whitehouse 6710b2d36f Clear snapshot cache before each test 2022-03-17 22:38:41 +00:00
Aaron Whitehouse b992beba19 Add test for monitoring immediately after running 2022-03-17 22:34:47 +00:00
Aaron Whitehouse d0f89c96bb Fix monitoring test after sanoid run 2022-03-17 22:31:15 +00:00
Aaron Whitehouse 02aedfaaa2 Test monitoring after sanoid cron 2022-03-17 22:22:39 +00:00
Aaron Whitehouse 867b755bb1 Delete temp disk images as part of teardown 2022-03-17 22:19:36 +00:00
Aaron Whitehouse 49589e2a17 Comment out zpool export, as now in python 2022-03-17 22:17:17 +00:00
Aaron Whitehouse 33648050dd Clean up monitoring tests zpool creation/teardown 2022-03-17 22:13:13 +00:00
Aaron Whitehouse 8571510685 Fix pool_target issues in test. 2022-03-17 21:57:40 +00:00
Aaron Whitehouse 3e9730d135 debugging 2022-03-17 21:54:36 +00:00
Aaron Whitehouse 890c785d0b Fixes to zpool creation test. 2022-03-17 21:51:29 +00:00
Aaron Whitehouse 37bce97d6e add test 2022-03-17 21:46:07 +00:00
Aaron Whitehouse e556495dea Create zpool, test. 2022-03-17 21:45:49 +00:00
Aaron Whitehouse c8f2b3f283 Fix return code of first test 2022-03-17 21:25:22 +00:00
Aaron Whitehouse 501c9921c4 Test return code for monitoring no pool 2022-03-17 14:34:08 +00:00
Aaron Whitehouse 26777c2c68 Add 2nd section to sanoid.conf for monitoring test 2022-03-17 14:23:18 +00:00
Aaron Whitehouse f93985111f add second section 2022-03-17 14:19:05 +00:00
Aaron Whitehouse c488df5983 Fix test output. 2022-03-17 11:10:49 +00:00
Aaron Whitehouse 8bb8d38cc8 Remove check on test 2022-03-17 11:07:49 +00:00
Aaron Whitehouse c21d8d0168 Fix path to sanoid snapshot cache file 2022-03-17 11:03:29 +00:00
Aaron Whitehouse 123e35e804 Fix --monitor-snapshots command in test 2022-03-17 10:59:44 +00:00
Aaron Whitehouse 1bdb60715c add subprocess import 2022-03-17 10:57:00 +00:00
Aaron Whitehouse 3655c02775 Test output with no zpool. 2022-03-17 10:54:48 +00:00
Aaron Whitehouse b3ee98a234 Test failure. 2022-03-17 10:37:43 +00:00
Aaron Whitehouse 372eadcb37 Add python test 2022-03-17 10:35:13 +00:00
Aaron Whitehouse e26671c97d Add monitoring test framework 2022-03-17 10:28:10 +00:00
Aaron Whitehouse cdbc1915ba Add new monitoring test scaffolding. 2022-03-17 10:27:04 +00:00
Aaron Whitehouse e963dd228f Add tests README with instructions on testing 2022-03-17 10:05:01 +00:00
26 changed files with 802 additions and 23 deletions

View File

@ -25,6 +25,9 @@ if ($args{'path'} eq '') {
}
}
# resolve given path to a canonical one
$args{'path'} = Cwd::realpath($args{'path'});
my $dataset = getdataset($args{'path'});
my %versions = getversions($args{'path'}, $dataset);

103
syncoid
View File

@ -498,7 +498,6 @@ sub syncdataset {
my $ret;
if (defined $origin) {
writelog('INFO', "Clone is recreated on target $targetfs based on $origin");
($ret, $stdout) = syncclone($sourcehost, $sourcefs, $origin, $targethost, $targetfs, $oldestsnap);
if ($ret) {
writelog('INFO', "clone creation failed, trying ordinary replication as fallback");
@ -506,12 +505,6 @@ sub syncdataset {
return 0;
}
} else {
if (!defined ($args{'no-stream'}) ) {
writelog('INFO', "Sending oldest full snapshot $sourcefs\@$oldestsnap to new target filesystem:");
} else {
writelog('INFO', "--no-stream selected; sending newest full snapshot $sourcefs\@$oldestsnap to new target filesystem:");
}
($ret, $stdout) = syncfull($sourcehost, $sourcefs, $targethost, $targetfs, $oldestsnap);
}
@ -532,8 +525,6 @@ sub syncdataset {
# $originaltargetreadonly = getzfsvalue($targethost,$targetfs,$targetisroot,'readonly');
# setzfsvalue($targethost,$targetfs,$targetisroot,'readonly','on');
writelog('INFO', "Updating new target filesystem with incremental $sourcefs\@$oldestsnap ... $newsyncsnap:");
(my $ret, $stdout) = syncincremental($sourcehost, $sourcefs, $targethost, $targetfs, $oldestsnap, $newsyncsnap, 0);
if ($ret != 0) {
@ -865,6 +856,16 @@ sub syncdataset {
# those that exist on the source. Remaining are the snapshots
# that are only on the target. Then sort to remove the oldest
# snapshots first.
# regather snapshots on source and target
%snaps = getsnaps('source',$sourcehost,$sourcefs,$sourceisroot,0);
if ($targetexists) {
my %targetsnaps = getsnaps('target',$targethost,$targetfs,$targetisroot,0);
my %sourcesnaps = %snaps;
%snaps = (%sourcesnaps, %targetsnaps);
}
my @to_delete = sort { sortsnapshots(\%snaps, $a, $b) } grep {!exists $snaps{'source'}{$_}} keys %{ $snaps{'target'} };
while (@to_delete) {
# Create batch of snapshots to remove
@ -898,7 +899,6 @@ sub runsynccmd {
my $disp_pvsize = $pvsize == 0 ? 'UNKNOWN' : readablebytes($pvsize);
my $sendoptions;
if ($sendsource =~ / -t /) {
writelog('INFO', "Resuming interrupted zfs send/receive from $sourcefs to $targetfs (~ $disp_pvsize remaining):");
$sendoptions = getoptionsline(\@sendoptions, ('P','V','e','v'));
} elsif ($sendsource =~ /#/) {
$sendoptions = getoptionsline(\@sendoptions, ('L','V','c','e','w'));
@ -934,12 +934,13 @@ sub runsynccmd {
my $recvcmd = "$targetsudocmd $zfscmd receive $recvoptions $targetfsescaped 2>&1";
my $synccmd = buildsynccmd($sendcmd,$recvcmd,$pvsize,$sourceisroot,$targetisroot);
writelog('INFO', "Sync size: ~$disp_pvsize");
writelog('DEBUG', "sync size: ~$disp_pvsize");
writelog('DEBUG', "$synccmd");
# make sure target is (still) not currently in receive.
if (iszfsbusy($targethost,$targetfs,$targetisroot)) {
writelog('WARN', "Cannot sync now: $targetfs is already target of a zfs receive process.");
my $targetname = buildnicename($targethost, $targetfs);
writelog('WARN', "Cannot sync now: $targetname is already target of a zfs receive process.");
return (1, '');
}
@ -971,6 +972,16 @@ sub syncfull {
my $sendsource = "$sourcefsescaped\@$snapescaped";
my $pvsize = getsendsize($sourcehost,"$sourcefs\@$snapname",0,$sourceisroot);
my $srcname = buildnicename($sourcehost, $sourcefs, $snapname);
my $targetname = buildnicename($targethost, $targetfs);
my $disp_pvsize = $pvsize == 0 ? 'UNKNOWN' : readablebytes($pvsize);
if (!defined ($args{'no-stream'}) ) {
writelog('INFO', "Sending oldest full snapshot $srcname to new target filesystem $targetname (~ $disp_pvsize):");
} else {
writelog('INFO', "--no-stream selected; sending newest full snapshot $srcname to new target filesystem $targetname: (~ $disp_pvsize)");
}
return runsynccmd($sourcehost, $sourcefs, $sendsource, $targethost, $targetfs, $pvsize);
} # end syncfull()
@ -1011,8 +1022,11 @@ sub syncincremental {
foreach my $i (0..(scalar(@intsnaps) - 2)) {
my $snapa = $intsnaps[$i];
my $snapb = $intsnaps[$i + 1];
writelog('INFO', "Performing an incremental sync between '$snapa' and '$snapb'");
syncincremental($sourcehost, $sourcefs, $targethost, $targetfs, $snapa, $snapb, 1) == 0 or return $?;
(my $ret, my $stdout) = syncincremental($sourcehost, $sourcefs, $targethost, $targetfs, $snapa, $snapb, 1);
if ($ret != 0) {
return ($ret, $stdout);
}
}
# Return after finishing the -i syncs so that we don't try to do another -I
@ -1026,6 +1040,12 @@ sub syncincremental {
my $sendsource = "$streamarg $sourcefsescaped\@$fromsnapescaped $sourcefsescaped\@$tosnapescaped";
my $pvsize = getsendsize($sourcehost,"$sourcefs\@$fromsnap","$sourcefs\@$tosnap",$sourceisroot);
my $srcname = buildnicename($sourcehost, $sourcefs, $fromsnap);
my $targetname = buildnicename($targethost, $targetfs);
my $disp_pvsize = $pvsize == 0 ? 'UNKNOWN' : readablebytes($pvsize);
writelog('INFO', "Sending incremental $srcname ... $tosnap to $targetname (~ $disp_pvsize):");
return runsynccmd($sourcehost, $sourcefs, $sendsource, $targethost, $targetfs, $pvsize);
} # end syncincremental()
@ -1038,6 +1058,12 @@ sub syncclone {
my $sendsource = "-i $originescaped $sourcefsescaped\@$tosnapescaped";
my $pvsize = getsendsize($sourcehost,$origin,"$sourcefs\@$tosnap",$sourceisroot);
my $srcname = buildnicename($sourcehost, $origin);
my $targetname = buildnicename($targethost, $targetfs);
my $disp_pvsize = $pvsize == 0 ? 'UNKNOWN' : readablebytes($pvsize);
writelog('INFO', "Clone is recreated on target $targetname based on $srcname (~ $disp_pvsize):");
return runsynccmd($sourcehost, $sourcefs, $sendsource, $targethost, $targetfs, $pvsize);
} # end syncclone()
@ -1047,6 +1073,12 @@ sub syncresume {
my $sendsource = "-t $receivetoken";
my $pvsize = getsendsize($sourcehost,"","",$sourceisroot,$receivetoken);
my $srcname = buildnicename($sourcehost, $sourcefs);
my $targetname = buildnicename($targethost, $targetfs);
my $disp_pvsize = $pvsize == 0 ? 'UNKNOWN' : readablebytes($pvsize);
writelog('INFO', "Resuming interrupted zfs send/receive from $srcname to $targetname (~ $disp_pvsize remaining):");
return runsynccmd($sourcehost, $sourcefs, $sendsource, $targethost, $targetfs, $pvsize);
} # end syncresume()
@ -1058,6 +1090,11 @@ sub syncbookmark {
my $tosnapescaped = escapeshellparam($tosnap);
my $sendsource = "-i $sourcefsescaped#$bookmarkescaped $sourcefsescaped\@$tosnapescaped";
my $srcname = buildnicename($sourcehost, $sourcefs, '', $bookmark);
my $targetname = buildnicename($targethost, $targetfs);
writelog('INFO', "Sending incremental $srcname ... $tosnap to $targetname:");
return runsynccmd($sourcehost, $sourcefs, $sendsource, $targethost, $targetfs, 0);
} # end syncbookmark
@ -1110,12 +1147,24 @@ sub compressargset {
decomrawcmd => 'zstd',
decomargs => '-dc',
},
'zstdmt-fast' => {
rawcmd => 'zstdmt',
args => '-3',
decomrawcmd => 'zstdmt',
decomargs => '-dc',
},
'zstd-slow' => {
rawcmd => 'zstd',
args => '-19',
decomrawcmd => 'zstd',
decomargs => '-dc',
},
'zstdmt-slow' => {
rawcmd => 'zstdmt',
args => '-19',
decomrawcmd => 'zstdmt',
decomargs => '-dc',
},
'xz' => {
rawcmd => 'xz',
args => '',
@ -1138,7 +1187,7 @@ sub compressargset {
if ($value eq 'default') {
$value = $DEFAULT_COMPRESSION;
} elsif (!(grep $value eq $_, ('gzip', 'pigz-fast', 'pigz-slow', 'zstd-fast', 'zstd-slow', 'lz4', 'xz', 'lzo', 'default', 'none'))) {
} elsif (!(grep $value eq $_, ('gzip', 'pigz-fast', 'pigz-slow', 'zstd-fast', 'zstdmt-fast', 'zstd-slow', 'zstdmt-slow', 'lz4', 'xz', 'lzo', 'default', 'none'))) {
writelog('WARN', "Unrecognised compression value $value, defaulting to $DEFAULT_COMPRESSION");
$value = $DEFAULT_COMPRESSION;
}
@ -1507,7 +1556,7 @@ sub getnewestsnapshot {
my $snaps = shift;
foreach my $snap (sort { sortsnapshots($snaps, $b, $a) } keys %{ $snaps{'source'} }) {
# return on first snap found - it's the newest
writelog('INFO', "NEWEST SNAPSHOT: $snap");
writelog('DEBUG', "NEWEST SNAPSHOT: $snap");
return $snap;
}
# must not have had any snapshots on source - looks like we'd better create one!
@ -2233,6 +2282,26 @@ sub snapisincluded {
return 1;
}
sub buildnicename {
my ($host,$fs,$snapname,$bookmarkname) = @_;
my $name;
if ($host) {
$host =~ s/-S \/tmp\/syncoid[a-zA-Z0-9-@]+ //g;
$name = "$host:$fs";
} else {
$name = "$fs";
}
if ($snapname) {
$name = "$name\@$snapname";
} elsif ($bookmarkname) {
$name = "$name#$bookmarkname";
}
return $name;
}
__END__
=head1 NAME
@ -2251,7 +2320,7 @@ syncoid - ZFS snapshot replication tool
Options:
--compress=FORMAT Compresses data during transfer. Currently accepted options are gzip, pigz-fast, pigz-slow, zstd-fast, zstd-slow, lz4, xz, lzo (default) & none
--compress=FORMAT Compresses data during transfer. Currently accepted options are gzip, pigz-fast, pigz-slow, zstd-fast, zstdmt-fast, zstd-slow, zstdmt-slow, lz4, xz, lzo (default) & none
--identifier=EXTRA Extra identifier which is included in the snapshot name. Can be used for replicating to multiple targets.
--recursive|r Also transfers child datasets
--skip-parent Skips syncing of the parent dataset. Does nothing without '--recursive' option.

View File

@ -0,0 +1,18 @@
#!/bin/bash
set -x
# this test will create pools in a number of states
# and check the output text and return code of
# sanoid --monitor-snapshots
. ../common/lib.sh
# prepare
setup
checkEnvironment
disableTimeSync
# set timezone
ln -sf /usr/share/zoneinfo/Europe/Vienna /etc/localtime
python3 test_monitoring.py

View File

@ -0,0 +1,37 @@
[sanoid-test-1]
use_template = production
[sanoid-test-2]
use_template = demo
[template_production]
hourly = 36
daily = 30
monthly = 3
yearly = 0
autosnap = yes
autoprune = no
hourly_warn = 90m
hourly_crit = 360m
daily_warn = 28h
daily_crit = 32h
weekly_warn = 0
weekly_crit = 0
monthly_warn = 32d
monthly_crit = 40d
yearly_warn = 0
yearly_crit = 0
[template_demo]
daily = 60
hourly_warn = 290m
hourly_crit = 360m
daily_warn = 28h
daily_crit = 48h
weekly_warn = 0
weekly_crit = 0
monthly_warn = 32d
monthly_crit = 40d
yearly_warn = 0
yearly_crit = 0

View File

@ -0,0 +1,163 @@
#!/usr/bin/env python3
# this software is licensed for use under the Free Software Foundation's GPL v3.0 license, as retrieved
# from http://www.gnu.org/licenses/gpl-3.0.html on 2014-11-17. A copy should also be available in this
# project's Git repository at https://github.com/jimsalterjrs/sanoid/blob/master/LICENSE.
import os
import subprocess
import time
import unittest
sanoid_cmd = os.environ.get("SANOID")
pool_disk_image1 = "/zpool1.img"
pool_name1 = "sanoid-test-1"
pool_disk_image2 = "/zpool2.img"
pool_name2 = "sanoid-test-2"
clk_id = time.CLOCK_REALTIME
starting_time = time.clock_gettime(clk_id)
def monitor_snapshots_command():
"""Runs sanoid --monitor-snapshots and returns a CompletedProcess instance"""
return_info = subprocess.run([sanoid_cmd, "--monitor-snapshots"], capture_output=True)
return return_info
def run_sanoid_cron_command():
"""Runs sanoid and returns a CompletedProcess instance"""
return_info = subprocess.run([sanoid_cmd, "--cron", "--verbose"], capture_output=True, check=True)
return return_info
def advance_time(seconds):
"""Advances the system clock by seconds"""
# Get the current time
clk_id = time.CLOCK_REALTIME
time_seconds = time.clock_gettime(clk_id)
# print("Current unix time is", time_seconds, "or", time.asctime(time.gmtime(time_seconds)), "in GMT")
# Set the clock to the current time plus seconds
time.clock_settime(clk_id, time_seconds + seconds)
# Print the new time
time_seconds = time.clock_gettime(clk_id)
# print("Current unix time is", time_seconds, "or", time.asctime(time.gmtime(time_seconds)), "in GMT")
return time_seconds
class TestMonitoringOutput(unittest.TestCase):
def test_no_zpool(self):
"""Test what happens if there is no zpool at all"""
return_info = monitor_snapshots_command()
self.assertEqual(return_info.stdout, b"CRIT: sanoid-test-1 has no daily snapshots at all!, CRIT: sanoid-test-1 has no hourly snapshots at all!, CRIT: sanoid-test-1 has no monthly snapshots at all!, CRIT: sanoid-test-2 has no daily snapshots at all!, CRIT: sanoid-test-2 has no hourly snapshots at all!, CRIT: sanoid-test-2 has no monthly snapshots at all!\n")
self.assertEqual(return_info.returncode, 2)
class TestsWithZpool(unittest.TestCase):
"""Tests that require a test zpool"""
def setUp(self):
"""Set up the zpool"""
subprocess.run(["truncate", "-s", "512M", pool_disk_image1], check=True)
subprocess.run(["zpool", "create", "-f", pool_name1, pool_disk_image1], check=True)
subprocess.run(["truncate", "-s", "512M", pool_disk_image2], check=True)
subprocess.run(["zpool", "create", "-f", pool_name2, pool_disk_image2], check=True)
# Clear the snapshot cache in between
subprocess.run([sanoid_cmd, "--force-update"])
def tearDown(self):
"""Clean up on either passed or failed tests"""
subprocess.run(["zpool", "export", pool_name1])
subprocess.run(["rm", "-f", pool_disk_image1])
subprocess.run(["zpool", "export", pool_name2])
subprocess.run(["rm", "-f", pool_disk_image2])
time.clock_settime(clk_id, starting_time)
def test_with_zpool_no_snapshots(self):
"""Test what happens if there is a zpool, but with no snapshots"""
# Run sanoid --monitor-snapshots before doing anything else
return_info = monitor_snapshots_command()
self.assertEqual(return_info.stdout, b"CRIT: sanoid-test-1 has no daily snapshots at all!, CRIT: sanoid-test-1 has no hourly snapshots at all!, CRIT: sanoid-test-1 has no monthly snapshots at all!, CRIT: sanoid-test-2 has no daily snapshots at all!, CRIT: sanoid-test-2 has no hourly snapshots at all!, CRIT: sanoid-test-2 has no monthly snapshots at all!\n")
self.assertEqual(return_info.returncode, 2)
def test_immediately_after_running_sanoid(self):
"""Test immediately after running sanoid --cron"""
run_sanoid_cron_command()
return_info = monitor_snapshots_command()
self.assertEqual(return_info.stdout, b"OK: all monitored datasets (sanoid-test-1, sanoid-test-2) have fresh snapshots\n")
self.assertEqual(return_info.returncode, 0)
def test_one_warning_hourly(self):
"""Test one warning on hourly snapshots, no critical warnings, to check output and error status"""
run_sanoid_cron_command()
# Advance 100 mins to trigger the hourly warning on sanoid-test-1 but nothing else
advance_time(100 * 60)
return_info = monitor_snapshots_command()
# Output should be something like:
# WARN: sanoid-test-1 newest hourly snapshot is 1h 40m 0s old (should be < 1h 30m 0s)\n
# But we cannot be sure about the exact time as test execution could be different on
# different machines, so ignore the bits that may be different.
self.assertEqual(return_info.stdout[:49], b"WARN: sanoid-test-1 newest hourly snapshot is 1h ")
self.assertEqual(return_info.stdout[-30:], b"s old (should be < 1h 30m 0s)\n")
self.assertEqual(return_info.returncode, 1)
def test_two_criticals_hourly(self):
"""Test two criticals (hourly), to check output and error status"""
run_sanoid_cron_command()
# Advance 390 mins to trigger the hourly critical on both sanoid-test-1 and sanoid-test-2
advance_time(390 * 60)
return_info = monitor_snapshots_command()
# Output should be something like:
# CRIT: sanoid-test-1 newest hourly snapshot is 6h 30m 1s old (should be < 6h 0m 0s), CRIT: sanoid-test-2 newest hourly snapshot is 6h 30m 1s old (should be < 6h 0m 0s)\n
# But we cannot be sure about the exact time as test execution could be different on
# different machines, so ignore the bits that may be different.
comma_location = return_info.stdout.find(b",")
self.assertEqual(return_info.stdout[:49], b"CRIT: sanoid-test-1 newest hourly snapshot is 6h ")
self.assertEqual(return_info.stdout[comma_location - 28:comma_location], b"s old (should be < 6h 0m 0s)")
self.assertEqual(return_info.stdout[comma_location:comma_location + 51], b", CRIT: sanoid-test-2 newest hourly snapshot is 6h ")
self.assertEqual(return_info.stdout[-29:], b"s old (should be < 6h 0m 0s)\n")
self.assertEqual(return_info.returncode, 2)
def test_two_criticals_hourly_two_warnings_daily(self):
"""Test two criticals (hourly) and two warnings (daily), to check output and error status"""
run_sanoid_cron_command()
# Advance more than 28 hours to trigger the daily warning on both sanoid-test-1 and sanoid-test-2
advance_time(29 * 60 * 60)
return_info = monitor_snapshots_command()
# Output should be something like:
# CRIT: sanoid-test-1 newest hourly snapshot is 1d 5h 0m 0s old (should be < 6h 0m 0s), CRIT: sanoid-test-2 newest hourly snapshot is 1d 5h 0m 0s old (should be < 6h 0m 0s), WARN: sanoid-test-1 newest daily snapshot is 1d 5h 0m 0s old (should be < 1d 4h 0m 0s), WARN: sanoid-test-2 newest daily snapshot is 1d 5h 0m 0s old (should be < 1d 4h 0m 0s)\n
# But we cannot be sure about the exact time as test execution could be different on
# different machines, so ignore the bits that may be different.
print(return_info.stdout)
output_list = return_info.stdout.split(b", ")
self.assertEqual(output_list[0][:49], b"CRIT: sanoid-test-1 newest hourly snapshot is 1d ")
self.assertEqual(output_list[0][-28:], b"s old (should be < 6h 0m 0s)")
self.assertEqual(output_list[1][:49], b"CRIT: sanoid-test-2 newest hourly snapshot is 1d ")
self.assertEqual(output_list[1][-28:], b"s old (should be < 6h 0m 0s)")
self.assertEqual(output_list[2][:48], b"WARN: sanoid-test-1 newest daily snapshot is 1d ")
self.assertEqual(output_list[2][-31:], b"s old (should be < 1d 4h 0m 0s)")
self.assertEqual(output_list[3][:48], b"WARN: sanoid-test-2 newest daily snapshot is 1d ")
self.assertEqual(output_list[3][-32:], b"s old (should be < 1d 4h 0m 0s)\n")
self.assertEqual(return_info.returncode, 2)
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,18 @@
#!/bin/bash
set -x
# this test will create pools in a number of states
# and check the output text and return code of
# sanoid --monitor-snapshots
. ../common/lib.sh
# prepare
setup
checkEnvironment
disableTimeSync
# set timezone
ln -sf /usr/share/zoneinfo/Europe/Vienna /etc/localtime
python3 test_monitoring.py

View File

@ -0,0 +1,41 @@
[sanoid-test-1]
use_template = production
[sanoid-test-2]
use_template = demo
[template_production]
hourly = 36
daily = 30
monthly = 3
yearly = 0
autosnap = yes
autoprune = no
hourly_warn = 90m
hourly_crit = 360m
daily_warn = 28h
daily_crit = 32h
weekly_warn = 0
weekly_crit = 0
monthly_warn = 32d
monthly_crit = 40d
yearly_warn = 0
yearly_crit = 0
monitor_dont_warn = true
monitor_dont_crit = Yes
[template_demo]
daily = 60
hourly_warn = 290m
hourly_crit = 360m
daily_warn = 28h
daily_crit = 48h
weekly_warn = 0
weekly_crit = 0
monthly_warn = 32d
monthly_crit = 40d
yearly_warn = 0
yearly_crit = 0
monitor_dont_warn = ON
monitor_dont_crit = 1

View File

@ -0,0 +1,163 @@
#!/usr/bin/env python3
# this software is licensed for use under the Free Software Foundation's GPL v3.0 license, as retrieved
# from http://www.gnu.org/licenses/gpl-3.0.html on 2014-11-17. A copy should also be available in this
# project's Git repository at https://github.com/jimsalterjrs/sanoid/blob/master/LICENSE.
import os
import subprocess
import time
import unittest
sanoid_cmd = os.environ.get("SANOID")
pool_disk_image1 = "/zpool1.img"
pool_name1 = "sanoid-test-1"
pool_disk_image2 = "/zpool2.img"
pool_name2 = "sanoid-test-2"
clk_id = time.CLOCK_REALTIME
starting_time = time.clock_gettime(clk_id)
def monitor_snapshots_command():
"""Runs sanoid --monitor-snapshots and returns a CompletedProcess instance"""
return_info = subprocess.run([sanoid_cmd, "--monitor-snapshots"], capture_output=True)
return return_info
def run_sanoid_cron_command():
"""Runs sanoid and returns a CompletedProcess instance"""
return_info = subprocess.run([sanoid_cmd, "--cron", "--verbose"], capture_output=True, check=True)
return return_info
def advance_time(seconds):
"""Advances the system clock by seconds"""
# Get the current time
clk_id = time.CLOCK_REALTIME
time_seconds = time.clock_gettime(clk_id)
# print("Current unix time is", time_seconds, "or", time.asctime(time.gmtime(time_seconds)), "in GMT")
# Set the clock to the current time plus seconds
time.clock_settime(clk_id, time_seconds + seconds)
# Print the new time
time_seconds = time.clock_gettime(clk_id)
# print("Current unix time is", time_seconds, "or", time.asctime(time.gmtime(time_seconds)), "in GMT")
return time_seconds
class TestMonitoringOutput(unittest.TestCase):
def test_no_zpool(self):
"""Test what happens if there is no zpool at all"""
return_info = monitor_snapshots_command()
self.assertEqual(return_info.stdout, b"CRIT: sanoid-test-1 has no daily snapshots at all!, CRIT: sanoid-test-1 has no hourly snapshots at all!, CRIT: sanoid-test-1 has no monthly snapshots at all!, CRIT: sanoid-test-2 has no daily snapshots at all!, CRIT: sanoid-test-2 has no hourly snapshots at all!, CRIT: sanoid-test-2 has no monthly snapshots at all!\n")
self.assertEqual(return_info.returncode, 0)
class TestsWithZpool(unittest.TestCase):
"""Tests that require a test zpool"""
def setUp(self):
"""Set up the zpool"""
subprocess.run(["truncate", "-s", "512M", pool_disk_image1], check=True)
subprocess.run(["zpool", "create", "-f", pool_name1, pool_disk_image1], check=True)
subprocess.run(["truncate", "-s", "512M", pool_disk_image2], check=True)
subprocess.run(["zpool", "create", "-f", pool_name2, pool_disk_image2], check=True)
# Clear the snapshot cache in between
subprocess.run([sanoid_cmd, "--force-update"])
def tearDown(self):
"""Clean up on either passed or failed tests"""
subprocess.run(["zpool", "export", pool_name1])
subprocess.run(["rm", "-f", pool_disk_image1])
subprocess.run(["zpool", "export", pool_name2])
subprocess.run(["rm", "-f", pool_disk_image2])
time.clock_settime(clk_id, starting_time)
def test_with_zpool_no_snapshots(self):
"""Test what happens if there is a zpool, but with no snapshots"""
# Run sanoid --monitor-snapshots before doing anything else
return_info = monitor_snapshots_command()
self.assertEqual(return_info.stdout, b"CRIT: sanoid-test-1 has no daily snapshots at all!, CRIT: sanoid-test-1 has no hourly snapshots at all!, CRIT: sanoid-test-1 has no monthly snapshots at all!, CRIT: sanoid-test-2 has no daily snapshots at all!, CRIT: sanoid-test-2 has no hourly snapshots at all!, CRIT: sanoid-test-2 has no monthly snapshots at all!\n")
self.assertEqual(return_info.returncode, 0)
def test_immediately_after_running_sanoid(self):
"""Test immediately after running sanoid --cron"""
run_sanoid_cron_command()
return_info = monitor_snapshots_command()
self.assertEqual(return_info.stdout, b"OK: all monitored datasets (sanoid-test-1, sanoid-test-2) have fresh snapshots\n")
self.assertEqual(return_info.returncode, 0)
def test_one_warning_hourly(self):
"""Test one warning on hourly snapshots, no critical warnings, to check output and error status"""
run_sanoid_cron_command()
# Advance 100 mins to trigger the hourly warning on sanoid-test-1 but nothing else
advance_time(100 * 60)
return_info = monitor_snapshots_command()
# Output should be something like:
# WARN: sanoid-test-1 newest hourly snapshot is 1h 40m 0s old (should be < 1h 30m 0s)\n
# But we cannot be sure about the exact time as test execution could be different on
# different machines, so ignore the bits that may be different.
self.assertEqual(return_info.stdout[:49], b"WARN: sanoid-test-1 newest hourly snapshot is 1h ")
self.assertEqual(return_info.stdout[-30:], b"s old (should be < 1h 30m 0s)\n")
self.assertEqual(return_info.returncode, 0)
def test_two_criticals_hourly(self):
"""Test two criticals (hourly), to check output and error status"""
run_sanoid_cron_command()
# Advance 390 mins to trigger the hourly critical on both sanoid-test-1 and sanoid-test-2
advance_time(390 * 60)
return_info = monitor_snapshots_command()
# Output should be something like:
# CRIT: sanoid-test-1 newest hourly snapshot is 6h 30m 1s old (should be < 6h 0m 0s), CRIT: sanoid-test-2 newest hourly snapshot is 6h 30m 1s old (should be < 6h 0m 0s)\n
# But we cannot be sure about the exact time as test execution could be different on
# different machines, so ignore the bits that may be different.
comma_location = return_info.stdout.find(b",")
self.assertEqual(return_info.stdout[:49], b"CRIT: sanoid-test-1 newest hourly snapshot is 6h ")
self.assertEqual(return_info.stdout[comma_location - 28:comma_location], b"s old (should be < 6h 0m 0s)")
self.assertEqual(return_info.stdout[comma_location:comma_location + 51], b", CRIT: sanoid-test-2 newest hourly snapshot is 6h ")
self.assertEqual(return_info.stdout[-29:], b"s old (should be < 6h 0m 0s)\n")
self.assertEqual(return_info.returncode, 0)
def test_two_criticals_hourly_two_warnings_daily(self):
"""Test two criticals (hourly) and two warnings (daily), to check output and error status"""
run_sanoid_cron_command()
# Advance more than 28 hours to trigger the daily warning on both sanoid-test-1 and sanoid-test-2
advance_time(29 * 60 * 60)
return_info = monitor_snapshots_command()
# Output should be something like:
# CRIT: sanoid-test-1 newest hourly snapshot is 1d 5h 0m 0s old (should be < 6h 0m 0s), CRIT: sanoid-test-2 newest hourly snapshot is 1d 5h 0m 0s old (should be < 6h 0m 0s), WARN: sanoid-test-1 newest daily snapshot is 1d 5h 0m 0s old (should be < 1d 4h 0m 0s), WARN: sanoid-test-2 newest daily snapshot is 1d 5h 0m 0s old (should be < 1d 4h 0m 0s)\n
# But we cannot be sure about the exact time as test execution could be different on
# different machines, so ignore the bits that may be different.
print(return_info.stdout)
output_list = return_info.stdout.split(b", ")
self.assertEqual(output_list[0][:49], b"CRIT: sanoid-test-1 newest hourly snapshot is 1d ")
self.assertEqual(output_list[0][-28:], b"s old (should be < 6h 0m 0s)")
self.assertEqual(output_list[1][:49], b"CRIT: sanoid-test-2 newest hourly snapshot is 1d ")
self.assertEqual(output_list[1][-28:], b"s old (should be < 6h 0m 0s)")
self.assertEqual(output_list[2][:48], b"WARN: sanoid-test-1 newest daily snapshot is 1d ")
self.assertEqual(output_list[2][-31:], b"s old (should be < 1d 4h 0m 0s)")
self.assertEqual(output_list[3][:48], b"WARN: sanoid-test-2 newest daily snapshot is 1d ")
self.assertEqual(output_list[3][-32:], b"s old (should be < 1d 4h 0m 0s)\n")
self.assertEqual(return_info.returncode, 0)
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,18 @@
#!/bin/bash
set -x
# this test will create pools in a number of states
# and check the output text and return code of
# sanoid --monitor-snapshots
. ../common/lib.sh
# prepare
setup
checkEnvironment
disableTimeSync
# set timezone
ln -sf /usr/share/zoneinfo/Europe/Vienna /etc/localtime
python3 test_monitoring.py

View File

@ -0,0 +1,41 @@
[sanoid-test-1]
use_template = production
[sanoid-test-2]
use_template = demo
[template_production]
hourly = 36
daily = 30
monthly = 3
yearly = 0
autosnap = yes
autoprune = no
hourly_warn = 90m
hourly_crit = 360m
daily_warn = 28h
daily_crit = 32h
weekly_warn = 0
weekly_crit = 0
monthly_warn = 32d
monthly_crit = 40d
yearly_warn = 0
yearly_crit = 0
monitor_dont_warn = FALSE
monitor_dont_crit = yes
[template_demo]
daily = 60
hourly_warn = 290m
hourly_crit = 360m
daily_warn = 28h
daily_crit = 48h
weekly_warn = 0
weekly_crit = 0
monthly_warn = 32d
monthly_crit = 40d
yearly_warn = 0
yearly_crit = 0
monitor_dont_warn = Off
monitor_dont_crit = On

View File

@ -0,0 +1,163 @@
#!/usr/bin/env python3
# this software is licensed for use under the Free Software Foundation's GPL v3.0 license, as retrieved
# from http://www.gnu.org/licenses/gpl-3.0.html on 2014-11-17. A copy should also be available in this
# project's Git repository at https://github.com/jimsalterjrs/sanoid/blob/master/LICENSE.
import os
import subprocess
import time
import unittest
sanoid_cmd = os.environ.get("SANOID")
pool_disk_image1 = "/zpool1.img"
pool_name1 = "sanoid-test-1"
pool_disk_image2 = "/zpool2.img"
pool_name2 = "sanoid-test-2"
clk_id = time.CLOCK_REALTIME
starting_time = time.clock_gettime(clk_id)
def monitor_snapshots_command():
"""Runs sanoid --monitor-snapshots and returns a CompletedProcess instance"""
return_info = subprocess.run([sanoid_cmd, "--monitor-snapshots"], capture_output=True)
return return_info
def run_sanoid_cron_command():
"""Runs sanoid and returns a CompletedProcess instance"""
return_info = subprocess.run([sanoid_cmd, "--cron", "--verbose"], capture_output=True, check=True)
return return_info
def advance_time(seconds):
"""Advances the system clock by seconds"""
# Get the current time
clk_id = time.CLOCK_REALTIME
time_seconds = time.clock_gettime(clk_id)
# print("Current unix time is", time_seconds, "or", time.asctime(time.gmtime(time_seconds)), "in GMT")
# Set the clock to the current time plus seconds
time.clock_settime(clk_id, time_seconds + seconds)
# Print the new time
time_seconds = time.clock_gettime(clk_id)
# print("Current unix time is", time_seconds, "or", time.asctime(time.gmtime(time_seconds)), "in GMT")
return time_seconds
class TestMonitoringOutput(unittest.TestCase):
def test_no_zpool(self):
"""Test what happens if there is no zpool at all"""
return_info = monitor_snapshots_command()
self.assertEqual(return_info.stdout, b"CRIT: sanoid-test-1 has no daily snapshots at all!, CRIT: sanoid-test-1 has no hourly snapshots at all!, CRIT: sanoid-test-1 has no monthly snapshots at all!, CRIT: sanoid-test-2 has no daily snapshots at all!, CRIT: sanoid-test-2 has no hourly snapshots at all!, CRIT: sanoid-test-2 has no monthly snapshots at all!\n")
self.assertEqual(return_info.returncode, 0)
class TestsWithZpool(unittest.TestCase):
"""Tests that require a test zpool"""
def setUp(self):
"""Set up the zpool"""
subprocess.run(["truncate", "-s", "512M", pool_disk_image1], check=True)
subprocess.run(["zpool", "create", "-f", pool_name1, pool_disk_image1], check=True)
subprocess.run(["truncate", "-s", "512M", pool_disk_image2], check=True)
subprocess.run(["zpool", "create", "-f", pool_name2, pool_disk_image2], check=True)
# Clear the snapshot cache in between
subprocess.run([sanoid_cmd, "--force-update"])
def tearDown(self):
"""Clean up on either passed or failed tests"""
subprocess.run(["zpool", "export", pool_name1])
subprocess.run(["rm", "-f", pool_disk_image1])
subprocess.run(["zpool", "export", pool_name2])
subprocess.run(["rm", "-f", pool_disk_image2])
time.clock_settime(clk_id, starting_time)
def test_with_zpool_no_snapshots(self):
"""Test what happens if there is a zpool, but with no snapshots"""
# Run sanoid --monitor-snapshots before doing anything else
return_info = monitor_snapshots_command()
self.assertEqual(return_info.stdout, b"CRIT: sanoid-test-1 has no daily snapshots at all!, CRIT: sanoid-test-1 has no hourly snapshots at all!, CRIT: sanoid-test-1 has no monthly snapshots at all!, CRIT: sanoid-test-2 has no daily snapshots at all!, CRIT: sanoid-test-2 has no hourly snapshots at all!, CRIT: sanoid-test-2 has no monthly snapshots at all!\n")
self.assertEqual(return_info.returncode, 0)
def test_immediately_after_running_sanoid(self):
"""Test immediately after running sanoid --cron"""
run_sanoid_cron_command()
return_info = monitor_snapshots_command()
self.assertEqual(return_info.stdout, b"OK: all monitored datasets (sanoid-test-1, sanoid-test-2) have fresh snapshots\n")
self.assertEqual(return_info.returncode, 0)
def test_one_warning_hourly(self):
"""Test one warning on hourly snapshots, no critical warnings, to check output and error status"""
run_sanoid_cron_command()
# Advance 100 mins to trigger the hourly warning on sanoid-test-1 but nothing else
advance_time(100 * 60)
return_info = monitor_snapshots_command()
# Output should be something like:
# WARN: sanoid-test-1 newest hourly snapshot is 1h 40m 0s old (should be < 1h 30m 0s)\n
# But we cannot be sure about the exact time as test execution could be different on
# different machines, so ignore the bits that may be different.
self.assertEqual(return_info.stdout[:49], b"WARN: sanoid-test-1 newest hourly snapshot is 1h ")
self.assertEqual(return_info.stdout[-30:], b"s old (should be < 1h 30m 0s)\n")
self.assertEqual(return_info.returncode, 1)
def test_two_criticals_hourly(self):
"""Test two criticals (hourly), to check output and error status"""
run_sanoid_cron_command()
# Advance 390 mins to trigger the hourly critical on both sanoid-test-1 and sanoid-test-2
advance_time(390 * 60)
return_info = monitor_snapshots_command()
# Output should be something like:
# CRIT: sanoid-test-1 newest hourly snapshot is 6h 30m 1s old (should be < 6h 0m 0s), CRIT: sanoid-test-2 newest hourly snapshot is 6h 30m 1s old (should be < 6h 0m 0s)\n
# But we cannot be sure about the exact time as test execution could be different on
# different machines, so ignore the bits that may be different.
comma_location = return_info.stdout.find(b",")
self.assertEqual(return_info.stdout[:49], b"CRIT: sanoid-test-1 newest hourly snapshot is 6h ")
self.assertEqual(return_info.stdout[comma_location - 28:comma_location], b"s old (should be < 6h 0m 0s)")
self.assertEqual(return_info.stdout[comma_location:comma_location + 51], b", CRIT: sanoid-test-2 newest hourly snapshot is 6h ")
self.assertEqual(return_info.stdout[-29:], b"s old (should be < 6h 0m 0s)\n")
self.assertEqual(return_info.returncode, 0)
def test_two_criticals_hourly_two_warnings_daily(self):
"""Test two criticals (hourly) and two warnings (daily), to check output and error status"""
run_sanoid_cron_command()
# Advance more than 28 hours to trigger the daily warning on both sanoid-test-1 and sanoid-test-2
advance_time(29 * 60 * 60)
return_info = monitor_snapshots_command()
# Output should be something like:
# CRIT: sanoid-test-1 newest hourly snapshot is 1d 5h 0m 0s old (should be < 6h 0m 0s), CRIT: sanoid-test-2 newest hourly snapshot is 1d 5h 0m 0s old (should be < 6h 0m 0s), WARN: sanoid-test-1 newest daily snapshot is 1d 5h 0m 0s old (should be < 1d 4h 0m 0s), WARN: sanoid-test-2 newest daily snapshot is 1d 5h 0m 0s old (should be < 1d 4h 0m 0s)\n
# But we cannot be sure about the exact time as test execution could be different on
# different machines, so ignore the bits that may be different.
print(return_info.stdout)
output_list = return_info.stdout.split(b", ")
self.assertEqual(output_list[0][:49], b"CRIT: sanoid-test-1 newest hourly snapshot is 1d ")
self.assertEqual(output_list[0][-28:], b"s old (should be < 6h 0m 0s)")
self.assertEqual(output_list[1][:49], b"CRIT: sanoid-test-2 newest hourly snapshot is 1d ")
self.assertEqual(output_list[1][-28:], b"s old (should be < 6h 0m 0s)")
self.assertEqual(output_list[2][:48], b"WARN: sanoid-test-1 newest daily snapshot is 1d ")
self.assertEqual(output_list[2][-31:], b"s old (should be < 1d 4h 0m 0s)")
self.assertEqual(output_list[3][:48], b"WARN: sanoid-test-2 newest daily snapshot is 1d ")
self.assertEqual(output_list[3][-32:], b"s old (should be < 1d 4h 0m 0s)\n")
self.assertEqual(return_info.returncode, 1)
if __name__ == '__main__':
unittest.main()

31
tests/README.md Normal file
View File

@ -0,0 +1,31 @@
### Requirements ###
Tests must be run inside a virtual machine. This is for your own safety, as the tests may create and destroy zpools etc.
A VM with 35GB of storage and 8 cores running Ubuntu 20.04 completes the tests in about 5 hours.
#### Packages ####
The tests require the following packages to be installed in the VM (Ubuntu 20.04 package names are used, translate as appropriate):
```
zfsutils-linux
libconfig-inifiles-perl
libcapture-tiny-perl
```
```
apt install zfsutils-linux libconfig-inifiles-perl libcapture-tiny-perl
```
#### Install sanoid within the VM ####
Install sanoid within the VM, for example
```
apt install git
git clone https://github.com/jimsalterjrs/sanoid.git
mkdir /etc/sanoid/
cp sanoid/sanoid.defaults.conf /etc/sanoid/
```
### Run the tests ##
This requires root/sudo privileges.
```
cd sanoid/tests/
./run-tests.sh
```

View File

@ -10,7 +10,7 @@ function setup {
export SANOID="../../sanoid"
# make sure that there is no cache file
rm -f /var/cache/sanoidsnapshots.txt
rm -f /var/cache/sanoid/snapshots.txt
# install needed sanoid configuration files
[ -f sanoid.conf ] && cp sanoid.conf /etc/sanoid/sanoid.conf

View File

@ -1,6 +1,6 @@
#!/bin/bash
# run's all the available tests
# runs all the available tests
for test in $(find . -mindepth 1 -maxdepth 1 -type d -printf "%P\n" | sort -g); do
if [ ! -x "${test}/run.sh" ]; then
@ -17,8 +17,11 @@ for test in $(find . -mindepth 1 -maxdepth 1 -type d -printf "%P\n" | sort -g);
cd "${test}"
echo -n y | bash run.sh > "${LOGFILE}" 2>&1
if [ $? -eq 0 ]; then
ret=$?
if [ $ret -eq 0 ]; then
echo "[PASS]"
elif [ $ret -eq 130 ]; then
echo "[SKIPPED]"
else
echo "[FAILED] (see ${LOGFILE})"
fi

View File

@ -28,6 +28,8 @@ zfs create -o mountpoint="${MOUNT_TARGET}" "${POOL_NAME}"/src
dd if=/dev/urandom of="${MOUNT_TARGET}"/big_file bs=1M count=200
sleep 1
../../../syncoid --debug --compress=none --source-bwlimit=2m "${POOL_NAME}"/src "${POOL_NAME}"/dst &
syncoid_pid=$!
sleep 5

View File

@ -28,6 +28,8 @@ zfs create -o mountpoint="${MOUNT_TARGET}" "${POOL_NAME}"/src
dd if=/dev/urandom of="${MOUNT_TARGET}"/big_file bs=1M count=200
sleep 1
zfs snapshot "${POOL_NAME}"/src@big
../../../syncoid --debug --no-sync-snap --compress=none --source-bwlimit=2m "${POOL_NAME}"/src "${POOL_NAME}"/dst &
syncoid_pid=$!

View File

@ -7,9 +7,13 @@ set -e
. ../../common/lib.sh
POOL_IMAGE="/tmp/jimsalterjrs_sanoid_815.img"
if [ -z "$ALLOW_INVASIVE_TESTS" ]; then
exit 130
fi
POOL_IMAGE="/tmp/syncoid-test-11.zpool"
POOL_SIZE="64M"
POOL_NAME="jimsalterjrs_sanoid_815"
POOL_NAME="syncoid-test-11"
truncate -s "${POOL_SIZE}" "${POOL_IMAGE}"

View File

@ -17,8 +17,11 @@ for test in $(find . -mindepth 1 -maxdepth 1 -type d -printf "%P\n" | sort -g);
cd "${test}"
echo | bash run.sh > "${LOGFILE}" 2>&1
if [ $? -eq 0 ]; then
ret=$?
if [ $ret -eq 0 ]; then
echo "[PASS]"
elif [ $ret -eq 130 ]; then
echo "[SKIPPED]"
else
echo "[FAILED] (see ${LOGFILE})"
fi