2
2
from fabric .api import hide , lcd , local , settings , sudo
3
3
from inspect import getmembers , isfunction
4
4
from os import listdir
5
- from os .path import dirname , exists , expanduser , isdir , join
5
+ from os .path import dirname , exists , expanduser , join , splitext
6
6
from sys import modules
7
7
8
+ from .behaviors import MultiprocessedCommand
8
9
from .constants import CONTIKI_FOLDER , COOJA_FOLDER , EXPERIMENT_FOLDER , FRAMEWORK_FOLDER , TEMPLATES_FOLDER
9
10
from .decorators import command , expand_file , report_bad_input , stderr
10
- from .helpers import copy_files , copy_folder , move_folder , read_config , remove_files , remove_folder , \
11
- std_input , write_config
11
+ from .helpers import copy_files , copy_folder , move_files , move_folder , remove_files , remove_folder , \
12
+ std_input , read_config , write_config
12
13
from .install import check_cooja , modify_cooja , register_new_path_in_profile , \
13
14
update_cooja_build , update_cooja_user_properties
14
15
from .logconfig import logging , HIDDEN_ALL
@@ -23,8 +24,8 @@ def get_commands():
23
24
24
25
25
26
# ****************************** TASKS ON INDIVIDUAL EXPERIMENT ******************************
26
- @command (examples = ["my-simulation" ], autocomplete = lambda : list_experiments ())
27
27
@report_bad_input
28
+ @command (examples = ["my-simulation" ], autocomplete = lambda : list_experiments ())
28
29
def do_clean (name , ask = True ):
29
30
"""
30
31
Remove an experiment.
@@ -33,16 +34,16 @@ def do_clean(name, ask=True):
33
34
:param ask: ask confirmation
34
35
"""
35
36
if not exists (join (EXPERIMENT_FOLDER , name )):
36
- logging .debug (" > Folder does not exist !" )
37
+ logging .warning (" > Folder does not exist !" )
37
38
elif ask and std_input () == "yes" :
38
39
logging .debug (" > Cleaning folder..." )
39
40
with hide (* HIDDEN_ALL ):
40
41
with lcd (EXPERIMENT_FOLDER ):
41
42
local ("rm -rf {}" .format (name ))
42
43
43
44
44
- @command (examples = ["my-simulation true" ], autocomplete = lambda : list_experiments ())
45
45
@report_bad_input
46
+ @command (examples = ["my-simulation true" ], autocomplete = lambda : list_experiments ())
46
47
def do_cooja (name , with_malicious = False ):
47
48
"""
48
49
Start an experiment in Cooja with/without the malicious mote.
@@ -58,8 +59,8 @@ def do_cooja(name, with_malicious=False):
58
59
local ("make cooja-with{}-malicious" .format ("" if with_malicious else "out" ))
59
60
60
61
61
- @command (examples = ["my-simulation" , "my-simulation target=z1 debug=true" ], autocomplete = lambda : list_experiments ())
62
62
@report_bad_input
63
+ @command (examples = ["my-simulation" , "my-simulation target=z1 debug=true" ], autocomplete = lambda : list_experiments ())
63
64
def do_make (name , ** kwargs ):
64
65
"""
65
66
Make a new experiment.
@@ -69,9 +70,9 @@ def do_make(name, **kwargs):
69
70
"""
70
71
global reuse_bin_path
71
72
if exists (join (EXPERIMENT_FOLDER , name )):
72
- logging .debug (" > Folder already exists !" )
73
+ logging .warning (" > Folder already exists !" )
73
74
if std_input ("Proceed anyway ? (yes|no) [default: no] " ) != "yes" :
74
- return
75
+ exit ( 0 )
75
76
logging .info ("CREATING EXPERIMENT '{}'" .format (name ))
76
77
logging .debug (" > Validating parameters..." )
77
78
params = validated_parameters (kwargs )
@@ -144,18 +145,21 @@ def do_make(name, **kwargs):
144
145
remove_folder ((path , 'obj_{}' .format (params ["target" ])))
145
146
146
147
147
- @command (examples = ["my-simulation" ], autocomplete = lambda : list_experiments ())
148
148
@report_bad_input
149
+ @command (examples = ["my-simulation" ], autocomplete = lambda : list_experiments ())
149
150
def do_remake (name ):
150
151
"""
151
152
Remake the malicious mote of an experiment.
152
153
(meaning that it lets all simulation's files unchanged except ./motes/malicious.[target])
153
154
154
155
:param name: experiment name
155
156
"""
157
+ path = get_path (EXPERIMENT_FOLDER , name )
158
+ if not exists (path ):
159
+ logging .error ("Experiment '{}' does not exist !" .format (name ))
160
+ exit (2 )
156
161
logging .info ("REMAKING MALICIOUS MOTE FOR EXPERIMENT '{}'" .format (name ))
157
162
logging .debug (" > Retrieving parameters..." )
158
- path = get_path (EXPERIMENT_FOLDER , name )
159
163
params = read_config (path )
160
164
ext_lib = params .get ("ext_lib" )
161
165
logging .debug (" > Recompiling malicious mote..." )
@@ -194,29 +198,49 @@ def do_remake(name):
194
198
remove_folder ((path , 'obj_{}' .format (params ["target" ])))
195
199
196
200
197
- @command (examples = ["my-simulation" ], autocomplete = lambda : list_experiments ())
198
201
@report_bad_input
202
+ @command (examples = ["my-simulation" ], autocomplete = lambda : list_experiments (), behavior = MultiprocessedCommand )
199
203
def do_run (name ):
200
204
"""
201
205
Run an experiment.
202
206
203
207
:param name: experiment name
204
208
"""
205
- logging .info ("PROCESSING EXPERIMENT '{}'" .format (name ))
206
209
path = get_path (EXPERIMENT_FOLDER , name )
210
+ if not exists (path ):
211
+ logging .error ("Experiment '{}' does not exist !" .format (name ))
212
+ return False
213
+ logging .info ("PROCESSING EXPERIMENT '{}'" .format (name ))
214
+ check_structure (path , remove = True )
215
+ data , results = join (path , 'data' ), join (path , 'results' )
207
216
with hide (* HIDDEN_ALL ):
208
- with lcd (path ):
209
- logging .debug (" > Running both simulations (with and without the malicious mote)..." )
210
- local ("make run-without-malicious" )
211
- local ("make run-with-malicious" )
212
- remove_files (path ,
213
- 'COOJA.log' ,
214
- 'COOJA.testlog' )
217
+ for sim in ["without" , "with" ]:
218
+ with lcd (path ):
219
+ logging .debug (" > Running simulation {} the malicious mote..." .format (sim ))
220
+ local ("make run-{}-malicious" .format (sim ), capture = True )
221
+ remove_files (path ,
222
+ 'COOJA.log' ,
223
+ 'COOJA.testlog' )
224
+ # once the execution is over, gather the screenshots into a single GIF and keep the first and
225
+ # the last screenshots ; move these to the results folder
226
+ with lcd (data ):
227
+ local ('convert -delay 10 -loop 0 network*.png wsn-{}-malicious.gif' .format (sim ))
228
+ network_images = {int (fn .split ('.' )[0 ].split ('_' )[- 1 ]): fn for fn in listdir (data ) \
229
+ if fn .startswith ('network_' )}
230
+ move_files (data , results , 'wsn-{}-malicious.gif' .format (sim ))
231
+ net_start_old = network_images [min (network_images .keys ())]
232
+ net_start , ext = splitext (net_start_old )
233
+ net_start_new = 'wsn-{}-malicious_start{}' .format (sim , ext )
234
+ net_end_old = network_images [max (network_images .keys ())]
235
+ net_end , ext = splitext (net_end_old )
236
+ net_end_new = 'wsn-{}-malicious_end{}' .format (sim , ext )
237
+ move_files (data , results , (net_start_old , net_start_new ), (net_end_old , net_end_new ))
238
+ remove_files (data , * network_images .values ())
215
239
216
240
217
241
# ****************************** COMMANDS ON SIMULATION CAMPAIGN ******************************
218
- @command (examples = ["my-simulation-campaign" ], autocomplete = lambda : list_campaigns ())
219
242
@expand_file (EXPERIMENT_FOLDER , 'json' )
243
+ @command (examples = ["my-simulation-campaign" ], autocomplete = lambda : list_campaigns ())
220
244
def do_drop (exp_file = 'experiments' ):
221
245
"""
222
246
Remove a campaign of experiments.
@@ -229,8 +253,8 @@ def do_drop(exp_file='experiments'):
229
253
remove_files (EXPERIMENT_FOLDER , exp_file )
230
254
231
255
232
- @command (examples = ["my-simulation-campaign" ], autocomplete = lambda : list_campaigns ())
233
256
@expand_file (EXPERIMENT_FOLDER , 'json' )
257
+ @command (examples = ["my-simulation-campaign" ], autocomplete = lambda : list_campaigns ())
234
258
def do_make_all (exp_file = "experiments" ):
235
259
"""
236
260
Make a campaign of experiments.
@@ -244,8 +268,8 @@ def do_make_all(exp_file="experiments"):
244
268
do_make (name , ** params )
245
269
246
270
247
- @command (examples = ["my-simulation-campaign" ], autocomplete = lambda : list_campaigns ())
248
271
@expand_file (EXPERIMENT_FOLDER , 'json' )
272
+ @command (examples = ["my-simulation-campaign" ], autocomplete = lambda : list_campaigns ())
249
273
def do_prepare (exp_file = 'experiments' ):
250
274
"""
251
275
Create a campaign of experiments from a template.
@@ -257,8 +281,8 @@ def do_prepare(exp_file='experiments'):
257
281
copy_files (TEMPLATES_FOLDER , dirname (exp_file ), ('experiments.json' , exp_file ))
258
282
259
283
260
- @command (examples = ["my-simulation-campaign" ], autocomplete = lambda : list_campaigns ())
261
284
@expand_file (EXPERIMENT_FOLDER , 'json' )
285
+ @command (examples = ["my-simulation-campaign" ], autocomplete = lambda : list_campaigns ())
262
286
def do_run_all (exp_file = "experiments" ):
263
287
"""
264
288
Run a campaign of experiments.
@@ -271,7 +295,7 @@ def do_run_all(exp_file="experiments"):
271
295
272
296
273
297
# ************************************** INFORMATION COMMANDS *************************************
274
- @command (examples = ["experiments" , "campaigns" ], autocomplete = ["campaigns" , "experiments" ])
298
+ @command (examples = ["experiments" , "campaigns" ], autocomplete = ["campaigns" , "experiments" ], reexec_on_emptyline = True )
275
299
def do_list (item_type = None ):
276
300
"""
277
301
List all available items of a specified type.
@@ -302,7 +326,6 @@ def do_config(contiki_folder='~/contiki', experiments_folder='~/Experiments'):
302
326
f .write ('[RPL Attacks Framework Configuration]\n ' )
303
327
f .write ('contiki_folder = {}\n ' .format (contiki_folder ))
304
328
f .write ('experiments_folder = {}\n ' .format (experiments_folder ))
305
- do_config .description = "Create a configuration file at ~/.rpl-attacks.conf for RPL Attacks Framework."
306
329
307
330
308
331
@command ()
@@ -321,26 +344,39 @@ def do_setup():
321
344
"""
322
345
Setup the framework.
323
346
"""
347
+ logging .info ("SETTING UP OF THE FRAMEWORK" )
348
+ recompile = False
324
349
# install Cooja modifications
325
350
if not check_cooja (COOJA_FOLDER ):
326
- logging .info ( "INSTALLING COOJA ADD-ONS " )
351
+ logging .debug ( " > Installing Cooja add-ons... " )
327
352
# modify Cooja.java and adapt build.xml and ~/.cooja.user.properties
328
353
modify_cooja (COOJA_FOLDER )
329
354
update_cooja_build (COOJA_FOLDER )
330
355
update_cooja_user_properties ()
331
- # install VisualizerScreenshot plugin in Cooja
332
- visualizer = join (COOJA_FOLDER , 'apps' , 'visualizer_screenshot' )
333
- if not exists (visualizer ):
334
- logging .debug (" > Installing VisualizerScreenshot Cooja plugin..." )
335
- copy_folder ('src/visualizer_screenshot' , visualizer )
336
- # recompile Cooja for making the changes take effect
356
+ recompile = True
357
+ # install VisualizerScreenshot plugin in Cooja
358
+ visualizer = join (COOJA_FOLDER , 'apps' , 'visualizer_screenshot' )
359
+ if not exists (visualizer ):
360
+ logging .debug (" > Installing VisualizerScreenshot Cooja plugin..." )
361
+ copy_folder ('src/visualizer_screenshot' , visualizer )
362
+ recompile = True
363
+ # recompile Cooja for making the changes take effect
364
+ if recompile :
337
365
with lcd (COOJA_FOLDER ):
338
366
logging .debug (" > Recompiling Cooja..." )
339
367
with settings (warn_only = True ):
340
368
local ("ant clean" )
341
369
local ("ant jar" )
342
370
else :
343
- logging .info ("COOJA IS UP-TO-DATE" )
371
+ logging .debug (" > Cooja is up-to-date" )
372
+ # install imagemagick
373
+ with hide (* HIDDEN_ALL ):
374
+ imagemagick_apt_output = local ('apt-cache policy imagemagick' , capture = True )
375
+ if 'Unable to locate package' in imagemagick_apt_output :
376
+ logging .debug (" > Installing imagemagick package..." )
377
+ sudo ("apt-get install imagemagick -y &" )
378
+ else :
379
+ logging .debug (" > Imagemagick is installed" )
344
380
# install msp430 (GCC) upgrade
345
381
with hide (* HIDDEN_ALL ):
346
382
msp430_version_output = local ('msp430-gcc --version' , capture = True )
@@ -349,7 +385,7 @@ def do_setup():
349
385
"Would you like to upgrade it now ? (yes|no) [default: no] "
350
386
answer = std_input (txt )
351
387
if answer == "yes" :
352
- logging .info ( "UPGRADING msp430-gcc FROM VERSION 4.6.3 TO 4.7.0" )
388
+ logging .debug ( " > Upgrading msp430-gcc from version 4.6.3 to 4.7.0... " )
353
389
logging .warning ("If you encounter problems with this upgrade, please refer to:\n "
354
390
"https://github.com/contiki-os/contiki/wiki/MSP430X" )
355
391
with lcd ('src/' ):
@@ -359,10 +395,10 @@ def do_setup():
359
395
local ('export PATH=/usr/local/msp430/bin:$PATH' )
360
396
register_new_path_in_profile ()
361
397
else :
362
- logging .info ( "UPGRADE OF LIBRARY msp430-gcc ABORTED " )
398
+ logging .warning ( "Upgrade of library msp430-gcc aborted " )
363
399
logging .warning ("You may experience problems of mote memory size at compilation" )
364
400
else :
365
- logging .info ( "LIBRARY msp430-gcc IS UP-TO-DATE ( 4.7.0)" )
401
+ logging .debug ( " > Library msp430-gcc is up-to-date (version 4.7.0)" )
366
402
367
403
368
404
# **************************************** MAGIC COMMAND ****************************************
0 commit comments