2e0af0e2c7dcbfc4914fbea31f41570fec11e264
[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 from nepi.resources.linux.node import OSType
43
44 from optparse import OptionParser, SUPPRESS_HELP
45
46 import os
47 import time
48
49 def add_node(ec, host, user, ssh_key = None):
50     node = ec.register_resource("LinuxNode")
51     ec.set(node, "hostname", host)
52     ec.set(node, "username", user)
53     ec.set(node, "identity", ssh_key)
54     ec.set(node, "cleanHome", 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("LinuxApplication")
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("LinuxApplication")
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("LinuxApplication")
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
155     usage = "usage: %prog -p <pl-host> -s <pl-slice> -l <linux-host> -u <linux-user> -m <movie> -e <exp-id> -i <ssh_key>"
156
157     parser = OptionParser(usage=usage)
158     parser.add_option("-p", "--pl-host", dest="pl_host", 
159             help="PlanetLab hostname (already added to the <pl-slice> on the web site)", 
160             default = pl_host, type="str")
161     parser.add_option("-s", "--pl-slice", dest="pl_slice", 
162             help="PlanetLab slicename", default = pl_slice, type="str")
163     parser.add_option("-l", "--linux-host", dest="linux_host", 
164             help="Hostname of second Linux host (non PlanetLab)",
165             default = linux_host, type="str")
166     parser.add_option("-u", "--linux-user", dest="linux_user", 
167             help="User for extra Linux host (non PlanetLab)", default = linux_host,
168             type="str")
169     parser.add_option("-m", "--movie", dest="movie", 
170             help="Stream movie", type="str")
171     parser.add_option("-e", "--exp-id", dest="exp_id", 
172             help="Label to identify experiment", type="str")
173     parser.add_option("-i", "--pl-ssh-key", dest="pl_ssh_key", 
174             help="Path to private SSH key to be used for connection", 
175             default = pl_ssh_key, type="str")
176
177     (options, args) = parser.parse_args()
178
179     if not options.movie:
180         parser.error("movie is a required argument")
181
182     return (options.pl_host, options.pl_slice, options.linux_host, 
183             options.linux_user, options.movie, options.exp_id, 
184             options.pl_ssh_key)
185
186 if __name__ == '__main__':
187     ( pl_host, pl_user, linux_host, linux_user, movie, exp_id, pl_ssh_key 
188             ) = get_options()
189
190     # Create the ExperimentController instance
191     ec = ExperimentController(exp_id = exp_id)
192
193     # Register ResourceManager (RM) 
194
195     # Register first PlanetLab host
196     node1 = add_node(ec, pl_host, pl_user, pl_ssh_key)
197
198     # Register CCN setup for PL host
199     peers = [linux_host]
200     ccnd1 = add_ccnd(ec, OSType.FEDORA, peers)
201     ec.register_connection(ccnd1, node1)
202
203     # Register content producer application (ccnseqwriter)
204     pub = add_publish(ec, movie)
205     ec.register_connection(pub, node1)
206
207     # The movie can only be published after ccnd is running
208     ec.register_condition(pub, ResourceAction.START, 
209             ccnd1, ResourceState.STARTED)
210    
211     # Register Linux host
212     node2 = add_node(ec, linux_host, linux_user)
213
214     # Register CCN setup for Linux host
215     peers = [pl_host]
216     ccnd2 = add_ccnd(ec, "ubuntu", peers)
217     ec.register_connection(ccnd2, node2)
218      
219     # Register consumer application (ccncat)
220     stream = add_stream(ec)
221     ec.register_connection(stream, node2)
222
223     # The stream can only be retrieved after ccnd is running
224     ec.register_condition(stream, ResourceAction.START, 
225             ccnd2, ResourceState.STARTED)
226
227     # And also, the stream can only be retrieved after it was published
228     ec.register_condition(stream, ResourceAction.START, 
229             pub, ResourceState.STARTED)
230  
231     # Deploy all ResourceManagers
232     ec.deploy()
233
234     # Wait until the applications are finished
235     apps = [ccnd1, pub, ccnd2, stream]
236     ec.wait_finished(apps)
237
238     # Shutdown the experiment controller
239     ec.shutdown()
240