2 # Copyright (c) 2010 Zmanda Inc. All Rights Reserved.
4 # This program is free software; you can redistribute it and/or modify it
5 # under the terms of the GNU General Public License version 2 as published
6 # by the Free Software Foundation.
8 # This program is distributed in the hope that it will be useful, but
9 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 # You should have received a copy of the GNU General Public License along
14 # with this program; if not, write to the Free Software Foundation, Inc.,
15 # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 # Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
18 # Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
20 use lib '@amperldir@';
24 use Amanda::Config qw( :init :getconf );
26 use Amanda::DB::Catalog;
34 Usage: $0 [--hostwidth width] [--diskwidth width] [--skipmissed]
35 [--last] [--num0] [--togo0] [--verbose] [[--config] CONFIG]
37 This script generates to standard output an overview of the filesystems
38 dumped over time and the type of dump done on a particular day, such as
39 a full dump, or an incremental, or if the dump failed.
41 You may override the default configuration `@DEFAULT_CONFIG@' by using
42 the --config command line option. On larger installations, this script
43 will take a while to run. In this case, run it with --verbose to see
49 # overrideable defaults
50 my $opt_config = undef;
51 my $opt_hostwidth = 8;
52 my $opt_diskwidth = 20;
53 my $opt_skipmissed = 0;
59 GetOptions('config=s' => \$opt_config,
60 'hostwidth=i' => \$opt_hostwidth,
61 'diskwidth=i' => \$opt_diskwidth,
62 'skipmissed' => \$opt_skipmissed,
65 'togo0' => \$opt_togo0,
66 'verbose' => \$opt_verbose)
69 unless(defined($opt_config)) {
71 $opt_config = $ARGV[0];
77 #Initialize configuration
78 config_init($CONFIG_INIT_EXPLICIT_NAME, $opt_config);
79 my ($cfgerr_level, @cfgerr_errors) = config_errors();
80 if ($cfgerr_level >= $CFGERR_WARNINGS) {
81 config_print_errors();
82 if ($cfgerr_level >= $CFGERR_ERRORS) {
83 die("errors processing config file");
88 $cfgerr_level = Amanda::Disklist::read_disklist();
89 die("Config errors") if ($cfgerr_level >= $CFGERR_WARNINGS);
92 foreach my $dle (Amanda::Disklist::all_disks()) {
93 $disks{$dle->{"host"}->{"hostname"}}{$dle->{"name"}}++;
99 my ($date, $host, $disk);
101 print STDERR "Processing $opt_config dumps\n";
102 foreach my $dump (Amanda::DB::Catalog::sort_dumps(['hostname','diskname','write_timestamp'],Amanda::DB::Catalog::get_dumps())) {
103 $host = $dump->{"hostname"};
104 $disk = $dump->{"diskname"};
105 $date = substr($dump->{"dump_timestamp"},0,8);
107 if (defined $disks{$host}{$disk}) {
108 defined($level{$host}{$disk}{$date}) or
109 $level{$host}{$disk}{$date} = '';
110 $level{$host}{$disk}{$date} .= ($dump->{"status"} eq 'OK') ? $dump->{"level"} : 'E';
115 # Process the status to arrive at a "last" status
117 for $host (sort keys %disks) {
118 for $disk (sort keys %{$disks{$host}}) {
119 $level{$host}{$disk}{"0000LAST"} = '';
120 for $date (sort keys %dates) {
121 next unless defined($level{$host}{$disk}{$date});
122 if ($level{$host}{$disk}{$date} eq "E"
123 && $level{$host}{$disk}{"0000LAST"} =~ /^\d/ ) {
124 $level{$host}{$disk}{"0000LAST"} .= $level{$host}{$disk}{$date};
126 $level{$host}{$disk}{"0000LAST"} = $level{$host}{$disk}{$date};
133 # Number of level 0 backups
135 for $host (sort keys %disks) {
136 for $disk (sort keys %{$disks{$host}}) {
137 $level{$host}{$disk}{'0000NML0'} = 0;
138 for $date (sort keys %dates) {
139 if (defined($level{$host}{$disk}{$date})
140 && $level{$host}{$disk}{$date} =~ /0/) {
141 $level{$host}{$disk}{'0000NML0'} += 1;
148 # Runs to the last level 0
150 for $host (sort keys %disks) {
151 for $disk (sort keys %{$disks{$host}}) {
152 $level{$host}{$disk}{'0000TOGO'} = 0;
154 for $date (sort keys %dates) {
155 if (defined($level{$host}{$disk}{$date})
156 && $level{$host}{$disk}{$date} =~ /0/) {
157 $level{$host}{$disk}{'0000TOGO'} = $togo;
165 unless ($opt_skipmissed)
166 # touch all the dates just in case whole days were missed.
168 my ($start, $finish) =
170 my($y,$m,$d) = /(....)(..)(..)/;
171 POSIX::mktime(0,0,0,$d,$m-1,$y-1900);
172 } (sort keys %dates)[0,-1];
174 # Special case of only one date
175 if (defined($finish)) {
176 while ($start < $finish) {
177 my @l = localtime $start;
178 $dates{sprintf("%d%02d%02d", 1900+$l[5], $l[4]+1, $l[3])}++;
184 #Add the "last" entry
185 $dates{"0000LAST"}=1 if ($opt_last);
187 #Add the "Number of Level 0s" entry
188 $dates{"0000NML0"}=1 if ($opt_num0);
190 #Add the "Runs to go" entry
191 $dates{"0000TOGO"}=1 if ($opt_togo0);
196 my ($host, $disk, @cols) = @_;
197 $host = substr($host, 0, $opt_hostwidth);
198 $disk = substr($disk, 0, $opt_diskwidth);
200 sprintf("%-0${opt_hostwidth}s %-0${opt_diskwidth}s ", $host, $disk) .
201 join(" ", map(sprintf("%-2s ", $_), @cols)) .
206 my ($host, $disk, $date) = @_;
207 my $levels = $level{$host}{$disk}{$date};
209 # no dumps on this date
210 $levels = '-' unless defined($levels);
212 return substr($levels, -2);
216 row('', 'date', map((/....(..) .. /x)[0], sort keys %dates));
217 row('host', 'disk', map((/.... .. (..)/x)[0], sort keys %dates));
220 for $host (sort keys %disks) {
221 for $disk (sort keys %{$disks{$host}}) {
223 map(fmt_levels($host, $disk, $_), sort keys %dates));