#!/usr/bin/env python

import os
import errno
import shutil
import glob
import sys
import tempfile
import inspect

try:
    sysname, nodename, x, x, machine = os.uname()
except:
    import platform
    sysname, nodename, x, x, machine, x = platform.uname()

postinstall_d = sys.path[0]
if '/catalog/' in postinstall_d:
    # hpux packaging subsystem executes the postinstall from dir
    # /var/tmp/XXXXXXXXX/catalog/opensvc/commands/
    postinstall_d = "/usr/share/opensvc/bin"
    lsb = True
elif postinstall_d == "/usr/share/opensvc/bin":
    lsb = True
else:
    # windows install or unix execution from a non-lsb tree (ex: /opt/opensvc/)
    lsb = False

if lsb:
    pathsbin = "/usr/bin"
    pathsvc = None
    pathetc = "/etc/opensvc"
    pathvar = "/var/lib/opensvc"
    pathlck = '/var/lib/opensvc/lock'
    pathtmp = "/var/tmp/opensvc"
    pathlog = "/var/log/opensvc"
    pathbin = "/usr/share/opensvc/bin"
    pathlib = "/usr/share/opensvc/lib"
    pathini = "/usr/share/opensvc/bin/init"
    pathusr = None
else:
    pathsbin = postinstall_d
    pathsvc = os.path.realpath(os.path.join(pathsbin, '..'))
    pathetc = os.path.join(pathsvc, 'etc')
    pathvar = os.path.join(pathsvc, 'var')
    pathlck = os.path.join(pathvar, 'lock')
    pathtmp = os.path.join(pathsvc, 'tmp')
    pathlog = os.path.join(pathsvc, 'log')
    pathbin = postinstall_d
    pathlib = os.path.join(pathsvc, 'lib')
    pathini = os.path.join(pathsvc, 'bin', 'init')
    pathusr = os.path.join(pathsvc, 'usr')

def make_sure_path_exists(path):
    try:
        os.makedirs(path, 0755)
    except OSError, exception:
        if exception.errno != errno.EEXIST:
            raise

def logit(msg,stdout=False,stderr=False):
    curframe = inspect.currentframe()
    calframe = inspect.getouterframes(curframe, 2)
    try:
        import datetime
        timestamp = str(datetime.datetime.now())
    except:
        timestamp = '?'

    osvlog = os.path.join(pathlog, 'postinstall.log')
    content = '['+calframe[1][3]+']['+timestamp+'] '+msg
    f = open(osvlog, 'a')
    f.write(content+'\n')
    f.close()
    if stdout:
        print msg
    if stderr:
        print >>sys.stderr, "error ==> " + msg

make_sure_path_exists(pathlog)
logit("\nStarting OpenSVC postinstall\n",stdout=True)

SolarisRootRelocate = False
if sysname == 'SunOS' and "PKG_INSTALL_ROOT" in os.environ and os.environ['PKG_INSTALL_ROOT'] != '/':
     logit("SunOS PKG_INSTALL_ROOT <%s>"%(os.environ['PKG_INSTALL_ROOT']))
     SolarisRootRelocate = True

variables = {
  "pathsvc": pathsvc,
  "pathsbin": pathsbin,
  "pathbin": pathbin,
  "pathetc": pathetc,
  "pathvar": pathvar,
  "pathtmp": pathtmp,
  "pathlib": pathlib,
  "pathlog": pathlog,
  "pathusr": pathusr,
  "SolarisRootRelocate": SolarisRootRelocate
}
for key in variables:
    logit("var %s <%s>"%(key,variables[key]))

def install_cron():
    logit("begin")
    if sysname == 'Windows':
        logit("windows not applicable")
        return 
    else:
        return install_cron_unix()

def install_cron_windows():
    logit("begin")
    logit("install OsvcSched service",stdout=True)
    schedstop()
    schedremove()
    schedinstall()
    schedstart()

def schedremove():
    logit("begin")
    cmd = ' remove'
    schedcmd(cmd)

def schedstart():
    logit("begin")
    cmd = ' start'
    schedcmd(cmd)

def schedstop():
    logit("begin")
    cmd = ' stop'
    schedcmd(cmd)

def schedinstall():
    logit("begin")
    cmd = ''
    cmd += ' --username LocalSystem'
    cmd += ' --startup auto'
    cmd += ' install\n'
    schedcmd(cmd)

def schedcmd(_cmd):
    logit("begin")
    logit("_cmd %s"%_cmd)
    rc = '"'+sys.executable+'" "'+os.path.join(pathlib, 'rcWinScheduler.py')+'"'
    cmd = "@echo off\n"
    cmd += rc
    cmd += _cmd
    fd, fname = tempfile.mkstemp(dir=pathtmp, suffix='.cmd')
    f = os.fdopen(fd, 'w')
    f.write(cmd)
    f.close()
    import subprocess
    subprocess.call([fname])
    os.unlink(fname)
 
