#!/usr/bin/perl
BEGIN
{
    $::XCATROOT =
      $ENV{'XCATROOT'} ? $ENV{'XCATROOT'}
      : -d '/opt/xcat' ? '/opt/xcat'
      :                  '/usr';
}
use lib "$::XCATROOT/lib/perl";
use strict;

use Getopt::Long;
require xCAT::MsgUtils;
require xCAT::DSHCLI;
require xCAT::Client;

use xCAT::Utils;
use xCAT::TableUtils;
use File::Basename;

$::XCATROOT = "/opt/xcat";
my $os        = "";
my $profile   = "";
my $interface = "";
my $version;
my $drivers         = "";
my $otherInterfaces = "";
my $kernel          = "";
my @oses;        # available OSes.
my @profiles;    # available profiles
my $profDir;     # root where you do ./genimage from
my $help;
my $match = 0;
my $imagename;
my $arch;
my $permission;
my $rootlimit;
my $tmplimit;
my $krpmver;
my $kerneldir;
my $mode;
my $interactive;
my $onlyinitrd;
my $dryrun;
my $ignorekernelchk;
my $noupdate;

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

=head3 print_usage   - usage message

=cut

#-----------------------------------------------------------------------------
sub print_usage
{
    print "Usage:\n";
    print "    genimage\n\n";
    print "    genimage --dryrun\n\n";
    print '    genimage  -o <osver> [-a <arch>] -p <profile> -i <nodebootif> -n <nodenetdrivers> [--onlyinitrd] [-r <otherifaces>] [-k <kernelver>] [-g <krpmver>] [-m statelite] [-l rootlimitsize] [-t tmplimitsize] [--permission <permission>] [--interactive] [--dryrun]'."\n\n";
    print '    genimage [-o <osver>] [-a <arch>] [-p <profile>] [-i <nodebootif>] [-n <nodenetdrivers>] [--onlyinitrd] [-r <otherifaces>] [-k <kernelver>] [-g <krpmver>] [-m statelite] [-l rootlimitsize] [-t tmplimitsize] [--permission <permission>] [--interactive] [--dryrun] [--noupdate] <imagename>' . "\n\n";
    print "      --permission is used for statelite only\n";
    print "      -g is used for SLES only\n\n";
    print "      -m is used for urbuntu, debian and fedora12 only\n\n";
    print "Examples:\n";
    print "    genimage\n";
    print "    genimage --interactive\n";
    print "    genimage -i eth0 -n tg3 -o sles11 -p compute\n";
    print "    genimage -i eth0 -n tg3 -o sles11 -p compute --onlyinitrd\n";
    print "    genimage -i eth0 -r eth1,eth2 -n tg3,bnx2 -o centos5.1 -p compute --interactive\n";
    print "    genimage -i eth0 -n tg3,bnx2 -o sles11 -p compute --dryrun\n";
    print "    genimage -i eth0 -n igb,e1000e,e1000,bnx2,tg3 -o centos5.4 -p nfsroot --permission 777\n";
    print "    genimage -i eth0 -n tg3 --interactive myimagename\n";
    print "    genimage myimagename\n";
}

if (!GetOptions(
        'a=s'             => \$arch,
        'p=s'             => \$profile,
        'o=s'             => \$os,
        'n=s'             => \$drivers,
        'i=s'             => \$interface,
        'r=s'             => \$otherInterfaces,
        'l=s'             => \$rootlimit,
        't=s'             => \$tmplimit,
        'k=s'             => \$kernel,
        'g=s'             => \$krpmver,
        'm=s'             => \$mode,
        'permission=s'    => \$permission,
        'kerneldir=s'     => \$kerneldir,
        'interactive'     => \$interactive,
        'onlyinitrd'      => \$onlyinitrd,
        'dryrun'          => \$dryrun,
        'ignorekernelchk' => \$ignorekernelchk,
        'noupdate'        => \$noupdate,
        'h|help'          => \$help,
        'v|version'       => \$version,
    )) {
    &print_usage;
    exit 1;
}

if ($help) {
    &print_usage;
    exit 0;
}

if ($version) {
    my $version = xCAT::Utils->Version();
    xCAT::MsgUtils->message("N", $version);
    exit 0;

}
if (@ARGV > 0) {
    $imagename = $ARGV[0];
}

