#!/usr/bin/perl
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# bos720 src/bos/usr/bin/cdat/cdat-init.pl 1.11 
#  
# Licensed Materials - Property of IBM 
#  
# COPYRIGHT International Business Machines Corp. 2010,2011 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
# @(#)18    1.11  src/bos/usr/bin/cdat/cdat-init.pl, cdat, bos720 7/15/11 04:48:54
use warnings;
use strict;
use Getopt::Long;
use XML::LibXML;
use File::Path;		# needed for mkpath
use Sys::Hostname;
use cdat;
use messages;

#
# Constants.
#
my $SSH_KEYGEN = '/usr/bin/ssh-keygen';
my $MKLV       = '/usr/sbin/mklv';
my $CRFS       = '/usr/sbin/crfs';
my $MOUNT      = '/usr/sbin/mount';
my $DATAPREFIX = '/cdat';
my $XMLFILE    = 'cdat.xml';
my $USER       = 'cdat';
my $VGNAME     = 'rootvg';
my $LVNAME     = 'cdat';
my $FSSIZE     = '10G';
my $LVFS       = 'jfs2';

######################################################################
# Function:	usage
# Purpose:	Display usage.
# Tasks:	Print usage and exit.
# Input:	None
# Output:	None
######################################################################
sub usage()
{
    printf(STDERR catgets(MSG_CDAT_INIT_USAGE,
        "Usage: cdat init -h\n".
	"       cdat init [-c [-g VGName] [-s FSSize]] [-d Directory]\n".
	"                 [-l LVName] [-u User]\n"));
    exit(1);
}