def save_file(infile):
    logit("begin")
    logit("infile <%s>"%infile)
    if not os.path.exists(infile):
        return True
    try:
        import datetime
        timestamp = str(datetime.datetime.now())
        tmp = timestamp.replace(" ", ".")
        ts = tmp.replace(":", ".")
    except:
        ts = 'opensvc.postinstall'
    ofname = os.path.basename(infile)
    logit("ofname <%s>"%ofname)
    nfname = ofname + '.crontab.' + ts
    logit("nfname <%s>"%nfname)
    outfile = os.path.join(os.sep, pathtmp, nfname)
    logit("outfile <%s>"%outfile)
    
    logit("saving file <%s> to <%s>"%(infile,outfile),stdout=True)
    try:
        shutil.copyfile(infile, outfile)
    except:
        import traceback
        traceback.print_exc()
        logit("error while trying to save file <%s> to <%s>"%(infile,outfile),stderr=True)
        return False
    return True


def install_cron_unix():
    logit("begin")
    """install opensvc cron jobs
    """

    nodemgr = os.path.join(pathsbin, 'nodemgr')
    ce = [{
           'sched': "* * * * *",
           'reset_sched': True,
           'user': "",
           'cmd': "[ -x "+nodemgr+" ] && "+nodemgr+" schedulers >/dev/null 2>&1",
           'marker': nodemgr + ' schedulers',
           'ok': False
    }]
    remove_entries = [
      'bin/nodemgr compliance check',
      'bin/svcmon ',
      'bin/cron/opensvc',
      'svcmgr resource monitor',
      'svcmgr resource_monitor',
      'nodemgr cron',
      'perfagt.'+sysname,
    ]

    purge = []
    root_crontab = False

    """ order of preference
    """
    if sysname == 'SunOS' :
	    if SolarisRootRelocate is True:
	        suncron = os.environ["PKG_INSTALL_ROOT"] + '/var/spool/cron/crontabs/root'
                root_crontab_locs = [
                   suncron
                ]
	    else:
	        root_crontab_locs = [ '/var/spool/cron/crontabs/root' ]
    else:
        root_crontab_locs = [
            '/etc/cron.d/opensvc',
            '/var/spool/cron/crontabs/root',
            '/var/spool/cron/root',
            '/var/cron/tabs/root',
            '/usr/lib/cron/tabs/root',
        ]
    for loc in root_crontab_locs:
        logit("looping crontab location <%s>"%loc)
        if os.path.exists(os.path.dirname(loc)):
            if not root_crontab:
                root_crontab = loc
                logit("identifying <%s> as root crontab"%root_crontab)
                if root_crontab == '/etc/cron.d/opensvc':
                    logit("assigning root:root as crontab owner")
                    ce[0]['user'] = "root"
            elif os.path.exists(loc):
                logit("adding <%s> to purge table"%loc)
                purge.append(loc)

    if not root_crontab:
        logit("no root crontab found in usual locations <%s>"%str(root_crontab_locs),stderr=True)
        return False

    ce[0]['full'] = ' '.join([ce[0]['sched'], ce[0]['user'], ce[0]['cmd']])
    logit("osvcagt crontab entry <%s>"%ce[0]['full'])

    new = False
    if os.path.exists(root_crontab):
        try:
            f = open(root_crontab, 'r')
            new = f.readlines()
            f.close()
            logit("loaded crontab <%s> content <%s>"%(root_crontab,new))
        except:
            f.close()
            import traceback
            traceback.print_exc()

        i = -1
        for line in new:
            i += 1
            for c in ce:
                if c['full'] is None:
                    continue
                if line.find(c['marker']) != -1:
                    if line.strip().startswith("#"):
                        continue
                    if c['ok']:
                        new[i] = ""
                        continue
                    if c['reset_sched']:
                        sched = c['sched']
                    else:
                        sched = ' '.join(line.split()[:5])
                    new[i] = ' '.join([sched, c['user'], c['cmd']])+'\n'
                    c['ok'] = True
        for c in ce:
            if c['full'] is not None and not c['ok']:
                new.append(c['full']+'\n')
    else:
        new = []
        for c in ce:
            if c['full'] is not None and not c['ok']:
                new.append(c['full']+'\n')
        logit("no crontab <%s>. building new content <%s>"%(root_crontab,new))

    if not new:
        logit("problem preparing the new crontab",stderr=True)
        return False
 
    i = -1
    for line in new:
        i += 1
        for re in remove_entries:
            logit("looping re <%s>"%re)
            if line.find(re) != -1:
                logit("delete line <%s> from <%s>"%(re,root_crontab))
                del new[i]
    
    logit("saving crontab <%s>"%root_crontab)
    try:
        save_file(root_crontab)
    except:
        logit('Error while trying to backup crontab <%s>. skipping crontab update'%(root_crontab),stderr=True)
        return False

    logit("updating crontab <%s> with content <%s>"%(root_crontab,new))
    try:
        f = open(root_crontab, 'w')
        f.write(''.join(new))
        f.close()
    except:
        logit("error while trying to update crontab %s"%root_crontab,stderr=True)
        f.close()
        import traceback
        traceback.print_exc()

    """ Activate changes (actually only needed on HP-UX)
    """
    if sysname in ("HP-UX", "SunOS") and root_crontab.find('/var/spool/') != -1:
        logit("crontab activation requested")
        cmd = ['crontab', root_crontab]
        ret = os.system(' '.join(cmd))

    for loc in purge:
        try:
            f = open(loc, 'r')
            new = [ line for line in f.readlines() if line.find('opensvc.daily') == -1 and line.find('svcmon --updatedb') == -1 ]
            f.close()
            f = open(loc, 'w')
            f.write(''.join(new))
            f.close()
        except:
            f.close()
            import traceback
            traceback.print_exc()

    """ Clean up old standard file locations
    """
    for f in ['/etc/cron.daily/opensvc', '/etc/cron.daily/opensvc.daily']:
        if os.path.exists(f):
            logit("removing %s"%f)
            os.unlink(f)

