Plugins directory.
[nodemanager.git] / plugins / codemux.py
1 # $Id$
2 # $URL$
3
4 """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."""
5
6 import logger
7 import os
8 import vserver
9 from sets import Set
10 from config import Config
11
12 CODEMUXCONF="/etc/codemux/codemux.conf"
13
14 def start(options, config):
15     pass
16
17
18 def GetSlivers(data):
19     """
20     For each sliver with the codemux attribute, parse out "host,port" 
21     and make entry in conf.  Restart service after.
22     """
23     logger.log("codemux:  Starting.", 2)
24     # slices already in conf
25     slicesinconf = parseConf()
26     # slices that need to be written to the conf
27     codemuxslices = {}
28     
29     # XXX Hack for planetflow
30     if slicesinconf.has_key("root"): _writeconf = False
31     else: _writeconf = True
32
33     # Parse attributes and update dict of scripts
34     for sliver in data['slivers']:
35         for attribute in sliver['attributes']:
36             if attribute['tagname'] == 'codemux':
37                 # add to conf.  Attribute is [host, port]
38                 params = {'host': attribute['value'].split(",")[0], 
39                           'port': attribute['value'].split(",")[1]}
40                 try:
41                     # Check to see if sliver is running.  If not, continue
42                     if vserver.VServer(sliver['name']).is_running():
43                         # Check if new or needs updating
44                         if (sliver['name'] not in slicesinconf.keys()) \
45                         or (params not in slicesinconf.get(sliver['name'], [])):
46                             logger.log("codemux:  Updaiting slice %s using %s" % \
47                                 (sliver['name'], params['host']))
48                             #  Toggle write.
49                             _writeconf = True
50                         # Add to dict of codemuxslices.  Make list to support more than one
51                         # codemuxed host per slice.
52                         codemuxslices.setdefault(sliver['name'],[])
53                         codemuxslices[sliver['name']].append(params)
54                 except:
55                     logger.log("codemux:  sliver %s not running yet.  Deferring."\
56                                 % sliver['name'])
57                     pass
58
59     # Remove slices from conf that no longer have the attribute
60     for deadslice in Set(slicesinconf.keys()) - Set(codemuxslices.keys()):
61         # XXX Hack for root slice
62         if deadslice != "root": 
63             logger.log("codemux:  Removing %s" % deadslice)
64             _writeconf = True 
65
66     if _writeconf:  writeConf(sortDomains(codemuxslices))
67
68 def writeConf(slivers, conf = CODEMUXCONF):
69     '''Write conf with default entry up top. Elements in [] should have lower order domain names first. Restart service.'''
70     f = open(conf, "w")
71     # This needs to be the first entry...
72     try: 
73         f.write("* root 1080 %s\n" % Config().PLC_PLANETFLOW_HOST)
74     except AttributeError: 
75         logger.log("codemux:  Can't find PLC_CONFIG_HOST in config. Using PLC_API_HOST")
76         f.write("* root 1080 %s\n" % Config().PLC_API_HOST)
77     # Sort items for like domains
78     for mapping in slivers:
79         for (host, params) in mapping.iteritems():
80             if params['slice'] == "root":  continue
81             f.write("%s %s %s\n" % (host, params['slice'], params['port']))
82     f.truncate()
83     f.close()
84     try:  restartService()
85     except:  logger.log_exc()
86
87 def sortDomains(slivers):
88     '''Given a dict of {slice: {domainname, port}}, return array of slivers with lower order domains first'''
89     dnames = {} # {host: slice}
90     for (slice, params) in slivers.iteritems():
91         for mapping in params:
92             dnames[mapping['host']] = {"slice":slice, "port": mapping['port']}
93     hosts = dnames.keys()
94     # sort by length
95     hosts.sort(key=str.__len__)
96     # longer first
97     hosts.reverse()
98     # make list of slivers
99     sortedslices = []
100     for host in hosts: sortedslices.append({host: dnames[host]})
101     
102     return sortedslices
103         
104 def parseConf(conf = CODEMUXCONF):
105     '''Parse the CODEMUXCONF and return dict of slices in conf. {slice: (host,port)}'''
106     slicesinconf = {} # default
107     try: 
108         f = open(conf)
109         for line in f.readlines():
110             if line.startswith("#") \
111             or (len(line.split()) > 4) \
112             or (len(line.split()) < 3):
113                 continue
114             (host, slice, port) = line.split()[:3]
115             logger.log("codemux:  found %s in conf" % slice, 2)
116             slicesinconf.setdefault(slice, [])
117             slicesinconf[slice].append({"host": host, "port": port})
118         f.close()
119     except IOError: logger.log_exc()
120     return slicesinconf
121
122 def restartService():
123     logger.log("codemux:  Restarting codemux service")
124     os.system("/etc/init.d/codemux stop")
125     f = os.popen("/sbin/pidof codemux")
126     tmp = f.readlines()
127     f.close()
128     if len(tmp) > 0: 
129         pids = tmp[0].rstrip("\n").split()
130         for pid in pids:
131             logger.log("codemux:  Killing stalled pid %s" % pid, 2)
132             os.kill(pid, 9)
133     os.system("/etc/init.d/codemux start")