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