def activate_chkconfig(svc):
    logit("begin")
    cmd = ['chkconfig', '--add', svc]
    ret = os.system(' '.join(cmd))
    if ret > 0:
        return False
    return True

def activate_systemd(launcher):
    logit("begin")
    systemdsvc = 'opensvc-agent.service'
    
    # populate systemd tree with opensvc unit file
    src = os.path.join(pathini, 'systemd.opensvc-agent.service')
    dst = os.path.join('/etc/systemd/system/', systemdsvc)
    logit("installing systemd unit file",stdout=True)
    try:
        shutil.copyfile(src, dst)
        os.chmod(dst, 0644)
    except:
        logit("issue met while trying to install systemd unit file",stderr=True)
    
    # add symlink to resolve systemd service call
    systemd_call = os.path.join(pathini, "opensvc.init")
    if not os.path.islink(systemd_call):
        if os.path.exists(systemd_call):
            logit("removing %s"%systemd_call)
            os.unlink(systemd_call)
        msg = "create link %s -> %s"%(systemd_call, launcher)
        logit(msg)
        try:
            os.symlink(launcher, systemd_call)
        except:
            logit("issue met while trying to create %s symlink" % system_call,stderr=True)

    # set systemd call as ExecStart and ExecStop
    os.system("sed -i 's@/usr/share/opensvc/bin/init/opensvc.init@"+systemd_call+"@' "+dst)

    # reload systemd configuration
    logit("reloading systemd configuration",stdout=True)
    cmd = ['systemctl', '-q', 'daemon-reload']
    ret = os.system(' '.join(cmd))
    if ret > 0:
        logit("issue met during systemctl reload",stderr=True)
    
    # enable opensvc agent startup through systemd
    logit("enabling systemd configuration")
    cmd = ['systemctl', '-q', 'enable', systemdsvc]
    ret = os.system(' '.join(cmd))
    if ret > 0:
        logit("issue met during systemctl enable",stderr=True)


def systemd_mgmt():
    logit("begin")
    cmd = ['systemctl', '--version', '>>/dev/null', '2>&1']
    ret = os.system(' '.join(cmd))
    if ret > 0:
        return False
    return True

def activate_ovm(launcher):
    logit("begin")
    activate_chkconfig('zopensvc')

def activate_redhat(launcher):
    logit("begin")
    activate_chkconfig('opensvc')

def activate_debian(launcher):
    logit("begin")
    cmd = ['update-rc.d', '-f', 'opensvc', 'remove']
    ret = os.system(' '.join(cmd))
    if ret > 0:
        logit("issue met while trying to remove opensvc rc launchers",stderr=True)
        return False
    cmd = ['update-rc.d', 'opensvc', 'defaults']
    ret = os.system(' '.join(cmd))
    if ret > 0:
        logit("issue met while trying to install opensvc rc launchers",stderr=True)
        return False
    return True

def activate_hpux(launcher):
    logit("begin")
    rc = "/sbin/init.d/opensvc"
    links = ["/sbin/rc1.d/K010opensvc", "/sbin/rc2.d/K010opensvc", "/sbin/rc3.d/S990opensvc"]
    if os.path.exists("/sbin/rc2.d/S990opensvc"):
        logit("removing /sbin/rc2.d/S990opensvc")
        os.unlink("/sbin/rc2.d/S990opensvc")
    for l in links:
        if not os.path.islink(l):
            if os.path.exists(l):
                logit("removing %s"%l)
                os.unlink(l)
            logit("create link %s -> %s"%(l,rc))
            os.symlink(rc, l)
    try:
        f = open("/etc/rc.config.d/opensvc", "w")
        f.write("RUN_OPENSVC=1\n")
        f.close()
    except:
        logit("issue met while trying to install rc.config.d opensvc file",stderr=True)
        f.close()
        import traceback
        traceback.print_exc()
    return True

def activate_AIX(launcher):
    logit("begin")
    rc = "/etc/rc.d/init.d/opensvc"
    links = ["/etc/rc.d/rc2.d/S990opensvc"]
    for l in links:
        if not os.path.islink(l):
            if os.path.exists(l):
                logit("removing %s"%l)
                os.unlink(l)
            logit("create link %s -> %s"%(l,rc))
            os.symlink(rc, l)
    return True

