#!/usr/bin/env python

'''
USAGE:   gpperfmon_install --port GPDB_PORT [--enable --password GPMON_PASSWORD] [--pgpass PATH_TO_FILE] [--gpperfmonport GPPERFMON_PORT] [--verbose]

         where this script will install the gpperfmon database and schema

         --enable option will also do the following tasks as a convenience:
              1) create a gpmon super user
              2) add a line to pg_hba.conf to allow access from master host for user gpmon
              3) add a line to pg pass file
              4) set gucs to enable gpperfmon

         when using --enable, --password must be specified

        --password will set the password for gpmon superuser
        --port is the port used by gpperfmon to connect to GPDB
        --pgpass is an option to allow overriding default path of $HOME/.pgpass
        --gpperfmonport sets the guc 'gpperfmon_port' for gpperfmon communication (default is 8888)
        --verbose will show output from sub-commands
'''

import os, sys, time, re
from subprocess import Popen

try:
    from optparse import Option, OptionParser
    from gppylib.gpparseopts import OptParser, OptChecker
    from gppylib.userinput import ask_input
    from gppylib.gplog import get_default_logger, setup_tool_logging
    from gppylib.commands.unix import getLocalHostname, getUserName
except ImportError, e:
    sys.exit('Cannot import modules.  Please check that you have sourced greenplum_path.sh.  Detail: ' + str(e))

EXECNAME = os.path.split(__file__)[-1]

class Command:
    def __init__(self, cmdstr, showOutput=False):
        self.cmd = cmdstr
        self.verbose = showOutput

def run_command(cmd, verbose=False):

    cmdstr = cmd.cmd

    if not options.verbose and not cmd.verbose:
        cmdstr = "%s >& /dev/null" % cmdstr
    # hide password
    if bool(re.search('CREATE ROLE.*ENCRYPTED PASSWORD',cmdstr)):
        regex = re.compile('ENCRYPTED\sPASSWORD\s\'(.*)\'')
        logger.info(regex.sub('ENCRYPTED PASSWORD \'********\'',cmdstr))
    elif bool(re.search('echo.*:gpperfmon:gpmon:',cmdstr)):
        regex = re.compile(':gpperfmon:gpmon:(.*)\"')
        logger.info(regex.sub(':gpperfmon:gpmon:********',cmdstr))
    else:
        logger.info(cmdstr)
    p = Popen(cmdstr, shell=True, executable="/bin/bash")
    sts = os.waitpid(p.pid, 0)[1]
    if sts:
        raise Exception("error on cmd " + cmdstr)

def validate_password(input, ignore):
    if len(input) < 1:
        return None
    else:
        return input


def cli_help():
    help_path = os.path.join(sys.path[0], '..', 'docs', 'cli_help', EXECNAME + '_help')
    f = None
    try:
        try:
            f = open(help_path);
            return f.read(-1)
        except:
            return ''
    finally:
        if f: f.close()


def usage():
    print cli_help() or __doc__


