Evolution of an OpenShift context switcher

Although OpenShift’s web console is quite handy, most often I prefer to interact with projects using the oc command.

But switching projects was always kind of a hassle. While oc project is completely fine for switching between projects on the same cluster, switching to projects on a different cluster requires to switch the “context” with oc config use-context. And the argument to this later command is tricky, as it’s a combination of a project and a cluster name.

For a long time I was using oc config get-contexts to list all the “contexts” I’ve ever used, copied the name of the context from its output and crafted the oc config use-context command. This of course became quickly tedious.

The first attempt to improve this workflow was to write a bash-script which would attach numbers to the contexts, let me pick the context by the number and switch to it. I called this script ctx and placed in ~/.local/bin, which is in $PATH.

ctx also took an optional argument, which was used to filter the choices that were offered, so that instead of picking from a long list of contexts, I could quickly narrow down the list to a few, or even one, in which case the context was made active without even asking for a selection. This further lowered the cognitive load of switching contexts :) .

Here is how using ctx looked like:

ctx command v1

As you can see from the examples above, results where not re-indexed. Contexts not matching the search string were simply not shown.

Here is how the script looked like at this point:

#!/usr/bin/bash

set -eu

filter=${1:-""}
readarray -t contexts < <(oc config get-contexts -o name)
readarray options < <(printf '%s\n' "${contexts[@]}" | cat -n | grep "$filter")

if [ ${#options[@]} -eq 1 ]; then
    choice=$(printf '%s' "${options[@]}" | awk '{print $1}')
elif [ ${#options[@]} -eq 0 ]; then
    echo "Ups, found nothing"
    exit 1
else
    printf '%s' "${options[@]}"
    echo -n "Enter your choice: "
    read choice
fi

choice=$((choice-1))
oc config use-context "${contexts[$choice]}"

The most challenging in writing the above was working with arrays. I still find working with arrays in bash hard and unintuitive, so it took me some reading and experimentation to get it right.

After using the above script for a few days, two things started to bother me:

  1. I found entering a number a little bit annoying and unnatural from a UX point of view.
  2. I often found myself making a typo when entering the search term, which forced me to either correct it before running the command or, in case I didn’t notice, to run the command again with the correct term.

All the above was extra effort I wanted to get rid of.

The second issue made me think about implementing some kind of “fuzzy searching”, where one can make typos while still getting meaningful results. I’ve seen this type of search the first time in Sublime Text some years ago, and I instantly became a big fan of it.

In the terminal I was using fzf for similar purposes, so I started to look into how I could use it to improve the search results returned by the script above. And then I realized, it would be not only possible to have results tolerate the errors made by my lazy typing, but I could also use fzf’s interface to do the selection, instead of having to type in a number to pick a context.

To my surprise this turned my script in a one-liner:

oc config get-contexts -o name | fzf -q ${1:-""} | xargs oc config use-context

And the user experience was much more to my liking, too :)

ctx command v2