#!/usr/bin/env python
# Copyright (c) 2005-2007 XenSource, Inc

# Code ripped out of 'xgt' script for now
import commands, xmlrpclib, os, sys, httplib, socket, urllib2, signal

verbose = True

##### begin hack.  Provide xmlrpc over UNIX domain socket (cut+pasted from eliloader):
class UDSHTTPConnection(httplib.HTTPConnection):
    """ Stupid hacked up HTTPConnection subclass to allow HTTP over Unix domain
    sockets. """
    def connect(self):
        path = self.host.replace("_", "/")
        self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        self.sock.connect(path)

class UDSHTTP(httplib.HTTP):
    _connection_class = UDSHTTPConnection

class UDSTransport(xmlrpclib.Transport):
    def make_connection(self, host):
        return UDSHTTP(host)

def xapi_local():
    return xmlrpclib.Server("http://_var_xapi_xapi/", transport=UDSTransport())
##### end hack.


class CommandException(Exception):
    pass


def run(cmd, *args):
    debug("+ " + cmd % args)
    (ret, out) = commands.getstatusoutput(cmd % args)
    if verbose:
        try: 
            for line in out.split("\n"):
                log("| " + line)
        except TypeError, e:
            pass
    if ret != 0:
        debug ("run - command %s failed with %d" , cmd, ret)
        raise CommandException(out)
    return out

def log(fmt, *args):
    print fmt % args

def debug(msg, *args):
    if verbose:
        print msg % args

def create_partition(lvpath):
    # 1. write a partition table:
    pipe = os.popen('/sbin/fdisk %s' % lvpath, 'w')

    pipe.write('n\n') # new partition
    pipe.write('p\n') # primary
    pipe.write("1\n") # 1st partition
    pipe.write('\n')  # default start cylinder
    pipe.write('\n')  # size: as big as image
    pipe.write('w\n') # write partition table

    # XXX we must ignore certain errors here as fdisk will
    # sometimes return non-zero signalling error conditions
    # we don't care about.  Should fix to detect these cases
    # specifically.
    rc = pipe.close()
    if rc == None: 
        rc = 0
        log("fdisk exited with rc %d (some non-zero exits can be ignored safely)." % rc)

def map_partitions(lvpath):
    run("/sbin/kpartx -a %s", lvpath)
    ps = []
    for line in run("/sbin/kpartx -l %s" % lvpath).split("\n"):
        ps.append("/dev/mapper/" + line.split()[0])
    return ps

def unmap_partitions(lvpath):
    run("/sbin/kpartx -d %s", lvpath)

def umount(mountpoint):
    run("umount -l %s",mountpoint)

if __name__ == "__main__":
    #os.setpgrp()
    xvda = os.getenv("xvda")
    xvdb = os.getenv("xvdb")
    debug("Guest's xvda is on %s" % xvda)
    debug("Guest's xvdb is on %s" % xvdb)
    if xvda == None or xvdb == None:
        raise "Need to pass in device names for xvda and xvdb through the environment"
    
    vm = os.getenv("vm")

    server = xapi_local ()
    try:
        session_id = server.session.login_with_password('','')['Value']
        uuid = server.VM.get_uuid(session_id, vm)['Value']
        mountpoint = "/tmp/installer/%s" % (uuid)
    finally:
        server.session.logout(session_id)

    def sighandler(signum, frame):
	umount(mountpoint)
        os.killpg(0,signal.SIGKILL)
	exit(1)

    signal.signal(signal.SIGTERM,sighandler)

    create_partition(xvda)
    create_partition(xvdb)

    try:
        xvda_parts = map_partitions(xvda)

        run("/sbin/mkfs.ext3 %s", xvda_parts[0])

        xgt = "/opt/xensource/packages/xgt/%s.xgt" % os.path.basename(sys.argv[0])

        run("/bin/mkdir -p %s", mountpoint)
        try:
            run("/bin/mount %s %s", xvda_parts[0], mountpoint)
            run("/usr/bin/unzip -p %s root.tar.bz2 | tar -C %s -jx", xgt, mountpoint)
        finally:
            run("/bin/umount %s", mountpoint)
            run("/bin/rmdir %s", mountpoint)
        run("/usr/bin/unzip -p %s swap.img | dd of=%s oflag=direct bs=1M", xgt, xvdb)

        try:
            session_id = server.session.login_with_password('','')['Value']
            vbds = server.VM.get_VBDs(session_id, vm)['Value']
            for i in vbds:
                dev = server.VBD.get_userdevice(session_id, i)['Value']
                if dev == "0":
                    server.VBD.set_bootable(session_id, i, True)
        finally:
            server.session.logout(session_id)
    finally:
        unmap_partitions(xvda)
