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

BEGIN { $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : -d '/opt/xcat' ? '/opt/xcat' : '/usr'; }

use lib "$::XCATROOT/probe/lib/perl";
use probe_utils;
use File::Basename;
use Net::Ping;
use Getopt::Long qw(:config no_ignore_case);

use Data::Dumper;
use warnings;

my $program_name = basename("$0");
my $help;
my $noderange = "";
my $test;
my $output  = "stdout";
my $verbose = 0;
my $rst     = 0;

$::USAGE = "Usage:
    $program_name -h
    $program_name [-V|--verbose]

Description:
    Use this command to check osimage defintions in xCAT DB. 

Options:
    -h : Get usage information of $program_name
    -V : To print additional debug information.
";

#-------------------------------------
# main process
#-------------------------------------
if (
    !GetOptions("--help|h" => \$help,
        "T"                  => \$test,
        "V|verbose"          => \$VERBOSE))
{
    probe_utils->send_msg("$output", "f", "Invalid parameter for $program_name");
    probe_utils->send_msg("$output", "d", "$::USAGE");
    exit 1;
}

if ($help) {
    if ($output ne "stdout") {
        probe_utils->send_msg("$output", "d", "$::USAGE");
    } else {
        print "$::USAGE";
    }
    exit 0;
}

if ($test) {
    probe_utils->send_msg("$output", "o", "Use this command to check osimage defintions in xCAT DB.");
    exit 0;
}

if (scalar(@ARGV) >= 1) {

    # After processing all the expected flags and arguments,
    # there is still left over stuff on the command line
    probe_utils->send_msg("$output", "f", "Invalid flag or parameter: @ARGV");
    probe_utils->send_msg("$output", "d", "$::USAGE");
    exit 1;
}

# Run all osinage probe checks one after another
check_for_duplicate_rootimgdir();
check_for_valid_osimage_attributes();

# Check for osimage definitions with duplicate values for rootimgdir
sub check_for_duplicate_rootimgdir {
    my $na = "N/A";

    my %rootimgdir_osimage_hash;
    my $any_dups = 0;

    my $all_osimages_rootimgdir = `lsdef -t osimage -i rootimgdir -c 2> /dev/null`;
    chomp($all_osimages_rootimgdir);
    my @all_osimages_rootimgdir_lines = split("[\n\r]", $all_osimages_rootimgdir);

    if (scalar(@all_osimages_rootimgdir_lines) <= 0) {

        # There were no osimages found. Issue a warning and exit.
        probe_utils->send_msg("$output", "w", "No osimages were found.");
        return 1;
    }

    # Build a hash of key="rootimgdir" value="osimagename"
    foreach (@all_osimages_rootimgdir_lines) {
        probe_utils->send_msg("$output", "d", "Processing $_.") if ($VERBOSE);
        my ($osimage_name, $rootimgdir) = split ":", $_;
        if ($rootimgdir eq " rootimgdir=") {
            # Exclude entries that do not have rootimg set
            probe_utils->send_msg("$output", "d", "No rootimgdir for osimage $osimage_name") if ($VERBOSE);
            next;
        }
        # Check if hash already has the same key, indicating another osimage definition has the same rootimgdir
        if (exists($rootimgdir_osimage_hash{$rootimgdir})) {
            # Build a list of osimages that have the same rootimgdir
            $rootimgdir_osimage_hash{$rootimgdir} .= "," . $osimage_name;
            $any_dups = 1;
        }
        else {
            $rootimgdir_osimage_hash{$rootimgdir} = $osimage_name;
        }

    }

    #print Dumper(\%rootimgdir_osimage_hash) if ($VERBOSE);
    my $rc = 1;

    if ($any_dups) {
        # Loop through each entry in hash to print a list of osimgage objects that point to the same rootimgdir
        foreach $rootimgdirpath (keys %rootimgdir_osimage_hash) {
            my @list_of_osimages = split ",", $rootimgdir_osimage_hash{$rootimgdirpath};
            if (scalar(@list_of_osimages) > 1) {
                # More than one entry in the hash value, means we
                # have more than one osimage point to the same rootimgdir
                my $print_list = join("\n  ",@list_of_osimages);
                $rootimgdirpath=~s/^\s+//; #discard leading space
                probe_utils->send_msg("$output", "w", "Identical root image directory ($rootimgdirpath) is configured for the diskless osimages: \n  $print_list");
            }
        }
    }
    else {
        probe_utils->send_msg("$output", "o", "No diskless osimages with identical root image directories were found.");
        $rc = 0;
    }

    return $rc;
}

# Check attributes in osimage definitions for valid format
sub check_for_valid_osimage_attributes {
    my $na = "N/A";

    my $rc = 0;

    my %rootimgdir_osimage_hash;
    my $any_dups = 0;

    # Check if any osimage object has "template" attribute set to service.tmpl or compute.tmpl
    my $all_osimages_template = `lsdef -t osimage -i template -c 2> /dev/null`;
    chomp($all_osimages_template);
    my @all_osimages_template_lines = split("[\n\r]", $all_osimages_template);

    if (scalar(@all_osimages_template_lines) <= 0) {

        # There were no osimages found. Issue a warning and exit.
        probe_utils->send_msg("$output", "w", "No osimages were found.");
        return 1;
    }
    foreach (@all_osimages_template_lines) {
        probe_utils->send_msg("$output", "d", "Processing $_.") if ($VERBOSE);
        my ($osimage_name, $template) = split ":", $_;
        if ($template eq " template=") {
            # Exclude entries that do not have template attribute set
            probe_utils->send_msg("$output", "d", "No template for osimage $osimage_name") if ($VERBOSE);
            next;
        }
        my ($junk, $template_file) = split "=", $template;
        if (($template_file =~ /compute.tmpl/) || ($template_file =~ /service.tmpl/)) {
            if ($template_file !~ /ubuntu/) {
                # Skip Ubintu osimages, currently ok to have service.tmpl and compute.tmpl for them
                probe_utils->send_msg("$output", "w", "Default 'template' value is being used by $osimage_name \n".
                                      "  If this image was generated by 'copycds -n <os version>', make sure the <os version> specified\n".
                                      "  follows xCAT naming convention (for example 'rhels7.2')");
            }
        }
    }

    return $rc;
}