######################################################################
# Function:	main
# Purpose:	Entry point of the init subcommand.
# Tasks:	Create repository.
# Input:	None
# Output:	None
######################################################################
sub main
{
    my ($rc, $create, $directory, $user, $vgname, $lvname, $fssize);

    # Parse command line options
    Getopt::Long::Configure('bundling', 'no_ignore_case');
    $rc = GetOptions(
	'h'   => \&usage,
	'c'   => \$create,
	'd=s' => \$directory,
	'u=s' => \$user,
	'g=s' => \$vgname,
	'l=s' => \$lvname,
	's=s' => \$fssize,
	);
    if (!$rc || @ARGV != 0) {
	usage();
    }

    # options -g and -s can only be used along with -c
    if ((defined($vgname) || defined($fssize)) && !defined($create)) {
        usage();
    }

    # if -d not specified, use default
    $directory = $DATAPREFIX if (!defined($directory));

    if (substr($directory, 0, 1) ne "/") {
        printf(STDERR catgets(MSG_NEEDS_ABSOLUTE_PATH,
	    "-d needs an absolute path.\n"));
        exit(1);
    }

    # if -u not specified, use default
    $user = $USER if (!defined($user));

    printf(catgets(MSG_CHECKING_USER, "Checking user %s..."), $user);

    # check if a user with that name already exists
    my ($name, $pass, $uid, $gid, $quota, $comment,
        $gcos, $dir, $shell, $expire) = getpwnam($user);
    if (!defined($name)) {
	# specified user does not already exist, create it
	printf(catgets(MSG_CREATING_MISSING_USER, "Creating missing user.\n"));

	system("/usr/sbin/lsrole CdatMaster > /dev/null 2>&1");
	if ($? != 0) {
	    # check if the ibm.ps.client.bind authorization exists
	    system("/usr/sbin/lsauth ibm.ps.client.bind > /dev/null 2>&1");
	    if ($? != 0) {
                # create the authorization hierarchy if it does not exist
	        system("/usr/bin/mkauth ibm > /dev/null 2>&1");
	        system("/usr/bin/mkauth ibm.ps > /dev/null 2>&1");
	        system("/usr/bin/mkauth ibm.ps.client > /dev/null 2>&1");
                # create the bind authorization
	        system("/usr/bin/mkauth ibm.ps.client.bind > /dev/null 2>&1");
	        if ($? != 0) {
	            printf(STDERR catgets(MSG_CANNOT_CREATE_AUTH,
	                "Cannot create RBAC authorization %s.\n"),
		        'ibm.ps.client.bind');
	            exit(2);
	        }
	    }
            # create the CdatMaster RBAC role
	    system("/usr/bin/mkrole authorizations=aix.fs.manage.change,aix.ras.pureScale,ibm.ps.client.bind CdatMaster > /dev/null 2>&1");
	    if ($? != 0) {
	        printf(STDERR catgets(MSG_CANNOT_CREATE_ROLE,
	            "Cannot create RBAC role %s.\n"), 'CdatMaster');
	        exit(2);
	    }
	    # set entries in the kernel security tables
	    system("/usr/sbin/setkst -q -t role,auth > /dev/null 2>&1");
	}

	system("/usr/bin/mkuser roles=CdatMaster default_roles=CdatMaster gecos='Cluster Data Aggregation Tool' '$user'");
	if ($? != 0) {
            printf(STDERR catgets(MSG_CANNOT_CREATE_USER,
	        "Cannot create user %s.\n"), $user);
	    exit(2);
	}
	# Ask for an initial password such that user can log in
	system("/usr/bin/passwd '$user'");

	# Retrieve UID/GID of newly created user
	($name, $pass, $uid, $gid, $quota, $comment,
	 $gcos, $dir, $shell, $expire) = getpwnam($user);
    } else {
	printf(catgets(MSG_FOUND, "found\n"));
    }

    #
    # "Refresh" the crontab file (make sure it exists).
    #
    system("EDITOR=/usr/bin/cat /usr/bin/crontab -e $user > /dev/null");
    # Ignore if it fails as it is not a fatal condition

    printf(catgets(MSG_CHECKING_FOR_SSH, "Checking for SSH..."));
    if ( -x "$SSH_KEYGEN" ) {
	printf(catgets(MSG_FOUND, "found\n"));

        # Create SSH directory.
        my $sshdir = "$dir/.ssh";

        if (! -d "$sshdir") {
	    # SSH directory does not already exist, create it
	    $rc = mkpath($sshdir, 0, 0700);
	    if (!$rc) {
                printf(STDERR catgets(MSG_CANNOT_CREATE_DIR,
	            "Cannot create directory %s.\n"), $sshdir);
	        exit(2);
	    }
	    # Set directory owner
	    $rc = chown($uid, $gid, $dir);
	    if (!$rc) {
                printf(STDERR catgets(MSG_CANNOT_CHANGE_OWNER,
	            "Cannot change %s owner.\n"), $dir);
	        exit(2);
	    }
	    $rc = chown($uid, $gid, $sshdir);
	    if (!$rc) {
                printf(STDERR catgets(MSG_CANNOT_CHANGE_OWNER,
	            "Cannot change %s owner.\n"), $sshdir);
	        exit(2);
	    }
        }
	if (! -e "$sshdir/known_hosts") {
	    my $fh;
	    # Create initially empty known_hosts file
	    open($fh, '>', "$sshdir/known_hosts") and close($fh);
	}
	# Always fix the known_hosts file owner
	chown($uid, $gid, "$sshdir/known_hosts");
	# Ignore if it fails as it is not a fatal condition

        # Generate public/private SSH keys.
        printf(catgets(MSG_CHECKING_FOR_SSH_KEYS, "Checking for SSH keys..."));
        my $priv = "$sshdir/id_rsa";
        my $pub  = "$sshdir/id_rsa.pub";
        if (! -e $priv || ! -e $pub) {
	    my $localhost = hostname;
	    system("$SSH_KEYGEN -t rsa -f $priv -N \"\" -C $user\@$localhost > /dev/null 2>&1");
	    if ($? != 0) {
                printf(STDERR catgets(MSG_CANNOT_CREATE_SSH_KEYS,
	            "Cannot create SSH keys.\n"));
                exit(2);
	    }
	    # Change owner of the public/private SSH keys
	    $rc = chown($uid, $gid, $priv);
	    if (!$rc) {
                printf(STDERR catgets(MSG_CANNOT_CHANGE_OWNER,
	            "Cannot change %s owner.\n"), $priv);
	        exit(2);
	    }
	    $rc = chown($uid, $gid, $pub);
	    if (!$rc) {
                printf(STDERR catgets(MSG_CANNOT_CHANGE_OWNER,
	            "Cannot change %s owner.\n"), $pub);
	        exit(2);
	    }
            printf(catgets(MSG_GENERATED, "generated\n"));
        } else {
            printf(catgets(MSG_FOUND, "found\n"));
        }
    } else {
    	printf(catgets(MSG_NOT_FOUND, "not found\n"));
    }

    #
    # Create data repository directory.
    #
    printf(catgets(MSG_CHECKING_DIRECTORY, "Checking directory %s..."),
        $directory);
    if (! -d "$directory") {
	$rc = mkpath($directory, 0, 0700);
	if (!$rc) {
            printf(STDERR catgets(MSG_CANNOT_CREATE_DIR,
	        "Cannot create directory %s.\n"), $directory);
	    exit(3);
	}
        printf(catgets(MSG_CREATED, "created\n"));
    } else {
        printf(catgets(MSG_FOUND, "found\n"));
    }

    if (defined($create)) {
	# option -c was specified

	# if -l not specified, use default
	$lvname = $LVNAME if (!defined($lvname));

	# if -g not specified, use default
	$vgname = $VGNAME if (!defined($vgname));

	# if -s not specified, use default
	$fssize = $FSSIZE if (!defined($fssize));

        printf(catgets(MSG_CREATING_LOGICAL_VOLUME,
            "Creating logical volume %s in volume group %s..."),
            $lvname, $vgname);

	# Create Logical Volume.
	system("$MKLV -y $lvname -t $LVFS $vgname $fssize");
	if ($? != 0) {
            printf(STDERR catgets(MSG_CANNOT_CREATE_LV,
	        "Cannot create logical volume %s in volume group %s.\n"),
		$lvname, $vgname);
	    exit(4);
	}

	# Create filesystem and mountpoint.
	system("$CRFS -v $LVFS -d $lvname -m $directory -A yes");
	if ($? != 0) {
            printf(STDERR catgets(MSG_CANNOT_CREATE_FS,
	        "Cannot create filesystem on %s.\n"), $lvname);
	    exit(4);
	}

	# Mount filesystem.
	system("$MOUNT $directory");
	if ($? != 0) {
            printf(STDERR catgets(MSG_CANNOT_MOUNT_FS,
	        "Cannot mount filesystem on %s.\n"), $directory);
	    exit(4);
	}
        printf(catgets(MSG_DONE, "done\n"));
    } elsif (defined($lvname)) {
	# option -c was not specified but -l was specified

	# Create filesystem and mountpoint.
        printf(catgets(MSG_CREATING_FS,
            "Creating filesystem on existing logical volume %s.\n"),
            $lvname);
	system("$CRFS -v $LVFS -d $lvname -m $directory -A yes");
	if ($? != 0) {
            printf(STDERR catgets(MSG_CANNOT_CREATE_FS,
	        "Cannot create filesystem on %s.\n"), $lvname);
	    exit(4);
	}

	# Mount filesystem.
	system("$MOUNT $directory");
	if ($? != 0) {
            printf(STDERR catgets(MSG_CANNOT_MOUNT_FS,
	        "Cannot mount filesystem on %s.\n"), $directory);
	    exit(4);
	}
        printf(catgets(MSG_DONE, "Done\n"));
    }
    $rc = chown($uid, $gid, $directory);
    if (!$rc) {
        printf(STDERR catgets(MSG_CANNOT_CHANGE_OWNER,
            "Cannot change %s owner.\n"), $directory);
	exit(3);
    }
    # always fix permissions
    chmod(0700, $directory);

    #
    # Update the ODM database.
    #
    cdat::odm_set_user($user);
    cdat::odm_set_path($directory);

    #
    # Create an initially empty cdat XML file.
    #

    printf(catgets(MSG_CREATING_XML_FILE, "Checking XML file..."));
    if (! -e "$directory/$XMLFILE") {
	my $tree = XML::LibXML->createDocument('1.0', cdat::locale_charmap);
	if (!defined($tree)) {
            printf(STDERR catgets(MSG_CANNOT_CREATE,
	        "Cannot create %s.\n"), "$directory/$XMLFILE");
            exit(1);
	}
	my $root_elt = $tree->createElement('collect-list');
	$tree->setDocumentElement($root_elt);
	$tree->toFile("$directory/$XMLFILE", 2);
	$rc = chown($uid, $gid, "$directory/$XMLFILE");
	if (!$rc) {
            printf(STDERR catgets(MSG_CANNOT_CHANGE_OWNER,
	        "Cannot change %s owner.\n"), "$directory/$XMLFILE");
	    exit(1);
	}
        printf(catgets(MSG_CREATED, "created\n"));
    } else {
        printf(catgets(MSG_FOUND, "found\n"));
    }

    printf(catgets(MSG_DONE, "Done.\n"));
}

main;