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.
Prerequisites #
- You use zsh as your main shell
- You have fzf and its completion set up
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.