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

SRE Consulting engagements

Due to extreme demand on my Office Hours I’m opening a paid consulting stream for those that want more of my time and are willing to pay for it - i.e. SRE leaders, Seasoned Professionals and Companies that need advice. Are you a seasoned... Continue →