source: trunk/backuppc-silzigan/backuppc-silzigan @ 414

Last change on this file since 414 was 414, checked in by g7moreau, 5 years ago
  • Commit back a lot of change !
  • Property svn:executable set to *
File size: 13.3 KB
Line 
1#!/usr/bin/perl
2#
3# 2011/06/21 Gabriel Moreau <Gabriel.Moreau@univ-grenoble-alpes.fr>
4#
5# apt-get install iputils-ping rsync nmap perl-base libyaml-perl libio-all-perl libfile-finder-perl libnet-ldap-perl
6
7use strict;
8use warnings;
9
10use Getopt::Long qw(GetOptions);
11use YAML;
12use IO::All;
13use File::Basename;
14use File::Finder;
15use Net::LDAP;
16use List::Util qw(shuffle);
17use Logger::Syslog;
18
19my $command = shift @ARGV || 'help';
20
21my %cmd_db = (
22   'help'         => \&cmd_help,
23   'version'      => \&cmd_version,
24   'generate'     => \&cmd_generate,
25   'update'       => \&cmd_update,
26   'init'         => \&cmd_init_db,
27   'exclude-list' => \&cmd_exclude_list,
28   );
29
30#-------------------------------------------------------------------------------
31
32my ($LDAP_H, $LDAP_BASE);
33my $LIMIT_TIMESTAMP = time() - (8 * 24 * 3600); # 8 days
34
35if (defined $cmd_db{$command}) {
36   $cmd_db{$command}->(@ARGV);
37   }
38else {
39   print {*STDERR} "backuppc-silzigan: command $command not found\n\n";
40   $cmd_db{help}->();
41   exit 1;
42   }
43
44exit;
45
46#-------------------------------------------------------------------------------
47
48sub open_ldap {
49   # AuthLDAPUrl          "ldap://ldapserver.mylab.fr/ou=Users,dc=mylab,dc=fr?uid?sub"
50   # AuthLDAPBindDN       "cn=ldapconnect,ou=System,dc=mylab,dc=fr"
51   # AuthLDAPBindPassword "Rhalala128"
52
53   my ($masterLDAP, $masterDN, $masterPw);
54
55   for my $config_line (io('/etc/apache2/conf.d/backuppc.conf')->chomp->slurp) {
56      ($masterLDAP, $LDAP_BASE) = ($1, $2) if $config_line =~ m{ ^\s* AuthLDAPUrl [^/]+ // ([^/]+) / (ou=[^?]+) }xms;
57      $masterDN = $1 if $config_line =~ m{ ^\s* AuthLDAPBindDN \s+ " ([^"]+) " }xms;
58      $masterPw = $1 if $config_line =~ m{ ^\s* AuthLDAPBindPassword \s+ " ([^"]+) " }xms;
59      }
60
61   $LDAP_H = Net::LDAP->new( "$masterLDAP" ) or die "$@";
62   my $mesg = $LDAP_H->bind("$masterDN", password => "$masterPw");
63
64   return;
65   }
66
67#-------------------------------------------------------------------------------
68
69sub close_ldap {
70   $LDAP_H->unbind();
71   return;
72   }
73
74#-------------------------------------------------------------------------------
75
76sub cmd_update {
77   local @ARGV = @_;
78
79   my $search_config_file = File::Finder->type('f')->name('*.yaml');
80   for my $config_file (File::Finder->eval($search_config_file)->in('/etc/backuppc')) {
81      cmd_generate("$config_file", @ARGV);
82      }
83
84   add_oldcomputer();
85   
86   update_hosts();
87   }
88
89#-------------------------------------------------------------------------------
90
91sub add_oldcomputer {
92   my $admin = 'sys-admin';
93
94   my %hostdb = ();
95   for my $hostline (io('/etc/backuppc/hosts.order')->chomp->slurp) {
96      next if not $hostline =~ m/^\w/;
97      my ($host) = split /\s+/, $hostline, 2;
98      $hostdb{$host}++;
99      }
100
101   # Reset hosts database
102   print '' > io('/etc/backuppc/hosts.oldcomputer');
103
104   for my $pc (io->dir('/var/lib/backuppc/pc')->all_dirs) {
105      my $pcname = $pc->filename;
106      my $pcpath = $pc->pathname;
107      next if not -e "$pcpath/backups";
108      next if not -e "/etc/backuppc/$pcname.pl";
109
110      my $user = 'root';
111      my $host = $pcname;
112      ($host, $user) = split /_/, $pcname, 2 if $pcname =~ m/_/;
113      next if exists $hostdb{$pcname};
114
115      my $full_period;
116      for (io("/etc/backuppc/$pcname.pl")->chomp->slurp) {
117         m/FullPeriod/ or next;
118         $full_period++;
119         last;
120         }
121
122      io("/etc/backuppc/$pcname.pl")->append('$Conf{FullPeriod} = "-2";') if not $full_period;
123     
124      # Add to hosts database
125      print "$pcname 0 sleeping $admin,$user\n" >> io('/etc/backuppc/hosts.oldcomputer');
126      }
127   }
128
129#-------------------------------------------------------------------------------
130
131sub cmd_generate {
132   local @ARGV = @_;
133   my $config_file = shift @ARGV;
134
135   my ($verbose);
136
137   GetOptions(
138      'verbose'   => \$verbose,
139      );
140
141   my $CONFIG;
142   
143   eval {
144      $CONFIG = YAML::LoadFile($config_file);
145      };
146   if ($@) {
147      warning "Error: bad YAML in file $config_file";
148      return;
149      }
150
151   $CONFIG->{default}{namespace} ||= basename($config_file, '.yaml');
152   $CONFIG->{default}{path}      ||= "/etc/backuppc/auto/$CONFIG->{default}{namespace}";
153   $CONFIG->{default}{hosts}     ||= "$CONFIG->{default}{path}/hosts";
154   $CONFIG->{default}{exclude}   ||= "/usr/lib/kont/etc/backuppc/exclude.txt";
155
156   if (not -d "/etc/backuppc/auto/$CONFIG->{default}{namespace}") {
157      io("/etc/backuppc/auto/$CONFIG->{default}{namespace}")->mkpath({mode => 0755});
158      }
159
160   print '' > io($CONFIG->{default}{hosts});
161
162   open_ldap();
163   LOOP_ON_COMPUTER:
164   for my $computer ( keys %{$CONFIG->{computers}}) {
165      my $login = $CONFIG->{computers}{$computer}{login} || 'root';
166
167      LOOP_ON_USER:
168      for my $user (  keys %{$CONFIG->{computers}{$computer}{users}}) {
169         my $pathshare = $CONFIG->{computers}{$computer}{share}
170                   || $CONFIG->{default}{share}
171                   || "/home/users";
172         my $share  = $CONFIG->{computers}{$computer}{users}{$user}{share}
173                   || "$pathshare/$user";
174         my $status = $CONFIG->{computers}{$computer}{users}{$user}{status}
175                   || $CONFIG->{computers}{$computer}{status}
176                   || $CONFIG->{default}{status}
177                   || 'auto';
178         my $admin  = $CONFIG->{computers}{$computer}{users}{$user}{admin}
179                   || $CONFIG->{computers}{$computer}{admin}
180                   || $CONFIG->{default}{admin}
181                   || 'root';
182
183         my $exclude = $CONFIG->{computers}{$computer}{users}{$user}{exclude}
184                   || $CONFIG->{computers}{$computer}{exclude}
185                   || '';
186
187         my @exclude_list = ();
188         if (ref($exclude) eq "ARRAY") {
189            push @exclude_list, @{$exclude};
190            }
191         else {
192            push @exclude_list, $exclude if not $exclude =~ m/^$/;
193            }
194         push @exclude_list, io($CONFIG->{default}{exclude})->chomp->slurp;
195         my $exclude_string = join ",\n", map { "    '$_'" } @exclude_list;
196
197         if ($status eq "auto") {
198            $status = "disable";
199            my $ldb = $LDAP_H->search(
200               base     => "$LDAP_BASE",
201               filter   => "(uid=$user)",
202               attrs    => ['shadowExpire', 'sambaKickoffTime'],
203               );
204            if (not $ldb->code ) {
205
206               LDAP_RESULT:
207               foreach my $entry ($ldb->entries) {
208
209                  my $user_expire_timestamp = $entry->get_value('sambaKickoffTime') || 0;
210                  my $user_shadow_expire = $entry->get_value('shadowExpire') || 0;
211
212                  if ($user_shadow_expire == 0) {
213                     $status = "enable";
214                     last LDAP_RESULT;
215                     }
216                  elsif (
217                     ( $user_expire_timestamp ne "" )
218                        and ( $user_expire_timestamp >  $LIMIT_TIMESTAMP )
219                     ) {
220                     $status = "enable";
221                     last LDAP_RESULT;
222                     }
223
224                  }
225               }
226            }
227
228         write_config($user, $computer, $share, $login, $admin, $status, $CONFIG, $exclude_string);
229
230         }
231
232      if (exists $CONFIG->{computers}{$computer}{subfolder}) {
233         my $home_path = $CONFIG->{computers}{$computer}{subfolder};
234         print STDERR "\nInfo: ssh on $login\@$computer\n" if $verbose;
235         my @ls = `/bin/ping -W 2 -c 1 $computer > /dev/null 2>&1 && {
236            /usr/bin/nmap  -p 22 -PN $computer | grep -q '^22/tcp[[:space:]]*open\b' && {
237               /usr/bin/rsync --dry-run $login\@$computer:$home_path /tmp/backuppc-test/ || echo Error for $login\@$computer | logger -t backuppc-silzigan;
238               };
239            };`;
240
241         $home_path =~ s{/[^/]*$}{};
242         LINE:
243         for my $line (@ls) {
244            chomp $line;
245            next LINE if not $line =~ m/skipping\sdirectory/;
246            next LINE if $line =~ m/lost\+found/;
247            next LINE if $line =~ m/administrator/;
248            my ($user) = reverse split /\s+/, $line;
249            $user =~ s{/$}{};
250            $user =~ s{.*/}{};
251            next LINE if not $user =~ m/^\w/;
252
253            my $share = "$home_path/$user";
254
255            my @exclude_list = ();
256            push @exclude_list, io($CONFIG->{default}{exclude})->chomp->slurp;
257            my $exclude_string = join ",\n", map { "    '$_'" } @exclude_list;
258
259            my $admin = $CONFIG->{computers}{$computer}{admin}
260                     || $CONFIG->{default}{admin}
261                     || 'root';
262
263            my $status = "disable";
264            my $ldb = $LDAP_H->search(
265               base     => "$LDAP_BASE",
266               filter   => "(uid=$user)",
267               attrs    => ['shadowExpire', 'sambaKickoffTime'],
268               );
269            if (not $ldb->code ) {
270
271               LDAP_RESULT:
272               foreach my $entry ($ldb->entries) {
273
274                  my $user_expire_timestamp = $entry->get_value('sambaKickoffTime') || 0;
275                  my $user_shadow_expire = $entry->get_value('shadowExpire') || 0;
276
277                  if ($user_shadow_expire == 0) {
278                     $status = "enable";
279                     last LDAP_RESULT;
280                     }
281                  elsif (
282                     ( $user_expire_timestamp ne "" )
283                        and ( $user_expire_timestamp >  $LIMIT_TIMESTAMP )
284                     ) {
285                     $status = "enable";
286                     last LDAP_RESULT;
287                     }
288
289                  }
290               }
291
292            write_config($user, $computer, $share, $login, $admin, $status, $CONFIG, $exclude_string);
293            }
294         }
295      }
296   close_ldap();
297   }
298
299#-------------------------------------------------------------------------------
300
301sub cmd_exclude_list {
302   print io('/usr/lib/kont/etc/backuppc/exclude.txt')->all;
303   }
304
305#-------------------------------------------------------------------------------
306
307sub write_config {
308   my ($user, $computer, $share, $login, $admin, $status, $CONFIG, $exclude) = @_;
309   my ($c) = split /\./, $computer;
310   my $backup_name = $c . '_'. $user;
311
312   return if $status eq 'disable' and not -e "/var/lib/backuppc/pc/$backup_name/backups";
313
314   print "$backup_name 0 $login $admin,$user\n" >> io($CONFIG->{default}{hosts});
315
316   my $share_string = "'$share'";
317   if (ref($share) eq "ARRAY") {
318      $share_string = join ', ', map("'$_'", @{$share});
319      }
320
321#   my $exclude = join ",\n", map { "    '$_'" } io('/usr/lib/kont/etc/backuppc/exclude.txt')->chomp->slurp;
322
323   print <<END > io("$CONFIG->{default}{path}/$backup_name.pl");
324\$Conf{XferMethod} = 'rsync';
325\$Conf{ClientNameAlias} = '$computer';
326\$Conf{RsyncShareName} = [ $share_string ];
327\$Conf{RsyncClientCmd} = '\$sshPath -q -x -l $login \$host \$rsyncPath \$argList+';
328\$Conf{RsyncClientRestoreCmd} = '\$sshPath -q -x -l $login \$host \$rsyncPath \$argList+';
329\$Conf{BackupFilesExclude} = {
330  '$share' => [
331$exclude
332  ]
333};
334END
335
336   print '$Conf{FullPeriod} = "-2";' >> io("$CONFIG->{default}{path}/$backup_name.pl") if $status eq 'disable';
337   symlink "$CONFIG->{default}{path}/$backup_name.pl", "/etc/backuppc/pc/$backup_name.pl";
338   }
339
340#-------------------------------------------------------------------------------
341
342sub update_hosts {
343   io->catfile('/etc/backuppc/hosts.main') > io('/etc/backuppc/hosts.order');
344   my @hosts = io('/etc/backuppc/hosts.main')->chomp->slurp;
345
346   push @hosts, io('/etc/backuppc/hosts.oldcomputer')->chomp->slurp;
347
348   my $search_host_file = File::Finder->type('f')->name('hosts');
349   for my $host_file (File::Finder->eval($search_host_file)->in('/etc/backuppc/auto')) {
350      print "#\n# $host_file\n#\n" >> io('/etc/backuppc/hosts.order');
351      io->catfile("$host_file") >> io('/etc/backuppc/hosts.order');
352      push @hosts, io("$host_file")->chomp->slurp;
353      }
354   my ($first, @host) = grep(/./, grep(!/^#/, @hosts));
355   print "$first\n" > io('/etc/backuppc/hosts');
356   print "$_\n" >> io('/etc/backuppc/hosts') for shuffle(@host);
357   }
358
359#-------------------------------------------------------------------------------
360
361sub cmd_init_db {
362   my $cfg = {
363      computers => {
364         'machine36.hmg.priv' => {
365            login => 'root',
366            share => '/home/users/%u',
367            status => 'auto',
368            users => {
369               'dupond' => {
370                  share => [ '/home/users/dupond', '/var/www/dupond' ],
371                  status => 'enable',
372                  },
373               'durand' => {
374                  share => '/home/users/durand',
375                  },
376               },
377            },
378         },
379      };
380
381   YAML::DumpFile("/tmp/template-backuppc.yaml", $cfg);
382   }
383
384#-------------------------------------------------------------------------------
385
386sub cmd_help {
387   print <<'END';
388backuppc-silzigan - cut into small pieces a computer configuration for backuppc
389
390 backuppc-silzigan init
391 backuppc-silzigan generate config_file.yaml [--verbose]
392 backuppc-silzigan update [--verbose]
393 backuppc-silzigan help
394 backuppc-silzigan version
395 backuppc-silzigan exclude-list
396END
397   return;
398   }
399
400#-------------------------------------------------------------------------------
401
402sub cmd_version {
403   print <<'END';
404backuppc-silzigan - cut into small pieces a computer configuration for backuppc
405Author: Gabriel Moreau <Gabriel.Moreau@univ-grenoble-alpes.fr>
406Copyright (C) 2011-2019, LEGI UMR 5519 / CNRS UGA G-INP, Grenoble, France
407
408$Id: backuppc-silzigan..host.legilnx32 3821 2013-12-20 08:03:14Z g7moreau $
409END
410   return;
411   }
Note: See TracBrowser for help on using the repository browser.