#!/usr/bin/perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
#(C)IBM Corp

#

BEGIN
{
    $::XCATROOT =
        $ENV{'XCATROOT'} ? $ENV{'XCATROOT'}
      : -d '/opt/xcat'   ? '/opt/xcat'
      : '/usr';
}
use lib "$::XCATROOT/lib/perl";
use Getopt::Long;
use xCAT::MsgUtils;
use xCAT::Utils;
use strict;

#-----------------------------------------------------------------------------

=head1  restorexCATdb 



 restorexCATdb  -p <directory containing db restore .csv files> 
 restorexCATdb -b -p <directory binary database backup> 


=cut

#-----------------------------------------------------------------------------
# Main
my $rc = 0;

&parse_args;
if ($::BINARY) {  # not using xCAT to dump, using the database utility
   my $DBname = xCAT::Utils->get_DBName;
   if ($DBname eq "DB2") {
     $rc=&DB2_binrestore;
     if ($rc == 0) {
       xCAT::MsgUtils->message("I", "Restore Complete. You can now restart the daemons.");
     } else {
       xCAT::MsgUtils->message("E", "Restore Failed.");
     }
     exit $rc;
   } else {
     if ($DBname eq "PG") {
       $rc=&PG_binrestore;
       if ($rc == 0) {
         xCAT::MsgUtils->message("I", "Restore Complete.");
       } else {
         xCAT::MsgUtils->message("I", "Restore Failed.");
       }
       exit $rc;
      }  else {
        xCAT::MsgUtils->message("E",
                            "Binary dump (-b) is not supported for $DBname");
        exit 1;
     }
   }
}
# read all the *.csv files from the input directory and restore the database
opendir DIRPATH, $::PATH;
if ($? != 0)
{
    my $msg = " Unable to read directory $::PATH \n";
    xCAT::MsgUtils->message("E", $msg);
    exit 1;
}
# read tables to skip during restore from site.skiptables attribute
my @output2=xCAT::TableUtils->get_site_attribute('skiptables');
my @skiptbls;
if (@output2) {
  @skiptbls = split (/\,/,$output2[0]);
}

my @files = readdir(DIRPATH);
foreach my $table (@files)
{
    if ($table ne '.' and $table ne '..')
    {
        my $tablename = $::PATH;
        $tablename .= "/";
        $tablename .= $table;
        if ( (!$::ALL) && (($table =~ /^eventlog/) || ($table =~ /^auditlog/))) {
            
          if ($::VERBOSEREST) {
            xCAT::MsgUtils->message("I", "Skipping $table\n");
          }
          next;
        }
        # skip teal tables
        if ( $table =~ /^x_teal/ ) {
           if ($::VERBOSEREST) {
            xCAT::MsgUtils->message("I", "Skipping $table\n");
           }
           next;
        }
        # skip ISNM tables except isnm_config
        if ( $table =~ /^isnm_perf/ ) {
          if ($::DUMPVERBOSE) {
            xCAT::MsgUtils->message("I", "Skipping $table\n");
          }
          next;
        }

        # skip and table in the site.skiptables attribute
        if (@skiptbls) {
          my ($tmptable,$suffix) = split(/\./,$table);
          chomp $tmptable;
          if (grep(/^$tmptable$/, @skiptbls)) {
            if ($::VERBOSEREST) {
             xCAT::MsgUtils->message("I", "Skipping $tmptable\n");
            }
             next;
          }
        }

        my $cmd = "tabrestore $tablename";
        my @errout = xCAT::Utils->runcmd($cmd, 0);
        if ($::RUNCMD_RC != 0)
        {    # error
            xCAT::MsgUtils->message("E", "Error running $cmd, @errout\n");
        } else {
          if ($::VERBOSEREST) {
            xCAT::MsgUtils->message("I", "Restoring $table.\n");
          }
        }
    }
}
closedir DIRPATH;
xCAT::MsgUtils->message("I", "Restore of Database Complete.");
exit $rc;

#-----------------------------------------------------------------------------

=head3 parse_args
  
  Parses for  input

=cut

#-----------------------------------------------------------------------------
sub parse_args
{
    my $msg;
    my    $usagemsg =
          " restorexCATdb  -h \n restorexCATdb -v \n restorexCATdb [-a] [-V] <-p> [path to restore .csv files]\n restorexCATdb -b [-V] <-t> [timestamp on restore backup file]  <-p> [path to restore backup file]";
    Getopt::Long::Configure("posix_default");
    Getopt::Long::Configure("no_gnu_compat");
    Getopt::Long::Configure("bundling");
    if (
        !GetOptions(
            'a|all'  => \$::ALL,
            'b|binary'  => \$::BINARY,
            'p|path=s'  => \$::PATH,
            't|timestamp=s'  => \$::TIMESTAMP,
            'h|help'    => \$::HELP,
            'V|verbose'    => \$::VERBOSEREST,
            'v|version' => \$::VERSION

        )
      )
    {
        xCAT::MsgUtils->message("E", $usagemsg);
        exit 1;
    }
    if ($::HELP)
    {
        xCAT::MsgUtils->message("I", $usagemsg);
        exit 0;
    }
    if ($::VERSION)
    {
        my $version = xCAT::Utils->Version();
        xCAT::MsgUtils->message("N", $version);

        exit 0;
    }
    if (!($::PATH))
    {
        my $msg = " -p with path to database files is required \n";
        xCAT::MsgUtils->message("E", $msg);
        exit 1;
    }
    if (!(-e $::PATH))
    {
        my $msg = " Input path must exist \n";
        xCAT::MsgUtils->message("E", $msg);
        exit 1;
    }

}
#-----------------------------------------------------------------------------

