b8132e52db4513a07948863f9f58b3a265573d7d
[nepi.git] / src / nepi / data / processing / ping / parser.py
1 #!/usr/bin/env python
2
3 ###############################################################################
4 #
5 #    CCNX benchmark
6 #    Copyright (C) 2014 INRIA
7 #
8 #    This program is free software: you can redistribute it and/or modify
9 #    it under the terms of the GNU General Public License version 2 as
10 #    published by the Free Software Foundation;
11 #
12 #    This program is distributed in the hope that it will be useful,
13 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #    GNU General Public License for more details.
16 #
17 #    You should have received a copy of the GNU General Public License
18 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 #
20 #
21 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
22 #
23 ###############################################################################
24
25 #
26 # This library contains functions to parse log files generated using ping. 
27 #
28
29 import collections
30 import re
31 import os
32
33 # RE to match line starting "traceroute to"
34 _rre = re.compile("\d+ bytes from ((?P<hostname>[^\s]+) )?\(?(?P<ip>[^\s]+)\)??: icmp_.eq=\d+ ttl=\d+ time=(?P<time>[^\s]+) ms")
35
36 def parse_file(filename):
37     """
38         filename: path to traceroute file
39
40     """
41
42     f = open(filename, "r")
43
44     # Traceroute info
45     target_ip = None
46     target_hostname = None
47    
48     data = []
49
50     for line in f:
51         # match traceroute to ...
52         m = re.match(_rre, line)
53         if not m:
54             continue
55
56         target_ip = m.groupdict()["ip"]
57         # FIX THIS: Make sure the regular expression does not inlcude 
58         # the ')' in the ip group 
59         target_ip = target_ip.replace(")","")
60         target_hostname = m.groupdict()["hostname"]
61         time = m.groupdict()["time"]
62         data.append((target_ip, target_hostname, time))
63
64     f.close()
65
66     return data
67
68 def annotate_cn_node(graph, nid1, ips2nid, data):
69     for (target_ip, target_hostname, time) in data:
70         nid2 = ips2nid[target_ip]
71
72         if "delays" not in graph.edge[nid1][nid2]:
73             graph.edge[nid1][nid2]["delays"] = []
74
75         time = float(time.replace("ms", "").replace(" ",""))
76
77         graph.edge[nid1][nid2]["delays"].append(time)
78
79 def annotate_cn_graph(logs_dir, graph): 
80     """ Add delay inormation to graph using data collected using
81     ping.
82
83     """
84     ips2nid = dict()
85
86     for nid in graph.nodes():
87         ips = graph.node[nid]["ips"]
88         for ip in ips:
89             ips2nid[ip] = nid
90
91     # Walk through the ping logs...
92     found_files = False
93
94     for dirpath, dnames, fnames in os.walk(logs_dir):
95         # continue if we are not at the leaf level (if there are subdirectories)
96         if dnames: 
97             continue
98         
99         # Each dirpath correspond to a different host
100         nid = os.path.basename(dirpath)
101     
102         for fname in fnames:
103             if fname.endswith(".ping"):
104                 found_files = True
105                 filename = os.path.join(dirpath, fname)
106                 data = parse_file(filename)
107                 annotate_cn_node(graph, nid, ips2nid, data)
108
109     if not found_files:
110         msg = "No PING output files were found to parse at %s " % logs_dir 
111         raise RuntimeError, msg
112
113     # Take as weight the most frequent value
114     for nid1, nid2 in graph.edges():
115         delays = collections.Counter(graph.edge[nid1][nid2]["delays"])
116         weight = delays.most_common(1)[0][0]
117         del graph.edge[nid1][nid2]["delays"]
118         graph.edge[nid1][nid2]["weight"] = weight
119
120     return graph
121
122