304db42639d4828cb9e1684e7229f1cd41328239
[nodemanager.git] / nm.py
1 #!/usr/bin/python
2
3 #
4 # Useful information can be found at https://svn.planet-lab.org/wiki/NodeManager
5 #
6
7 # Faiyaz Ahmed <faiyaza at cs dot princeton dot edu>
8 # Copyright (C) 2008 The Trustees of Princeton University
9
10
11 """Node Manager"""
12
13 import optparse
14 import time
15 import xmlrpclib
16 import socket
17 import os
18 import sys
19 import resource
20
21 import logger
22 import tools
23
24 from config import Config
25 from plcapi import PLCAPI 
26 import random
27 import net
28
29 id="$Id$"
30 savedargv = sys.argv[:]
31
32 known_modules=['conf_files', 'sm', 'bwmon', 'vsys', 'codemux']
33
34 parser = optparse.OptionParser()
35 parser.add_option('-d', '--daemon', action='store_true', dest='daemon', default=False, help='run daemonized')
36 parser.add_option('-s', '--startup', action='store_true', dest='startup', default=False, help='run all sliver startup scripts')
37 parser.add_option('-f', '--config', action='store', dest='config', default='/etc/planetlab/plc_config', help='PLC configuration file')
38 parser.add_option('-k', '--session', action='store', dest='session', default='/etc/planetlab/session', help='API session key (or file)')
39 parser.add_option('-p', '--period', action='store', dest='period', default=600, help='Polling interval (sec)')
40 parser.add_option('-r', '--random', action='store', dest='random', default=301, help='Range for additional random polling interval (sec)')
41 parser.add_option('-v', '--verbose', action='store_true', dest='verbose', default=False, help='more verbose log')
42 parser.add_option('-P', '--path', action='store', dest='path', default='/usr/share/NodeManager/plugins', help='Path to plugins directory')
43 parser.add_option('-m', '--module', action='store', dest='module', default='', help='run a single module among '+' '.join(known_modules))
44 (options, args) = parser.parse_args()
45
46 # Deal with plugins directory
47 if os.path.exists(options.path):
48     sys.path.append(options.path)
49     known_modules += [i[:-3] for i in os.listdir(options.path) if i.endswith(".py") and (i[:-3] not in known_modules)]
50
51 modules = []
52
53 def GetSlivers(plc):
54     '''Run call backs defined in modules'''
55     try: 
56         logger.log("Syncing w/ PLC")
57         data = plc.GetSlivers()
58     except: 
59         logger.log_exc()
60         #  XXX So some modules can at least boostrap.
61         data = {}
62     logger.log_slivers(data)
63     # Set i2 ip list for nodes in I2 nodegroup.
64     try: net.GetSlivers(plc, data)
65     except: logger.log_exc()
66     #  All other callback modules
67     for module in modules:
68         try:        
69             callback = getattr(module, 'GetSlivers')
70             callback(data)
71         except: logger.log_exc()
72
73 def run():
74     try:
75         if options.daemon: tools.daemon()
76
77         # set log level
78         if (options.verbose):
79             logger.set_level(logger.LOG_VERBOSE)
80
81         # Load /etc/planetlab/plc_config
82         config = Config(options.config)
83
84         try:
85             other_pid = tools.pid_file()
86             if other_pid != None:
87                 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)
88                 return
89         except OSError, err:
90             print "Warning while writing PID file:", err
91
92         # Load and start modules
93         if options.module:
94             assert options.module in known_modules
95             running_modules=[options.module]
96             logger.verbose('Running single module %s'%options.module)
97         else:
98             running_modules=known_modules
99         for module in running_modules:
100             try:
101                 m = __import__(module)
102                 m.start(options, config)
103                 modules.append(m)
104             except ImportError, err:
105                 print "Warning while loading module %s:" % module, err
106
107         # Load /etc/planetlab/session
108         if os.path.exists(options.session):
109             session = file(options.session).read().strip()
110         else:
111             session = options.session
112
113         # Initialize XML-RPC client
114         iperiod=int(options.period)
115         irandom=int(options.random)
116         plc = PLCAPI(config.plc_api_uri, config.cacert, session, timeout=iperiod/2)
117
118         while True:
119         # Main NM Loop
120             logger.verbose('mainloop - nm:getSlivers - period=%d random=%d'%(iperiod,irandom))
121             GetSlivers(plc)
122             delay=iperiod + random.randrange(0,irandom)
123             logger.verbose('mainloop - sleeping for %d s'%delay)
124             time.sleep(delay)
125     except: logger.log_exc()
126
127
128 if __name__ == '__main__':
129     logger.log("Entering nm.py "+id)
130     stacklim = 512*1024  # 0.5 MiB
131     curlim = resource.getrlimit(resource.RLIMIT_STACK)[0]  # soft limit
132     if curlim > stacklim:
133         resource.setrlimit(resource.RLIMIT_STACK, (stacklim, stacklim))
134         # for some reason, doesn't take effect properly without the exec()
135         python = '/usr/bin/python'
136         os.execv(python, [python] + savedargv)
137     run()
138 else:
139     # This is for debugging purposes.  Open a copy of Python and import nm
140     tools.as_daemon_thread(run)