If API can't be contacted, let modules bootstrap when applicable.
[nodemanager.git] / nm.py
1 #!/usr/bin/python
2 """Node Manager"""
3
4 import optparse
5 import time
6 import xmlrpclib
7 import socket
8 import os
9 import sys
10 import resource
11
12 import logger
13 import tools
14
15 from config import Config
16 from plcapi import PLCAPI 
17 import random
18 import net
19
20 id="$Id$"
21 savedargv = sys.argv[:]
22
23 known_modules=['proper', 'conf_files', 'sm', 'bwmon']
24
25 parser = optparse.OptionParser()
26 parser.add_option('-d', '--daemon', action='store_true', dest='daemon', default=False, help='run daemonized')
27 parser.add_option('-s', '--startup', action='store_true', dest='startup', default=False, help='run all sliver startup scripts')
28 parser.add_option('-f', '--config', action='store', dest='config', default='/etc/planetlab/plc_config', help='PLC configuration file')
29 parser.add_option('-k', '--session', action='store', dest='session', default='/etc/planetlab/session', help='API session key (or file)')
30 parser.add_option('-p', '--period', action='store', dest='period', default=600, help='Polling interval (sec)')
31 parser.add_option('-r', '--random', action='store', dest='random', default=301, help='Range for additional random polling interval (sec)')
32 parser.add_option('-v', '--verbose', action='store_true', dest='verbose', default=False, help='more verbose log')
33 parser.add_option('-m', '--module', action='store', dest='module', default='', help='run a single module among '+' '.join(known_modules))
34 (options, args) = parser.parse_args()
35
36 modules = []
37
38 def GetSlivers(plc):
39     try: data = plc.GetSlivers()
40     except: 
41         logger.log_exc()
42         #  XXX So some modules can at least boostrap.
43         data = {}
44     if (options.verbose):
45         logger.log_slivers(data)
46     # Set i2 ip list for nodes in I2 nodegroup.
47     try: net.GetSlivers(plc, data)
48     except: logger.log_exc()
49     #  All other callback modules
50     for module in modules:
51         try:        
52             callback = getattr(module, 'GetSlivers')
53             callback(data)
54         except: logger.log_exc()
55
56 def run():
57     try:
58         if options.daemon: tools.daemon()
59
60         # set log level
61         if (options.verbose):
62             logger.set_level(logger.LOG_VERBOSE)
63
64         # Load /etc/planetlab/plc_config
65         config = Config(options.config)
66
67         try:
68             other_pid = tools.pid_file()
69             if other_pid != None:
70                 print """There might be another instance of the node manager running as pid %d.  If this is not the case, please remove the pid file %s""" % (other_pid, tools.PID_FILE)
71                 return
72         except OSError, err:
73             print "Warning while writing PID file:", err
74
75         # Load and start modules
76         if options.module:
77             assert options.module in known_modules
78             running_modules=[options.module]
79             logger.verbose('Running single module %s'%options.module)
80         else:
81             running_modules=known_modules
82         for module in running_modules:
83             try:
84                 m = __import__(module)
85                 m.start(options, config)
86                 modules.append(m)
87             except ImportError, err:
88                 print "Warning while loading module %s:" % module, err
89
90         # Load /etc/planetlab/session
91         if os.path.exists(options.session):
92             session = file(options.session).read().strip()
93         else:
94             session = options.session
95
96         # Initialize XML-RPC client
97         iperiod=int(options.period)
98         irandom=int(options.random)
99         plc = PLCAPI(config.plc_api_uri, config.cacert, session, timeout=iperiod/2)
100
101         while True:
102         # Main NM Loop
103             logger.verbose('mainloop - nm:getSlivers - period=%d random=%d'%(iperiod,irandom))
104             GetSlivers(plc)
105             delay=iperiod + random.randrange(0,irandom)
106             logger.verbose('mainloop - sleeping for %d s'%delay)
107             time.sleep(delay)
108     except: logger.log_exc()
109
110
111 if __name__ == '__main__':
112     logger.log("Entering nm.py "+id)
113     stacklim = 512*1024  # 0.5 MiB
114     curlim = resource.getrlimit(resource.RLIMIT_STACK)[0]  # soft limit
115     if curlim > stacklim:
116         resource.setrlimit(resource.RLIMIT_STACK, (stacklim, stacklim))
117         # for some reason, doesn't take effect properly without the exec()
118         python = '/usr/bin/python'
119         os.execv(python, [python] + savedargv)
120     run()
121 else:
122     # This is for debugging purposes.  Open a copy of Python and import nm
123     tools.as_daemon_thread(run)