2dc39abbdba2800d050efa48f16e4296ec17d017
[nepi.git] / examples / linux / testing / ccncat_2_nodes.py
1 #!/usr/bin/env python
2
3 #
4 #    NEPI, a framework to manage network experiments
5 #    Copyright (C) 2013 INRIA
6 #
7 #    This program is free software: you can redistribute it and/or modify
8 #    it under the terms of the GNU General Public License version 2 as
9 #    published by the Free Software Foundation;
10 #
11 #    This program is distributed in the hope that it will be useful,
12 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
13 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 #    GNU General Public License for more details.
15 #
16 #    You should have received a copy of the GNU General Public License
17 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 #
19 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
20
21
22 # NOTE: This experiment example uses the generic LinuxApplication
23 #       ResourceManager to do the CCN set up in the hosts.
24 #       Alternatively, CCN specific ResourceManagers can be used
25 #       (i.e. LinuxCCND, LinuxCCNR, etc...), and those require less 
26 #       manual configuration.
27 #
28 #
29
30 # CCN topology:
31 #
32 #                
33 #                 
34 #  content                ccncat
35 #  Linux host               Linux host
36 #  0 ------- Internet ------ 0
37 #           
38
39 from nepi.execution.ec import ExperimentController, ECState 
40 from nepi.execution.resource import ResourceState, ResourceAction 
41 from nepi.resources.linux.node import OSType
42
43 from optparse import OptionParser, SUPPRESS_HELP
44
45 import getpass
46 import os
47 import time
48
49 def add_node(ec, host, user, ssh_key = None):
50     node = ec.register_resource("linux::Node")
51     ec.set(node, "hostname", host)
52     ec.set(node, "username", user)
53     ec.set(node, "identity", ssh_key)
54     ec.set(node, "cleanExperiment", True)
55     ec.set(node, "cleanProcesses", True)
56     return node
57
58 def add_ccnd(ec, os_type, peers):
59     if os_type == OSType.FEDORA:
60         depends = ( " autoconf openssl-devel  expat-devel libpcap-devel "
61                 " ecryptfs-utils-devel libxml2-devel automake gawk " 
62                 " gcc gcc-c++ git pcre-devel make ")
63     else: # UBUNTU
64         depends = ( " autoconf libssl-dev libexpat-dev libpcap-dev "
65                 " libecryptfs0 libxml2-utils automake gawk gcc g++ "
66                 " git-core pkg-config libpcre3-dev make ")
67
68     sources = "http://www.ccnx.org/releases/ccnx-0.7.1.tar.gz"
69
70     build = (
71         # Evaluate if ccnx binaries are already installed
72         " ( "
73             "  test -f ${BIN}/ccnx-0.7.1/bin/ccnd"
74         " ) || ( "
75         # If not, untar and build
76             " ( "
77                 " mkdir -p ${SRC}/ccnx-0.7.1 && "
78                 " tar xf ${SRC}/ccnx-0.7.1.tar.gz --strip-components=1 -C ${SRC}/ccnx-0.7.1 "
79              " ) && "
80                 "cd ${SRC}/ccnx-0.7.1 && "
81                 # Just execute and silence warnings...
82                 "( ./configure && make ) "
83          " )") 
84
85     install = (
86         # Evaluate if ccnx binaries are already installed
87         " ( "
88             "  test -f ${BIN}/ccnx-0.7.1/bin/ccnd"
89         " ) || ( "
90             "  mkdir -p ${BIN}/ccnx-0.7.1/bin && "
91             "  cp -r ${SRC}/ccnx-0.7.1/bin ${BIN}/ccnx-0.7.1"
92         " )"
93     )
94
95     env = "PATH=$PATH:${BIN}/ccnx-0.7.1/bin"
96
97     # BASH command -> ' ccndstart ; ccndc add ccnx:/ udp  host ;  ccnr '
98     command = "ccndstart && "
99     peers = map(lambda peer: "ccndc add ccnx:/ udp  %s" % peer, peers)
100     command += " ; ".join(peers) + " && "
101     command += " ccnr & "
102
103     app = ec.register_resource("linux::Application")
104     ec.set(app, "depends", depends)
105     ec.set(app, "sources", sources)
106     ec.set(app, "install", install)
107     ec.set(app, "build", build)
108     ec.set(app, "env", env)
109     ec.set(app, "command", command)
110
111     return app
112
113 def add_publish(ec, movie):
114     env = "PATH=$PATH:${BIN}/ccnx-0.7.1/bin"
115     command = "ccnseqwriter -r ccnx:/VIDEO"
116
117     app = ec.register_resource("linux::Application")
118     ec.set(app, "stdin", movie)
119     ec.set(app, "env", env)
120     ec.set(app, "command", command)
121
122     return app
123
124 def add_stream(ec):
125     env = "PATH=$PATH:${BIN}/ccnx-0.7.1/bin"
126     command = "sudo -S dbus-uuidgen --ensure ; ( ccncat ccnx:/VIDEO | vlc - ) "
127
128     app = ec.register_resource("linux::Application")
129     ec.set(app, "depends", "vlc")
130     ec.set(app, "forwardX11", True)
131     ec.set(app, "env", env)
132     ec.set(app, "command", command)
133
134     return app
135
136 def get_options():
137     pl_slice = os.environ.get("PL_SLICE")
138
139     # We use a specific SSH private key for PL if the PL_SSHKEY is specified or the
140     # id_rsa_planetlab exists 
141     default_key = "%s/.ssh/id_rsa_planetlab" % (os.environ['HOME'])
142     default_key = default_key if os.path.exists(default_key) else None
143     pl_ssh_key = os.environ.get("PL_SSHKEY", default_key)
144
145     # Default planetlab host
146     pl_host = "planetlab2.u-strasbg.fr"
147
148     # Another Linux host 
149     # IMPORTANT NOTE: you must replace this host for another one
150     #       you have access to. You must set up your SSH keys so
151     #       the host can be accessed through SSH without prompting
152     #       for a password. The host must allow X forwarding using SSH.
153     linux_host = 'roseval.pl.sophia.inria.fr'
154     linux_user = getpass.getuser()
155     
156     usage = "usage: %prog -p <pl-host> -s <pl-slice> -l <linux-host> -u <linux-user> -m <movie> -e <exp-id> -i <ssh_key>"
157
158     parser = OptionParser(usage=usage)
159     parser.add_option("-p", "--pl-host", dest="pl_host", 
160             help="PlanetLab hostname (already added to the <pl-slice> on the web site)", 
161             default = pl_host, type="str")
162     parser.add_option("-s", "--pl-slice", dest="pl_slice", 
163             help="PlanetLab slicename", default = pl_slice, type="str")
164     parser.add_option("-l", "--linux-host", dest="linux_host", 
165             help="Hostname of second Linux host (non PlanetLab)",
166             default = linux_host, type="str")
167     parser.add_option("-u", "--linux-user", dest="linux_user", 
168             help="User for extra Linux host (non PlanetLab)", 
169             default = linux_user, type="str")
170     parser.add_option("-m", "--movie", dest="movie", 
171             help="Stream movie", type="str")
172     parser.add_option("-e", "--exp-id", dest="exp_id", 
173             help="Label to identify experiment", type="str")
174     parser.add_option("-i", "--pl-ssh-key", dest="pl_ssh_key", 
175             help="Path to private SSH key to be used for connection", 
176             default = pl_ssh_key, type="str")
177
178     (options, args) = parser.parse_args()
179
180     if not options.movie:
181         parser.error("movie is a required argument")
182
183     return (options.pl_host, options.pl_slice, options.linux_host, 
184             options.linux_user, options.movie, options.exp_id, 
185             options.pl_ssh_key)
186
187 if __name__ == '__main__':
188     ( pl_host, pl_user, linux_host, linux_user, movie, exp_id, pl_ssh_key 
189             ) = get_options()
190
191     # Create the ExperimentController instance
192     ec = ExperimentController(exp_id = exp_id)
193
194     # Register ResourceManager (RM) 
195
196     # Register first PlanetLab host
197     node1 = add_node(ec, pl_host, pl_user, pl_ssh_key)
198
199     # Register CCN setup for PL host
200     peers = [linux_host]
201     ccnd1 = add_ccnd(ec, OSType.FEDORA, peers)
202     ec.register_connection(ccnd1, node1)
203
204     # Register content producer application (ccnseqwriter)
205     pub = add_publish(ec, movie)
206     ec.register_connection(pub, node1)
207
208     # The movie can only be published after ccnd is running
209     ec.register_condition(pub, ResourceAction.START, 
210             ccnd1, ResourceState.STARTED)
211    
212     # Register Linux host
213     node2 = add_node(ec, linux_host, linux_user)
214
215     # Register CCN setup for Linux host
216     peers = [pl_host]
217     ccnd2 = add_ccnd(ec, "ubuntu", peers)
218     ec.register_connection(ccnd2, node2)
219      
220     # Register consumer application (ccncat)
221     stream = add_stream(ec)
222     ec.register_connection(stream, node2)
223
224     # The stream can only be retrieved after ccnd is running
225     ec.register_condition(stream, ResourceAction.START, 
226             ccnd2, ResourceState.STARTED)
227
228     # And also, the stream can only be retrieved after it was published
229     ec.register_condition(stream, ResourceAction.START, 
230             pub, ResourceState.STARTED)
231  
232     # Deploy all ResourceManagers
233     ec.deploy()
234
235     # Wait until the applications are finished
236     apps = [ccnd1, pub, ccnd2, stream]
237     ec.wait_finished(apps)
238
239     # Shutdown the experiment controller
240     ec.shutdown()
241