=head3 DB2_binrestore

    Uses the DB2 Database supplied restore utility to restore the database

=cut

#-----------------------------------------------------------------------------
sub DB2_binrestore
{
    my $msg;
    my $rc=0;
    if (!($::TIMESTAMP)){
       xCAT::MsgUtils->message("E", "To restore from a binary backup, the timestamp of the backup must be provided with the -t option.");
          return 1;
    }
    # check to see if  xcatd running.   Cannot restore if it is
    my $cmd = "ps -ef | grep xcatd";
    my @output=xCAT::Utils->runcmd($cmd, -1);
    if ($::RUNCMD_RC == 0) {  # found something
       if (grep(/xcatd: SSL listener/, @output)) { # xcatd running
          xCAT::MsgUtils->message("E", "xcatd is still accessing the database. All applications accessing the DB2 database must be stopped before you can restore.");
          return 1;

       }
    }
    # get password from cfgloc

    my $cmd="cat /etc/xcat/cfgloc";
    my $info=xCAT::Utils->runcmd($cmd, -1);
    if ($::RUNCMD_RC != 0) {
      xCAT::MsgUtils->message("E", "Cannot read /etc/xcat/cfgloc.");
      return 1;
    }
    chomp($info);
    my ($db,$inst,$pw) = split(/\|/, $info);

    # Hopefully nothing else is accessing the database, so try restore
    $cmd="db2 restore db xcatdb user xcatdb using $pw from $::PATH taken at $::TIMESTAMP";
    $rc  = &rundb2cmd($cmd);  # must su to xcatdb
    if ($rc != 0)
    {
      xCAT::MsgUtils->message("E", " $cmd error.");
      return 1;
    }
    #  Now roll forward any tranactions since the backup
    $cmd="db2 rollforward database xcatdb to end of logs and complete";
    $rc  = &rundb2cmd($cmd);  # must su to xcatdb
    if ($rc != 0)
    {
      xCAT::MsgUtils->message("E", " $cmd error.");
      return 1;
    }
    return 0;
}
#-----------------------------------------------------------------------------

=head3 PG_binrestore 
  
    Uses the PostgreSQL Database supplied backup utility to restore the database

=cut

#-----------------------------------------------------------------------------
sub PG_binrestore 
{
    my $msg;
    my $rc=0;
    my $pgcmddir               = "/usr/bin";      
    # get path to Postgresql commands if running 9.X version
    my $cmd = "rpm -qa | grep postgresql";
    my @output=xCAT::Utils->runcmd($cmd, 0);
    if ($::RUNCMD_RC != 0)
    {
      my $message =
      "\nPostgreSQL is not installed.  If on AIX, it should be first obtained from the xcat dependency tarballs and installed before running this command.\n If on Linux, install from the OS CDs.";
    xCAT::MsgUtils->message("E", " $cmd failed. $message");
    exit(1);
    }
    # check if 9.X release,  setup different
    if  (grep(/postgresql9/, @output)) {  # postgresql 9.x
       # figure out which 9.x release  and build path
       # for example 9.x release /usr/pgsql-9.x/bin
       my @parseout= split(/\-/, $output[0]);
       my @ptflevel= split ("postgresql9",$parseout[0]);
       my $postgres9=@ptflevel[1];  # set it to the PTF level
       $pgcmddir        = "/usr/pgsql-9.$postgres9/bin"; # pg cmds location
    }
    # Get database, admin from cfgloc file
    my $cmd="cat /etc/xcat/cfgloc";
    my $info=xCAT::Utils->runcmd($cmd, -1);
    if ($::RUNCMD_RC != 0) {
      xCAT::MsgUtils->message("E", "Cannot read /etc/xcat/cfgloc."); 
      return 1;
    }
    chomp($info); 
    my ($db,$admin,$pw) = split(/\|/, $info); 
    my ($info1,$info2) = split(/=/,$db);
    my ($dbname,$host) = split(/;/,$info2);
    
    # restore from backup file
    my $cmd="$pgcmddir/pg_restore  $::PATH -U postgres -d $dbname -c ";
    my $info=xCAT::Utils->runcmd($cmd, -1);
    if ($::RUNCMD_RC != 0) {
      xCAT::MsgUtils->message("E", "$cmd failed"); 
      return 1;
    }
    return 0;
   
}
#-----------------------------------------------------------------------------

=head3   rundb2cmd


  Run a commmand as the xcatdb instance id
  Input: command

=cut
#-----------------------------------------------------------------------------
sub rundb2cmd
{
    my $orgcmd = shift;
    my $rc     = 0;
    my $cmd    = "\'";
    $cmd .= $orgcmd;
    $cmd .= ' 2>&1';
    $cmd .= "\'";
    system("su - xcatdb -c $cmd");
    if ($? > 0)    # error
    {
        $rc = $? >> 8;
    }
    return ($rc);
}