diff --git a/.gitignore b/.gitignore index 3d56d93e..f63154c0 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,5 @@ init/znapzend.service init/znapzend.sysv init/znapzend.upstart init/znapzend.xml +init/org.znapzend.plist +.DS_Store diff --git a/README.md b/README.md index a7e8fe6b..b75b0493 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,11 @@ since the installed perl version is probably very old. On OmniOS/SmartOS you will need perl and gnu-make. +On macOS, if you have not already installed the Xcode command line tools, you can +get them from the command line (Terminal app) with: + + xcode-select --install (or just install the full Xcode app from the Apple app store). + With that in place you can now utter: ```sh diff --git a/configure.ac b/configure.ac index ef1736a6..ea0509e6 100644 --- a/configure.ac +++ b/configure.ac @@ -194,6 +194,7 @@ AC_CONFIG_FILES([ init/znapzend.sysv init/znapzend.upstart init/znapzend.xml + init/org.znapzend.plist ]) AC_SUBST(VERSION) diff --git a/init/README.md b/init/README.md index 652119a2..c1eeb2d8 100644 --- a/init/README.md +++ b/init/README.md @@ -13,6 +13,19 @@ replacing the tags in the corresponding ```.in``` template file to match your existing system layout (replace ```@BINDIR@``` usually with ```/usr/local/bin``` to match other setup documentation). +## macOS/launchd + +For macOS launchd, you can copy the generated ```org.znapzend.plist``` +file to ```/Library/LaunchDaemons``` and then start the daemon with: + +```sh +launchctl load /Library/LaunchDaemons/org.znapzend.plist +``` + +```Note:``` It is recommended to ```not``` set the ```--daemonize``` flag of ```znapzend``` +as launchd will lose control of the process. Check out ```init/org.znapzend.plist.in``` +for an example plist. + ## Solaris/Illumos For solaris/illumos OSes you can tell configure to install a znapzend diff --git a/init/org.znapzend.plist.in b/init/org.znapzend.plist.in new file mode 100644 index 00000000..241300f9 --- /dev/null +++ b/init/org.znapzend.plist.in @@ -0,0 +1,30 @@ + + + + + EnvironmentVariables + + PATH + /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin + + KeepAlive + + Crashed + + + Label + org.znapzend + ProgramArguments + + @BINDIR@/org.znapzend + + RunAtLoad + + StandardErrorPath + /var/log/org.znapzend.stderr + StandardOutPath + /var/log/org.znapzend.stdout + ThrottleInterval + 30 + + diff --git a/lib/ZnapZend.pm b/lib/ZnapZend.pm index d3917215..ca3312cc 100644 --- a/lib/ZnapZend.pm +++ b/lib/ZnapZend.pm @@ -129,7 +129,7 @@ my $refreshBackupPlans = sub { $self->backupSets($self->zConfig->getBackupSetEnabled($dataSet)); @{$self->backupSets} - or $self->zLog->warn("No backup set defined or enabled, yet. run 'znapzendzetup' to setup znapzend"); + or die "No backup set defined or enabled, yet. run 'znapzendzetup' to setup znapzend\n"; for my $backupSet (@{$self->backupSets}){ $backupSet->{srcPlanHash} = $self->zTime->backupPlanToHash($backupSet->{src_plan}); @@ -157,7 +157,7 @@ my $refreshBackupPlans = sub { for (keys %$backupSet){ my ($key) = /^dst_([^_]+)_plan$/ or next; - #check if destination exists (i.e. is valid) otherwise recheck as dst might be online, now + #check if destination exists (i.e. is valid) otherwise recheck as dst might be online, now if (!$backupSet->{"dst_$key" . '_valid'}){ $backupSet->{"dst_$key" . '_valid'} = @@ -175,7 +175,7 @@ my $refreshBackupPlans = sub { }; } $backupSet->{"dst_$key" . '_valid'} or - $self->zLog->warn("destination '" . $backupSet->{"dst_$key"} + $self->zLog->warn("destination '" . $backupSet->{"dst_$key"} . "' does not exist or is offline. will be rechecked every run..."); }; } @@ -227,7 +227,7 @@ my $sendRecvCleanup = sub { my $sendFailed = 0; my $startTime = time; $self->zLog->info('starting work on backupSet ' . $backupSet->{src}); - + #get all sub datasets of source filesystem; need to send them all individually if recursive my $srcSubDataSets = $backupSet->{recursive} eq 'on' ? $self->zZfs->listSubDataSets($backupSet->{src}) : [ $backupSet->{src} ]; @@ -254,7 +254,7 @@ my $sendRecvCleanup = sub { } } - #recheck non valid dst as it might be online, now + #recheck non valid dst as it might be online, now if (!$backupSet->{"dst_$key" . '_valid'}) { $backupSet->{"dst_$key" . '_valid'} = @@ -397,7 +397,7 @@ my $createSnapshot = sub { local $ENV{ZNAP_TIME} = $timeStamp; my $skip = 0; - + if ($backupSet->{pre_znap_cmd} && $backupSet->{pre_znap_cmd} ne 'off'){ $self->zLog->info("running pre snapshot command on $backupSet->{src}"); @@ -468,7 +468,7 @@ my $sendWorker = sub { $fc->on( spawn => sub { my ($fc, $pid) = @_; - + $self->zLog->debug('send/receive worker for ' . $backupSet->{src} . " spawned ($pid)"); $backupSet->{send_pid} = $pid; @@ -505,7 +505,7 @@ my $snapWorker = sub { #snapshot worker callback sub { my ($fc, $err) = @_; - + $self->zLog->warn('taking snapshot on ' . $backupSet->{src} . ' failed: ' . $err) if $err; @@ -528,7 +528,7 @@ my $snapWorker = sub { $fc->on( spawn => sub { my ($fc, $pid) = @_; - + $self->zLog->debug('snapshot worker for ' . $backupSet->{src} . " spawned ($pid)"); $backupSet->{snap_pid} = $pid; @@ -662,7 +662,7 @@ sub start { $self->$refreshBackupPlans($self->dataset); $self->$createWorkers; }; - + $self->$refreshBackupPlans($self->dataset); $self->$createWorkers; @@ -670,12 +670,12 @@ sub start { $self->zLog->info("znapzend (PID=$$) initialized -- resuming normal operations."); # if Mojo is running with EV, signals will not be received if the IO loop - # is sleeping so lets activate it periodically + # is sleeping so lets activate it periodically ### RM_COMM_4_TEST ### # remove ### RM_COMM_4_TEST ### comments for testing purpose. ### RM_COMM_4_TEST ### if (0) { Mojo::IOLoop->recurring(1 => sub { }) if not $self->runonce; ### RM_COMM_4_TEST ### } - + #start eventloop Mojo::IOLoop->start; @@ -755,4 +755,3 @@ Shadfl@cpan.orgE> 2014-05-30 had Initial Version =cut - diff --git a/t/znapzend.t b/t/znapzend.t index 755d994a..a25d2ba2 100755 --- a/t/znapzend.t +++ b/t/znapzend.t @@ -54,6 +54,7 @@ sub runCommand { } use Test::More; +use Test::Exception; use_ok 'ZnapZend'; @@ -65,12 +66,15 @@ is (runCommand('--help'), 1, 'znapzend help'); is (runCommand(), 1, 'znapzend'); -is (runCommand(qw(--runonce=tank/source)), 1, 'znapzend --runonce'); +throws_ok { runCommand(qw(--runonce=nosets) ) } qr/No backup set defined or enabled/, + 'znapzend dies with no backup sets defined or enabled at startup'; + +# seems to allow tests to continue so why not? +is (runCommand('--help'), 1, 'znapzend help'); is (runCommand(qw(--daemonize --debug),'--features=oracleMode,recvu', qw( --pidfile=znapzend.pid)), 1, 'znapzend --daemonize'); done_testing; - -1; +1;