LinuxApplication: Changed directory structure to store experiment files in the Linux...
[nepi.git] / examples / linux / ccn / 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 as published by
9 #    the Free Software Foundation, either version 3 of the License, or
10 #    (at your option) any later version.
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 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
21
22
23 # NOTE: This experiment example uses the generic LinuxApplication
24 #       ResourceManager to do the CCN set up in the hosts.
25 #       Alternatively, CCN specific ResourceManagers can be used
26 #       (i.e. LinuxCCND, LinuxCCNR, etc...), and those require less 
27 #       manual configuration.
28 #
29 #
30
31 # CCN topology:
32 #
33 #                
34 #                 
35 #  content                ccncat
36 #  PL host               Linux host
37 #  0 ------- Internet ------ 0
38 #           
39
40 from nepi.execution.ec import ExperimentController, ECState 
41 from nepi.execution.resource import ResourceState, ResourceAction, \
42         populate_factory
43 from nepi.resources.linux.node import OSType
44
45 from optparse import OptionParser, SUPPRESS_HELP
46
47 import os
48 import time
49
50 def add_node(ec, host, user, ssh_key = None):
51     node = ec.register_resource("LinuxNode")
52     ec.set(node, "hostname", host)
53     ec.set(node, "username", user)
54     ec.set(node, "identity", ssh_key)
55     ec.set(node, "cleanHome", True)
56     ec.set(node, "cleanProcesses", True)
57     return node
58
59 def add_ccnd(ec, os_type, peers):
60     if os_type == OSType.FEDORA:
61         depends = ( " autoconf openssl-devel  expat-devel libpcap-devel "
62                 " ecryptfs-utils-devel libxml2-devel automake gawk " 
63                 " gcc gcc-c++ git pcre-devel make ")
64     else: # UBUNTU
65         depends = ( " autoconf libssl-dev libexpat-dev libpcap-dev "
66                 " libecryptfs0 libxml2-utils automake gawk gcc g++ "
67                 " git-core pkg-config libpcre3-dev make ")
68
69     sources = "http://www.ccnx.org/releases/ccnx-0.7.1.tar.gz"
70
71     build = (
72         # Evaluate if ccnx binaries are already installed
73         " ( "
74             "  test -f ${BIN}/ccnx-0.7.1/bin/ccnd"
75         " ) || ( "
76         # If not, untar and build
77             " ( "
78                 " mkdir -p ${SRC}/ccnx-0.7.1 && "
79                 " tar xf ${SRC}/ccnx-0.7.1.tar.gz --strip-components=1 -C ${SRC}/ccnx-0.7.1 "
80              " ) && "
81                 "cd ${SRC}/ccnx-0.7.1 && "
82                 # Just execute and silence warnings...
83                 "( ./configure && make ) "
84          " )") 
85
86     install = (
87         # Evaluate if ccnx binaries are already installed
88         " ( "
89             "  test -f ${BIN}/ccnx-0.7.1/bin/ccnd"
90         " ) || ( "
91             "  mkdir -p ${BIN}/ccnx-0.7.1/bin && "
92             "  cp -r ${SRC}/ccnx-0.7.1/bin ${BIN}/ccnx-0.7.1"
93         " )"
94     )
95
96     env = "PATH=$PATH:${BIN}/ccnx-0.7.1/bin"
97
98     # BASH command -> ' ccndstart ; ccndc add ccnx:/ udp  host ;  ccnr '
99     command = "ccndstart && "
100     peers = map(lambda peer: "ccndc add ccnx:/ udp  %s" % peer, peers)
101     command += " ; ".join(peers) + " && "
102     command += " ccnr & "
103
104     app = ec.register_resource("LinuxApplication")
105     ec.set(app, "depends", depends)
106     ec.set(app, "sources", sources)
107     ec.set(app, "install", install)
108     ec.set(app, "build", build)
109     ec.set(app, "env", env)
110     ec.set(app, "command", command)
111
112     return app
113
114 def add_publish(ec, movie):
115     env = "PATH=$PATH:${BIN}/ccnx-0.7.1/bin"
116     command = "ccnseqwriter -r ccnx:/VIDEO"
117
118     app = ec.register_resource("LinuxApplication")
119     ec.set(app, "stdin", movie)
120     ec.set(app, "env", env)
121     ec.set(app, "command", command)
122
123     return app
124
125 def add_stream(ec):
126     env = "PATH=$PATH:${BIN}/ccnx-0.7.1/bin"
127     command = "sudo -S dbus-uuidgen --ensure ; ( ccncat ccnx:/VIDEO | vlc - ) "
128
129     app = ec.register_resource("LinuxApplication")
130     ec.set(app, "depends", "vlc")
131     ec.set(app, "forwardX11", True)
132     ec.set(app, "env", env)
133     ec.set(app, "command", command)
134
135     return app
136
137 def get_options():
138     pl_slice = os.environ.get("PL_SLICE")
139
140     # We use a specific SSH private key for PL if the PL_SSHKEY is specified or the
141     # id_rsa_planetlab exists 
142     default_key = "%s/.ssh/id_rsa_planetlab" % (os.environ['HOME'])
143     default_key = default_key if os.path.exists(default_key) else None
144     pl_ssh_key = os.environ.get("PL_SSHKEY", default_key)
145
146     # Default planetlab host
147     pl_host = "planetlab2.u-strasbg.fr"
148
149     # Another Linux host 
150     # IMPORTANT NOTE: you must replace this host for another one
151     #       you have access to. You must set up your SSH keys so
152     #       the host can be accessed through SSH without prompting
153     #       for a password. The host must allow X forwarding using SSH.
154     linux_host = 'roseval.pl.sophia.inria.fr'
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)", default = linux_host,
169             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     # Search for available RMs
192     populate_factory()
193     
194     # Create the ExperimentController instance
195     ec = ExperimentController(exp_id = exp_id)
196
197     # Register ResourceManager (RM) 
198
199     # Register first PlanetLab host
200     node1 = add_node(ec, pl_host, pl_user, pl_ssh_key)
201
202     # Register CCN setup for PL host
203     peers = [linux_host]
204     ccnd1 = add_ccnd(ec, OSType.FEDORA, peers)
205     ec.register_connection(ccnd1, node1)
206
207     # Register content producer application (ccnseqwriter)
208     pub = add_publish(ec, movie)
209     ec.register_connection(pub, node1)
210
211     # The movie can only be published after ccnd is running
212     ec.register_condition(pub, ResourceAction.START, 
213             ccnd1, ResourceState.STARTED)
214    
215     # Register Linux host
216     node2 = add_node(ec, linux_host, linux_user)
217
218     # Register CCN setup for Linux host
219     peers = [pl_host]
220     ccnd2 = add_ccnd(ec, "ubuntu", peers)
221     ec.register_connection(ccnd2, node2)
222      
223     # Register consumer application (ccncat)
224     stream = add_stream(ec)
225     ec.register_connection(stream, node2)
226
227     # The stream can only be retrieved after ccnd is running
228     ec.register_condition(stream, ResourceAction.START, 
229             ccnd2, ResourceState.STARTED)
230
231     # And also, the stream can only be retrieved after it was published
232     ec.register_condition(stream, ResourceAction.START, 
233             pub, ResourceState.STARTED)
234  
235     # Deploy all ResourceManagers
236     ec.deploy()
237
238     # Wait until the applications are finished
239     apps = [ccnd1, pub, ccnd2, stream]
240     ec.wait_finished(apps)
241
242     # Shutdown the experiment controller
243     ec.shutdown()
244