merges from v2
[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         # TODO: handle dns failure here.
97     api.AuthCheck()
98
99     try:
100         env = 'production'
101         if len(sys.argv) > 1:
102             env = sys.argv[1]
103     except:
104         traceback.print_exc()
105
106     while True:
107         try:
108             # NOTE: here we are inferring the runlevel by environmental
109             #         observations.  We know how this process was started by the
110             #         given command line argument.  Then in bootmanager
111             #         runlevle, the bm.log gives information about the current
112             #         activity.
113             # other options:
114             #   call plc for current boot state?
115             #   how long have we been running?
116             if env == "bootmanager":
117                 bs_val = extract_from('/tmp/bm.log', 'Current boot state:')
118                 if len(bs_val) > 0: bs_val = bs_val.split()[-1]
119                 ex_val = extract_from('/tmp/bm.log', 'Exception')
120                 fs_val = extract_from('/tmp/bm.log', 'mke2fs')
121                 bm_val = check_running("BootManager.py")
122
123                 if bs_val in ['diag', 'diagnose', 'safeboot', 'disabled', 'disable']:
124                     api.ReportRunlevel({'run_level' : 'safeboot'})
125
126                 elif len(ex_val) > len("Exception"):
127                     api.ReportRunlevel({'run_level' : 'failboot'})
128
129                 elif len(fs_val) > 0 and len(bm_val) > 0:
130                     api.ReportRunlevel({'run_level' : 'reinstall'})
131
132                 else:
133                     api.ReportRunlevel({'run_level' : 'failboot'})
134
135             elif env == "production":
136                 api.ReportRunlevel({'run_level' : 'boot'})
137             else:
138                 api.ReportRunlevel({'run_level' : 'failboot'})
139                 
140         except:
141             print "reporting error: ", os.popen("uptime").read().strip()
142             traceback.print_exc()
143
144         sys.stdout.flush()
145         # TODO: change to a configurable value
146         time.sleep(60*15)
147
148 if __name__ == "__main__":
149     main()