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