#!/usr/bin/env perl
# generate the image for mic
# Since the root file system for mic is generated on the host by
# micctrl command, this script only help to generate the /etc/hosts,
# /root/.ssh from the management node to the root file system.

BEGIN
{
    $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
}
use lib "$::XCATROOT/lib/perl";

use strict;
use File::Path;
use File::Basename;
use File::Copy;
use File::Find;
use Getopt::Long;
Getopt::Long::Configure("bundling");
Getopt::Long::Configure("pass_through");

use FindBin;
use lib "$FindBin::Bin/../imgutils";
use imgutils;
use xCAT::Table;


my $arch;
my $profile;
my $osver;
my $pkglist;
my $srcdir;
my $otherpkglist;
my $rootimg_dir;
my $srcdir_otherpkgs;
my $tempfile;
my $postinstall;
my $rootimgdir;
my $prompt;

my $imagename;

GetOptions(
    'a=s'            => \$arch,
    'p=s'            => \$profile,
    'o=s'            => \$osver,
    'pkglist=s'      => \$pkglist,
    'srcdir=s'       => \$srcdir,
    'otherpkglist=s' => \$otherpkglist,
    'otherpkgdir=s'  => \$srcdir_otherpkgs,
    'tempfile=s'     => \$tempfile,
    'postinstall=s'  => \$postinstall,
    'rootimgdir=s'   => \$rootimgdir,
    'imagename=s'    => \$imagename,
    'interactive'    => \$prompt,
);

if ($rootimgdir) {
    $rootimg_dir = $rootimgdir . "/rootimg";    # for 2.8.4 and later
} else {
    $rootimg_dir = "$srcdir/overlay/package"; # for 2.8.3 that rootimgdir was not set by default
}

my @yumdirs;
if (!$imagename && @ARGV > 0) {
    $imagename = $ARGV[0];
}
unless ($imagename) {
    print "Error: osimage name needs be specified.\n";
    exit 1;
}

sub isyumdir {
    if ($File::Find::name =~ /\/repodata$/) {
        my $location = $File::Find::name;
        $location =~ s/\/repodata$//;
        push @yumdirs, $location;
    }
}

# creae default paths
mkpath "$srcdir/common";
mkpath "$srcdir/overlay/rootimg";
mkpath "$srcdir/overlay/simple";
mkpath "$srcdir/overlay/package";
mkpath "$srcdir/overlay/rpm";

