import repository from arizona
[raven.git] / publish / smbaker-experiment / build / viniexperiment / usr / local / bin / viniexperiment.py
1 #!/usr/bin/python
2
3 import fcntl
4 import os
5 import subprocess
6 import sys
7 from owl import Field, Owl
8 import socket
9
10 import vinirspecparse
11
12 OWL_URL = "http://owl.cs.arizona.edu/owl/"
13 DBS = ["vini2"]
14
15 glo_nodeid = "unknown"
16 glo_nodes = {}
17
18 def load_ifconfig():
19     args = ["/sbin/ifconfig"]
20     sub = subprocess.Popen(args, stderr = subprocess.STDOUT, stdout = subprocess.PIPE)
21     sub.wait()
22
23     if (sub.returncode != 0):
24         print >> sys.stderr, "ifconfig failed with error", sub.returncode
25         return []
26
27     interfaces = {}
28
29     interface = None
30
31     for line in sub.stdout.readlines():
32         if (len(line)<=1):
33             interface = None
34             continue
35
36         if (line[0] != " "):
37             interface = line.split()[0]
38             interfaces[interface] = {"interface": interface}
39
40         if (interface == None):
41             continue
42
43         # cleanup a few things to make them easier to parse
44         line = line.replace("HWaddr ", "HWaddr:")
45         line = line.replace("addr: ", "addr:")
46
47         line = line.strip()
48         parts = line.split()
49
50         prefix = ""
51         if (len(parts)>0):
52             if parts[0] == "RX":
53                 prefix = "rx_"
54             elif parts[0] == "TX":
55                 prefix = "tx_"
56             elif parts[0] == "inet":
57                 prefix = "inet_"
58             elif parts[0] == "inet6":
59                 prefix = "inet6_"
60
61         for part in parts:
62             if ":" in part:
63                 (tag,value) = part.split(":",1)
64
65                 tag = (prefix+tag).lower()
66
67                 dict = interfaces[interface]
68                 dict[tag] = value
69
70     return interfaces
71
72 def dump_interfaces(interfaces):
73     for interface in interfaces.keys():
74         dict = interfaces[interface]
75         print interface+":"
76         for key in dict:
77             print "  ", key+":", dict[key]
78
79 def ping(remote_addr):
80     args = ["ping", "-c", "5", "-i", "0.2", remote_addr]
81
82     sub = subprocess.Popen(args, stderr = subprocess.STDOUT, stdout = subprocess.PIPE)
83     sub.wait()
84     if (sub.returncode != 0):
85         print >> sys.stderr, "ping of", remote_addr, "failed with error", sub.returncode
86         return None
87
88     avg = None
89     for line in sub.stdout.readlines():
90         parts = line.strip().split()
91         if len(parts)>=5:
92             if parts[0] == "rtt":
93                 units = parts[4]
94                 funcs = parts[3].split("/")
95                 if len(funcs)>=4:
96                     avg = funcs[1]
97
98     if not avg:
99         print >> sys.stderr, "failed to extract average ping time"
100         return None
101
102     avg = float(avg)
103
104     # if units are not milliseconds, adjust
105     if (units == "s"):
106         avg = avg/1000.0
107
108     print "ping remote:", remote_addr, "result:", avg
109
110     return avg
111
112 def is_nodeid_lower(a,b):
113     try:
114        # convert them to integers and compare
115        a=int(a)
116        b=int(b)
117        return (a<b)
118     except:
119        # if something went wrong, just return True
120        return True
121
122 def ping_interface(interface):
123     global glo_nodeid
124
125     local_addr = interface.get("inet_addr", None)
126     if not local_addr:
127         print >> sys.stderr, "failed to determine local addr for", interface
128         return
129
130     remote_nodeid = interface["interface"]
131     if remote_nodeid[:4] == "a10x":
132         remote_nodeid = remote_nodeid[4:]
133
134     if not is_nodeid_lower(glo_nodeid, remote_nodeid):
135         print "skipping ping of", remote_nodeid, "because it's less than", glo_nodeid
136         return
137
138     parts = local_addr.split(".")
139     net = int(parts[3]) & 252
140     x = int(parts[3]) & ~252
141     if (x==1):
142        y = 2
143     else:
144        y = 1
145     remote_addr = ".".join(parts[:3]) + "." + str(net + y)
146
147     result = ping(remote_addr)
148
149     if result != None:
150         report_owl(glo_nodeid, remote_nodeid, result)
151
152 def ping_all(interfaces):
153     for interface in interfaces.keys():
154         if (interface[0] == "a"):
155             ping_interface(interfaces[interface])
156
157     #ping("198.0.0.108")
158
159 def node_id_to_name(x):
160     x=str(x)
161     if not x.startswith("n"):
162         x="n"+x
163
164     if x in glo_nodes:
165         node = glo_nodes[x]
166         return node.get("hostname", "unknown-hostname")
167     else:
168         return "not-in-nodelist"
169
170 def report_owl(local_nodeid, remote_nodeid, pingtime):
171     local_hostname = node_id_to_name(local_nodeid)
172     remote_hostname = node_id_to_name(remote_nodeid)
173
174     values = {}
175     values["basic.id"] = "n" + local_nodeid + "-" + "n" + remote_nodeid
176     values["vini.endpoint1"] = local_nodeid
177     values["vini.endpoint2"] = remote_nodeid
178     values["vini.hostname1"] = local_hostname
179     values["vini.hostname2"] = remote_hostname
180     values["vini.ping"] = int(pingtime)
181
182     print "updating owl"
183     print values
184
185     owl = Owl(OWL_URL, 10, 600, 600)
186     owl.update(DBS, values)
187
188     print "update complete"
189
190 def register_owl():
191     print "registering with owl"
192
193     owl = Owl(OWL_URL, 10, 600, 600)
194
195     fBasicID = Field("id", "basic", "string", "ID")
196     owl.register(DBS, "basic", "1.0", [fBasicID], "Basic")
197
198     fViniEndpoint1 = Field("endpoint1", "vini", "string", "endpoint 1")
199     fViniHost1 = Field("hostname1", "vini", "string", "hostname 1")
200     fViniEndpoint2 = Field("endpoint2", "vini", "string", "endpoint 2")
201     fViniHost2 = Field("hostname2", "vini", "string", "hostname 2")
202     fViniPing = Field("ping", "vini", "integer", "ping (ms)")
203     owl.register(DBS, "vini", "1.4", [fViniEndpoint1, fViniHost1, fViniEndpoint2, fViniHost2, fViniPing])
204
205     """
206     XXX decided not to do this....
207     fViniLat1 = Field("latitude1", "vinicoords", "string", "latitude1")
208     fViniLong1 = Field("longitude1", "vinicoords", "string", "longitude1")
209     fViniLat2 = Field("latitude2", "vinicoords", "string", "latitude2")
210     fViniLong2 = Field("latitude2", "vinicoords", "string", "longitude2")
211     owl.register(DBS, "vinicoords", "1.0", [fViniLat1, fViniLong1, fViniLat2, fViniLong2])
212     """
213
214     print "registration complete"
215
216 def check_only_one_instance():
217     fp = open("/tmp/viniexperiment.pid", 'w')
218     try:\r
219         fcntl.lockf(fp, fcntl.LOCK_EX | fcntl.LOCK_NB)\r
220     except IOError:\r
221         # another instance is running\r
222         print >> sys.stderr, "This program is already running"\r
223         sys.exit(0)\r
224 \r
225     return fp\r
226
227 def main():
228     global glo_nodeid
229     global glo_nodes
230
231     mutex = check_only_one_instance()
232
233     if os.path.exists("/etc/planetlab/node_id"):
234         glo_nodeid = file("/etc/planetlab/node_id").readline().strip()
235
236     if os.path.exists("/etc/viniexperiment/vini_rspec.xml"):
237        glo_nodes = vinirspecparse.parse_rspec("/etc/viniexperiment/vini_rspec.xml")
238
239     register_owl()
240
241     interfaces = load_ifconfig()
242     dump_interfaces(interfaces)
243     ping_all(interfaces)
244
245 if __name__=="__main__":
246     main()