Simple module for toggling network namespaces based on slice attributes
[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', 'trellis']
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('-m', '--module', action='store', dest='module', default='', help='run a single module among '+' '.join(known_modules))
43 (options, args) = parser.parse_args()
44
45 modules = []
46
47 def GetSlivers(plc):
48     '''Run call backs defined in modules'''
49     try: 
50         logger.log("Syncing w/ PLC")
51         data = plc.GetSlivers()
52     except: 
53         logger.log_exc()
54         #  XXX So some modules can at least boostrap.
55         data = {}
56     if (options.verbose):
57         logger.log_slivers(data)
58     # Set i2 ip list for nodes in I2 nodegroup.
59     try: net.GetSlivers(plc, data)
60     except: logger.log_exc()
61     #  All other callback modules
62     for module in modules:
63         try:        
64             callback = getattr(module, 'GetSlivers')
65             callback(data)
66         except: logger.log_exc()
67
68 def run():
69     try:
70         if options.daemon: tools.daemon()
71
72         # set log level
73         if (options.verbose):
74             logger.set_level(logger.LOG_VERBOSE)
75
76         # Load /etc/planetlab/plc_config
77         config = Config(options.config)
78
79         try:
80             other_pid = tools.pid_file()
81             if other_pid != None:
82                 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)
83                 return
84         except OSError, err:
85             print "Warning while writing PID file:", err
86
87         # Load and start modules
88         if options.module:
89             assert options.module in known_modules
90             running_modules=[options.module]
91             logger.verbose('Running single module %s'%options.module)
92         else:
93             running_modules=known_modules
94         for module in running_modules:
95             try:
96                 m = __import__(module)
97                 m.start(options, config)
98                 modules.append(m)
99             except ImportError, err:
100                 print "Warning while loading module %s:" % module, err
101
102         # Load /etc/planetlab/session
103         if os.path.exists(options.session):
104             session = file(options.session).read().strip()
105         else:
106             session = options.session
107
108         # Initialize XML-RPC client
109         iperiod=int(options.period)
110         irandom=int(options.random)
111         plc = PLCAPI(config.plc_api_uri, config.cacert, session, timeout=iperiod/2)
112
113         while True:
114         # Main NM Loop
115             logger.verbose('mainloop - nm:getSlivers - period=%d random=%d'%(iperiod,irandom))
116             GetSlivers(plc)
117             delay=iperiod + random.randrange(0,irandom)
118             logger.verbose('mainloop - sleeping for %d s'%delay)
119             time.sleep(delay)
120     except: logger.log_exc()
121
122
123 if __name__ == '__main__':
124     logger.log("Entering nm.py "+id)
125     stacklim = 512*1024  # 0.5 MiB
126     curlim = resource.getrlimit(resource.RLIMIT_STACK)[0]  # soft limit
127     if curlim > stacklim:
128         resource.setrlimit(resource.RLIMIT_STACK, (stacklim, stacklim))
129         # for some reason, doesn't take effect properly without the exec()
130         python = '/usr/bin/python'
131         os.execv(python, [python] + savedargv)
132     run()
133 else:
134     # This is for debugging purposes.  Open a copy of Python and import nm
135     tools.as_daemon_thread(run)