3 from nepi.core.design import ExperimentDescription, FactoriesProvider
4 from nepi.core.execute import ExperimentController
5 from nepi.util.constants import ApplicationStatus as AS
8 from optparse import OptionParser, SUPPRESS_HELP
17 # Trak SIGTERM, and set global termination flag instead of dying
19 def _finalize(sig,frame):
21 TERMINATE.append(None)
22 signal.signal(signal.SIGTERM, _finalize)
23 signal.signal(signal.SIGINT, _finalize)
25 def create_slice_desc(slicename, plc_host, pl_user, pl_pwd, pl_ssh_key,
26 port_base, root_dir, exp_desc):
27 pl_provider = FactoriesProvider("planetlab")
28 slice_desc = exp_desc.add_testbed_description(pl_provider)
29 slice_desc.set_attribute_value("homeDirectory", root_dir)
30 slice_desc.set_attribute_value("slice", slicename)
31 slice_desc.set_attribute_value("sliceSSHKey", pl_ssh_key)
32 slice_desc.set_attribute_value("authUser", pl_user)
33 slice_desc.set_attribute_value("authPass", pl_pwd)
34 slice_desc.set_attribute_value("plcHost", plc_host)
35 slice_desc.set_attribute_value("tapPortBase", port_base)
36 # Kills all running processes before starting the experiment
37 slice_desc.set_attribute_value("dedicatedSlice", True)
38 slice_desc.set_attribute_value("plLogLevel", "DEBUG")
41 def create_node(hostname, pl_inet, slice_desc):
42 pl_node = slice_desc.create("Node")
43 pl_node.set_attribute_value("hostname", hostname)
44 pl_node.set_attribute_value("label", hostname)
45 pl_iface = slice_desc.create("NodeInterface")
46 #pl_iface.set_attribute_value("label", "iface_%s" % hostname)
47 pl_iface.connector("inet").connect(pl_inet.connector("devs"))
48 pl_node.connector("devs").connect(pl_iface.connector("node"))
51 def create_tunnel(node, peer, pl_nodes, slice_desc, subnet):
52 pl_node = pl_nodes[node]
53 pl_peer = pl_nodes[peer]
55 pl_tun = slice_desc.create("TunInterface")
56 pl_tun.set_attribute_value("label", "tun_%s%s" % (node, peer))
57 pl_node.connector("devs").connect(pl_tun.connector("node"))
59 pl_tunpeer = slice_desc.create("TunInterface")
60 pl_tunpeer.set_attribute_value("label", "tun_%s%s" % (peer, node))
61 pl_peer.connector("devs").connect(pl_tunpeer.connector("node"))
63 pl_tun.connector("udp").connect(pl_tunpeer.connector("udp"))
65 iterhosts = subnet.iterhosts()
66 addr = iterhosts.next()
67 ip = pl_tun.add_address()
68 ip.set_attribute_value("Address", addr.exploded)
69 ip.set_attribute_value("NetPrefix", subnet.prefixlen)
71 peeraddr = iterhosts.next()
72 peerip = pl_tunpeer.add_address()
73 peerip.set_attribute_value("Address", peeraddr.exploded)
74 peerip.set_attribute_value("NetPrefix", subnet.prefixlen)
76 def create_ccnd(pl_node, slice_desc):
77 pl_app = slice_desc.create("CCNxDaemon")
78 # Add multicast ccn route
79 #pl_app.set_attribute_value("ccnroutes", "udp 224.0.0.204 2869")
80 pl_app.enable_trace("stdout")
81 pl_app.enable_trace("stderr")
82 pl_app.connector("node").connect(pl_node.connector("apps"))
84 def create_ccnsendchunks(pl_node, slice_desc):
85 pl_app = slice_desc.create("Application")
86 path_to_video = os.path.join(os.path.dirname(os.path.abspath(__file__)),
87 "big_buck_bunny_240p_mpeg4_lq.ts")
88 pl_app.set_attribute_value("stdin", path_to_video)
89 pl_app.set_attribute_value("command", "ccnsendchunks ccnx:/VIDEO")
90 pl_app.enable_trace("stdout")
91 pl_app.enable_trace("stderr")
92 pl_app.connector("node").connect(pl_node.connector("apps"))
95 def exec_ccncatchunks(slicename, hostname):
96 print "Starting Vlc streamming ..."
97 login = "%s@%s" % (slicename, hostname)
98 command = 'PATH=$PATH:$(ls | egrep nepi-ccnd- | head -1)/bin; ccncatchunks2 ccnx:/VIDEO'
99 proc1 = subprocess.Popen(['ssh', login, command], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell = False)
100 proc2 = subprocess.Popen(['vlc', '-'], stdin=proc1.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
103 def create_ed(hostnames, vsys_vnet, slicename, plc_host, pl_user, pl_pwd, pl_ssh_key,
104 port_base, root_dir):
106 # Create the experiment description object
107 exp_desc = ExperimentDescription()
109 # Create the slice description object
110 slice_desc = create_slice_desc(slicename, plc_host, pl_user, pl_pwd, pl_ssh_key,
111 port_base, root_dir, exp_desc)
113 # Create the Internet box object
114 pl_inet = slice_desc.create("Internet")
116 # Create the Node boxes
118 for hostname in hostnames:
119 pl_node = create_node(hostname, pl_inet, slice_desc)
120 pl_nodes[hostname] = pl_node
122 # Get the base network segment (slice vsys_vnet) to assign all the IP addresses
123 # to the virtual interfaces
124 base = ipaddr.IPNetwork(vsys_vnet)
126 # Calculate the number of virtual networks required to connect all the nodes
127 # with all other nodes as the binomial coeficient C(n, 2), with n = #nodes
129 c = math.factorial(n) / (2 * math.factorial(n-2))
131 # Validate that we can get 'c' /30 subnetworks
132 if c > math.pow(2, (30 - base.prefixlen)):
133 raise RuntimeError("Insufficient address segment %s for experiment", vsys_vnet)
135 # Create the subnetwors iterator
136 iter_sub = base.iter_subnets(new_prefix=30)
138 # Create tunnels between nodes
139 for i, node in enumerate(hostnames):
140 peers = hostnames[i+1:]
142 subnet = iter_sub.next()
143 create_tunnel(node, peer, pl_nodes, slice_desc, subnet)
145 # Create ccnd daemons in all nodes
146 for pl_node in pl_nodes.values():
147 create_ccnd(pl_node, slice_desc)
149 # Create a ccnsendchunks in a randomly chosen node to publish some content
150 hostname = random.choice(pl_nodes.keys())
151 pl_node = pl_nodes[hostname]
152 pl_app = create_ccnsendchunks(pl_node, slice_desc)
154 return exp_desc, pl_nodes, hostname, pl_app
156 def run(hostnames, vsys_vnet, slicename, plc_host, pl_user, pl_pwd, pl_ssh_key,
157 port_base, root_dir):
159 exp_desc, pl_nodes, hostname, pl_app = create_ed(hostnames, vsys_vnet,
160 slicename, plc_host, pl_user, pl_pwd, pl_ssh_key, port_base,
163 xml = exp_desc.to_xml()
164 controller = ExperimentController(xml, root_dir)
167 while not TERMINATE and controller.status(pl_app.guid) == AS.STATUS_NOT_STARTED:
172 hostnames = pl_nodes.keys()
173 hostnames.remove(hostname)
174 # Randomnly choose a different hostname, than the one executing
175 # ccnsendchunks, to execute ccncatchunks and retrieve the VIDEO
176 hostname = random.choice(hostnames)
177 proc = exec_ccncatchunks(slicename, hostname)
179 while not TERMINATE and proc and proc.poll() is None:
184 err = proc.stderr.read()
187 out = proc.stdout.read()
191 controller.shutdown()
193 if __name__ == '__main__':
194 root_dir = tempfile.mkdtemp()
195 slicename = os.environ.get("PL_SLICE")
196 pl_host = os.environ.get("PL_HOST", "www.planet-lab.eu")
197 port_base = 2000 + (os.getpid() % 1000) * 13
198 pl_ssh_key = os.environ.get(
200 "%s/.ssh/id_rsa_planetlab" % (os.environ['HOME'],) )
201 pl_user = os.environ.get('PL_USER')
202 pl_pwd = os.environ.get('PL_PASS')
203 pl_vsys_vnet = os.environ.get('PL_VSYS_NET')
204 pl_hostnames = os.environ.get('PL_HOSTNAMES')
205 default_hostnames = ['openlab02.pl.sophia.inria.fr',
207 #'planetlab2.di.unito.it',
208 #'merkur.planetlab.haw-hamburg.de',
209 #'planetlab1.cs.uit.no',
210 #'planetlab3.cs.st-andrews.ac.uk',
211 #'planetlab2.cs.uoi.gr',
212 #'planetlab3.xeno.cl.cam.ac.uk',
213 #'planet2.inf.tu-dresden.de',
214 #'planetlab2.csg.uzh.ch',
215 #'planetlab2.upm.ro',
216 #'planetlab-um00.di.uminho.pt',
217 #'planetlabpc2.upf.edu',
219 'planetlab2.esprit-tn.com' ]
221 usage = "usage: %prog -s <pl_slice> -H <pl_host> -k <ssh_key> -u <pl_user> -p <pl_password> -v <vsys_vnet> -N <host_names> "
223 parser = OptionParser(usage=usage)
224 parser.add_option("-s", "--slicename", dest="slicename",
225 help="PlanetLab slicename", default=slicename, type="str")
226 parser.add_option("-H", "--pl-host", dest="pl_host",
227 help="PlanetLab site (e.g. www.planet-lab.eu)",
228 default=pl_host, type="str")
229 parser.add_option("-k", "--ssh-key", dest="pl_ssh_key",
230 help="Path to private ssh key used for PlanetLab authentication",
231 default=pl_ssh_key, type="str")
232 parser.add_option("-u", "--pl-user", dest="pl_user",
233 help="PlanetLab account user (i.e. Registration email address)",
234 default=pl_user, type="str")
235 parser.add_option("-p", "--pl-pwd", dest="pl_pwd",
236 help="PlanetLab account password", default=pl_pwd, type="str")
237 parser.add_option("-v", "--vsys-vnet", dest="vsys_vnet",
238 help="Value of the vsys_vnet tag addigned to your slice. (e.g. 192.168.3.0/16)",
239 default=pl_vsys_vnet, type="str")
240 parser.add_option("-N", "--host-names", dest="hostnames",
241 help="Comma separated list of PlanetLab hostnames to use",
242 default=pl_hostnames, type="str")
243 (options, args) = parser.parse_args()
245 hostnames = map(string.strip, options.hostnames.split(",")) if options.hostnames else default_hostnames
246 vsys_vnet = options.vsys_vnet
247 slicename = options.slicename
248 pl_host = options.pl_host
249 pl_user= options.pl_user
250 pl_pwd = options.pl_pwd
251 pl_ssh_key = options.pl_ssh_key
254 hostnames = ['nepi1.pl.sophia.inria.fr',
255 'nepi2.pl.sophia.inria.fr',
256 'nepi3.pl.sophia.inria.fr',
257 'nepi5.pl.sophia.inria.fr']
259 pl_host = "nepiplc.pl.sophia.inria.fr"
260 vsys_vnet = "192.168.2.0/24"
263 run(hostnames, vsys_vnet, slicename, pl_host, pl_user, pl_pwd, pl_ssh_key,