Running script on SSH frontend

 

Level: Difficult

Duration: 45 minutes

Prerequisites: Configure SSH Access /  Submit an experiment with M3 nodes / Experiment CLI client / Nodes Serial Link Aggregation

Description: The goal of this tutorial is to show how to launch a script on the SSH frontend during an experiment. This feature gives you the opportunity to write a simple experiment controller and automate the setup of your scenario (eg. flashing firmwares or getting serial output for M3 nodes, SSH access and configuration for A8 nodes). You have two options, associate a script file at the experiment submission, thus it will be launched automatically at the beginning of the experiment, or launch it dynamically during the experiment. In both cases, this script will be executed in a screen session with your user id. In this tutorial, you will use this feature to store the serial output of the nodes into a file with the serial_aggregator tool.

Here, commands are executed from the SSH frontend, but you could do exactly the same from your local environment by installing the IoT-LAB CLI tools on your computer.
  • Connect to the Grenoble site SSH frontend
    my_computer$ ssh <login>@grenoble.iot-lab.info

    Note: if you did not already authenticate using iotlab-auth, do it now:

    <login>@grenoble:~$ iotlab-auth -u <login>
  • Create a file named aggregator_script with the following content:
    <login>@grenoble:~$ cat aggregator_script
    #!/bin/bash
    
    # Redirect all nodes serial output to a file
    readonly OUTFILE="${HOME}/.iot-lab/${EXP_ID}/aggregator_log"
    
    echo "Launch serial_aggregator with exp_id==${EXP_ID}" >&2
    serial_aggregator -i ${EXP_ID} 2> /dev/null 1> ${OUTFILE}

    This bash script uses the serial_aggregator tool to redirect serial output of the experiment nodes in a log file.
    Note1: When the script starts, the EXP_ID environment variable is set with the experiment id and can be accessed from your script.
    Note2: The script can be written in any scripting language, like Python.

  • Submit an experiment with:
    • five M3 nodes (eg. dynamically allocated by the scheduler)
    • a firmware association with sensors-collecting.iotlab-m3 (eg. the firmware prints sensors values every second on the serial link)
    • a site association with your aggregator_script
    <login>@grenoble:~$ wget https://raw.githubusercontent.com/wiki/iot-lab/iot-lab/firmwares/sensors-collecting.iotlab-m3 -O sensors-collecting.iotlab-m3
    <login>@grenoble:~$ iotlab-experiment submit -d 60 -l 5,archi=m3:at86rf231+site=grenoble,sensors-collecting.iotlab-m3 --site-association grenoble,script=aggregator_script
  • Wait until the experiment is launched and verify the script execution on the SSH frontend in the screen session
    <login>@grenoble:~$ iotlab-experiment wait
    Waiting that experiment <exp_id> gets in state Running
    "Running"
    <login>@grenoble:~$ screen -ls
    There is a screen on:
     4699.<exp-id>-<login> (28/03/2017 15:17:06) (Detached)
    1 Socket in /var/run/screen/S-<login>.
    <login>@grenoble:~$ screen -r
    Launch serial_aggregator with exp_id==<exp_id>

    Use Ctrl+a d shortcut to detach from screen session after the screen -r command

  • Verify that the aggregator_log file exists and contains the serial output of the nodes
    <login>@grenoble:~$ cat .iot-lab/last/aggregator_log
    1490707035.275759;m3-14;gyros: 1776 -446 122 xyz m°/s
    1490707035.280817;m3-13;gyros: -332 -280 -288 xyz m°/s
    1490707035.342859;m3-13;light: 113.906860 lux
    1490707035.343804;m3-13;press: 994.614990 mbar
    1490707035.347815;m3-10;light: 427.490234 lux
    1490707035.349177;m3-10;press: 994.469238 mbar
    1490707035.395238;m3-14;light: 161.621094 lux
    1490707035.396399;m3-14;press: 994.343994 mbar
    1490707035.426228;m3-11;light: 628.448486 lux
    1490707035.426339;m3-11;press: 994.469971 mbar

    Note: .iot-lab/last is a symlink to your last experiment directory (.iot-lab/<exp_id>)

  • You may also find a log file in your homedir with standard error redirection (eg. stderr)
    <login>@grenoble:~$ cat .iot-lab/last/run_script.log
    Waiting that experiment <exp_id>/<login> gets in state Running
    "Running"
    Experiment '<exp_id>/<login>' is Running
    Running script: 'aggregator_script'
    Launch serial_aggregator with exp_id==<exp_id>
  • You can visualize the status of your script execution and kill it manually
    <login>@grenoble:~$ iotlab-experiment script --status
    {
     "0": { "grenoble.iot-lab.info": "Running"}
    }
    <login>@grenoble:~$ iotlab-experiment script --kill
    {
     "0": ["grenoble.iot-lab.info"]
    }
    <login>@grenoble:~$ iotlab-experiment script --status
    {
     "0": { "grenoble.iot-lab.info": "Idle"}
    }
  • As you can set a running script at experiment submission, it’s possible to launch it dynamically at any moment during your experiment (eg. state=Running). If there is a script execution in progress it will stop it and execute the new one.
    <login>@grenoble:~$ iotlab-experiment script --run grenoble,script=aggregator_script
    {
     "0": ["grenoble.iot-lab.info"]
    }
  • You can also pass a script config file attached to your script file. In this example, we pass a user password via the aggregator_script_config file and execute iotlab-auth command with it in the aggregator_script file.
    <login>@grenoble:~$ cat aggregator_script_config
    PASSWORD=<password>
    <login>@grenoble:~$ cat aggregator_script
    #!/bin/bash
    
    if [ "$#" -eq 1 ]; then
     echo "Script config path: $1" >&2
     source $1
     iotlab-auth -u ${USER} -p ${PASSWORD} || exit 1
    fi
    
    # Redirect all nodes serial output to a file
    readonly OUTFILE="${HOME}/.iot-lab/${EXP_ID}/aggregator_log"
    
    echo "Launch serial_aggregator with exp_id: ${EXP_ID}" >&2
    serial_aggregator -i ${EXP_ID} 2> /dev/null 1> ${OUTFILE}
    <login>@grenoble:~$ iotlab-experiment script --run grenoble,script=aggregator_script,scriptconfig=aggregator_script_config
    {
     "0": [ "grenoble.iot-lab.info"]
    }
    <login>@grenoble:~$ cat .iot-lab/last/run_script.log
    ...
    Running script: 'aggregator_script'
    Using script config: 'aggregator_script_config'
    Script config path: /var/run/script_tools/script/<exp_id>-config
    ...