if ((!$imagename) && (!$profile) && (!$os) && (!$arch)) {
    my $tmpimgs = `lsdef -t osimage -w provmethod=~'/statelite|netboot/' |cut -d' ' -f1`;
    if ($? == 0) {
        if (($tmpimgs) && ($tmpimgs !~ /^Could/)) { #Could is returned when the osimage table is empty
            my @images = split('\n', $tmpimgs);
            print "Do you want to re-generate an existing image from the osimage table? ";
            print "[y/n] ";
            my $conf = <stdin>;
            chomp($conf);
            if ($conf ne "" && $conf !~ /N|n|[Nn][Oo]/) {
                $match = 0;
                while (1) {
                    print "Available images: \n";
                    foreach (sort @images) {
                        print "   $_\n";
                    }

                    # default is the first image
                    print "Which image do you want to re-generate? [";
                    print $images[0];
                    print "] ";

                    my $img = <stdin>;
                    chomp($img);
                    if ($img eq "") {
                        $imagename = $images[0];
                        last;
                    }
                    foreach (@images) {
                        if ($img eq $_) {
                            $imagename = $img;
                            $match     = 1;
                        }
                    }
                    if ($match) {
                        last;
                    } else {
                        print "$img is not found in the osimage table.\n";
                    }
                }
            }
        }
    }
}


# get the install directory
my @entries    = xCAT::TableUtils->get_site_attribute("installdir");
my $installdir = $entries[0];
chomp($installdir);

# lots of error checking to make sure it exists.
if ($installdir eq '') {
    print "Could not get install directory from site table.  Assuming your OSes are stored in '/install'\n";
    $installdir = "/install";
}

unless (-d $installdir) {
    print "The directory where your OS distributions resides: $installdir does not exist.  Please check site table\n";
    exit 1;
}

if ((!$imagename) && (!$os)) {
    my @dircontents = `ls $installdir`;
    chomp(@dircontents);
    foreach (@dircontents) {

        # SL matches Scientific Linux, sl matches sles amd sled
        if ($_ =~ /(rhel|fedora|SL|centos|sl|suse)/) {
            push @oses, $_;
        }
    }

    if ($#oses == -1) {
        print "There are no OS repositories in $installdir.  Please run copycds for the OS first.\n";
        exit 1;
    }

    # now they have the OSes, make sure they select one that is available
    $match = 0;
    while (1) {
        print "Available OSes: \n";
        foreach (@oses) {
            print "   $_\n";
        }

        # default is the first OS cause in many cases, they'll only have 1.
        print "Which OS do you want to build a image for? [";
        print $oses[0];
        print "] ";

        $os = <stdin>;
        chomp($os);
        if ($os eq "") {
            $os = $oses[0];
            last;
        }
        foreach (@oses) {
            if ($os eq $_) {
                $match = 1;
            }
        }

        if ($match) {
            last;
        } else {
            print "$os is not found in '$installdir'\n";
        }
    }

    chomp($os);
}
if ($os) { print "  OS: $os\n"; }



### Get the Profile ####
my $osfamily = $os;
$osfamily =~ s/\d+//g;
$osfamily =~ s/\.//g;
if ($osfamily =~ /rh/) {
    $osfamily = "rh";
}

# OS version on s390x can contain 'sp', e.g. sles11sp1
# If the $osfamily contains 'sles' and 'sp', the $osfamily = sles
if ($osfamily =~ /sles/ && $osfamily =~ /sp/) {
    $osfamily = "sles";
}

#print "OSfamily: $osfamily\n";
$profDir = "$::XCATROOT/share/xcat/netboot/$osfamily";
unless (-d $profDir) {
    print "Unable to find genimage script in $profDir\n";
    exit 1;
}

if ((!$imagename) && (!$profile)) {
    my $profDir2 = "$installdir/custom/netboot/$osfamily";
    my @proList  = `ls $profDir/*.pkglist`;
    if (-d $profDir2) {
        @proList = (@proList, `ls $profDir2/*.pkglist`);
    }
    my %seen = ();
    foreach (@proList) {
        my $f = basename($_);
        $f =~ s/([^\.]*).*/$1/;
        chomp($f);
        $seen{$f}++;
    }
    @profiles = sort keys %seen;
    if ($#profiles == -1) {
        print "There are no profiles in $::XCATROOT/share/xcat/netboot/$osfamily.\n";
        exit 1;
    }
    $match = 0;
    while (1) {
        print "Available Profiles for $os: \n";
        foreach (@profiles) {
            print "   $_\n";
        }

        # default is the first OS cause in many cases, they'll only have 1.
        print "Which profile do you want to use for $os?  [";
        print "$profiles[0] ";
        print "] ";

        $profile = <stdin>;
        chomp($profile);
        if ($profile eq "") {
            $profile = $profiles[0];
            last;
        }
        foreach (@profiles) {
            if ($profile eq $_) {
                $match = 1;
            }
        }
        if ($match == 1) {
            last;
        }
    }
}
if ($profile) { print "  Profile: $profile\n"; }

