#!/usr/bin/env perl
use strict;
use warnings;
use SMT::Agent::Utils;
use XML::XPath;

sub jobhandler
{
  my ($jobtype, $jobid, $args, $verbose) =  @_;

  SMT::Agent::Utils::logger ("jobhandler for update called", $jobid);
  SMT::Agent::Utils::logger ("update runs jobid \"$jobid\"", $jobid);

  # check whether this handler can handle requested jobtype
  SMT::Agent::Utils::error ("wrong job handler: \"update\" cannot handle \"$jobtype\"", $jobid) if ( $jobtype ne "update" );

  my $xpQuery = XML::XPath->new(xml => $args);
  eval { SMT::Agent::Utils::error("no argument section found for this job", $jobid) unless ( $xpQuery->exists('/arguments[1]')); };
  my $argSet;
  eval { $argSet = $xpQuery->find('/arguments[1]') };
  SMT::Agent::Utils::error("xml data is not parsable", $jobid) if ($@);
  SMT::Agent::Utils::error("too many argument sections found for this job", $jobid) unless ( (defined $argSet) && ($argSet->size() == 1) );
  my $arg = $argSet->pop();

  my $agreelicenses = $arg->getAttribute('agreelicenses');
  my $agreeSet;
  eval { $agreeSet = $xpQuery->find('/arguments[1]/options[1]/agreelicenses[1]') };
  SMT::Agent::Utils::error("xml data is not parsable", $jobid) if ($@);
  foreach my $_n ($agreeSet->get_nodelist()) {
      $agreelicenses = $_n->string_value() if (defined $_n);
      last if defined $agreelicenses;
  }
  $agreelicenses = (defined $agreelicenses && ($agreelicenses =~ /^1$/ || $agreelicenses =~ /^true$/)) ? 1 : 0;


  # patchwithupdate option was introduced with new smt server and client, thus only in options element
  my $patchwithupdate;
  my $pawupSet;
  eval { $pawupSet = $xpQuery->find('/arguments[1]/options[1]/patchwithupdate[1]') };
  foreach my $_n ($pawupSet->get_nodelist()) {
      $patchwithupdate = $_n->string_value() if (defined $_n);
      last if defined $patchwithupdate;
  }
  $patchwithupdate = (defined $patchwithupdate && ($patchwithupdate =~ /^1$/ || $patchwithupdate =~ /^true$/)) ? 1 : 0;

  # reboot
  my $reboot;
  my $rebootSet;
  eval { $rebootSet = $xpQuery->find('/arguments[1]/options[1]/reboot[1]') };
  foreach my $_n ($rebootSet->get_nodelist()) {
      $reboot = $_n->string_value() if (defined $_n);
      last if defined $reboot;
  }
  $reboot = "never" unless defined $reboot;

  my $rebootAllowed = SMT::Agent::Utils::isAgentAllowed('reboot') ? 1 : 0;
  SMT::Agent::Utils::error("update with enforced reboot denied", $jobid) if ( ($reboot eq 'enforce') && ! $rebootAllowed );

  #== ZYPPER
  my $command = "/usr/bin/zypper";
  my $retval;
  my ($stdoutup, $stderrup, $stdout1, $stderr1, $stdout2, $stderr2, $stdout, $stderr) = undef;

  #==  run zypper patch ==
  my @cmdArgs;
  push (@cmdArgs, "--no-cd");                                   # ignore CD/DVD repositories
  push (@cmdArgs, "--non-interactive");                         # don't ask any questions
  push (@cmdArgs, "patch");                                     # patch
  push (@cmdArgs, "--with-interactive");                        # include interactive patches anyhow
  push (@cmdArgs, "-l") if $agreelicenses;                      # agree licenses

  ($retval, $stdout1, $stderr1) = SMT::Agent::Utils::executeCommand($command, undef, @cmdArgs);

  # run zypper again if needed because of pkgmgr patches
  ($retval, $stdout2, $stderr2) = SMT::Agent::Utils::executeCommand($command, undef, @cmdArgs) if ($retval == 103);

  #== run zypper update if needed - but only if patch was successful ==
  if (($retval == 0) && $patchwithupdate)
  {
      my @upcmdArgs;
      push (@upcmdArgs, "--no-cd");                                   # ignore CD/DVD repositories
      push (@upcmdArgs, "--non-interactive");                         # don't ask any questions
      push (@upcmdArgs, "update");                                    # update
      push (@upcmdArgs, "-l") if $agreelicenses;                      # agree licenses

      ($retval, $stdoutup, $stderrup) = SMT::Agent::Utils::executeCommand($command, undef, @upcmdArgs);
  }

  $stdout = '';
  $stderr = '';
  $stdout .= $stdout1 if $stdout1;
  $stderr .= $stderr1 if $stderr1;
  $stdout .= $stdout2 if $stdout2;
  $stderr .= $stderr2 if $stderr2;
  $stdout .= $stdoutup if $stdoutup;
  $stderr .= $stderrup if $stderrup;

  my $mesg = "update failed";
  $mesg = "update successfully finished" if $retval == 0;

  my $exitcode = $retval;
  my $statuscode = ($retval == 0) ? 1:2;
  my $doReboot = ($reboot eq 'enforce') ? 1:0;
  if ($exitcode == 102)
  {
      if ($reboot eq 'never')
      {
          $mesg = "update successfully finished and reboot needed";
          $statuscode = 6;
      }
      elsif ($reboot eq 'ifneeded' || $reboot eq 'enforce')
      {
          if ($rebootAllowed)
          {
              $mesg = "update successfully finished and reboot executed";
              $doReboot = 1;
              $statuscode = 1;
          }
          else
          {
              $mesg = "update successfully finished and reboot needed, automatic reboot denied";
              $doReboot = 0;
              $statuscode = 6;
          }
      }
  }

  SMT::Agent::Utils::logger("job results: $mesg");
  SMT::Agent::Utils::logger("job statuscode: $retval, exitcode: $exitcode");

  if ($doReboot && $statuscode == 1)
  {
      `/sbin/shutdown -r +1 > /dev/null 2>&1 &`;
  }

  return (
    stdout => ((defined $stdout) && $verbose) ? $stdout : '',
    stderr => ((defined $stderr) && $verbose) ? $stderr : '',
    exitcode => $exitcode,
    success => $statuscode,
    message => $mesg,
    breakloop => ($doReboot && $statuscode == 1) ? 'true':'false'
  );
}

SMT::Agent::Utils::logger ("successfully loaded handler for jobtype \"update\"");

return 1;