def activate_OSF1(launcher):
    logit("begin")
    rc = "/sbin/init.d/opensvc"
    links = ["/sbin/rc0.d/K010opensvc", "/sbin/rc2.d/K010opensvc", "/sbin/rc3.d/S990opensvc"]
    for l in links:
	if not os.path.islink(l):
	    if os.path.exists(l):
                logit("removing %s"%l)
	        os.unlink(l)
            logit("symlinking %s and %s"%(rc,l))
	    os.symlink(rc, l)
    return True

def activate_SunOS(launcher):
    logit("begin")
    if SolarisRootRelocate is True:
        rc = "/etc/init.d/opensvc"
        links = [os.environ["PKG_INSTALL_ROOT"] + "/etc/rc0.d/K00opensvc", os.environ["PKG_INSTALL_ROOT"] + "/etc/rc3.d/S99opensvc"]
    else:
	rc = "/etc/init.d/opensvc"
	links = ["/etc/rc0.d/K00opensvc", "/etc/rc3.d/S99opensvc"]
    logit("rc <%s>"%rc)
    for l in links:
        logit("link <%s>"%l)
        if not os.path.islink(l):
            if os.path.exists(l):
                logit("removing %s"%l)
                os.unlink(l)
            logit("symlinking %s and %s"%(rc,l))
            os.symlink(rc, l)
    return True

def activate_FreeBSD(launcher):
    logit("begin")
    return True

def activate_Darwin(launcher):
    logit("begin")
    return True

def update_file(filename, srctext, replacetext):
    logit("begin")
    """ replace into filename srctext by replacetext
    """
    import fileinput
    for line in fileinput.input(filename, inplace=1):
        if line.rstrip('\n') == srctext.rstrip('\n') :
            line = replacetext
        msg=line.rstrip('\n')
        logit(msg,stdout=True)
    fileinput.close()

def install_params(path2file):
    logit("begin")
    """ install template file with tunable variables
    """
    if os.path.exists(path2file):
        logit("file %s already present"%path2file)
        return

    try:
        f = open(path2file, "w")
    except:
        import traceback
        traceback.print_exc()
    else:
        logit("writing new <%s>"%path2file)
        f.write("# OpenSVC startup and wrapper configuration file\n")
        f.write("#\n")
        f.write("# You may need to adapt parameters to fit your environment\n")
        f.write("# This file is not modified during software upgrades\n")
        f.write("# If empty, default settings are used in the init script\n\n\n")
        f.write("\n")
        f.write("#\n")
        f.write("# Arguments passed to the 'svcmgr boot' command at system boot\n")
        f.write("#\n")
        f.write("#OSVC_BOOT_OPTS=\n")
        f.write("\n")
        f.write("#\n")
        f.write("# If set to true, the OpenSVC launcher will start in the\n")
        f.write("# background, avoiding timeouts in init managers. The default\n")
        f.write("# is to launch services in the foreground.\n")
        f.write("#\n")
        f.write("#OSVC_BACKGROUND=true\n")
        f.write("\n")
        f.write("#\n")
        f.write("# Wrapper configuration\n")
        f.write("#\n")
        f.write("#OSVC_ROOT_PATH=/opt/opensvc\n")
        f.write("#OSVC_PYTHON=python\n")
        f.write("#LD_LIBRARY_PATH=\n")
        f.write("#LD_PRELOAD=\n")
        f.write("\n")
        f.close()
 
def install_rc():
    logit("begin")
    """install startup script
    """
    params = None
    copyrc = True

    if os.path.exists('/etc/debian_version'):
        rc = '/etc/init.d/opensvc'
        params = '/etc/default/opensvc'
        src = os.path.join(pathini, 'opensvc.init.debian')
        if systemd_mgmt():
            logit("debian with systemd")
            copyrc = False
            activate = activate_systemd
        else:
            logit("debian with update-rc.d (rely on insserv)")
            activate = activate_debian
    elif os.path.exists('/etc/SuSE-release'):
        rc = '/etc/init.d/opensvc'
        params = '/etc/sysconfig/opensvc'
        src = os.path.join(pathini, 'opensvc.init.suse')
        if systemd_mgmt():
            logit("SuSE with systemd")
            copyrc = False
            activate = activate_systemd
        else:
            logit("SuSE with chkconfig (rely on insserv)")
            activate = activate_redhat       
    elif os.path.exists('/etc/redhat-release'):
        params = '/etc/sysconfig/opensvc'
        src = os.path.join(pathini, 'opensvc.init.redhat')
        try:
            f = open('/etc/redhat-release', 'r')
            buff = f.read()
            f.close()
        except:
            buff = ""
        if buff.find('Oracle VM server') != -1:
            rc = '/etc/init.d/zopensvc'
            activate = activate_ovm
        else:
            rc = '/etc/init.d/opensvc'
            if systemd_mgmt():
                logit("Red Hat with systemd")
                copyrc = False
                activate = activate_systemd
            else:
                logit("Red Hat with chkconfig (rely on insserv)")
                activate = activate_redhat    

    elif sysname == "HP-UX":
        rc = '/sbin/init.d/opensvc'
        src = os.path.join(pathini, 'opensvc.init.hpux')
        activate = activate_hpux
    elif sysname == "SunOS":
	if SolarisRootRelocate is True:
            rc = os.environ["PKG_INSTALL_ROOT"] + '/etc/init.d/opensvc'
            params = os.environ["PKG_INSTALL_ROOT"] + '/etc/default/opensvc'
            src = os.environ["PKG_INSTALL_ROOT"] + os.path.join(pathini, 'opensvc.init.SunOS')
        else:
            rc = '/etc/init.d/opensvc'
            params = '/etc/default/opensvc'
            src = os.path.join(pathini, 'opensvc.init.SunOS')
        activate = activate_SunOS
    elif sysname == "OSF1":
        rc = '/sbin/init.d/opensvc'
        src = os.path.join(pathini, 'opensvc.init.OSF1')
        activate = activate_OSF1
    elif sysname == "FreeBSD":
        rc = '/etc/rc.d/opensvc'
        params = '/etc/defaults/opensvc'
        src = os.path.join(pathini, 'opensvc.init.FreeBSD')
        activate = activate_FreeBSD
    elif sysname == "AIX":
        rc = '/etc/rc.d/init.d/opensvc'
        src = os.path.join(pathini, 'opensvc.init.AIX')
        activate = activate_AIX
    elif sysname == "Darwin":
        rc = '/Library/LaunchDaemons/com.opensvc.svcmgr.plist'
        params = '/etc/defaults/opensvc'
        src = os.path.join(pathini, 'darwin.com.opensvc.svcmgr.plist')
        activate = activate_Darwin
    elif sysname == 'Windows':
        return False
    else:
        logit("could not select an init script: unsupported operating system",stderr=True)
        return False

    if os.path.islink(rc):
        logit("removing link %s"%rc)
        os.unlink(rc)

    if copyrc:
        logit("copying src launcher script to rc")
        shutil.copyfile(src, rc)
        os.chmod(rc, 0755)

    if params is not None and not os.path.exists(params):
        logit("installing default parameters file")
        install_params(params)
        
    activate(src)

