Command Scripting
In this section we make use of Deviceplane's features to write custom scripts to manage your devices however you decide!
We'll go over (in order of complexity):
- Printing out the names of offline devices - Useful for piping to other commands
- Running a command on multiple devices - And printing the output of each run in STDOUT
- Running a full bash script on multiple devices - With a workflow for saving the output of each run to a separate file
After reading this page, you should know where to start if you want to run batch scripts to get the output of files on your devices, perform package upgrades or install kernel updates on your entire fleet, or simply create a local script to periodically log a list of offline devices, which you could show in your menu bar.
Prerequisites
For ease of use, these examples use jq
, a simple CLI utility for parsing JSON.
It's available on most
package managers and can also be downloaded as a binary.
Commands
Printing out the names all offline devices
To print out all information on devices, we
can use the deviceplane device list
command. Pass in a filter argument, --filter
status=offline
, and we can select only the offline devices. Output json with
-o
json
and pipe into jq
, then
select the name
attribute of each
object.
Our final command is:
deviceplane device list --filter status=offline -o json | jq '.[] | .name'
And should list the names of all offline devices. Currently, there's only one device offline in our demo project, so our output looks like this:
"condescending-feynman"
Reading the output of a command on all devices
In order to read the output of a command run
on a device, we'll have to SSH into the device, and run the command. However, we
can't SSH into devices that are offline, so let's first grab the list of all
devices that are online. We can use the same command as in the last section, just
remember to filter status to be online instead of offline: deviceplane
device list --filter status=online -o json | jq '.[] | .name'
We can pipe this into xargs
-n1 -I {} echo "The device {} is online"
to echo for each line of
output we get, replacing {}
with the
contents of each line. Next, we'll replace echo
with our ssh command.
Our ssh command will look like deviceplane
ssh $DEVICE_NAME $COMMAND
, for each device, substituting $COMMAND
with the command that we want to run on the device. Let's say we need every device's
bound IP addresses. We can use the hostname
-i
command to get the IP addresses, so our command will be deviceplane ssh $DEVICE_NAME hostname
-i
, and if we'd like, we can prefix it with an echo
command to echo out the device name before printing the IPs.
Now, putting it all together, we get:
deviceplane device list --filter status=online -o json | jq '.[] | .name' | xargs -n1 -I {} deviceplane ssh {} "echo {}\'s IPs: && hostname -I"
Which gives us the output:
elegant-lamarr's IPs:10.0.0.135 172.17.0.1 169.254.73.24 169.254.249.211 2601:645:8400:9760::dcff 2601:645:8400:9760:7ff2:b063:4c20:1bf9condescending-jones's IPs:10.0.0.208 172.17.0.1 169.254.120.233 169.254.28.194 2601:645:8400:9760::c13e 2601:645:8400:9760:c1a8:d7c3:2285:64a3pedantic-mcnulty's IPs:64.227.52.167 10.46.0.6 172.17.0.1competent-bohr's IPs:10.0.0.187 172.17.0.1 2601:645:8400:9760:4ddb:c01d:c7b9:f801 2601:645:8400:9760:9ed:313:6b5:739e 2601:645:8400:9760:20ce:500e:ef1c:b81 2601:645:8400:9760:114d:839f:c601:96eb 2601:645:8400:9760:11b3:1009:165:3f8d 2601:645:8400:9760:e90a:fa6:79f:5df6 2601:645:8400:9760:3dd1:e263:35d5:f8dd 2601:645:8400:9760:d4e3:4c1:5240:446d
Running a bash script on multiple devices
For more complicated workflows, just a single command isn't enough. You might want an entire script to be run, and its output saved separately for each device.
The following script takes in a second file, and runs it on all online devices, storing the output for each device in a separate text file:
#!/bin/bashset -e# Get all devices, and split them into online and offline devices# Note, doing it this way ensures that we don't have devices missing from a list. For example, if a device changes state between two queries, we might miss it in our list.ALL_DEVICES=$(deviceplane device list -o json)ONLINE_DEVICES=$(echo $ALL_DEVICES | jq -r '.[] | select(.status == "online") | .name')OFFLINE_DEVICES=$(echo $ALL_DEVICES | jq -r '.[] | select(.status == "offline") | .name')echo "Online Devices:" $ONLINE_DEVICESecho "Offline Devices (will not run commands on):" $OFFLINE_DEVICEStotal=$(($(echo "$ONLINE_DEVICES" | wc -l )))i=0for DEVICE in $ONLINE_DEVICESdo((i++))echo "($i of $total) running on $DEVICE"# Get our input file, and execute it on the device, then save that output into a fileecho "$(deviceplane ssh "$DEVICE" "$(cat $1)")" > "$DEVICE"_output.txtdone
So, if our second file were the following:
#!/bin/bashset -eecho "My current host name is:"hostnameecho "\n"echo "My IPs are:"hostname -iecho "\n"echo "Creating and deleting a new file:"touch newfile.txtlsrm newfile.txt
We could name our files batch-execute.sh
and command.sh
, and run the following
(after chmod +x batch-execute.sh
):
./batch-execute.sh command.sh
Which would output the following:
Online Devices: elegant-lamarr condescending-jones pedantic-mcnulty competent-bohrOffline Devices (will not run commands on): condescending-feynman(1 of 4) running on elegant-lamarr(2 of 4) running on condescending-jones(3 of 4) running on pedantic-mcnulty(4 of 4) running on competent-bohr
And leave the following files:
ls -ltotal 48-rwxr-xr-x 1 cyrusroshan staff 574 Jan 27 23:24 batch-execute.sh-rw-r--r-- 1 cyrusroshan staff 190 Jan 27 23:24 command.sh-rw-r--r-- 1 cyrusroshan staff 213 Jan 27 23:32 competent-bohr_output.txt-rw-r--r-- 1 cyrusroshan staff 199 Jan 27 23:32 condescending-jones_output.txt-rw-r--r-- 1 cyrusroshan staff 199 Jan 27 23:32 elegant-lamarr_output.txt-rw-r--r-- 1 cyrusroshan staff 271 Jan 27 23:32 pedantic-mcnulty_output.txt
To look at the output for the device elegant-lamarr, read the file elegant-lamarr_output.txt to find:
My current host name is:raspberrypiMy IPs are:127.0.1.1Creating and deleting a new file:binbootdevetchomeliblost+foundmediamntnewfile.txtoptprocrootrunsbinsrvsystmpusrvar