# get the interface
if ((!$imagename) && (!$interface)) {
    while (1) {
        print "OPTIONAL: Which specific network interface will the image boot from? [<blank>]";
        $interface = <stdin>;
        chomp($interface);
        if ($interface eq "") {
            last;
        } else {
            print "You want your stateless machines to boot off of ";
            print "$interface";
            print "? ";
            print "[Y/n] ";
            my $conf = <stdin>;
            chomp($conf);
            if ($conf eq "") {
                last;
            }
            if ($conf =~ /Y|y|[Yy][Ee][Ss]/) {
                last;
            }
        }
    }
    if ($interface) { print "  Interface: $interface\n"; }
    else { print "  No interface specified.  The interface will be determined at network boot time.\n"; }
}



print "Generating image: \n";
my @arg;
if ($imagename) {
    push @arg, "$imagename";
}

if ($interface) {
    push @arg, "-i";
    push @arg, "$interface";
}
if ($drivers) {
    push @arg, "-n";
    push @arg, "$drivers";
}
if ($os) {
    push @arg, "-o";
    push @arg, "$os";
}
if ($profile) {
    push @arg, "-p";
    push @arg, "$profile";
}
if ($arch) {
    push @arg, "-a";
    push @arg, "$arch";
}

if ($kernel) {
    push @arg, "-k";
    push @arg, "$kernel";
}

if ($otherInterfaces) {
    push @arg, "-r";
    push @arg, "$otherInterfaces";
}

if ($permission) {
    push @arg, "--permission";
    push @arg, "$permission";
}

if ($rootlimit) {
    push @arg, "-l";
    push @arg, "$rootlimit";
}

if ($tmplimit) {
    push @arg, "-t";
    push @arg, "$tmplimit";
}

if ($krpmver) {
    push @arg, "-g";
    push @arg, "$krpmver";
}

if ($mode) {
    push @arg, "-m";
    push @arg, "$mode";
}

if ($kerneldir) {
    push @arg, "--kerneldir";
    push @arg, "$kerneldir";
}

my $tempfile = "/tmp/xcat_genimage.$$";
push @arg, "--tempfile";    #this is the file that contains the output
push @arg, "$tempfile";

if ($interactive) {
    push @arg, "--interactive";
}


if ($onlyinitrd) {
    push @arg, "--onlyinitrd";
}

if ($dryrun) {
    push @arg, "--dryrun";
}

if ($ignorekernelchk) {
    push @arg, "--ignorekernelchk";
}

if ($noupdate) {
    push @arg, "--noupdate";
}

my $cmdref;
push(@{ $cmdref->{arg} }, @arg);
$cmdref->{command}->[0] = "genimage";

if (!$interactive) {
    xCAT::Client::submit_request($cmdref, \&xCAT::Client::handle_response);
    exit $xCAT::Client::EXITCODE;
} else {
    if ($dryrun) { exit 0; }

    #when in interactive mode, first call genimage.pm get info from DB,
    xCAT::Client::submit_request($cmdref, \&xCAT::Client::handle_response);

    #then call the specific genimage under /opt/xcat/share...
    if (-f $tempfile) {
        my $cmdname;

        #read the command name
        open(FILE1, "<$tempfile");
        my @output = <FILE1>;
        if (@output > 0) {
            $cmdname = $output[0];
        } else {
            close FILE1;
            return 1;
        }
        close FILE1;

        # run the specific genimage command
        #print "cmdname=$cmdname\n";
        system("$cmdname");

        #then call genimage.pm to save the DB
        my @arg1;
        push @arg1, $tempfile;
        my $request;
        push(@{ $request->{arg} }, @arg1);
        $request->{command}->[0] = "saveimgdata";
        xCAT::Client::submit_request($request, \&xCAT::Client::handle_response);
        exit $xCAT::Client::EXITCODE;
    } else {
        exit 1;
    }
}

