############################################################################### # # Copyright notice # # (c) 2018 Alexander Schulz # # This script is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # The GNU General Public License can be found at # http://www.gnu.org/copyleft/gpl.html. # A copy is found in the textfile GPL.txt and important notices to the license # from the author is found in LICENSE.txt distributed with these scripts. # # This script is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # This copyright notice MUST APPEAR in all copies of the script! # ############################################################################### # $Id: 98_systemd_watchdog.pm 17206 2018-08-25 18:18:49Z hexenmeister $ package main; use strict; use warnings; use POSIX; use Time::HiRes qw(gettimeofday); use Socket; sub watchdog_client_NotifySystemD($$); sub watchdog_client_Stop($); sub watchdog_client_Start($); sub watchdog_client_ProcessTimer(@); sub watchdog_client_IsWDAvailable($); sub systemd_watchdog_Initialize($) { my ($hash) = @_; # Consumer $hash->{DefFn} = "watchdog_client_Define"; $hash->{UndefFn} = "watchdog_client_Undefine"; $hash->{ShutdownFn} = "watchdog_client_Shutdown"; $hash->{NotifyFn} = "watchdog_client_Notify"; #Log3($hash->{NAME},5,"Watchdog Client: Debug: watchdog_client_Initialize"); RemoveInternalTimer($hash); return undef; } sub watchdog_client_IsWDAvailable($) { my ( $hash ) = @_; #return 1; # TODO XXX TEST return defined($hash->{'.systemd'}); } sub watchdog_client_Define($$) { my ( $hash, $def ) = @_; #Log3($hash->{NAME},5,"Watchdog Client: Debug: watchdog_client_Define"); my $name = $hash->{NAME}; # prevent multiple instances my @devices = devspec2array("TYPE=watchdog_client"); foreach my $dev (@devices) { if($dev ne $name) { return "only one instance is allowed"; } } # remove old timer RemoveInternalTimer($hash); # check systemd watchdog available my $sname = $ENV{NOTIFY_SOCKET}; if(defined($sname)) { $hash->{'systemd-watchdog'}="available"; $hash->{'.systemd'}=1; Log3($hash->{NAME},4,"Watchdog Client: systemd-watchdog available. starting watchdog client"); } else { $hash->{'systemd-watchdog'}="not available"; $hash->{'.systemd'}=undef; Log3($hash->{NAME},1,"Watchdog Client: systemd watchdog is not available. Module inactiv."); } # Initialize watchdog_client_Start($hash); return undef; } sub watchdog_client_Undefine($) { my ($hash) = @_; #Log3($hash->{NAME},5,"Watchdog Client: Debug: watchdog_client_Undefine"); # Clean up watchdog_client_Stop($hash); return undef; } sub watchdog_client_Shutdown($) { my ($hash) = @_; #Log3($hash->{NAME},5,"Watchdog Client: Debug: watchdog_client_Shutdown"); return undef unless defined $hash->{'.initialized'}; # Shutdown => Deaktivate watchdog my $name = $hash->{NAME}; Log3($name,2,"Watchdog Client: Shutting down"); watchdog_client_Stop($hash); return undef; } sub watchdog_client_Notify($$) { my ($hash,$dev) = @_; #Log3($hash->{NAME},1,"Watchdog Client: Debug: watchdog_client_Notify: --- "); if( $dev->{NAME} eq "global" ) { # if( grep(m/^INITIALIZED$/, @{$events}) ) { # Log3($hash->{NAME},1,"Watchdog Client: Debug: watchdog_client_Notify: INITIALIZED"); # watchdog_client_Start($hash) unless defined $hash->{'.initialized'}; # return undef; # } elsif( grep(m/^REREADCFG$/, @{$events}) ) { # # # return undef; # } if( grep(m/^(INITIALIZED|REREADCFG)$/, @{$dev->{CHANGED}}) ) { #Log3($hash->{NAME},5,"Watchdog Client: Debug: watchdog_client_Notify: GLOBAL"); watchdog_client_Start($hash) unless defined $hash->{'.initialized'}; } } } sub watchdog_client_ProcessTimer(@) { my ($hash) = @_; #Log3($hash->{NAME},5,"Watchdog Client: Debug: watchdog_client_ProcessTimer"); # Reset watchdog watchdog_client_NotifySystemD($hash, "WATCHDOG=1\n"); my $sleep = $hash->{'sleep-time'}; $sleep = 30 unless defined $sleep; my $now = gettimeofday(); my $next = int($now) + $sleep; InternalTimer($next, 'watchdog_client_ProcessTimer', $hash, 0); readingsSingleUpdate($hash,"next",FmtTime($next),1); } sub watchdog_client_Start($) { my ($hash) = @_; #Log3($hash->{NAME},5,"Watchdog Client: Debug: watchdog_client_Start"); unless ($main::init_done) { return if $hash->{'.firsttime'}; watchdog_client_NotifySystemD($hash, "STATUS=starting\n"); watchdog_client_NotifySystemD($hash, "MAINPID=$$\n"); readingsSingleUpdate($hash,"state","starting",1); $hash->{'.firsttime'}=1; return; } return if $hash->{'.initialized'}; unless (watchdog_client_IsWDAvailable($hash)) { Log3($hash->{NAME},2,"Watchdog Client: no systemd watchdog available"); readingsSingleUpdate($hash,"state","inactiv",1); readingsSingleUpdate($hash,"next","none",1); return; } my $sleep = ($ENV{WATCHDOG_USEC} // 120000000) / 4 / 1000000; $hash->{'sleep-time'} = $sleep; $hash->{'.initialized'} = 1; my $next = int(gettimeofday()) + 1; InternalTimer($next, 'watchdog_client_ProcessTimer', $hash, 0); # System ready watchdog_client_NotifySystemD($hash, "READY=1\n"); watchdog_client_NotifySystemD($hash, "MAINPID=$$\n"); watchdog_client_NotifySystemD($hash, "STATUS=started\n"); Log3($hash->{NAME},2,"Watchdog Client: initialized"); readingsSingleUpdate($hash,"state","active",1); } sub watchdog_client_Stop($) { my ($hash) = @_; #Log3($hash->{NAME},5,"Watchdog Client: Debug: watchdog_client_Stop"); watchdog_client_NotifySystemD($hash, "STOPPING=1\n"); watchdog_client_NotifySystemD($hash, "STATUS=stopping\n"); RemoveInternalTimer($hash); $hash->{'.initialized'} = 0; my $name = $hash->{NAME}; Log3($name,2,"Watchdog Client: deactivated"); readingsSingleUpdate($hash,"state","deactivated",1); } sub watchdog_client_NotifySystemD($$) { my ($hash,$cmd) = @_; #Log3($hash->{NAME},5,"Watchdog Client: Debug: watchdog_client_NotifySystemD: $cmd"); return unless defined $hash->{'.initialized'}; return unless watchdog_client_IsWDAvailable($hash); my $name = $hash->{NAME}; #Log3($name,1,"Watchdog Client: notify systemd-watchdog: $cmd"); my $sname = $ENV{NOTIFY_SOCKET}; if(!defined($sname)) { #watchdog_client_Stop($hash); Log3($name,1,"Watchdog Client: NOTIFY_SOCKET not available. Please configure systemd-watchdog properly!"); return; } Log3($name,4,"Watchdog Client: notify systemd-watchdog: $cmd"); my $sock_addr = sockaddr_un($sname); socket(my $server, PF_UNIX,SOCK_DGRAM,0); connect($server, $sock_addr); print $server $cmd; close($server); } 1; =pod =item summary_DE Sendet periodisch eine keep-alive Nachricht an das Systemd. =begin html_DE

Systemd Watchdog Client

=end html_DE =item summary Sends periodically keep-alive message to the systemd. =begin html

Systemd Watchdog Client

=end html =cut