###### main()
if __name__ == '__main__':

    logger = get_default_logger()
    setup_tool_logging(EXECNAME,getLocalHostname(),getUserName())

    gphome = os.environ.get('GPHOME')
    if not gphome:
        logger.error("GPHOME not set")
        sys.exit(1)

    if not os.path.isfile('/bin/bash'):
        logger.error("can not find /bin/bash")
        sys.exit(1)

    parser = OptParser(option_class=OptChecker)
    parser.remove_option('-h')
    parser.add_option('-h', '-?', '--help', action='store_true')
    parser.add_option('-e', '--enable', action='store_true')
    parser.add_option('-v', '--verbose', action='store_true')
    parser.add_option('-p', '--password', type='string')
    parser.add_option('-P', '--port', type='int')
    parser.add_option('-r', '--gpperfmonport', type='int', default=8888)
    parser.add_option('--pgpass', type='string')
    (options, args) = parser.parse_args()

    if options.help:
        usage()
        sys.exit(1)

    if not options.port:
        logger.error("--port must be specified")
        sys.exit(1)

    if options.enable and (not options.password):
        logger.error("when enabling gpperfmon --password must be specified")
        sys.exit(1)

    if not options.enable and options.password:
        logger.error ("--password is only used when enabling gpperfmon")
        sys.exit(1)

    commands = list()

    cmd = Command("createdb gpperfmon")
    commands.append(cmd)
    cmd = Command("PGPORT=%d psql -f %s/lib/gpperfmon/gpperfmon.sql gpperfmon" % (options.port, gphome))
    commands.append(cmd)

    if options.enable:

        master_data_dir = os.getenv('MASTER_DATA_DIRECTORY')
        pg_hba = "%s/pg_hba.conf" % master_data_dir
        home_dir = os.getenv('HOME')

        if not master_data_dir:
            logger.error("MASTER_DATA_DIRECTORY must be set")
            sys.exit(1)

        if not home_dir:
            logger.error("$HOME must be set")
            sys.exit(1)

        if options.pgpass:
            pg_pass = options.pgpass
        else:
            pg_pass = "%s/.pgpass" % home_dir

        old_pg_pass = "%s.%d" % (pg_pass, time.time())

        if not os.path.isfile( pg_hba ):
            logger.error("can not find pg_hba.conf at %s" % pg_hba)
            sys.exit(1)

        if not os.path.isdir(home_dir):
            logger.error("can not find $HOME")
            sys.exit(1)

        cmd = Command("""PGPORT=%d psql template1 -c "DROP ROLE IF EXISTS gpmon" """ % options.port)
        commands.append(cmd)

        cmd = Command("""PGPORT=%d psql template1 -c "CREATE ROLE gpmon WITH SUPERUSER CREATEDB LOGIN ENCRYPTED PASSWORD '%s'" """ % (options.port, options.password))
        commands.append(cmd)

        cmd = Command("""echo "local    gpperfmon         gpmon         md5" >> %s""" % pg_hba, showOutput=True)
        commands.append(cmd)

        cmd = Command("""echo "host     all         gpmon         127.0.0.1/28    md5" >> %s""" % pg_hba, showOutput=True)
        commands.append(cmd)

        cmd = Command("""echo "host     all         gpmon         ::1/128    md5" >> %s""" % pg_hba, showOutput=True)
        commands.append(cmd)

        ################################################
        # these commands add a new line to the top of .pgpass and save a copy of old .pgpass
        cmd = Command("""touch %s""" % (pg_pass))
        commands.append(cmd)

        cmd = Command("""mv -f %s %s""" % (pg_pass, old_pg_pass))
        commands.append(cmd)

        cmd = Command("""echo "*:%d:gpperfmon:gpmon:%s" >> %s""" % (options.port, options.password, pg_pass), showOutput=True)
        commands.append(cmd)

        cmd = Command("""cat %s >> %s""" % (old_pg_pass, pg_pass), showOutput=True)
        commands.append(cmd)

        cmd = Command("""chmod 0600 %s""" % pg_pass)
        commands.append(cmd)
        ################################################

        cmd = Command("PGPORT=%d gpconfig -c gp_enable_gpperfmon -v on" % (options.port))
        commands.append(cmd)

        cmd = Command("PGPORT=%d gpconfig -c gpperfmon_port -v %d" % (options.port, options.gpperfmonport))
        commands.append(cmd)

        cmd = Command("PGPORT=%d gpconfig -c gp_external_enable_exec -v on --masteronly" % (options.port))
        commands.append(cmd)

        cmd = Command("PGPORT=%d gpconfig -c gpperfmon_log_alert_level -v warning" % (options.port))
        commands.append(cmd)

    command = None
    try:
        for c in (commands):
            command = c
            run_command(command)
    except:
        logger.error("error on command: %s" % command.cmd)
        logger.error("gpperfmon not successfully installed")
        sys.exit(1)

    if options.enable:
        logger.info("gpperfmon will be enabled after a full restart of GPDB")
    else:
        logger.info("gpperfmon schema successfully installed")



