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