rewrite modul and add extra logDir backup

This commit is contained in:
Marko Oldenburg 2019-03-28 15:12:11 +01:00
parent 3ac7e48592
commit b0a134e779

View File

@ -1,8 +1,7 @@
################################################################ ################################################################
# $Id: 98_backup.pm 18643 2019-02-19 14:33:01Z CoolTux $ # Developed with Kate
# vim: ts=2:et
# #
# (c) 2012 Copyright: Martin Fischer (m_fischer at gmx dot de) # (c) 2012-2019 Copyright: Martin Fischer (m_fischer at gmx dot de)
# Maintained by Marko Oldenburg since 2019 # Maintained by Marko Oldenburg since 2019
# All rights reserved # All rights reserved
# #
@ -21,211 +20,251 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
#
# $Id$
#
################################################################ ################################################################
package main; package main;
use strict; use strict;
use warnings; use warnings;
use FHEM::Meta;
sub CommandBackup($$); #####################################
sub parseConfig($); sub backup_Initialize($$) {
sub readModpath($$); my %hash = ( Fn => 'FHEM::backup::CommandBackup',
sub createArchiv($$$); Hlp => ',create a backup of fhem configuration, state and modpath' );
$cmds{backup} = \%hash;
return FHEM::Meta::InitMod( __FILE__, \%hash );
}
######################################
## unserer packagename
package FHEM::backup;
use strict;
use warnings;
use FHEM::Meta;
use GPUtils qw(GP_Import)
; # wird für den Import der FHEM Funktionen aus der fhem.pl benötigt
## Import der FHEM Funktionen
BEGIN {
GP_Import(
qw(AttrVal
gettimeofday
ResolveDateWildcards
attr
Log
fhemForked
defs
configDBUsed
TimeNow
BC_searchTelnet
BC_telnetDevice
DoTrigger)
);
}
my @pathname; my @pathname;
##################################### sub CommandBackup($$) {
sub my ($cl, $param) = @_;
backup_Initialize($$)
{ my $byUpdate = ($param && $param eq 'startedByUpdate');
my %hash = ( Fn => "CommandBackup", my $modpath = AttrVal('global', 'modpath', '');
Hlp => ",create a backup of fhem configuration, state and modpath" ); my $configfile = AttrVal('global', 'configfile', '');
$cmds{backup} = \%hash; my $statefile = AttrVal('global', 'statefile', '');
my $logDir = AttrVal('global', 'logdir', 'none');
my $now = gettimeofday();
my @t = localtime($now);
$statefile = ResolveDateWildcards($statefile, @t);
# prevent duplicate entries in backup list for default config, forum #54826
$configfile = '' if ($configfile eq 'fhem.cfg' || configDBUsed());
$statefile = '' if ($statefile eq './log/fhem.save');
my $msg;
my $ret;
Log(1, 'NOTE: make sure you have a database backup!') if(configDBUsed());
# set backupdir
my $backupdir;
if (!defined($attr{global}{backupdir})) {
$backupdir = $modpath . '/backup';
}
else {
if ($attr{global}{backupdir} =~ m/^\/.*/) {
$backupdir = $attr{global}{backupdir};
}
elsif ($attr{global}{backupdir} =~ m/^\.+\/.*/) {
$backupdir = $modpath . '/' . $attr{global}{backupdir};
}
else {
$backupdir = $modpath . '/' . $attr{global}{backupdir};
}
}
# create backupdir if not exists
if (!-d $backupdir) {
Log(4, 'backup create backupdir: ' . $backupdir);
$ret = `(mkdir -p $backupdir) 2>&1`;
if ($ret) {
chomp($ret);
$msg = 'backup: ' . $ret;
return $msg;
}
}
if(configDBUsed()) {
# add configDB configuration file
push(@pathname, 'configDB.conf');
Log(4, 'backup include: \'configDB.conf\'');
}
else {
# get pathnames to archiv
push(@pathname, $configfile) if($configfile);
Log(4, 'backup include: ' . $configfile);
$ret = parseConfig($configfile);
push(@pathname, $statefile) if($statefile);
Log(4, 'backup include: ' . $statefile);
}
$ret = readModpath($modpath,$backupdir);
## add extra logdir path to backup
push(@pathname, $logDir) if($logDir ne 'none');
# create archiv
$ret = createArchiv($backupdir, $cl, $byUpdate);
@pathname = [];
undef @pathname;
return $ret;
} }
##################################### sub parseConfig($);
sub
CommandBackup($$)
{
my ($cl, $param) = @_;
my $byUpdate = ($param && $param eq "startedByUpdate"); sub parseConfig($) {
my $modpath = AttrVal("global", "modpath",""); my $configfile = shift;
my $configfile = AttrVal("global", "configfile", ""); # we need default value to read included files
my $statefile = AttrVal("global", "statefile", ""); $configfile = $configfile ? $configfile : 'fhem.cfg';
my $now = gettimeofday(); my $fh;
my @t = localtime($now); my $msg;
$statefile = ResolveDateWildcards($statefile, @t); my $ret;
# prevent duplicate entries in backup list for default config, forum #54826 if (!open($fh,$configfile)) {
$configfile = '' if ($configfile eq 'fhem.cfg' || configDBUsed()); $msg = 'Can\'t open ' . $configfile . ': ' . $!;
$statefile = '' if ($statefile eq "./log/fhem.save"); Log(1, 'backup ' . $msg);
my $msg; return $msg;
my $ret;
Log 1, "NOTE: make sure you have a database backup!" if(configDBUsed());
# set backupdir
my $backupdir;
if (!defined($attr{global}{backupdir})) {
$backupdir = "$modpath/backup";
} else {
if ($attr{global}{backupdir} =~ m/^\/.*/) {
$backupdir = $attr{global}{backupdir};
} elsif ($attr{global}{backupdir} =~ m/^\.+\/.*/) {
$backupdir = "$modpath/$attr{global}{backupdir}";
} else {
$backupdir = "$modpath/$attr{global}{backupdir}";
} }
}
# create backupdir if not exists while (my $l = <$fh>) {
if (!-d $backupdir) { $l =~ s/[\r\n]//g;
Log 4, "backup create backupdir: '$backupdir'"; if ($l =~ m/^\s*include\s+(\S+)\s*.*$/) {
$ret = `(mkdir -p $backupdir) 2>&1`; if (-e $1) {
if ($ret) { push @pathname, $1;
chomp $ret; Log(4, 'backup include: ' . $1);
$msg = "backup: $ret"; $ret = parseConfig($1);
return $msg; }
else {
Log(1, 'backup configfile: ' . $1 . ' does not exists! File not included.');
}
}
} }
}
if(configDBUsed()) { close $fh;
# add configDB configuration file return $ret;
push @pathname, 'configDB.conf';
Log 4, "backup include: 'configDB.conf'";
} else {
# get pathnames to archiv
push @pathname, $configfile if($configfile);
Log 4, "backup include: '$configfile'";
$ret = parseConfig($configfile);
push @pathname, $statefile if($statefile);
Log 4, "backup include: '$statefile'";
}
$ret = readModpath($modpath,$backupdir);
# create archiv
$ret = createArchiv($backupdir, $cl, $byUpdate);
@pathname = [];
undef @pathname;
return $ret;
} }
sub sub readModpath($$) {
parseConfig($) my ($modpath,$backupdir) = @_;
{ my $msg;
my $configfile = shift; my $ret;
# we need default value to read included files
$configfile = $configfile ? $configfile : 'fhem.cfg';
my $fh;
my $msg;
my $ret;
if (!open($fh,$configfile)) { if (!opendir(DH, $modpath)) {
$msg = "Can't open $configfile: $!"; $msg = 'Can\'t open $modpath: ' . $!;
Log 1, "backup $msg"; Log(1, 'backup ' . $msg);
return $msg; return $msg;
}
while (my $l = <$fh>) {
$l =~ s/[\r\n]//g;
if ($l =~ m/^\s*include\s+(\S+)\s*.*$/) {
if (-e $1) {
push @pathname, $1;
Log 4, "backup include: '$1'";
$ret = parseConfig($1);
} else {
Log 1, "backup configfile: '$1' does not exists! File not included."
}
} }
}
close $fh; my @files = <$modpath/*>;
return $ret; foreach my $file (@files) {
if ($file eq $backupdir && (-d $file || -l $file)) {
Log(4, 'backup exclude: ' . $file);
}
else {
Log(4, 'backup include: ' . $file);
push @pathname, $file;
}
}
return $ret;
} }
sub sub createArchiv($$$) {
readModpath($$) my ($backupdir,$cl,$byUpdate) = @_;
{ my $backupcmd = (!defined($attr{global}{backupcmd}) ? undef : $attr{global}{backupcmd});
my ($modpath,$backupdir) = @_; my $symlink = (!defined($attr{global}{backupsymlink}) ? 'no' : $attr{global}{backupsymlink});
my $msg; my $tarOpts;
my $ret; my $msg;
my $ret;
if (!opendir(DH, $modpath)) { my $dateTime = TimeNow();
$msg = "Can't open $modpath: $!"; $dateTime =~ s/ /_/g;
Log 1, "backup $msg"; $dateTime =~ s/(:|-)//g;
return $msg;
} my $pathlist = join( '" "', @pathname );
my @files = <$modpath/*>;
foreach my $file (@files) { my $cmd='';
if ($file eq $backupdir && (-d $file || -l $file)) { if (!defined($backupcmd)) {
Log 4, "backup exclude: '$file'"; if (lc($symlink) eq 'no') {
} else { $tarOpts = 'cf';
Log 4, "backup include: '$file'"; }
push @pathname, $file; else {
$tarOpts = 'chf';
}
# prevents tar's output of "Removing leading /" and return total bytes of
# archive
# $cmd = "tar -$tarOpts - \"$pathlist\" |gzip > $backupdir/FHEM-$dateTime.tar.gz";
$cmd = "tar $tarOpts $backupdir/FHEM-$dateTime.tar.gz \"$pathlist\"";
} }
} else {
return $ret; $cmd = $backupcmd . ' \"' . $pathlist . '\"';
}
sub
createArchiv($$$)
{
my ($backupdir,$cl,$byUpdate) = @_;
my $backupcmd = (!defined($attr{global}{backupcmd}) ? undef : $attr{global}{backupcmd});
my $symlink = (!defined($attr{global}{backupsymlink}) ? "no" : $attr{global}{backupsymlink});
my $tarOpts;
my $msg;
my $ret;
my $dateTime = TimeNow();
$dateTime =~ s/ /_/g;
$dateTime =~ s/(:|-)//g;
my $pathlist = join( "\" \"", @pathname );
my $cmd="";
if (!defined($backupcmd)) {
if (lc($symlink) eq "no") {
$tarOpts = "cf";
} else {
$tarOpts = "chf";
} }
# prevents tar's output of "Removing leading /" and return total bytes of Log(2, 'Backup with command: ' . $cmd);
# archive if(!$fhemForked && !$byUpdate) {
$cmd = "tar -$tarOpts - \"$pathlist\" |gzip > $backupdir/FHEM-$dateTime.tar.gz"; use Blocking;
our $BC_telnetDevice;
BC_searchTelnet('backup');
my $tp = $defs{$BC_telnetDevice}{PORT};
} else { system("($cmd; echo Backup done;".
$cmd = "$backupcmd \"$pathlist\""; "$^X $0 localhost:$tp 'trigger global backup done')2>&1 &");
return "Started the backup in the background, watch the log for details";
}
} $ret = `($cmd) 2>&1`;
Log 2, "Backup with command: $cmd";
if(!$fhemForked && !$byUpdate) {
use Blocking;
our $BC_telnetDevice;
BC_searchTelnet("backup");
my $tp = $defs{$BC_telnetDevice}{PORT};
system("($cmd; echo Backup done;". if($ret) {
"$^X $0 localhost:$tp 'trigger global backup done')2>&1 &"); chomp $ret;
return "Started the backup in the background, watch the log for details"; Log(1, 'backup ' . $ret);
} }
$ret = `($cmd) 2>&1`;
if($ret) { if (!defined($backupcmd) && -e "$backupdir/FHEM-$dateTime.tar.gz") {
chomp $ret; my $size = -s "$backupdir/FHEM-$dateTime.tar.gz";
Log 1, "backup $ret"; $msg = "backup done: FHEM-$dateTime.tar.gz ($size Bytes)";
} DoTrigger('global', $msg);
if (!defined($backupcmd) && -e "$backupdir/FHEM-$dateTime.tar.gz") { Log(1, $msg);
my $size = -s "$backupdir/FHEM-$dateTime.tar.gz"; $ret .= "\n".$msg;
$msg = "backup done: FHEM-$dateTime.tar.gz ($size Bytes)"; }
DoTrigger("global", $msg);
Log 1, $msg; return $ret;
$ret .= "\n".$msg;
}
return $ret;
} }
1; 1;
@ -260,6 +299,47 @@ createArchiv($$$)
<br> <br>
</ul> </ul>
=end html =end html
=for :application/json;q=META.json 98_backup.pm
{
"abstract": "Modul to retrieves apt information about Debian update state",
"x_lang": {
"de": {
"abstract": "Modul um apt Updateinformationen von Debian Systemen zu bekommen"
}
},
"keywords": [
"fhem-mod-device",
"fhem-core",
"backup",
"tar"
],
"release_status": "stable",
"license": "GPL_2",
"author": [
"Marko Oldenburg <leongaultier@gmail.com>"
],
"x_fhem_maintainer": [
"CoolTux"
],
"x_fhem_maintainer_github": [
"LeonGaultier"
],
"prereqs": {
"runtime": {
"requires": {
"FHEM": 5.00918799,
"perl": 5.016,
"Meta": 0
},
"recommends": {
},
"suggests": {
}
}
}
}
=end :application/json;q=META.json
=cut =cut