sort domain name. lower order domains should be first.
[nodemanager.git] / 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
11 CODEMUXCONF="/etc/codemux/codemux.conf"
12
13 def start(options, config):
14     pass
15
16
17 def GetSlivers(data):
18     """For each sliver with the codemux attribute, parse out "host,port" and make entry in conf.  Restart service after."""
19     logger.log("codemux:  Starting.", 2)
20     # slices already in conf
21     slicesinconf = parseConf()
22     # slices that need to be written to the conf
23     codemuxslices = {}
24     
25     # XXX Hack for planetflow
26     if slicesinconf.has_key("root"): _writeconf = False
27     else: _writeconf = True
28
29     # Parse attributes and update dict of scripts
30     for sliver in data['slivers']:
31         for attribute in sliver['attributes']:
32             if attribute['name'] == 'codemux':
33                 # add to conf.  Attribute is [host, port]
34                 [host, port] = attribute['value'].split(",")
35                 try:
36                     # Check to see if sliver is running.  If not, continue
37                     if vserver.VServer(sliver['name']).is_running():
38                         # Add to dict of codemuxslices 
39                         codemuxslices[sliver['name']] = {'host': host, 'port': port}
40                         # Check if new
41                         if sliver['name'] not in slicesinconf.keys():
42                             logger.log("codemux:  New slice %s using %s" % \
43                                 (sliver['name'], host))
44                             #  Toggle write.
45                             _writeconf = True
46                         # Check old slivers for changes
47                         else:
48                             # Get info about slice in conf
49                             sliverinconf = slicesinconf[sliver['name']]
50                             # Check values for changes.
51                             if (sliverinconf['host'] != host) or \
52                                 (sliverinconf['port'] != port):
53                                 logger.log("codemux:  Updating slice %s" % sliver['name'])
54                                 # use updated values
55                                 codemuxslices[sliver['name']] = {'host': host, 'port': port}
56                                 #  Toggle write.
57                                 _writeconf = True
58                 except:
59                     logger.log("codemux:  sliver %s not running yet.  Deferring."\
60                                 % sliver['name'])
61
62                     logger.log_exc(name = "codemux")
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(codemuxslices)
73
74 def writeConf(slivers, conf = CODEMUXCONF):
75     '''Write conf with default entry up top.  Write lower order domain names first. Restart service.'''
76     f = open(conf, "w")
77     # This needs to be the first entry...
78     f.write("* root 1080\n")
79     # Sort items for like domains
80     for slice in sortDomains(slivers):
81         if slice == "root":  continue
82         f.write("%s %s %s\n" % (slivers[slice]['host'], slice, slivers[slice]['port']))
83     f.truncate()
84     f.close()
85     try:  restartService()
86     except:  logger.log_exc()
87
88 def sortDomains(slivers):
89     '''Given a dict of {slice: {domainname, port}}, return array of slivers with lower order domains first'''
90     dnames = {} # {host: slice}
91     for (slice,params) in slivers.iteritems():
92         dnames[params['host']] = slice
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(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("#") or (len(line.split()) != 3):
111                 continue
112             (host, slice, port) = line.split()[:3]
113             logger.log("codemux:  found %s in conf" % slice, 2)
114             slicesinconf[slice] = {"host": host, "port": port}
115         f.close()
116     except IOError: logger.log_exc()
117     return slicesinconf
118
119 def restartService():
120     logger.log("codemux:  Restarting codemux service")
121     os.system("/etc/init.d/codemux stop")
122     f = os.popen("/sbin/pidof codemux")
123     tmp = f.readlines()
124     f.close()
125     if len(tmp) > 0: 
126         pids = tmp[0].rstrip("\n").split()
127         for pid in pids:
128             logger.log("codemux:  Killing stalled pid %s" % pid, 2)
129             os.kill(pid, 9)
130     os.system("/etc/init.d/codemux start")