def gen_keys():
    logit("begin")
    if sysname == 'Windows':
        return
    home = os.path.expanduser("~root")
    logit("home <%s>"%home)
    if SolarisRootRelocate is True:
	home = os.environ['PKG_INSTALL_ROOT'] + os.path.expanduser("~root")
        logit("SunOS and relocatable install home is now <%s>"%home)
    sshhome = os.path.join(home, ".ssh")
    logit("sshhome <%s>"%sshhome)
    if not os.path.exists(sshhome):
        logit("create dir %s"%sshhome,stdout=True)
	os.makedirs(sshhome, 0700)
    priv = os.path.join(sshhome, "id_rsa")
    pub = os.path.join(sshhome, "id_rsa.pub")
    if os.path.exists(pub) or os.path.exists(priv):
        logit("either %s or %s already exist"%(pub,priv))
        return
    cmd = ['ssh-keygen', '-t', 'rsa', '-b', '2048', '-P', '""', '-f', priv]
    try:
        ret = os.system(' '.join(cmd))
    except:
        logit("Error while trying to generate ssh keys")

def missing_dir(pathd):
    logit("begin")
    if not os.path.exists(pathd):
            logit("create dir %s"%pathd,stdout=True)
	    os.makedirs(pathd, 0755)

def missing_dirs():
    logit("begin")
    missing_dir(pathlog)
    missing_dir(pathtmp)
    missing_dir(pathvar)
    missing_dir(pathetc)
    missing_dir(pathlck)

def convert_svclinks():
    logit("begin")
    missing_dir(pathetc)
    svcmgr = os.path.join(pathsbin, 'svcmgr')
    if not os.path.exists(svcmgr):
	logit("%s does not exist"%svcmgr)
        return 1
    rcService = os.path.realpath(os.path.join(pathbin, 'rcService'))
    if not os.path.exists(rcService):
	logit("%s does not exist"%rcService)
        return 1
    for fname in os.listdir(pathetc):
        fpath = os.path.join(pathetc, fname)
        if not os.path.islink(fpath):
            logit("%s is not a symlink"%fpath)
            continue
        rpath = os.path.realpath(fpath)
        if rpath != rcService:
            logit("%s != %s"%(rpath,rcService))
            continue
        logit("removing %s"%fpath)
        os.unlink(fpath)
        logit("create link %s -> %s"%(fpath,svcmgr))
        os.symlink(svcmgr, fpath)

def move_env_to_conf():
    for fpath in glob.glob(os.path.join(pathetc, "*.env")):
        svcname = os.path.basename(fpath)[:-4]
        new_basename = svcname+".conf"
        new_fpath = os.path.join(pathetc, new_basename)
        shutil.move(fpath, new_fpath)

