Skip to main content

Mike Kreuzer

Opinionated adventures in remote scripting

February 14, 2023

I've never been especially happy with any of the combinations I've used to script remote machine updates, & now that for the moment I work for myself I've had the luxury of trying to find a better way. Maybe I have. So herewith a few notes on my opinionated adventures in remote scripting.

I started out using Rake, which is what I'd been using to automate local tasks, adding Net::SSH for network connections. That was OK but the network code was clumsy, the opposite of Ruby's usual problem of too much magic, it was completely not magical in any way. It worked, but it was a pain to write, & worse to read.

So for a while there I wrote my own JavaScript task system & added fetch and… yeah, that was worse. Now I'm older & somewhat wiser I tend to think new JavaScript frameworks should be tolerated rather than encouraged. Not because JavaScript's bad in itself, it's not, I've always liked it as a language & have used it pretty much from the start, but what the world didn't need was yet another JavaScript library, & what I really didn't need was another project to maintain. I was & am trying (hard) to wind that back, not to expand it. JavaScript was promising, the task library I wrote was promising – & boy do the very popular JavaScript alternatives to it suck – but I moved on.

After that I tried & pretty quickly rejected Ansible. With only terse 'done' messages or badly broken formatting on replies from the commands on the remote boxes it was by far the worst of the bunch. That's also true when using Ansible for provisioning. I know it's widely used, it's arguably the standard there, but as the saying goes the two most abundant things in the universe are hydrogen & stupidity. See for example the popular JavaScript task runners. Oh boy.

Sticking with Python for a bit I tried Fabric. It was far better than Ansible, & better than Rake/Net::SSH when considered in isolation, but demonstrably much worse once I had to factor in the added pain of creating a virtual environment to run it in every time, just because Python people can't do versioning. (Python… some great ideas, wrapped up in some really terrible execution. Not a million miles from Swift in that respect, but I digress.)

So, back to Rake, but this time with SSHKit from Capistrano, a combination that hit the sweet spot for me. For example I can have a Rake file that in part reads something like:

# frozen_string_literal: true

require 'sshkit'

SSHKit.config.output_verbosity = :debug

desc 'Update pies'
task :update_pies do
  include SSHKit::DSL

  on ['pi1', 'pi2'], in: :sequence, wait: 5 do |host|
    puts host
    execute :sudo, 'apt-get update'
    execute :sudo, 'apt-get full-upgrade -y'

    execute 'pihole -up' if host == 'pi1'
  end
end

Which updates two Raspberry Pies including updating Pihole on one of them, all with a simple rake update_pies command, while also giving me all the feedback I'd get if I were to SSH in to the boxes & run those commands directly. That's the point I'd got to with Python's Fabric, but SSHKit has none of the pain of having to run Python. If you're stuck using Python for other things perhaps you may want to consider trying Fabric, but it's not worth converting for if you're not already mired in that ecosystem.

These are legacy Pi boxes too of course, after The Pi people set fire to their reputation & all the goodwill they ever had on Mastodon I'll not be getting any more. They were good, until they weren't, time to move on there.

Also, Happy Valentine's Day…