#!/usr/bin/perl # # 2011/06/21 gabriel use strict; use warnings; use YAML; use IO::All; use File::Basename; use File::Finder; use Net::LDAP; use List::Util qw(shuffle); my %CMD_DB = ( help => \&cmd_help, version => \&cmd_version, generate => \&cmd_generate, update => \&cmd_update, init => \&cmd_init_db, 'exclude-list' => \&cmd_exclude_list, ); my ($LDAP_H, $LDAP_BASE); my $LIMIT_TIMESTAMP = time() - (8 * 24 * 3600); # 8 days my $cmd = shift @ARGV || 'help'; if (defined $CMD_DB{$cmd}) { $CMD_DB{$cmd}->(@ARGV); } else { print {*STDERR} "backuppc-silzigan: command $cmd not found\n\n"; $CMD_DB{help}->(); exit 1; } exit; sub open_ldap { # AuthLDAPUrl "ldap://ldapserver.mylab.fr/ou=Users,dc=mylab,dc=fr?uid?sub" # AuthLDAPBindDN "cn=ldapconnect,ou=System,dc=mylab,dc=fr" # AuthLDAPBindPassword "Rhalala128" my ($masterLDAP, $masterDN, $masterPw); for my $config_line (io('/etc/apache2/conf.d/backuppc.conf')->chomp->slurp) { ($masterLDAP, $LDAP_BASE) = ($1, $2) if $config_line =~ m{ ^\s* AuthLDAPUrl [^/]+ // ([^/]+) / (ou=[^?]+) }xms; $masterDN = $1 if $config_line =~ m{ ^\s* AuthLDAPBindDN \s+ " ([^"]+) " }xms; $masterPw = $1 if $config_line =~ m{ ^\s* AuthLDAPBindPassword \s+ " ([^"]+) " }xms; } $LDAP_H = Net::LDAP->new( "$masterLDAP" ) or die "$@"; my $mesg = $LDAP_H->bind("$masterDN", password => "$masterPw"); return; } sub close_ldap { $LDAP_H->unbind(); return; } sub cmd_update { my $search_config_file = File::Finder->type('f')->name('*.yaml'); for my $config_file (File::Finder->eval($search_config_file)->in('/etc/backuppc')) { cmd_generate("$config_file"); } update_hosts(); } sub cmd_generate { my $config_file = shift; my $CONFIG = YAML::LoadFile($config_file); $CONFIG->{default}{namespace} ||= basename($config_file, '.yaml'); $CONFIG->{default}{path} ||= "/etc/backuppc/auto/$CONFIG->{default}{namespace}"; $CONFIG->{default}{hosts} ||= "$CONFIG->{default}{path}/hosts"; $CONFIG->{default}{exclude} ||= "/usr/lib/kont/etc/backuppc/exclude.txt"; if (not -d "/etc/backuppc/auto/$CONFIG->{default}{namespace}") { io("/etc/backuppc/auto/$CONFIG->{default}{namespace}")->mkpath({mode => 0755}); } print '' > io($CONFIG->{default}{hosts}); open_ldap(); LOOP_ON_COMPUTER: for my $computer ( keys %{$CONFIG->{computers}}) { my $login = $CONFIG->{computers}{$computer}{login} || 'root'; LOOP_ON_USER: for my $user ( keys %{$CONFIG->{computers}{$computer}{users}}) { my $pathshare = $CONFIG->{computers}{$computer}{share} || $CONFIG->{default}{share} || "/home/users"; my $share = $CONFIG->{computers}{$computer}{users}{$user}{share} || "$pathshare/$user"; my $status = $CONFIG->{computers}{$computer}{users}{$user}{status} || $CONFIG->{computers}{$computer}{status} || $CONFIG->{default}{status} || 'auto'; my $admin = $CONFIG->{computers}{$computer}{users}{$user}{admin} || $CONFIG->{computers}{$computer}{admin} || $CONFIG->{default}{admin} || 'root'; my $exclude = $CONFIG->{computers}{$computer}{users}{$user}{exclude} || $CONFIG->{computers}{$computer}{exclude} || ''; my @exclude_list = (); if (ref($exclude) eq "ARRAY") { push @exclude_list, @{$exclude}; } else { push @exclude_list, $exclude if not $exclude =~ m/^$/; } push @exclude_list, io($CONFIG->{default}{exclude})->chomp->slurp; my $exclude_string = join ",\n", map { " '$_'" } @exclude_list; if ($status eq "auto") { $status = "disable"; my $ldb = $LDAP_H->search( base => "$LDAP_BASE", filter => "(uid=$user)", attrs => ['shadowExpire', 'sambaKickoffTime'], ); if (not $ldb->code ) { LDAP_RESULT: foreach my $entry ($ldb->entries) { my $user_expire_timestamp = $entry->get_value('sambaKickoffTime') || 0; my $user_shadow_expire = $entry->get_value('shadowExpire') || 0; if ($user_shadow_expire == 0) { $status = "enable"; last LDAP_RESULT; } elsif ( ( $user_expire_timestamp ne "" ) and ( $user_expire_timestamp > $LIMIT_TIMESTAMP ) ) { $status = "enable"; last LDAP_RESULT; } } } } write_config($user, $computer, $share, $login, $admin, $status, $CONFIG, $exclude_string); } if (exists $CONFIG->{computers}{$computer}{subfolder}) { my $home_path = $CONFIG->{computers}{$computer}{subfolder}; my @ls = `/bin/ping -W 2 -c 1 $computer > /dev/null 2>&1 && { /usr/bin/rsync --dry-run $login\@$computer:$home_path /tmp/backuppc-test/ || echo Error for $login\@$computer | logger -t backuppc-silzigan; }`; $home_path =~ s{/[^/]*$}{}; LINE: for my $line (@ls) { chomp $line; next LINE if not $line =~ m/skipping\sdirectory/; next LINE if $line =~ m/lost+found/; next LINE if $line =~ m/administrator/; my ($user) = reverse split /\s+/, $line; $user =~ s{/$}{}; $user =~ s{.*/}{}; next LINE if not $user =~ m/^\w/; my $share = "$home_path/$user"; my @exclude_list = (); push @exclude_list, io($CONFIG->{default}{exclude})->chomp->slurp; my $exclude_string = join ",\n", map { " '$_'" } @exclude_list; my $admin = $CONFIG->{computers}{$computer}{admin} || $CONFIG->{default}{admin} || 'root'; my $status = "disable"; my $ldb = $LDAP_H->search( base => "$LDAP_BASE", filter => "(uid=$user)", attrs => ['shadowExpire', 'sambaKickoffTime'], ); if (not $ldb->code ) { LDAP_RESULT: foreach my $entry ($ldb->entries) { my $user_expire_timestamp = $entry->get_value('sambaKickoffTime') || 0; my $user_shadow_expire = $entry->get_value('shadowExpire') || 0; if ($user_shadow_expire == 0) { $status = "enable"; last LDAP_RESULT; } elsif ( ( $user_expire_timestamp ne "" ) and ( $user_expire_timestamp > $LIMIT_TIMESTAMP ) ) { $status = "enable"; last LDAP_RESULT; } } } write_config($user, $computer, $share, $login, $admin, $status, $CONFIG, $exclude_string); } } } close_ldap(); } sub cmd_exclude_list { print io('/usr/lib/kont/etc/backuppc/exclude.txt')->all; } sub write_config { my ($user, $computer, $share, $login, $admin, $status, $CONFIG, $exclude) = @_; my ($c) = split /\./, $computer; my $backup_name = $c . '_'. $user; return if $status eq 'disable' and not -e "/var/lib/backuppc/pc/$backup_name/backups"; print "$backup_name 0 $login $admin,$user\n" >> io($CONFIG->{default}{hosts}); my $share_string = "'$share'"; if (ref($share) eq "ARRAY") { $share_string = join ', ', map("'$_'", @{$share}); } # my $exclude = join ",\n", map { " '$_'" } io('/usr/lib/kont/etc/backuppc/exclude.txt')->chomp->slurp; print < io("$CONFIG->{default}{path}/$backup_name.pl"); \$Conf{XferMethod} = 'rsync'; \$Conf{ClientNameAlias} = '$computer'; \$Conf{RsyncShareName} = [ $share_string ]; \$Conf{RsyncClientCmd} = '\$sshPath -q -x -l $login \$host \$rsyncPath \$argList+'; \$Conf{RsyncClientRestoreCmd} = '\$sshPath -q -x -l $login \$host \$rsyncPath \$argList+'; \$Conf{BackupFilesExclude} = { '$share' => [ $exclude ] }; END print '$Conf{FullPeriod} = "-2";' >> io("$CONFIG->{default}{path}/$backup_name.pl") if $status eq 'disable'; symlink "$CONFIG->{default}{path}/$backup_name.pl", "/etc/backuppc/pc/$backup_name.pl"; } sub update_hosts { io->catfile('/etc/backuppc/hosts.main') > io('/etc/backuppc/hosts.order'); my @hosts = io('/etc/backuppc/hosts.main')->chomp->slurp; my $search_host_file = File::Finder->type('f')->name('hosts'); for my $host_file (File::Finder->eval($search_host_file)->in('/etc/backuppc/auto')) { print "#\n# $host_file\n#\n" >> io('/etc/backuppc/hosts.order'); io->catfile("$host_file") >> io('/etc/backuppc/hosts.order'); push @hosts, io("$host_file")->chomp->slurp; } my ($first, @host) = grep(/./, grep(!/^#/, @hosts)); print "$first\n" > io('/etc/backuppc/hosts'); print "$_\n" >> io('/etc/backuppc/hosts') for shuffle(@host); } sub cmd_init_db { my $cfg = { computers => { 'machine36.hmg.priv' => { login => 'root', share => '/home/users/%u', status => 'auto', users => { 'dupond' => { share => [ '/home/users/dupond', '/var/www/dupond' ], status => 'enable', }, 'durand' => { share => '/home/users/durand', }, }, }, }, }; YAML::DumpFile("/tmp/template-backuppc.yaml", $cfg); } sub cmd_help { print <<'END'; backuppc-silzigan - cut into small pieces a computer configuration for backuppc backuppc-silzigan init backuppc-silzigan generate config_file.yaml backuppc-silzigan update backuppc-silzigan help backuppc-silzigan version backuppc-silzigan exclude-list END return; } sub cmd_version { print <<'END'; backuppc-silzigan - cut into small pieces a computer configuration for backuppc Copyright (C) 2011-2013 Gabriel Moreau $Id: backuppc-silzigan..host.legilnx32 3821 2013-12-20 08:03:14Z g7moreau $ END return; }