def move_var_files_in_subdirs():
    for fpath in glob.glob(os.path.join(pathvar, "last_*")):
        dst = os.path.join(pathvar, "node")
        if not os.path.exists(dst):
            os.makedirs(dst)
        fname = os.path.basename(fpath)
        new_fpath = os.path.join(dst, fname)
        logit("move %s to %s" % (fpath, new_fpath))
        shutil.move(fpath, new_fpath)

    for fpath in glob.glob(os.path.join(pathvar, "*_last_*")):
        fname = os.path.basename(fpath)
        svcname = fname.split("_last_")[0]
        dst = os.path.join(pathvar, svcname)
        if not os.path.exists(dst):
            os.makedirs(dst)
        fname = fname.replace(svcname+"_", "")
        new_fpath = os.path.join(dst, fname)
        logit("move %s to %s" % (fpath, new_fpath))
        shutil.move(fpath, new_fpath)

    for fpath in glob.glob(os.path.join(pathvar, "*.push")):
        svcname = os.path.basename(fpath).split(".push")[0]
        dst = os.path.join(pathvar, svcname)
        if not os.path.exists(dst):
            os.makedirs(dst)
        fname = "last_pushed_env"
        new_fpath = os.path.join(dst, fname)
        logit("move %s to %s" % (fpath, new_fpath))
        shutil.move(fpath, new_fpath)

def move_usr_to_opt():
    logit("begin")
    linksvc = os.path.join(os.sep, 'service')
    old_pathsvc = os.path.join(os.sep, 'usr', 'local', 'opensvc')
    old_pathvar = os.path.join(old_pathsvc, 'var')
    old_pathetc = os.path.join(old_pathsvc, 'etc')

    if os.path.exists(old_pathvar):
        logit("found old var %s"%old_pathvar)
        for f in glob.glob(old_pathvar+'/*'):
            dst = os.path.join(pathvar, os.path.basename(f))
            if os.path.exists(dst) and dst.find('host_mode') == -1:
                logit("file %s already exist"%dst)
                continue
            if os.path.isdir(f):
                logit("copying dir %s to %s"%(f,dst))
                shutil.copytree(f, dst, symlinks=True)
            elif os.path.islink(f):
                linkto = os.readlink(f)
                logit("create link %s -> %s"%(dst,linto))
                os.symlink(linkto, dst)
            else:
                logit("copying file %s to %s"%(f,dst))
                shutil.copy2(f, dst)

    if os.path.exists(old_pathetc):
        logit("found old etc %s"%old_pathetc)
        for f in glob.glob(old_pathetc+'/*'):
            dst = os.path.join(pathetc, os.path.basename(f))
            if os.path.exists(dst):
                logit("file %s already exist"%dst)
                continue
            if os.path.islink(f):
                linkto = os.readlink(f)
                logit("create link %s -> %s"%(dst,linto))
                os.symlink(linkto, dst)
            elif os.path.isdir(f):
                logit("copying dir %s to %s"%(f,dst))
                shutil.copytree(f, dst, symlinks=True)
            else:
                logit("copying file %s to %s"%(f,dst))
                shutil.copy2(f, dst)

    if os.path.exists(old_pathsvc):
        logit("removing old_pathsvc %s"%old_pathsvc)
        shutil.rmtree(old_pathsvc)

    if os.path.islink(linksvc) and os.path.realpath(linksvc) == old_pathsvc:
        logit("removing linksvc %s"%linksvc)
        os.unlink(linksvc)

def install_etc_path():
    logit("begin")
    p = os.path.join(os.sep, 'etc', 'PATH')
    if not os.path.exists(p):
        logit("etc/PATH not found")
        return
    try:
        logit("loading %s"%(p))
        f = open(p, "r")
        buff = f.read()
        f.close()
    except:
        logit("issue met while trying to read %s"%(p),stderr=True)
        return
    l = buff.strip().split(":")
    n = len(l)
    for op in (pathbin, pathetc):
        if op in l:
            logit("dir %s already present in %s"%(op,p))
            continue
        logit("adding dir %s"%(op))
        l.append(op)
    if len(l) == n:
        logit("nothing changed in %s"%(p))
        return
    try:
        logit("updating %s"%(p))
        f = open(p, "w")
        f.write(":".join(l)+'\n')
        f.close()
    except:
        logit("issue met while trying to write %s"%(p),stderr=True)
        return

def install_profile():
    logit("begin")
    prof_d = os.path.join(os.sep, 'etc', 'profile.d')
    prof = os.path.join(prof_d, 'opensvc.sh')
    buff = "if ! echo ${PATH} | grep -q "+pathetc+"; then"+"\n"
    buff = buff+"    PATH=${PATH}:"+pathetc+"\n"
    buff = buff+"fi\n\n"
    buff = buff+"if ! echo ${PATH} | grep -qw "+pathsbin+"; then"+"\n"
    buff = buff+"    PATH=${PATH}:"+pathsbin+"\n"
    buff = buff+"fi\n"
    if not os.path.exists(prof_d):
        logit("no profile directory found")
        return
    try:
        logit("installing profile in file %s"%(prof))        
        f = open(prof, 'w')
        f.write(buff)
        f.close()
    except:
        logit("issue met while trying to install profile in file %s"%(prof),stderr=True)
        f.close()
        import traceback
        traceback.print_exc()

