use print() - import print_function - should be fine for both py2 and py3
[nepi.git] / examples / ccn_emu_live / planetlab.py
1 #!/usr/bin/env python
2 #
3 #    NEPI, a framework to manage network experiments
4 #    Copyright (C) 2013 INRIA
5 #
6 #    This program is free software: you can redistribute it and/or modify
7 #    it under the terms of the GNU General Public License version 2 as
8 #    published by the Free Software Foundation;
9 #
10 #    This program is distributed in the hope that it will be useful,
11 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
12 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 #    GNU General Public License for more details.
14 #
15 #    You should have received a copy of the GNU General Public License
16 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 #
18 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
19
20 from __future__ import print_function
21
22 from nepi.execution.ec import ExperimentController 
23 from nepi.execution.runner import ExperimentRunner
24 from nepi.util.netgraph import NetGraph, TopologyType
25 import nepi.data.processing.ccn.parser as ccn_parser
26
27 import networkx
28 import socket
29 import os
30
31 PL_NODES = dict({
32     0: "iraplab1.iralab.uni-karlsruhe.de",
33     1: "planetvs2.informatik.uni-stuttgart.de",
34     2: "dfn-ple1.x-win.dfn.de",
35     3: "planetlab2.extern.kuleuven.be",
36     4: "mars.planetlab.haw-hamburg.de",
37     5: "planetlab-node3.it-sudparis.eu",
38     6: "node2pl.planet-lab.telecom-lille1.eu",
39     7: "planetlab1.informatik.uni-wuerzburg.de",
40     8: "planet1.l3s.uni-hannover.de",
41     9: "planetlab1.wiwi.hu-berlin.de",
42     10: "pl2.uni-rostock.de", 
43     11: "planetlab1.u-strasbg.fr",
44     12: "peeramidion.irisa.fr",
45     13: "planetlab2.unineuchatel.ch", 
46     })
47
48 pl_slice = os.environ.get("PL_SLICE")
49 pl_user = os.environ.get("PL_USER")
50 pl_password = os.environ.get("PL_PASS")
51 pl_ssh_key = os.environ.get("PL_SSHKEY")
52
53 content_name = "ccnx:/test/bunny.ts"
54
55 pipeline = 4 # Default value for ccncat
56
57 operating_system = "f14"
58
59 country = "germany"
60
61 repofile = os.path.join(
62         os.path.dirname(os.path.realpath(__file__)), "repoFile1.0.8.2")
63
64 def add_collector(ec, trace_name, subdir, newname = None):
65     collector = ec.register_resource("Collector")
66     ec.set(collector, "traceName", trace_name)
67     ec.set(collector, "subDir", subdir)
68     if newname:
69         ec.set(collector, "rename", newname)
70
71     return collector
72
73 def add_pl_host(ec, nid):
74     hostname = PL_NODES[nid]
75
76     # Add a planetlab host to the experiment description
77     host = ec.register_resource("planetlab::Node")
78     ec.set(host, "hostname", hostname)
79     ec.set(host, "username", pl_slice)
80     ec.set(host, "identity", pl_ssh_key)
81     #ec.set(host, "pluser", pl_user)
82     #ec.set(host, "plpassword", pl_password)
83     #ec.set(host, "country", country)
84     #ec.set(host, "operatingSystem", operating_system)
85     ec.set(host, "cleanExperiment", True)
86     ec.set(host, "cleanProcesses", True)
87
88     # Annotate the graph
89     ec.netgraph.annotate_node(nid, "hostname", hostname)
90     ec.netgraph.annotate_node(nid, "host", host)
91     
92     # Annotate the graph node with an ip address
93     ip = socket.gethostbyname(hostname)
94     ec.netgraph.annotate_node_ip(nid, ip)
95
96 def add_pl_ccnd(ec, nid):
97     # Retrieve annotation from netgraph
98     host = ec.netgraph.node_annotation(nid, "host")
99     
100     # Add a CCN daemon to the planetlab node
101     ccnd = ec.register_resource("linux::CCND")
102     ec.set(ccnd, "debug", 7)
103     ec.register_connection(ccnd, host)
104     
105     # Collector to retrieve ccnd log
106     collector = add_collector(ec, "stderr", nid, "log")
107     ec.register_connection(collector, ccnd)
108
109     # Annotate the graph
110     ec.netgraph.annotate_node(nid, "ccnd", ccnd)
111
112 def add_pl_ccnr(ec, nid):
113     # Retrieve annotation from netgraph
114     ccnd = ec.netgraph.node_annotation(nid, "ccnd")
115     
116     # Add a CCN content repository to the planetlab node
117     ccnr = ec.register_resource("linux::CCNR")
118
119     ec.set(ccnr, "repoFile1", repofile)
120     ec.register_connection(ccnr, ccnd)
121
122 def add_pl_ccncat(ec, nid):
123     # Retrieve annotation from netgraph
124     ccnd = ec.netgraph.node_annotation(nid, "ccnd")
125     
126     # Add a CCN cat application to the planetlab node
127     ccncat = ec.register_resource("linux::CCNCat")
128     ec.set(ccncat, "pipeline", pipeline)
129     ec.set(ccncat, "contentName", content_name)
130     ec.register_connection(ccncat, ccnd)
131
132 def add_pl_fib_entry(ec, nid1, nid2):
133     # Retrieve annotations from netgraph
134     ccnd1 = ec.netgraph.node_annotation(nid1, "ccnd")
135     hostname2 = ec.netgraph.node_annotation(nid2, "hostname")
136     
137     # Add a FIB entry between one planetlab node and its peer
138     entry = ec.register_resource("linux::FIBEntry")
139     ec.set(entry, "host", hostname2)
140     ec.register_connection(entry, ccnd1)
141
142     # Collector to retrieve peering ping output (to measure neighbors delay)
143     ec.enable_trace(entry, "ping")
144     collector = add_collector(ec, "ping", nid1)
145     ec.register_connection(collector, entry)
146
147     return entry
148
149 def avg_interests(ec, run):
150     ## Process logs
151     logs_dir = ec.run_dir
152
153     (graph,
154         content_names,
155         interest_expiry_count,
156         interest_dupnonce_count,
157         interest_count,
158         content_count) = ccn_parser.process_content_history_logs(
159                 logs_dir,
160                 ec.netgraph.topology,
161                 parse_ping_logs = True)
162
163     shortest_path = networkx.shortest_path(graph, 
164             source = ec.netgraph.sources()[0], 
165             target = ec.netgraph.targets()[0])
166
167     ### Compute metric: Avg number of Interests seen per content name
168     ###                 normalized by the number of nodes in the shortest path
169     content_name_count = len(content_names.values())
170     nodes_in_shortest_path = len(shortest_path) - 1
171     metric = interest_count / (float(content_name_count) * float(nodes_in_shortest_path))
172
173     # TODO: DUMP RESULTS TO FILE
174     # TODO: DUMP GRAPH DELAYS!
175     f = open("/tmp/metric", "a+")
176     f.write("%.2f\n" % metric)
177     f.close()
178     print(" METRIC", metric)
179
180     return metric
181
182 def add_pl_edge(ec, nid1, nid2):
183     #### Add connections between CCN nodes
184     add_pl_fib_entry(ec, nid1, nid2)
185     add_pl_fib_entry(ec, nid2, nid1)
186
187 def add_pl_node(ec, nid):
188     ### Add CCN nodes (ec.netgraph holds the topology graph)
189     add_pl_host(ec, nid)
190     add_pl_ccnd(ec, nid)
191         
192     if nid == ec.netgraph.targets()[0]:
193         add_pl_ccnr(ec, nid)
194
195     if nid == ec.netgraph.sources()[0]:
196         add_pl_ccncat(ec, nid)
197
198 if __name__ == '__main__':
199
200     #### Create NEPI Experiment Description with LINEAR topology 
201     ec = ExperimentController("pl_ccn", 
202             topo_type = TopologyType.LINEAR, 
203             node_count = 4, 
204             #assign_ips = True,
205             assign_st = True,
206             add_node_callback = add_pl_node, 
207             add_edge_callback = add_pl_edge)
208     
209     print("Results stored at", ec.exp_dir)
210
211     #### Retrieve the content producing resource to wait for ot to finish
212     ccncat = ec.filter_resources("linux::CCNCat")
213    
214     #### Run experiment until metric convergences
215     rnr = ExperimentRunner()
216     runs = rnr.run(ec, min_runs = 10, max_runs = 300, 
217             compute_metric_callback = avg_interests,
218             wait_guids = ccncat,
219             wait_time = 0)
220