#! @PERL@
# Copyright (c) 2012-2012 Zmanda, Inc. All Rights Reserved.
# Copyright (c) 2013-2016 Carbonite, Inc. All Rights Reserved.
#
# This program 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.
#
# This program 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.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Contact information: Zmanda Inc., 465 S Mathlida Ave, Suite 300
# Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
use lib '@amperldir@';
use strict;
use warnings;
use Getopt::Long;
use File::Basename;
use IPC::Open3;
use Amanda::Device qw( :constants );
use Amanda::Debug qw( :logging );
use Amanda::Config qw( :init :getconf config_dir_relative );
use Amanda::Util qw( :constants );
use Amanda::Storage;
use Amanda::Changer;
use Amanda::Constants;
use Amanda::MainLoop;
use Amanda::Tapelist;
use Amanda::Label;
use Amanda::Disklist;
use Amanda::Curinfo;
Amanda::Util::setup_application("amadmin_perl", "server", $CONTEXT_CMDLINE, "amanda", "amanda");
my $config_overrides = new_config_overrides($#ARGV+1);
my ($opt_config, $opt_command);
my ($opt_no_default, $opt_print_source, $opt_exact_match, $opt_sort);
debug("Arguments: " . join(' ', @ARGV));
Getopt::Long::Configure(qw(bundling));
GetOptions(
'version' => \&Amanda::Util::version_opt,
'help|usage|?' => \&usage,
'no-default' => \$opt_no_default,
'print-source' => \$opt_print_source,
'exact-match' => \$opt_exact_match,
'sort' => \$opt_sort,
'o=s' => sub { add_config_override_opt($config_overrides, $_[1]); },
) or usage();
usage() unless (@ARGV);
$opt_config = shift @ARGV;
set_config_overrides($config_overrides);
config_init_with_global($CONFIG_INIT_EXPLICIT_NAME, $opt_config);
my ($cfgerr_level, @cfgerr_errors) = config_errors();
if ($cfgerr_level >= $CFGERR_WARNINGS) {
config_print_errors();
if ($cfgerr_level >= $CFGERR_ERRORS) {
die("errors processing config file");
}
}
Amanda::Util::finish_setup($RUNNING_AS_DUMPUSER);
usage() unless (@ARGV);
$opt_command = shift @ARGV;
my $exit_status = 0;
sub user_msg_err {
my $msg = shift;
print STDERR $msg->message() . "\n";
}
sub user_msg_out {
my $msg = shift;
print STDOUT "amadmin: " . $msg->message() . "\n";
}
sub main {
my ($finished_cb) = @_;
my $storage;
my $chg;
my $steps = define_steps
cb_ref => \$finished_cb,
finalize => sub { $storage->quit() if defined $storage;
$chg->quit() if defined $chg };
step start => sub {
if ($opt_command eq "reuse" or $opt_command eq "no-reuse") {
return $steps->{'reuse'}->();
} elsif ($opt_command eq "retention") {
return $steps->{'retention'}->();
}
my $diskfile = config_dir_relative(getconf($CNF_DISKFILE));
my $cfgerr_level = Amanda::Disklist::read_disklist('filename' => $diskfile);
($cfgerr_level < $CFGERR_ERRORS) || die "Errors processing disklist";
my $curinfodir = getconf($CNF_INFOFILE);
my $ci = Amanda::Curinfo->new($curinfodir);
Amanda::Disklist::do_on_match_disklist(
user_msg => \&user_msg_out,
exact_match => $opt_exact_match,
disk_cb => sub {
my $dle = shift;
if ($opt_command eq "force") {
$ci->force($dle);
} elsif ($opt_command eq "unforce") {
$ci->unforce($dle);
} elsif ($opt_command eq "force-level-1") {
$ci->force_level_1($dle);
} elsif ($opt_command eq "force-bump") {
$ci->force_bump($dle);
} elsif ($opt_command eq "force-no-bump") {
$ci->force_no_bump($dle);
} elsif ($opt_command eq "unforce-bump") {
$ci->unforce_bump($dle);
}
},
args => \@ARGV);
$finished_cb->();
};
step reuse => sub {
my $tlf = Amanda::Config::config_dir_relative(getconf($CNF_TAPELIST));
my ($tl, $message) = Amanda::Tapelist->new($tlf);
if (defined $message) {
print STDERR "amadmin: Could not read the tapelist: $message";
$exit_status = 1;
$finished_cb->();
}
$storage = Amanda::Storage->new(tapelist => $tl);
if ($storage->isa("Amanda::Changer::Error")) {
print STDERR "amadmin: $storage\n";
$exit_status = 1;
$finished_cb->();
}
$chg = $storage->{'chg'};
if ($chg->isa("Amanda::Changer::Error")) {
print STDERR "amadmin: $chg\n";
$exit_status = 1;
$finished_cb->();
}
my $Label = Amanda::Label->new(storage => $storage,
tapelist => $tl,
user_msg => \&user_msg_err);
if ($opt_command eq "reuse") {
if (@ARGV < 1) {
print STDERR "amadmin: expecting \"reuse <tapelabel> ...\"\n";
} else {
return $Label->reuse(labels => \@ARGV,
finished_cb => $finished_cb);
}
} elsif ($opt_command eq "no-reuse") {
if (@ARGV < 1) {
print STDERR "amadmin: expecting \"no-reuse <tapelabel> ...\"\n";
} else {
return $Label->no_reuse(labels => \@ARGV,
finished_cb => $finished_cb);
}
} else {
print STDERR "Only 'reuse' and 'no-reuse' command\n";
usage();
}
$finished_cb->();
};
step retention => sub {
my $tlf = Amanda::Config::config_dir_relative(getconf($CNF_TAPELIST));
my ($tl, $message) = Amanda::Tapelist->new($tlf);
if (defined $message) {
print STDERR "amadmin: Could not read the tapelist: $message";
$exit_status = 1;
$finished_cb->();
}
Amanda::Tapelist::compute_retention();
if (@ARGV) {
foreach my $label (@ARGV) {
my $tle = $tl->lookup_tapelabel($label);
if ($tle) {
my $retention_type = Amanda::Tapelist::get_retention_type($tle->{pool}, $tle->{label});
my $retention_name = $tl->get_retention_name($retention_type);
print "$tle->{storage} $tle->{pool} $tle->{label} $retention_name\n";
} else {
print "No '$label' label.\n";
}
}
} else {
foreach my $tle (@{$tl->{'tles'}}) {
my $retention_type = Amanda::Tapelist::get_retention_type($tle->{pool}, $tle->{label});
my $retention_name = $tl->get_retention_name($retention_type);
print "$tle->{storage} $tle->{pool} $tle->{label} $retention_name\n";
}
}
$finished_cb->();
};
}
main(\&Amanda::MainLoop::quit);
Amanda::MainLoop::run();
Amanda::Util::finish_application();
exit($exit_status);