def install_bash_completion():
    logit("begin")
    if pathsvc is None:
        return
    src = os.path.join(pathsvc, 'usr', 'share', 'bash_completion.d', 'opensvc')
    ds = [os.path.join(os.sep, 'etc', 'bash_completion.d'),
          os.path.join(os.sep, 'etc', 'bash', 'bash_completion.d')]
    for d in ds:
        dst = os.path.join(d, 'opensvc')
        if not os.path.exists(d):
            d = None
            continue
        else:
            break
    if d is None:
        logit("no bash completion directory found")
        return
    try:
        logit("installing bash completion file src %s to tgt %s"%(src,dst))
        shutil.copyfile(src, dst)
        os.chmod(dst, 0644)
    except:
        logit("issue met while trying to install bash completion file src %s to tgt %s"%(src,dst))        

def install_link(source, target):
    logit("begin")
    if source == '' or target == '':
        logit("bad parameters")
        return False
    if os.path.realpath(source) == os.path.realpath(target):
        logit("link already ok")
        return True
    if os.path.islink(target) or os.path.exists(target):
        logit("unlink %s",target)
        os.unlink(target)
    try:
        logit("create link %s -> %s"%(target,source))
        os.symlink(source,target)
    except:
        logit("issue met while trying to symlink src %s with tgt %s"%(source,target))

def install_pythonlink():
    logit("begin")
    if sysname == 'Windows':
        return install_pythonlink_windows()
    else:
        return install_pythonlink_unix()


def install_pythonlink_windows():
    logit("begin")
    logit("before appending pathlib to syspath")
    logit(os.environ["PATH"])
    sys.path = [pathlib] + sys.path
    logit("after appending pathlib to syspath")
    logit(os.environ["PATH"])
    from rcUtilitiesWindows import get_registry_value
    logit("before reading installfolder in registry")
    try:
        installfolder = get_registry_value('HKEY_CURRENT_USER', 'Software\\OpenSVC', 'path')
    except:
        logit("issue met while trying to read path into registry HKCU/Software/OpenSVC/path",stderr=True)
        sys.exit(1)

    installfolder = installfolder.rstrip('\\')   
    logit("installfolder = <"+installfolder+">")
    osvcenv = os.path.join(installfolder, 'osvcenv.cmd')
    content = '@echo off\nset OSVCROOT='+installfolder+'\nset OSVCPYTHONROOT=%OSVCROOT%\python\nset PYTHONPATH=%OSVCROOT%\lib\nset OSVCPYTHONEXEC=%OSVCPYTHONROOT%\python.exe\ncall inpath.cmd OSVCPYTHONROOT'
    logit(content)
    f = open(osvcenv, 'w')
    f.write(content)
    f.close()
		
def move_host_mode():
    logit("begin")
    hm = os.path.join(pathvar, 'host_mode')
    cf = os.path.join(pathetc, 'node.conf')
    nodemgr = os.path.join(pathsbin, 'nodemgr')
    if not os.path.exists(hm):
        logit("file %s does not exist"%hm)
        return
    try:
        fp = open(hm, 'r')
        mode = fp.read().split()[0]
        fp.close()
    except:
        logit("failed to read old host_mode. renamed to %s"%(hm+'.old'))
        shutil.move(hm, hm+'.old')
        return
    cmd = [nodemgr, 'set', '--param', 'node.host_mode', '--value', mode]
    ret = os.system(' '.join(cmd))
    if ret != 0:
        logit("failed to set host_mode in node.conf",stdout=True)
        return
    shutil.move(hm, hm+'.old')
 
def nodeconf_params():
    logit("begin")
    nodeconf = os.path.join(pathetc, 'node.conf')
    dotnodeconf = os.path.join(pathetc, '.node.conf')

    # reset etc/.node.conf (autogenerated)
    if os.path.exists(dotnodeconf):
        logit("unlink file %s"%dotnodeconf)
        os.unlink(dotnodeconf)

    if not os.path.exists(nodeconf):
        logit("file %s does not exist"%nodeconf)
        return

    import ConfigParser
    import copy
    try:
        config = ConfigParser.RawConfigParser()
    except AttributeError:
        logit("issue occured while trying to instantiate configparser")
        return
    config.read(nodeconf)
    changed = False

    # no DEFAULT in etc/node.conf
    for o in copy.copy(config.defaults()):
        logit("removing DEFAULT in node.conf")
        config.remove_option('DEFAULT', o)
        changed = True

    # sync section goes to etc/.node.conf
    if config.has_section('sync'):
        logit("removing sync in node.conf")
        config.remove_section('sync')
        changed = True

    for s in config.sections():
        for o in config.options(s):
            if o in ['sync_interval', 'push_interval', 'comp_check_interval']:
                logit("looping %s"%o)
                v = config.getint(s, o)
                config.remove_option(s, o)
                config.set(s, 'interval', v)
                changed = True
            if o in ['sync_days', 'push_days', 'comp_check_days']:
                logit("looping %s"%o)
                v = config.get(s, o)
                config.remove_option(s, o)
                config.set(s, 'days', v)
                changed = True
            if o in ['sync_period', 'push_period', 'comp_check_period']:
                logit("looping %s"%o)
                v = config.get(s, o)
                config.remove_option(s, o)
                config.set(s, 'period', v)
                changed = True

    if changed:
        logit("writing new node.conf")
        try:
            fp = open(nodeconf, 'w')
            config.write(fp)
            fp.close()
        except:
            logit("failed to write new %s"%nodeconf,stderr=True)

