#!/usr/bin/python

# isi_gather_info_slave - Executes the _gather script per node for a master
# isi_gather_info process.

import getopt
import os
import subprocess
import sys
import tempfile
import xml.etree.ElementTree as etree

import isi.config.array as array
import isi.config.arrcfg as arrcfg
import isi.app.lib.procs as procs

from isi.misc import sysctlbyname

PROGNAME = os.path.basename(sys.argv[0])
TMP_SUPPORT_DIR = None

class Options: pass

options = Options()

def main():
    get_options()
    if options.setup_local_dirs:
        setup_local_dirs()
        sys.exit(0)
    get_support_dir()

    check_get_gather_script()

    run_gather_script()

def get_master_node_name():
    master_devid = options.jobid.split('-')[0]
    cfg = arrcfg.config_load()
    return '-'.join([cfg.name, master_devid])

def verbose(str):
    if options.verbose:
        print str

def error(str):
    print >> sys.stderr, PROGNAME + ':', str
    sys.exit(1)

def isi_scp_main(file1, file2):
    '''isi_scp [OPTION]... [[USER@]HOST1:]FILE1 [[USER@]HOST2:]FILE2'''
    cmd_args = ['isi_scp']

    temp_file = None

    if options.user is not None:
        cmd_args += ['--user', options.user]
    if options.password is not None:
        # change to isi_scp pre later? for association?
        temp_file = tempfile.TemporaryFile('w+b', -1, 'isi_for_array')
        temp_file.write(options.password)
        temp_file.flush()
        temp_file.seek(0)
        dupfd = os.dup(temp_file.fileno())
        cmd_args += ['-q', '/dev/fd/%d' % dupfd]
        temp_file.close()
    cmd_args += [ file1, file2 ]
    p = subprocess.Popen(' '.join(cmd_args), stderr = subprocess.PIPE,
            stdout = subprocess.PIPE, close_fds = False, shell = True)
    output = p.stdout.readlines()
    exit = p.wait()
    if exit != 0:
        for line in output:
            print 'isi_scp: ' + line

    return exit

def get_support_dir():
    global TMP_SUPPORT_DIR

    RUN_DIR = os.path.join(os.path.sep + 'ifs', '.ifsvar', 'run' + os.path.sep)
    LOCAL_DIR = os.path.join(os.path.sep + 'var', 'crash', 'support', 'tmp',
            'run' + os.path.sep)
    grf_name = 'gather-%s.xml' % options.jobid
    grf_path = os.path.join(RUN_DIR, grf_name)

    need_download = False

    try:
        need_download = not os.access(grf_path, os.R_OK)
    except Exception, e:
        need_download = True

    if need_download:
        # Either on minority side. Need a local copy, can't write it to /ifs.
        if not os.path.exists(LOCAL_DIR):
            try:
                os.makedirs(LOCAL_DIR, 0775)
            except Exception, e:
                error('Couldn\'t make %s: %s' % (LOCAL_DIR, str(e)))
        else:
            os.chmod(LOCAL_DIR, 0775)

        grf_src_path = ':'.join([get_master_node_name(), grf_path])
        grf_dest_path = os.path.join(LOCAL_DIR, grf_name)

        verbose('Retrieving %s...' % grf_src_path)
        print 'To %s' % grf_dest_path
        if isi_scp_main(grf_src_path, grf_dest_path) != 0:
            error('Error reading gather run file.')

        grf_path = grf_paths[1]

    try:
        et = etree.parse(grf_path)
        root = et.getroot()
        TMP_SUPPORT_DIR = root.find('tmpdir').text
    except Exception, e:
        error('Error reading gather run file: %s' % str(e))

    try:
        os.unlink(grf_paths[1])
    except Exception, e:
        pass

def setup_local_dirs():
    SUPPORT_DIR = '/var/crash/support'
    TMP_SUPPORT_DIR = os.path.join(SUPPORT_DIR, 'tmp')
    PKG_SUPPORT_DIR = os.path.join(SUPPORT_DIR, 'pkg')

    dirs = [SUPPORT_DIR, TMP_SUPPORT_DIR, PKG_SUPPORT_DIR]

    for dir in dirs:
        if os.path.exists(dir):
            os.chmod(dir, 0775)
        else:
            os.makedirs(dir, 0775)

def run_gather_script():
    GATHER_SCRIPT = os.path.join(TMP_SUPPORT_DIR, '_gather')
    cmd = 'bash ' + GATHER_SCRIPT

    (exit, output) = procs.get_cmd_output(cmd)

def is_compliance():
    try:
        res = True if sysctlbyname('isi.compliance') == 1 else False
    except Exception, e:
        res = False

    return res

def check_get_gather_script():
    global TMP_SUPPORT_DIR

    gather_path = os.path.join(TMP_SUPPORT_DIR, '_gather')
    need_download = False

    try:
        if not (os.access(gather_path, os.R_OK)):
            need_download = True
    except:
        need_download = True

    if not need_download:
        return

    verbose('Retrieving %s:%s' % (get_master_node_name(), gather_path))

    dest_dir = os.path.join(os.path.sep, 'var', 'crash', 'support', 'tmp',
            TMP_SUPPORT_DIR[:-1].split(os.path.sep)[-1])

    master_devid = options.jobid.split('-')[0]

    # Don't run on ourselves.
    if array.getLocalId() == int(master_devid):
        return

    src_path = '%s:%s' % (get_master_node_name(), gather_path)

    exit = isi_scp_main(src_path, os.path.join(dest_dir, '_gather'))

    if not os.access('%s%s%s' % (dest_dir, os.path.sep, '_gather'), os.R_OK):
        error('Could not retrieve gather script.')

    TMP_SUPPORT_DIR = dest_dir

def get_options():

    global options

    options.jobid = None
    options.password = None
    options.user = None
    options.verbose = False
    options.setup_local_dirs = False

    try:
        opts, args = getopt.getopt(sys.argv[1:], 'hj:p:u:s',
                ['help', 'jobid=', 'user=', 'password=', 'verbose',\
                        'setup-dirs'])

        for o, a in opts:
            if o in ['-h', '--help']:
                usage(0)

            elif o in ['-j', '--jobid']:
                options.jobid = a.strip()

            elif o in ['-u', '--user']:
                options.user = a

            elif o in ['-p', '--password']:
                options.password = a

            elif o in ['--verbose']:
                options.verbose = True

            elif o in ['-s', '--setup-dirs']:
                options.setup_local_dirs = True

            else:
                print 'Unknown argument: %s' % o
                usage(1)

    except getopt.GetoptError, e:
        error(str(e.msg))

    if options.jobid is None and not options.setup_local_dirs:
        print 'Job id required.'
        usage(1)

    if options.user is None and is_compliance():
        options.user = 'compadmin'

def usage(exitcode):

    sys.stdout.write('''
Usage: %s [OPTION]...

Options:
  -h/--help         Print this message and exit.
  -j/--jobid        Specify master isi_gather_info job id.
  -s/--setup-dirs   Setup local directories and exit.
''' % PROGNAME)

    sys.exit(exitcode)

if __name__ == '__main__':
    main()
