# $Id$
# $URL$

"""Codemux configurator.  Monitors slice attributes and configures CoDemux to mux port 80 based on HOST field in HTTP request.  Forwards to localhost port belonging to configured slice."""

import logger
import os
import vserver
from sets import Set
from config import Config

CODEMUXCONF="/etc/codemux/codemux.conf"

def start(options, config):
    pass


def GetSlivers(data):
    """
    For each sliver with the codemux attribute, parse out "host,port" 
    and make entry in conf.  Restart service after.
    """
    logger.log("codemux:  Starting.", 2)
    # slices already in conf
    slicesinconf = parseConf()
    # slices that need to be written to the conf
    codemuxslices = {}
    
    # XXX Hack for planetflow
    if slicesinconf.has_key("root"): _writeconf = False
    else: _writeconf = True

    # Parse attributes and update dict of scripts
    for sliver in data['slivers']:
        for attribute in sliver['attributes']:
            if attribute['tagname'] == 'codemux':
                # add to conf.  Attribute is [host, port]
                params = {'host': attribute['value'].split(",")[0], 
                          'port': attribute['value'].split(",")[1]}
                try:
                    # Check to see if sliver is running.  If not, continue
                    if vserver.VServer(sliver['name']).is_running():
                        # Check if new or needs updating
                        if (sliver['name'] not in slicesinconf.keys()) \
                        or (params not in slicesinconf.get(sliver['name'], [])):
                            logger.log("codemux:  Updaiting slice %s using %s" % \
                                (sliver['name'], params['host']))
                            #  Toggle write.
                            _writeconf = True
                        # Add to dict of codemuxslices.  Make list to support more than one
                        # codemuxed host per slice.
                        codemuxslices.setdefault(sliver['name'],[])
                        codemuxslices[sliver['name']].append(params)
                except:
                    logger.log("codemux:  sliver %s not running yet.  Deferring."\
                                % sliver['name'])
                    pass

    # Remove slices from conf that no longer have the attribute
    for deadslice in Set(slicesinconf.keys()) - Set(codemuxslices.keys()):
        # XXX Hack for root slice
        if deadslice != "root": 
            logger.log("codemux:  Removing %s" % deadslice)
            _writeconf = True 

    if _writeconf:  writeConf(sortDomains(codemuxslices))

def writeConf(slivers, conf = CODEMUXCONF):
    '''Write conf with default entry up top. Elements in [] should have lower order domain names first. Restart service.'''
    f = open(conf, "w")
    # This needs to be the first entry...
    try: 
        f.write("* root 1080 %s\n" % Config().PLC_PLANETFLOW_HOST)
    except AttributeError: 
        logger.log("codemux:  Can't find PLC_CONFIG_HOST in config. Using PLC_API_HOST")
        f.write("* root 1080 %s\n" % Config().PLC_API_HOST)
    # Sort items for like domains
    for mapping in slivers:
        for (host, params) in mapping.iteritems():
            if params['slice'] == "root":  continue
            f.write("%s %s %s\n" % (host, params['slice'], params['port']))
    f.truncate()
    f.close()
    try:  restartService()
    except:  logger.log_exc()

def sortDomains(slivers):
    '''Given a dict of {slice: {domainname, port}}, return array of slivers with lower order domains first'''
    dnames = {} # {host: slice}
    for (slice, params) in slivers.iteritems():
        for mapping in params:
            dnames[mapping['host']] = {"slice":slice, "port": mapping['port']}
    hosts = dnames.keys()
    # sort by length
    hosts.sort(key=str.__len__)
    # longer first
    hosts.reverse()
    # make list of slivers
    sortedslices = []
    for host in hosts: sortedslices.append({host: dnames[host]})
    
    return sortedslices
        
def parseConf(conf = CODEMUXCONF):
    '''Parse the CODEMUXCONF and return dict of slices in conf. {slice: (host,port)}'''
    slicesinconf = {} # default
    try: 
        f = open(conf)
        for line in f.readlines():
            if line.startswith("#") \
            or (len(line.split()) > 4) \
            or (len(line.split()) < 3):
                continue
            (host, slice, port) = line.split()[:3]
            logger.log("codemux:  found %s in conf" % slice, 2)
            slicesinconf.setdefault(slice, [])
            slicesinconf[slice].append({"host": host, "port": port})
        f.close()
    except IOError: logger.log_exc()
    return slicesinconf

def restartService():
    logger.log("codemux:  Restarting codemux service")
    os.system("/etc/init.d/codemux stop")
    f = os.popen("/sbin/pidof codemux")
    tmp = f.readlines()
    f.close()
    if len(tmp) > 0: 
        pids = tmp[0].rstrip("\n").split()
        for pid in pids:
            logger.log("codemux:  Killing stalled pid %s" % pid, 2)
            os.kill(pid, 9)
    os.system("/etc/init.d/codemux start")

@@ -4842,314 +4842,14 @@
 mux 
-stop%22)%0A    f = os.popen(%22/sbin/pidof codemux%22)%0A    tmp = f.readlines()%0A    f.close()%0A    if len(tmp) %3E 0: %0A        pids = tmp%5B0%5D.rstrip(%22%5Cn%22).split()%0A        for pid in pids:%0A            logger.log(%22codemux:  Killing stalled pid %25s%22 %25 pid, 2)%0A            os.kill(pid, 9)%0A    os.system(%22/etc/init.d/codemux 
+condre
 star

Use codemux condrestart.