def save_exc():
    logit("begin")
    import traceback
    try:
        import tempfile

        try:
            import datetime
            now = str(datetime.datetime.now()).replace(' ', '-')
        except:
            now =""

        try:
            f = tempfile.NamedTemporaryFile(dir=pathtmp, prefix='exc-'+now+'-')
        except:
            return
        f.close()
        f = open(f.name, 'w')
        traceback.print_exc(file=f)
        logit("unexpected error. stack saved in %s"%f.name,stderr=True)
        f.close()
    except:
        logit("unexpected error",stderr=True)
        traceback.print_exc()

def purge_collector_api_cache():
    logit("begin")
    fname = os.path.join(pathvar, "collector")
    if os.path.exists(fname) and os.path.isfile(fname):
        logit("unlink file %s"%fname)
        os.unlink(fname)

def chmod_directories():
    logit("begin")
    if not hasattr(os, "walk"):
        logit("os.walk not available")
        return
    if sysname == 'Windows':
	logit("skip : unsupported on Windows")
        return
    for d in (pathbin, pathlib, pathusr):
        if d is None:
            continue
        for dirname, dirnames, filenames in os.walk(d):
            for subdirname in dirnames:
                dirpath = os.path.join(dirname, subdirname)
                try:
                    os.chmod(dirpath, 0755)
                    msg = "setting %s permissions to 0755" % dirpath
                except:
                    msg = "issue met while trying to set %s permissions to 0755" % dirpath
                logit(msg)

def log_file_info(path):
    try:
        info = os.lstat(path)
    except:
	msg = "issue met while trying to get [%s] os.lstat information" % path
        logit(msg)
	return
    string = "uid[%d] gid[%d] perms[%s] file[%s]" % (info.st_uid, info.st_gid, oct(info.st_mode & 0777), path)
    logit(string)

def dump_install_content():
    logit("begin")
    if sysname == 'Windows':
        logit("skip : unsupported on Windows")
        return
    if not hasattr(os, "walk"):
        logit("os.walk not available")
        return
    for d in (pathbin, pathlib, pathusr):
        if d is None:
            continue
        for dirname, dirnames, filenames in os.walk(d):
            for subdirname in dirnames:
                dirpath = os.path.join(dirname, subdirname)
                log_file_info(dirpath)
            for filename in filenames:
                filepath = os.path.join(dirname, filename)
                log_file_info(filepath)

def convert_to_lsb():
    logit("begin")
    if sysname == 'Windows':
        logit("skip : unsupported on Windows")
        return
    if len(glob.glob(pathetc+"/*")) > 0:
        logit("skip : skip convert to lsb because /etc/opensvc/ is not empty")
        return
    if not os.path.exists("/opt/opensvc"):
        logit("skip : skip convert to lsb because /opt/opensvc/ does not exist")
        return
    for p in glob.glob("/opt/opensvc/etc/*conf") + glob.glob("/opt/opensvc/etc/sssu") + glob.glob("/opt/opensvc/etc/*pem") + glob.glob("/opt/opensvc/etc/*pub"):
        logit("migrate " + p)
        shutil.copy(p, pathetc)
    for p in glob.glob("/opt/opensvc/etc/*.env"):
        logit("migrate " + p)
        svcname = os.path.basename(p)[:-4]
        shutil.copy(os.path.realpath(p), pathetc)
        os.symlink("/usr/bin/svcmgr", os.path.join(pathetc, svcname))
    for p in glob.glob("/opt/opensvc/etc/*.d") + glob.glob("/opt/opensvc/etc/*.dir"):
        logit("migrate " + p)
        if os.path.islink(p):
            bp = os.path.basename(p)
            linkto = os.readlink(p)
            if linkto.startswith("/opt/opensvc/etc"):
                linkto.replace("/opt/opensvc/etc/", "")
            dst = os.path.join(pathetc, bp)
            os.symlink(linkto, dst)
        elif os.path.isdir(p):
            bp = os.path.basename(p)
            dst = os.path.join(pathetc, bp)
            shutil.copytree(p, dst, symlinks=True)
        else:
            shutil.copy(p, pathetc)
    for p in glob.glob("/opt/opensvc/var/*"):
        if os.path.basename(p) == "btrfs":
            continue
        logit("migrate " + p)
        bp = os.path.basename(p)
        dst = os.path.join(pathvar, bp)
        if os.path.exists(dst):
            continue
        if os.path.isdir(p):
            try:
                shutil.copytree(p, dst, symlinks=True)
            except:
                # best effort for var
                pass
        else:
            shutil.copy(p, pathvar)

try:
    move_var_files_in_subdirs()
    move_usr_to_opt()
    missing_dirs()
    convert_svclinks()
    install_cron()
    install_rc()
    gen_keys()
    install_profile()
    install_etc_path()
    install_bash_completion()
    move_host_mode()
    nodeconf_params()
    purge_collector_api_cache()
    chmod_directories()
    convert_to_lsb()
    move_env_to_conf()
    dump_install_content()
    logit("\nOpenSVC postinstall terminated\n",stdout=True)
except:
    save_exc()
    sys.exit(1)