if ($otherpkglist) {

    # get the distroname
    my $oitab = xCAT::Table->new('osimage');
    unless ($oitab) {
        print "Error: Cannot open table osimage.\n";
        return 1;
    }

    # generate the yum configuration file

    my $aiddistro;
    my $oient = $oitab->getAttribs({ 'imagename' => $imagename }, 'osdistroname');
    if ($oient && $oient->{'osdistroname'}) {
        $aiddistro = $oient->{'osdistroname'};
    }

    my $distrotab = xCAT::Table->new('osdistro');
    unless ($distrotab) {
        print "Error: Cannot open table osdistro.\n";
        return 1;
    }
    my $aiddistrodir;
    my $distroent = $distrotab->getAttribs({ 'osdistroname' => $aiddistro }, 'dirpaths');
    if ($distroent && $distroent->{'dirpaths'}) {
        $aiddistrodir = $distroent->{'dirpaths'}
    }

    my @pkgdirs = split(",", $aiddistrodir);
    foreach my $dir (@pkgdirs) {
        find(\&isyumdir, <$dir/>);
        if (!grep /$dir/, @yumdirs) {
            print "The repository for $dir should be created before running the genimge. Try to run [createrepo $dir].\n";
        }
    }

    my $yumconfig;
    open($yumconfig, ">", "/tmp/genimage.$$.yum.conf");
    my $repnum = 0;
    foreach $srcdir (@yumdirs) {
        print $yumconfig "[$aiddistro-$repnum]\nname=$aiddistro-$repnum\nbaseurl=file://$srcdir\ngpgcheck=0\n\n";
        $repnum += 1;
    }
    $repnum -= 1;
    close($yumconfig);
    mkpath "$rootimg_dir/etc";

    my %extra_hash = imgutils::get_package_names($otherpkglist);
    my %extrapkgnames;

    my %repohash;
    if (keys(%extra_hash) > 0) {
        open($yumconfig, ">>", "/tmp/genimage.$$.yum.conf");
        my $index = 1;
        my $pass;
        foreach $pass (sort { $a <=> $b } (keys(%extra_hash))) {
            foreach (keys(%{ $extra_hash{$pass} })) {
                if ($_ eq "INCLUDEBAD") {
                    print "Unable to open the following pkglist files:\n" . join("\n", @{ $extra_hash{$pass}{INCLUDEBAD} });
                    exit 1;
                }

                if (($_ eq "PRE_REMOVE") || ($_ eq "POST_REMOVE") || ($_ eq "ENVLIST")) { next; }
                print $yumconfig "[otherpkgs$index]\nname=otherpkgs$index\nbaseurl=file://$srcdir_otherpkgs/$_\ngpgcheck=0\n\n";
                $repohash{$pass}{$index} = 1;
                $index++;
                my $pa = $extra_hash{$pass}{$_};
                $extrapkgnames{$pass} .= " " . join(' ', @$pa);
            }
        }
        close($yumconfig);
        $index--;
        my $yumcmd_base = "yum -y -c /tmp/genimage.$$.yum.conf --installroot=$rootimg_dir/ --disablerepo=* ";
        foreach (0 .. $repnum) {
            $yumcmd_base .= "--enablerepo=$aiddistro-$_ ";
        }

        foreach $pass (sort { $a <=> $b } (keys(%extra_hash))) {
            my $yumcmd = $yumcmd_base;
            foreach my $repo_index (keys %{ $repohash{$pass} }) {
                $yumcmd .= "--enablerepo=otherpkgs$repo_index ";
            }

            system("$yumcmd clean all");

            my $envlist;
            if (exists($extra_hash{$pass}{ENVLIST})) {
                $envlist = join(' ', @{ $extra_hash{$pass}{ENVLIST} });
            }

            # remove the packages that are specified in the otherpkgs.list files with leading '-'
            my $yumcmd_remove = "$yumcmd erase ";
            if (exists($extra_hash{$pass}{'PRE_REMOVE'})) {
                my $pa = $extra_hash{$pass}{'PRE_REMOVE'};
                my $rm_packges = join(' ', @$pa);
                if ($rm_packges) {
                    print "$envlist $yumcmd_remove $rm_packges\n";
                    my $rc = system("$envlist $yumcmd_remove $rm_packges");
                    if ($rc) {
                        print "yum invocation failed\n";
                        exit 1;
                    }
                }
            }

            # install extra packages
            $yumcmd .= "install ";

            # append extra pkg names to yum command
            if ($extrapkgnames{$pass}) {
                $yumcmd .= " $extrapkgnames{$pass} ";
                $yumcmd =~ s/ $/\n/;

                print "$envlist $yumcmd\n";
                my $rc = system("$envlist $yumcmd");
                if ($rc) {
                    print "yum invocation failed\n";
                    exit 1;
                }
            } else {
                print "No Packages marked for install\n";
            }

            # remove the packages that are specified in the otherpkgs.list files with leading '--'
            if (exists($extra_hash{$pass}{'POST_REMOVE'})) {
                my $pa = $extra_hash{$pass}{'POST_REMOVE'};
                my $rm_packges = join(' ', @$pa);
                if ($rm_packges) {
                    print "$envlist $yumcmd_remove $rm_packges\n";
                    my $rc = system("$envlist $yumcmd_remove $rm_packges");
                    if ($rc) {
                        print "yum invocation failed\n";
                        exit 1;
                    }
                }
            }
        }
    }
}

# run postinstall scripts
foreach my $post (split /,/, $postinstall) {
    if (!-x $post) {
        print "postinstall script $post is not executable\n";
        exit 1;
    }
    my $rc = system($postinstall, $rootimg_dir, $osver, $arch, $profile);
    if ($rc) {
        print "postinstall script $post failed\n";
        exit 1;
    }
}


my $fsdir     = "$srcdir/";
my $systemdir = "$fsdir/system";
mkpath($systemdir);

# this is the file list which includes the files which should be copied
# from MN to the root file system
my @sysfilelist = (
    "/etc/hosts",
    "/etc/group",
    "/etc/passwd",
    "/etc/shadow",
    "/etc/resolv.conf",
    "/etc/nsswitch.conf",
    "/etc/ssh/ssh_host_rsa_key",
    "/etc/ssh/ssh_config",
    "/etc/ssh/sshd_config",
    "/etc/ssh/ssh_host_dsa_key",
    "/root/.ssh/id_rsa",
    "/root/.ssh/id_rsa.pub",
    "/root/.ssh/authorized_keys",);

# do the copy
foreach my $file (@sysfilelist) {
    my $dirname = dirname("$systemdir/$file");
    unless (-d $dirname) {
        mkpath($dirname);
    }
    copy($file, "$systemdir/$file");
}


# Create emtpy common dir and common.filelist for later using
mkpath("$fsdir/common");
system("touch $fsdir/common.filelist");

print "Genimage for mic has been done.\n";

1;