Advanced Features

When the experiment is stopping or you kill manually the script execution a SIGTERM signal is sent to the script. It is possible to catch it and do some post script actions.

  • Edit the aggregator_script file to use the trap command and a catch_signal function.
    #!/bin/bash
    trap 'catch_signal; exit' SIGTERM
    
    catch_signal() {
     echo "Catch SIGTERM signal" >&2
     # cleanup actions here
    }
    
    if [ "$#" -eq 1 ]
     then
     echo "Source script config path: $1" >&2
     source $1
     iotlab-auth -u ${USER} -p ${PASSWORD}
    fi
    
    # Redirect all nodes serial output to a file
    readonly OUTFILE="${HOME}/.iot-lab/${EXP_ID}/aggregator_log"
    
    echo "Launch serial_aggregator with exp_id: ${EXP_ID}" >&2
    serial_aggregator -i ${EXP_ID} 2> /dev/null 1> ${OUTFILE}
  • Launch this script and see what’s happening when it is stopped
    <login>@grenoble:~$  iotlab-experiment script --run grenoble,script=aggregator_script,scriptconfig=aggregator_script_config
    {
     "0": [ "grenoble.iot-lab.info"]
    }
    <login>@grenoble:~$ iotlab-experiment script --kill
    {
     "0": ["grenoble.iot-lab.info"]
    }
    <login>@grenoble:~$ cat .iot-lab/last/run_script.log 
    ... 
    Got kill signal, sending SIGTERM to script and waiting for return...
    Catch SIGTERM signal
    Script returned: 0 
    ...