# 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: Carbonite Inc., 756 N Pastoria Ave
# Sunnyvale, CA 94085, or: http://www.zmanda.com
package Amanda::Rest::Dles;
use strict;
use warnings;
use Amanda::Config qw( :init :getconf config_dir_relative );
use Amanda::Device qw( :constants );
use Amanda::Storage;
use Amanda::Changer;
use Amanda::Header;
use Amanda::MainLoop;
use Amanda::Tapelist;
use Amanda::Label;
use Amanda::Curinfo;
use Amanda::Rest::Configs;
use Symbol;
use Data::Dumper;
use URI::Escape;
use vars qw(@ISA);
=head1 NAME
Amanda::Rest::Dles -- Rest interface to Amanda::Curinfo and other
DLE functionnalities.
=head1 INTERFACE
=over
=item Get a list (and setting) of all Dles
request:
GET /amanda/v1.0/configs/:CONF/dles
query arguments:
expand_application=1
expand_dumptype=1
expand_interface=1
expand_script=1
reply:
HTTP status: 200 OK
[
{
"module" : "amanda",
"source_line" : "242",
"severity" : "info",
"process" : "Amanda::Rest::Dles",
"diskfile" : "/amanda/h1/etc/amanda/test/disklist",
"source_filename" : "/amanda/h1/linux/lib/amanda/perl/Amanda/Rest/Dles.pm",
"component" : "rest-server",
"message" : "List of DLEs.",
"running_on" : "amanda-server",
"code" : "1400010",
"result" : [
{
"disk" : "/boot",
"dumptype" : "custom(10.5.15.56:_boot).114",
"host" : "10.5.15.56",
"spindle" : "-1",
"device" : "/boot"
},
{
"host" : "127.0.0.1",
"spindle" : "-1",
"device" : "/boot",
"disk" : "/bootAMGTAR",
"dumptype" : "custom(127.0.0.1:_bootAMGTAR).78"
}
]
}
]
=item Get a list (and setting) of all Dles for a host
request:
GET /amanda/v1.0/configs/:CONF/dles/hosts/:HOST
query arguments:
expand_application=1
expand_dumptype=1
expand_interface=1
expand_script=1
reply:
=item Get a list (and setting) of a Dle
request:
GET /amanda/v1.0/configs/:CONF/dles/hosts/:HOST/disk/:DISK
each '/' in the :DISK must be encoded as '%252F'
query arguments:
expand_application=1
expand_dumptype=1
expand_interface=1
expand_script=1
reply:
=item Change setting on Dles
request:
POST /amanda/v1.0/configs/:CONF/dles/hosts/:HOST/disks/:DISK
each '/' in the :DISK must be encoded as '%252F'
force=0|1
force_level_1=0|1
force_bump=0|1
force_no_bump=0|1
POST /amanda/v1.0/configs/:CONF/dles/hosts/:HOST
query arguments:
disk=DISK
force=0|1
force_level_1=0|1
force_bump=0|1
force_no_bump=0|1
reply:
HTTP status: 200 OK
[
{
"code" : "1300003",
"disk" : "/bootAMGTAR",
"host" : "localhost.localdomain",
"message" : "localhost.localdomain:/bootAMGTAR is set to a forced level 0 at next run.",
"severity" : "16",
"source_filename" : "/usr/lib/amanda/perl/Amanda/Curinfo.pm",
"source_line" : "336"
}
]
[
{
"code" : "1300019",
"disk" : "/bootAMGTAR",
"host" : "localhost.localdomain",
"message" : "force command for localhost.localdomain:/bootAMGTAR cleared.",
"severity" : "16",
"source_filename" : "/usr/lib/amanda/perl/Amanda/Curinfo.pm",
"source_line" : "365"
}
]
[
{
"code" : "1300021",
"disk" : "/bootAMGTAR",
"host" : "localhost.localdomain",
"message" : "no force command outstanding for localhost.localdomain:/bootAMGTAR, unchanged.",
"severity" : "16",
"source_filename" : "/usr/lib/amanda/perl/Amanda/Curinfo.pm",
"source_line" : "390"
}
]
[
{
"code" : "1300022",
"disk" : "/bootAMGTAR",
"host" : "localhost.localdomain",
"message" : "localhost.localdomain:/bootAMGTAR FORCE command was cleared",
"severity" : "16",
"source_filename" : "/usr/lib/amanda/perl/Amanda/Curinfo.pm",
"source_line" : "466"
}
]
[
{
"code" : "1300023",
"disk" : "/bootAMGTAR",
"host" : "localhost.localdomain",
"message" : "localhost.localdomain:/bootAMGTAR is set to a forced level 1 at next run.",
"severity" : "16",
"source_filename" : "/usr/lib/amanda/perl/Amanda/Curinfo.pm",
"source_line" : "434"
}
]
[
{
"code" : "1300020",
"disk" : "/bootAMGTAR",
"host" : "localhost.localdomain",
"message" : "force-level-1 command for localhost.localdomain:/bootAMGTAR cleared.",
"severity" : "16",
"source_filename" : "/usr/lib/amanda/perl/Amanda/Curinfo.pm",
"source_line" : "380"
}
]
[
{
"code" : "1300025",
"disk" : "/bootAMGTAR",
"host" : "localhost.localdomain",
"message" : "localhost.localdomain:/bootAMGTAR is set to bump at next run.",
"severity" : "16",
"source_filename" : "/usr/lib/amanda/perl/Amanda/Curinfo.pm",
"source_line" : "486"
}
]
[
{
"code" : "1300027",
"disk" : "/bootAMGTAR",
"host" : "localhost.localdomain",
"message" : "bump command for localhost.localdomain:/bootAMGTAR cleared.",
"severity" : "16",
"source_filename" : "/usr/lib/amanda/perl/Amanda/Curinfo.pm",
"source_line" : "547"
}
]
[
{
"code" : "1300026",
"disk" : "/bootAMGTAR",
"host" : "localhost.localdomain",
"message" : "localhost.localdomain:/bootAMGTAR is set to not bump at next run.",
"severity" : "16",
"source_filename" : "/usr/lib/amanda/perl/Amanda/Curinfo.pm",
"source_line" : "520"
}
]
=back
=cut
sub list {
my %params = @_;
Amanda::Util::set_pname("Amanda::Rest::Dles");
my ($status, @result_messages) = Amanda::Rest::Configs::config_init(@_);
return ($status, \@result_messages) if @result_messages;
if (defined $params{'DISK'} and !defined $params{'disk'}) {
$params{'disk'} = uri_unescape($params{'DISK'});
}
my $diskfile = config_dir_relative(getconf($CNF_DISKFILE));
Amanda::Disklist::unload_disklist();
my $cfgerr_level = Amanda::Disklist::read_disklist('filename' => $diskfile);
if ($cfgerr_level >= $CFGERR_ERRORS) {
push @result_messages, Amanda::Disklist::Message->new(
source_filename => __FILE__,
source_line => __LINE__,
code => 1400006,
severity => $Amanda::Message::ERROR,
diskfile => $diskfile,
cfgerr_level => $cfgerr_level);
return (-1, \@result_messages);
}
my @hosts;
if (defined $params{'HOST'}) {
my $host = Amanda::Disklist::get_host($params{'HOST'});
if (!$host) {
push @result_messages, Amanda::Disklist::Message->new(
source_filename => __FILE__,
source_line => __LINE__,
code => 1400007,
severity => $Amanda::Message::ERROR,
diskfile => $diskfile,
host => $params{'HOST'});
return (-1, \@result_messages);
}
@hosts = ( $host );
} else {
@hosts = Amanda::Disklist::all_hosts();
}
my @result;
foreach my $host (@hosts) {
my @disks;
if (defined $params{'disk'}) {
my $disk = $host->get_disk($params{'disk'});
if (!$disk) {
push @result_messages, Amanda::Disklist::Message->new(
source_filename => __FILE__,
source_line => __LINE__,
code => 1400008,
severity => $Amanda::Message::ERROR,
diskfile => $diskfile,
host => $host->{'hostname'},
disk => $params{'disk'});
next;
}
@disks = ( $disk );
} else {
@disks = $host->all_disks($host);
}
foreach my $disk (@disks) {
my $result = {
host => $host->{'hostname'},
disk => $disk->{'name'},
device => $disk->{'device'},
spindle => $disk->{'spindle'},
dumptype_name => dumptype_name($disk->{'config'}),
};
if ($params{'expand_dumptype'}) {
$result->{'dumptype'} = Amanda::Rest::Configs::dumptype_object($disk->{'config'}, %params);
}
push @result, $result;
}
}
if (@result) {
push @result_messages, Amanda::Disklist::Message->new(
source_filename => __FILE__,
source_line => __LINE__,
code => 1400010,
severity => $Amanda::Message::INFO,
diskfile => $diskfile,
result => \@result);
}
return (-1, \@result_messages);
}
sub setting {
my %params = @_;
Amanda::Util::set_pname("Amanda::Rest::Dles");
my ($status, @result_messages) = Amanda::Rest::Configs::config_init(@_);
return ($status, \@result_messages) if @result_messages;
if (defined $params{'DISK'} and !defined $params{'disk'}) {
$params{'disk'} = uri_unescape($params{'DISK'});
}
if (!defined $params{'disk'}) {
push @result_messages, Amanda::Disklist::Message->new(
source_filename => __FILE__,
source_line => __LINE__,
code => 1400009,
severity => $Amanda::Message::ERROR);
return (404, \@result_messages);
}
my $diskfile = config_dir_relative(getconf($CNF_DISKFILE));
Amanda::Disklist::unload_disklist();
my $cfgerr_level = Amanda::Disklist::read_disklist('filename' => $diskfile);
if ($cfgerr_level >= $CFGERR_ERRORS) {
push @result_messages, Amanda::Disklist::Message->new(
source_filename => __FILE__,
source_line => __LINE__,
code => 1400006,
severity => $Amanda::Message::ERROR,
diskfile => $diskfile,
cfgerr_level => $cfgerr_level);
return (-1, \@result_messages);
}
my $curinfodir = getconf($CNF_INFOFILE);;
my $ci = Amanda::Curinfo->new($curinfodir);
my $host = Amanda::Disklist::get_host($params{'HOST'});
if (!$host) { # $host->isa("Amanda::Message");
push @result_messages, Amanda::Disklist::Message->new(
source_filename => __FILE__,
source_line => __LINE__,
code => 1400007,
severity => $Amanda::Message::ERROR,
diskfile => $diskfile,
host => $params{'HOST'});
return (-1, \@result_messages);
}
my @disks;
if ($params{'disk'}) {
my $disk = $host->get_disk($params{'disk'});
if (!$disk) { # $disk->isa("Amanda::Message");
push @result_messages, Amanda::Disklist::Message->new(
source_filename => __FILE__,
source_line => __LINE__,
code => 1400008,
severity => $Amanda::Message::ERROR,
diskfile => $diskfile,
host => $params{'HOST'},
disk => $params{'disk'});
return (-1, \@result_messages);
}
push @disks, $disk;
} else {
@disks = $host->all_disks();
}
if (!defined $params{'force'} and
!defined $params{'force_level_1'} and
!defined $params{'force_bump'} and
!defined $params{'force_no_bump'}) {
push @result_messages, Amanda::Curinfo::Message->new(
source_filename => __FILE__,
source_line => __LINE__,
code => 1300030,
severity => $Amanda::Message::ERROR);
return (-1, \@result_messages);
}
my $a = 0;
$a++ if defined $params{'force'} and $params{'force'} == 1;
$a++ if defined $params{'force_level_1'} and $params{'force_level_1'} == 1;
$a++ if defined $params{'force_bump'} and $params{'force_bump'} == 1;
$a++ if defined $params{'force_no_bump'} and $params{'force_no_bump'} == 1;
if ($a > 1) {
push @result_messages, Amanda::Curinfo::Message->new(
source_filename => __FILE__,
source_line => __LINE__,
code => 1300031,
severity => $Amanda::Message::ERROR);
return (-1, \@result_messages);
}
# remove setting
for my $disk (@disks) {
if ((defined $params{'force'} and !$params{'force'}) or
(defined $params{'force_level_1'} and !$params{'force_level_1'})) {
push @result_messages, $ci->unforce($disk);
}
if ((defined $params{'force_bump'} and !$params{'force_bump'}) or
(defined $params{'force_no_bump'} and !$params{'force_no_bump'})) {
push @result_messages, $ci->unforce_bump($disk);
}
}
# add new setting
for my $disk (@disks) {
if (defined $params{'force'}) {
if ($params{'force'}) {
push @result_messages, $ci->force($disk);
}
}
if (defined $params{'force_level_1'}) {
if ($params{'force_level_1'}) {
push @result_messages, $ci->force_level_1($disk);
}
}
if (defined $params{'force_bump'}) {
if ($params{'force_bump'}) {
push @result_messages, $ci->force_bump($disk);
}
}
if (defined $params{'force_no_bump'}) {
if ($params{'force_no_bump'}) {
push @result_messages, $ci->force_no_bump($disk);
}
}
}
return ($status, \@result_messages);
}
sub info {
my %params = @_;
Amanda::Util::set_pname("Amanda::Rest::Dles");
my ($status, @result_messages) = Amanda::Rest::Configs::config_init(@_);
return ($status, \@result_messages) if @result_messages;
if (defined $params{'DISK'} and !defined $params{'disk'}) {
$params{'disk'} = uri_unescape($params{'DISK'});
}
if (!defined $params{'disk'}) {
push @result_messages, Amanda::Disklist::Message->new(
source_filename => __FILE__,
source_line => __LINE__,
code => 1400009,
severity => $Amanda::Message::ERROR);
return (404, \@result_messages);
}
my $diskfile = config_dir_relative(getconf($CNF_DISKFILE));
Amanda::Disklist::unload_disklist();
my $cfgerr_level = Amanda::Disklist::read_disklist('filename' => $diskfile);
if ($cfgerr_level >= $CFGERR_ERRORS) {
push @result_messages, Amanda::Disklist::Message->new(
source_filename => __FILE__,
source_line => __LINE__,
code => 1400006,
severity => $Amanda::Message::ERROR,
diskfile => $diskfile,
cfgerr_level => $cfgerr_level);
return (-1, \@result_messages);
}
my $curinfodir = getconf($CNF_INFOFILE);;
my $ci = Amanda::Curinfo->new($curinfodir);
my $host = Amanda::Disklist::get_host($params{'HOST'});
if (!$host) { # $host->isa("Amanda::Message");
push @result_messages, Amanda::Disklist::Message->new(
source_filename => __FILE__,
source_line => __LINE__,
code => 1400007,
severity => $Amanda::Message::ERROR,
diskfile => $diskfile,
host => $params{'HOST'});
return (-1, \@result_messages);
}
my @dles;
if ($params{'disk'}) {
my $disk = $host->get_disk($params{'disk'});
if (!$disk) { # $disk->isa("Amanda::Message");
push @result_messages, Amanda::Disklist::Message->new(
source_filename => __FILE__,
source_line => __LINE__,
code => 1400008,
severity => $Amanda::Message::ERROR,
diskfile => $diskfile,
host => $params{'HOST'},
disk => $params{'disk'});
return (-1, \@result_messages);
}
push @dles, $disk;
} else {
@dles = $host->all_disks();
}
for my $dle (@dles) {
my $info = $ci->get_dle_info($dle);
return $info if $info->isa("Amanda::Message");
$info->{'force-full'} = 1 if $info->isset($Amanda::Curinfo::Info::FORCE_FULL);
$info->{'force-level-1'} = 1 if $info->isset($Amanda::Curinfo::Info::FORCE_LEVEL_1);
$info->{'force-bump'} = 1 if $info->isset($Amanda::Curinfo::Info::FORCE_BUMP);
$info->{'force-no-bump'} = 1 if $info->isset($Amanda::Curinfo::Info::FORCE_NO_BUMP);
push @result_messages, Amanda::Curinfo::Message->new(
source_filename => __FILE__,
source_line => __LINE__,
code => 1300033,
severity => $Amanda::Message::SUCCESS,
host => $dle->{'host'}->{'hostname'},
disk => $dle->{'name'},
info => $info);
}
return ($status, \@result_messages);
}
1;