Runner is a command line tool for running commands on thousands of devices that support SSH. I wrote Runner and use it every single day, because unlike Ansible, Runner truly has no dependencies on the client or server side other than SSH. I have used Runner to build entire datacenters, so it is proven and tested and has a lot of well thought out features, which brings me to todays post. Since I initially debuted Runner I have added a lot of features, but I had yet to check them into github, until now. Here is a run down of Runner’s features.
- Runner takes your login credentials & doesn’t require you to setup SSH keys on the client machines/devices.
- Runner can be used through a bastion/jump host via an SSH tunnel (see prunner.py)
- Runner reads it’s main host list from a file ~/.runner/hosts/hosts-all
- Runner can accept custom hosts lists via -f
- -e can be used to echo a command before it is run, this is useful for running commands on F5 load balancers for example, when no output is returned on success.
- -T will allow you to tune the number of threads, but be careful you can easily exhaust your system or site resources (I.E. do NOT DOS your LDAP authentication servers by trying to do hundreds of threads across thousands of machines, unless you know they can handle it 😉 ).
- -s is for sudo for those users who have permissions in the sudoers file.
- -1 reduces any host list down to one host per pool. It uses a regex, which you will likely have to modify for your own host / device naming standard.
- -r can be used to supply a regular expression for matching hosts. Remember sometimes you have to quote the regex and/or escape the shell when using certain characters.
- -c will run a single command on many hosts, but -cf will run a series of commands listed in a file on any hosts specified. This is particularly useful for automations. For example, I used it to build out load balancer virtuals and pools on an F5.
- -p enables you to break apart the number of hosts to run at a time using a percentage. This is a handy & more humanized way to ensure you do not kill your machine or the infrastructure you are managing when you crank threads through the roof 😉
Now that I have taken the time to explain some of those cool features, here’s an example of what it looks like in action.
➜ ~ runner -l -r tuxlabs tuxlabs.com old.tuxlabs.com There were 2 hosts listed. ➜
Basic Run Using Only -c, -u and defaults
Note: User defaults to the user you are logged in as if you don’t specify -u . Since I am logged in as ‘jriedel’ I have specified the user tuxninja instead.
➜ ~ runner -r tuxlabs -c 'id' -u tuxninja RUNNER [INFO]: MATCHING HOSTNAMES WITH 'tuxlabs' RUNNER [INFO]: 2 HOSTS HAVE BEEN SELECTED RUNNER [INFO]: LOGFILE SET - /Users/jriedel/.runner/logs/runner.log.2015-08-25.01:59:59 RUNNER [INFO]: USER SET - tuxninja RUNNER [INFO]: SSH CONNECT TIMEOUT is: 10 seconds RUNNER [INFO]: THREADS SET - 20 RUNNER [INPUT]: Please Enter Site Pass: tuxlabs.com: uid=1000(tuxninja) gid=1000(tuxninja) groups=1000(tuxninja),27(sudo) old.tuxlabs.com: uid=1000(tuxninja) gid=1000(tuxninja) groups=1000(tuxninja),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),114(sambashare),1001(admin) RUNNER [RESULT]: Successfully logged into 2/2 hosts and ran your command(s) in 0:00:03 second(s) RUNNER [RESULT]: There were 0 login failures. RUNNER [INFO]: Your logfile can be viewed @ /Users/jriedel/.runner/logs/runner.log.2015-08-25.01:59:59 ➜ ~
The Same Run Using Sudo
Note: I just realized if you do not prompt for a password for sudo it will fail, I will have to fix that ! Whoops ! P.S. You should always prompt for a password when using sudo !
➜ ~ runner -r tuxlabs -c 'id' -u tuxninja -s RUNNER [INFO]: MATCHING HOSTNAMES WITH 'tuxlabs' RUNNER [INFO]: 2 HOSTS HAVE BEEN SELECTED RUNNER [INFO]: LOGFILE SET - /Users/jriedel/.runner/logs/runner.log.2015-08-25.02:10:27 RUNNER [INFO]: USER SET - tuxninja RUNNER [INFO]: SSH CONNECT TIMEOUT is: 10 seconds RUNNER [INFO]: THREADS SET - 20 RUNNER [INFO]: SUDO IS ON RUNNER [INPUT]: Please Enter Site Pass: tuxlabs.com: uid=0(root) gid=0(root) groups=0(root) old.tuxlabs.com: uid=0(root) gid=0(root) groups=0(root) RUNNER [RESULT]: Successfully logged into 2/2 hosts and ran your command(s) in 0:00:03 second(s) RUNNER [RESULT]: There were 0 login failures. RUNNER [INFO]: Your logfile can be viewed @ /Users/jriedel/.runner/logs/runner.log.2015-08-25.02:10:27 ➜ ~
Runner with a command file in super quiet mode !
➜ ~ cat lets-run-these uptime who date uptime -s ➜ ~ ➜ ~ runner -r tuxlabs -cf lets-run-these -T 2 -p 50 -qq -u tuxninja RUNNER [INPUT]: Please Enter Site Pass: tuxlabs.com: 05:17:51 up 14 days, 4:45, 0 users, load average: 0.00, 0.01, 0.05 old.tuxlabs.com: 03:17:52 up 80 days, 47 min, 1 user, load average: 0.42, 0.69, 0.78 old.tuxlabs.com: root pts/0 2015-08-25 02:23 (220.127.116.11) tuxlabs.com: Tue Aug 25 05:17:52 EDT 2015 old.tuxlabs.com: Tue Aug 25 03:17:53 CST 2015 tuxlabs.com: 2015-08-11 00:32:18 old.tuxlabs.com: 2015-06-06 02:30:42 ➜ ~
Example of a simple regex & a failure
➜ ~ runner -r old.* -l zsh: no matches found: old.* ➜ ~ ➜ ~ runner -r 'old.*' -l old.tuxlabs.com There was 1 host listed. ➜ ~
I hope you enjoyed the overview and new features. You can clone Runner on github.