import repository from arizona
[raven.git] / tools / phonehome / phonehome.py
1 #! /usr/bin/python
2 import os
3 import getopt
4 import time
5 import socket
6 import sys
7
8 import sieve
9
10 glo_status = 0
11
12 # simple checksum
13 def checksum256(st, modulo=256):
14     return reduce(lambda x,y:x+y, map(ord, st)) % modulo\r
15 \r
16 def do_random_delay():\r
17    delay = checksum256(socket.gethostname(), 157)\r
18    print "delaying " + str(delay) + " minutes"\r
19    time.sleep(delay * 60)\r
20
21 # do_tarbench is a benchmark that un-tars a large tarball
22 def do_tarbench():
23    global glo_status
24
25    print "running tarbench"
26
27    glo_status = os.system("tar -xjf bigtarball.tar.bz2")
28
29
30 def do_sha1bench():
31    global glo_status
32
33    print "running sha1bench"
34
35    glo_status = os.system("openssl dgst -sha1 bigtarball.tar.bz2")
36
37 def do_cpubench():
38    # cpu intensive benchmark - sieve of primes to 20,000,000
39    # this also consumes a fair amount of memory
40    # 7-23-07: scaled this back from 20,000,000 to 10,000,000 due to memory
41    # consumption
42
43    print "running cpubench"
44
45    for i in sieve.eratosthenes():
46        if i>10000000:
47            return
48    return
49
50 def do_loopbench():
51    print "running loopbench"
52
53    # cpu intensive benchmark - large nested loop
54    for i in range(0, 1000):
55        for j in range(0, 1000):
56            for k in range(0, 1000):
57                pass
58
59 def do_membench():
60    # memory intensive benchmark
61
62    print "running membench"
63
64    # 48 megabytes of 4000 byte strings, ought to consume about a page each
65    mb = 48
66    strsize = 4000
67    numstr = mb*1024*1024/strsize
68
69    # make the 4000 byte string
70    print "creating long string"
71    longstring = ""
72    for i in range(0, strsize):
73        longstring = longstring + "a"
74
75    # make up a list of unique strings
76    bytes = 0
77    print "creating list of strings"
78    list = []
79    for i in range(0, numstr):
80       thisstr = longstring + str(i)
81       list.append(thisstr)
82       bytes = bytes + len(thisstr)
83
84    print "wrote " + str(bytes/1024/1024) + " MB"
85
86    # touch the contents of all the elements in the list
87    print "reading the list of strings"
88    bytes = 0
89    for j in range(1, 1000):
90       for i in range(1, numstr):
91          foo = list[i-1] + list[i]
92          bytes = bytes + len(foo)
93
94    print "done, read " + str(bytes/1024/1024) + " MB"
95
96 def do_httpbench():
97    global glo_status
98
99    print "running httpbench"
100
101    glo_status = os.system("wget http://stork-repository.cs.arizona.edu/phonehome/10mbfile")
102
103 def do_s3bench():
104    global glo_status
105
106    print "running s3bench"
107
108    glo_status = os.system("wget http://s3.amazonaws.com/1rjppk51dyzqprs0h382stork/10mbfile")
109
110 # from arizonageneral.py
111 def getslicename():
112    try:
113       if os.path.isfile("/etc/slicename"):
114          slicefile = open("/etc/slicename")
115          slicename = slicefile.read().strip()
116          slicefile.close()
117       else:
118          return None
119    except (NameError, IOError):
120       return None
121
122    return slicename
123
124 def make_log_file(name):
125    name = "/tmp/" + name + ".log";
126
127    # remove the old one
128    if os.path.exists(name):
129       try:
130          os.remove(name)
131       except: # TODO: exception handling
132          print "failed to remove log file: " + name
133
134    try:
135       logfile = open(name, "w")
136       logfile.close()
137    except: # TODO: exception handling
138       print "failed to write log file: " + name
139
140 def get_file_modify_time(fn):
141    """ return last-modify-time of a file """
142    try:
143        return os.stat(fn)[8]
144    except: # TODO: exception handling
145        return -1
146
147 def get_log_time(fn):
148    """
149    Search for initscript log files in /usr/local/stork/var/log/initscript
150    and /tmp. Return the modify time of the newest log file.
151    """
152    t1 = -1
153    t2 = -1
154    fn1 = os.path.join("/usr/local/stork/var/log/initscript", fn)
155    if os.path.exists(fn1):
156        t1 = get_file_modify_time(fn)
157    fn2 = os.path.join("/tmp", fn)
158    if os.path.exists(fn2):
159        t2 = get_file_modify_time(fn2)
160    return max(t1, t2)
161
162 long_opts = ['delay=', "status=", "repeat="]
163
164 def main():
165    global glo_status
166
167    # get the time when the machine was booted
168    timeBoot = get_file_modify_time("/var/log/boot.log")
169
170    # get the time when the initscript was started
171    timeInitScriptStart = get_log_time("stork_initscript_stage1.log")
172
173    # get the time when the initscript installed the packages, before running
174    # stork for the first time
175    timeInitScriptPreRunStork = get_log_time("stork_initscript_stage2_prerunstork.log")
176
177    # get the time when the initscript was completed
178    timeInitScriptFinish = get_log_time("stork_initscript_stage2_complete.log")
179
180    slicename = getslicename()
181
182    if not slicename:
183       slicename = "unknownslicename"
184
185    # initialize default values for options
186    delay = 0
187    repeat_count = 1
188
189    # option processing
190    (options, tests) = getopt.getopt(sys.argv[1:], '', long_opts)
191    for opt in options:
192        name = opt[0]
193        val = opt[1]
194
195        if name == "--delay":
196            delay = int(val)
197        elif name == "--status":
198            glo_status = val
199        elif name == "--repeat":
200            repeat_count = int(val)
201
202    # the remaining arguments are the tests to run. If there is no argument, then
203    # assume we are doing a simple 'phonehome'.
204    if not tests:
205       tests = ["phonehome"]
206
207    while repeat_count > 0:
208       repeat_count = repeat_count - 1
209
210       if delay > 0:
211           print "delaying " + str(delay) + " seconds"
212           time.sleep(delay)
213
214       for name in tests:
215          timeTestStart =  time.time()
216
217          # if name is one of the benchmarks, then execute it
218          if name.startswith("tarbench"):
219             do_tarbench()
220          elif name.startswith("sha1bench"):
221             do_sha1bench()
222          elif name.startswith("cpubench"):
223             do_cpubench()
224          elif name.startswith("membench"):
225             do_membench()
226          elif name.startswith("loopbench"):
227             do_loopbench()
228          elif name.startswith("httpbench"):
229             do_httpbench()
230          elif name.startswith("delay"):
231             do_random_delay()
232          elif name.startswith("s3bench"):
233             do_s3bench()
234
235          # get the timestamp of the "lastinstall" log file. This will be the timestamp
236          # that a prior instance of phonehome was run.
237          timeLastInstall = get_file_modify_time("/tmp/lastinstall.log")
238
239          # make a couple of log files. The first is "lastinstall", which will always
240          # be created for the last package that was installed. It will let us
241          # measure package->package install times.
242          make_log_file("lastinstall")
243
244          # the second logfile is named after the test. It is not used yet.
245          make_log_file(name)
246
247          # the time we are ready to generate the report. If we ran a benchmark, then
248          # timeReport-timeTestStart is the elapsed time of the benchmark.
249          timeReport = time.time()
250
251          # for OWL - script
252          os.system("mkdir -p /usr/local/owl/scripts.d")
253          f = open("/usr/local/owl/scripts.d/" + name, "wt")
254          f.write("#!/bin/bash\n")
255          f.write("echo [" + name + "]\n")
256          #if (name == "phonehome"):
257          #    f.write("timeInitScript="+str(timeInitScriptFinish-timeInitScriptStart)+"\n")
258          f.write("echo timetest = %1.2f\n" % float(timeReport-timeTestStart))
259          f.write("echo timeinstall = %1.2f\n" % float(timeTestStart-timeLastInstall))
260          f.close()
261          os.system("chmod +x /usr/local/owl/scripts.d/" + name)
262
263          # for OWL - config file
264          os.system("mkdir -p /usr/local/owl/conf.d")
265          f = open("/usr/local/owl/conf.d/" + name + ".conf", "wt")
266          f.write("[Module]\n")
267          f.write("name = " + name + "\n")
268          f.write("version = 0.3\n");
269          f.write("heading = " + name + "\n");
270          f.write("fields = timetest,timeinstall\n")
271          f.write("[timetest]\n")
272          f.write("type = string\n")
273          f.write("heading = timeTest\n")
274          f.write("[timeinstall]\n")
275          f.write("type = string\n")
276          f.write("heading = timeInstall\n")
277          f.close()
278
279          retryCount = 0
280          retry = 5
281          delay = 1
282          while (retry > 0):
283             cmd = "curl http://stork-repository.cs.arizona.edu/phonehome/phonehome.php" + \
284                    "?name=" + name + \
285                    "\&slice=" + slicename + \
286                    "\&host=" + socket.gethostname() + \
287                    "\&timeBoot=" + str(int(timeBoot)) + \
288                    "\&timeNow=" + str(int(timeTestStart)) + \
289                    "\&retryCount=" + str(retryCount) + \
290                    "\&timeLastInstall=" + str(int(timeLastInstall)) + \
291                    "\&timeReport=" + str(int(timeReport)) + \
292                    "\&status=" + str(glo_status) + \
293                    "\&timeInitScriptStart=" + str(int(timeInitScriptStart)) + \
294                    "\&timeInitScriptPreRunStork=" + str(int(timeInitScriptPreRunStork)) + \
295                    "\&timeInitScriptFinish=" + str(int(timeInitScriptFinish))
296
297             print "executing: " + cmd
298
299             result = os.system(cmd)
300
301             if result == 0:
302                break
303
304             # exponential backoff on the retries. So far, this has not proven to be
305             # necessary, but in case we have network issues, a retry is a good idea.
306
307             print "retrying due to result " + str(result) + " delay = " + str(delay)
308             time.sleep(delay)
309             delay = delay * 2
310             retry = retry - 1
311
312             retryCount = retryCount + 1
313
314 if __name__ == "__main__":
315    main()