only use spaces... doh.
[monitor.git] / RunlevelAgent.py
1 #!/usr/bin/python
2
3 import xml, xmlrpclib
4 import logging
5 import time
6 import traceback
7 import sys
8 import os
9 import string
10
11 CONFIG_FILE="/tmp/source/configuration"
12 SESSION_FILE="/etc/planetlab/session"
13
14 def read_config_file(filename):
15     ## NOTE: text copied from BootManager.py 
16     # TODO: unify this code to make it common. i.e. use ConfigParser module
17     vars = {}
18     vars_file= file(filename,'r')
19     validConfFile = True
20     for line in vars_file:
21         # if its a comment or a whitespace line, ignore
22         if line[:1] == "#" or string.strip(line) == "":
23             continue
24
25         parts= string.split(line,"=")
26         if len(parts) != 2:
27             print "Invalid line in vars file: %s" % line
28             validConfFile = False
29             break
30
31         name= string.strip(parts[0])
32         value= string.strip(parts[1])
33         vars[name]= value
34
35     vars_file.close()
36     if not validConfFile:
37         print "Unable to read configuration vars."
38
39     return vars
40
41 try:
42     sys.path = ['/etc/planetlab'] + sys.path
43     import plc_config
44     api_server_url = "https://" + plc_config.PLC_API_HOST + plc_config.PLC_API_PATH
45 except:
46     filename=CONFIG_FILE
47     vars = read_config_file(filename)
48     api_server_url = vars['BOOT_API_SERVER']
49
50
51 class Auth:
52     def __init__(self, username=None, password=None, **kwargs):
53         if 'session' in kwargs:
54             self.auth= { 'AuthMethod' : 'session',
55                     'session' : kwargs['session'] }
56         else:
57             if username==None and password==None:
58                 self.auth = {'AuthMethod': "anonymous"}
59             else:
60                 self.auth = {'Username' : username,
61                             'AuthMethod' : 'password',
62                             'AuthString' : password}
63 class PLC:
64     def __init__(self, auth, url):
65         self.auth = auth
66         self.url = url
67         self.api = xmlrpclib.Server(self.url, verbose=False, allow_none=True)
68
69     def __getattr__(self, name):
70         method = getattr(self.api, name)
71         if method is None:
72             raise AssertionError("method does not exist")
73
74         return lambda *params : method(self.auth.auth, *params)
75
76     def __repr__(self):
77         return self.api.__repr__()
78
79 def extract_from(filename, pattern):
80     f = os.popen("grep -E %s %s" % (pattern, filename))
81     val = f.read().strip()
82     return val
83
84 def check_running(commandname):
85     f = os.popen("ps ax | grep -E %s | grep -v grep" % (commandname))
86     val = f.read().strip()
87     return val
88     
89
90 def main():
91
92     f=open(SESSION_FILE,'r')
93     session_str=f.read().strip()
94     api = PLC(Auth(session=session_str), api_server_url)
95     # NOTE: What should we do if this call fails?
96     api.AuthCheck()
97
98     try:
99         env = 'production'
100         if len(sys.argv) > 1:
101             env = sys.argv[1]
102     except:
103         traceback.print_exc()
104
105     while True:
106         try:
107             # NOTE: here we are inferring the runlevel by environmental
108             #         observations.  We know how this process was started by the
109             #         given command line argument.  Then in bootmanager
110             #         runlevle, the bm.log gives information about the current
111             #         activity.
112             # other options:
113             #   call plc for current boot state?
114             #   how long have we been running?
115             if env == "bootmanager":
116                 bs_val = extract_from('/tmp/bm.log', 'Current boot state:')
117                 if len(bs_val) > 0: bs_val = bs_val.split()[-1]
118                 ex_val = extract_from('/tmp/bm.log', 'Exception')
119                 fs_val = extract_from('/tmp/bm.log', 'mke2fs')
120                 bm_val = check_running("BootManager.py")
121
122                 if bs_val in ['diag', 'diagnose', 'safeboot', 'disabled', 'disable']:
123                     api.ReportRunlevel({'run_level' : 'safeboot'})
124
125                 elif len(ex_val) > len("Exception"):
126                     api.ReportRunlevel({'run_level' : 'failboot'})
127
128                 elif len(fs_val) > 0 and len(bm_val) > 0:
129                     api.ReportRunlevel({'run_level' : 'reinstall'})
130
131                 else:
132                     api.ReportRunlevel({'run_level' : 'failboot'})
133
134             elif env == "production":
135                 api.ReportRunlevel({'run_level' : 'boot'})
136             else:
137                 api.ReportRunlevel({'run_level' : 'failboot'})
138                 
139         except:
140             print "reporting error: ", os.popen("uptime").read().strip()
141             traceback.print_exc()
142
143         sys.stdout.flush()
144         # TODO: change to a configurable value
145         time.sleep(60*15)
146
147 if __name__ == "__main__":
148     main()