GCP SSH autocomplete with FZF and ZSH

I got inspired by AffectV post on AWS SSH completion and decided to write something similar for GCP.

Here’s the end result:
asciicast

Prerequisites #

Writing the module #

First, we need to figure out how to get the list of information we want. gcloud provides a somewhat sensible formatting and filtering options for that, e.g. if I want to get the name, zone and external IP of the instance in a flat tab-separated table, we’ll have to set options like so:

λ gcloud compute instances list \
                         --format="table[no-heading](name,zone,status,networkInterfaces[0].accessConfigs[0].natIP)" \
                         --filter="status=RUNNING"
my-web-v37r              australia-southeast1-c  RUNNING  XX.XXX.XX.XX
my-web-wp2d              australia-southeast1-c  RUNNING  XX.XXX.XX.XX
my-worker-b96q           australia-southeast1-c  RUNNING  XX.XXX.XX.XX

Perfect.

Note: if you want to add more information to your default output, you can use gcloud compute instances list --format=flattened to figure out what fields you need.

Now, let’s create a dummy ssh function so we don’t mess with default autocomplete and don’t put a latency penalty on autocompleting the regular ssh command:

gssh()
{
  ssh $@
}

Next, we’ll need to write a FZF completion module. For that, we’ll need to write a function _fzf_complete_$YOURCOMMAND, following one of FZF examples, e.g.:

_fzf_complete_gssh() {
  ARGS="$@"
  local machines
  machines=$(gcloud compute instances list \
             --format="table[no-heading](name,zone,status,networkInterfaces[0].accessConfigs[0].natIP)" \
             --filter="status=RUNNING")
  if [[ $ARGS == 'gssh '* ]]; then
    _fzf_complete "--reverse --multi" "$@" < <(
        echo $machines
    )
  else
    eval "zle ${fzf_default_completion:-expand-or-complete}"
  fi
}

Then, we need to tell FZF what to pass back to the executable once completion has been selected. In our case, we want the instance’s external IP, so we select the 4th column using awk:

_fzf_complete_gssh_post() {
    awk '{print $4}'
}

Putting it all together #

Here’s how our module looks like:

gssh()
{
  ssh $@
}

_fzf_complete_gssh() {
  ARGS="$@"
  local machines
  machines=$(gcloud compute instances list \
             --format="table[no-heading](name,zone,status,networkInterfaces[0].accessConfigs[0].natIP)" \
             --filter="status=RUNNING")
  if [[ $ARGS == 'gssh '* ]]; then
    _fzf_complete "--reverse --multi" "$@" < <(
        echo $machines
    )
  else
    eval "zle ${fzf_default_completion:-expand-or-complete}"
  fi
}

_fzf_complete_gssh_post() {
    awk '{print $4}'
}

The only thing we need to do is to paste it into our .zshrc (or include it using your favourite plugin manager) and we’re good to go.

Just type gssh **, and then press TAB.

 
0
Kudos
 
0
Kudos

Now read this

What’s making me happy 18-06-2017

Visiting NorCal and Seattle area over the past 2 weeks, it’s been nice to visit some of my old friends. Those moments, although brief do warm my heart. Took some time walking around Stanford. The Dish trail turned out to be a great walk.... Continue →