Skip to content

Instantly share code, notes, and snippets.

@seva-ramin
Last active November 15, 2020 17:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seva-ramin/b3f1d5232473f363191978a67c9e9dc9 to your computer and use it in GitHub Desktop.
Save seva-ramin/b3f1d5232473f363191978a67c9e9dc9 to your computer and use it in GitHub Desktop.
Unix like shell for Kubernetes resources; view your Kubernetes resources using commands like "ls", or "cat" with tab completion.
#!/bin/bash
# set prompt color to blue
CB=$'\e[35m'
CE=$'\e[0m'
es=$'\e' # read escape characters, $'\033' works too
back=$'\033[1D' # move curser back
eof=$'\004' # read end of file, Ctrl-D
tab=$'\t'
eol=$'\n' # end of line
bs=$'\177' # backspace key, 177 is DEL, may need to also cover 010 for BS on some keyboards
debugline=0
namespace=default
context="all"
# list of possible values for tab completion
tabbed=()
history=()
histindex=-1
root_tab() {
tabbed=(pods services deployments replicasets statefulsets configmaps secrets sa roles rolebindings pv nodes)
}
prompt() {
prm="${CB}$*${CE}$ "
}
prompt $namespace
switch_ns() {
n=$2
if [ X$n = X ]
then
objects=`kubectl get ns | awk '{print $1}' | grep -v NAME`
echo "$objects"
tabbed=()
for t in $objects; do tabbed+=($t); done
return
fi
kubectl get ns | awk '{print $1}' | grep -q $n
if [ $? -eq 1 ]
then
echo No such namespace: $n
return
fi
namespace=$n
_cd
}
_cd() {
d=$2
if [ X$d = X ] || [ X$d = X.. ] || [ X$d = X/ ]
then
context="all"
prompt $namespace
_list
return
fi
# check to see if we can see this resource
_list | grep -q $d
if [ $? -eq 1 ]
then
echo No such resource: $d
return
fi
context=$d
prompt "$namespace/$context"
_list
}
_list() {
arg=$2
case $context in
all)
if [ X$arg = X ]
then
root_tab
for t in ${tabbed[@]}; do echo $t; done
else
context=$arg
_list
context=all
root_tab
fi
;;
pods|services|deployments|replicasets|statefulsets|configmaps|secrets|sa|roles|rolebindings|pv|nodes)
if [ X$arg = X-a ]; then
kubectl get $context -n $namespace
elif [ X$arg = X ]; then
objects=`kubectl get $context -n $namespace | awk '{print $1}' | grep -v NAME`
echo "$objects"
tabbed=()
for t in $objects; do tabbed+=($t); done
else
# running ls on one object
kubectl get $context $arg -n $namespace
fi
;;
*)
echo "Panic! No view context"
exit
;;
esac
}
_less() {
r=$2
case $context in
pods|services|deployments|replicasets|statefulsets|configmaps|secrets|sa|roles|rolebindings|pv|nodes)
kubectl get $context $r -n $namespace -o yaml | less ;;
*)
echo "Panic! No view context"
exit ;;
esac
}
_cat() {
r=$2
case $context in
pods|services|deployments|replicasets|statefulsets|configmaps|secrets|sa|roles|rolebindings|pv|nodes)
kubectl get $context $r -n $namespace -o yaml ;;
*)
echo "Panic! No view context"
exit ;;
esac
}
_context() {
c=$2
if [ X$c = X ]
then
kubectl config get-contexts
return
fi
kubectl config current-context
}
_help() {
echo "Available commands:"
echo
echo "ns [<namespace>] show namespaces or switch to a <namespace>"
echo "ls [-a] list all resources in current view, '-a' expands further"
echo "ls object show brief info about a resource"
echo "cd start from root or change to a resource view"
echo "cat <resource> show the description of the <resource>"
echo "less <resource> page the description of the <resource>"
echo "more <resource> same as less"
echo "clear clear screen"
echo "history show command history, use up or down arrow to scroll"
echo "context [current] list all contexts or show current"
echo "kubectl [*] run raw kubectl command in current namespace"
echo "exit exit"
echo "help display this help message"
}
_debug() {
msg=$*
cols=`tput cols`
cols=$((cols - ${#msg}))
# save curser
tput sc
tput cup $debugline $cols
echo -n $'\e[31m'
echo -n $msg
debugline=$((debugline+1))
if [[ $debugline -gt 10 ]]; then
debugline=0
fi
# restore
echo -n $'\e[0m'
tput rc
}
root_tab
while true
do
IFS=
line=
echo -n "$prm"
while true
do
read -rsn1 c
# if escape character is present
if [[ $c == $es ]]; then
read -rsn2 c
# TODO - implement history
case $c in
'[A') # up arrow
if [[ $histindex -gt -1 ]]; then
if [[ ${#line} -gt 0 ]]; then
tput cub ${#line}
tput el
fi
line=${history[$histindex]}
echo -n "$line"
histindex=$((histindex - 1))
fi
;;
'[B') # down arror
if [ $histindex -gt -1 ] && [ $histindex -lt ${#history[@]} ]; then
if [[ ${#line} -gt 0 ]]; then
tput cub ${#line}
tput el
fi
line=${history[$histindex]}
echo -n "$line"
histindex=$((histindex + 1))
fi
;;
esac
else
case $c in
$eof)
if [ X${#line} = X0 ]; then
echo exiting
line=exit
break
fi
;;
$tab)
_tabbed=(${tabbed[@]}) # don't touch the tabbed list in the current context
len=`echo $line|awk '{print NF}'`
if [ $len -lt 2 ]; then
echo
for t in ${_tabbed[@]}; do echo $t; done
echo -n "${prm}${line}"
else
# get the last argument
substr=`echo $line|awk '{print $NF}'`
# find the ones that match current string
newtab=()
for t in ${_tabbed[@]};
do
if [[ $t == "$substr"* ]]; then
newtab+=($t)
fi
done
# override the previous values
_tabbed=(${newtab[@]})
# see if we can tab complete further
while true
do
l=${#substr} # length of the last word
l=$((l+1))
substr=`echo $_tabbed[0]| cut -c 1-$l`
newtab=()
for t in ${_tabbed[@]};
do
if [[ $t == "$substr"* ]]; then
newtab+=($t)
fi
done
# the length of both must be the same and non-zero
if [ ${#newtab[@]} == 0 ] || [ ${#newtab[@]} != ${#_tabbed[@]} ]; then
break
fi
line=`echo $line | awk '{$(NF--)="";print}'`
line="$line$substr"
_tabbed=(${newtab[@]})
done
# prints all the values that match
echo
for t in ${_tabbed[@]};
do
echo $t
done
echo -n "${prm}${line}"
fi
;;
$eol) echo -n "end of line" ;;
$'\025') # Ctrl-U - erase to the beg of prompt
tput cub ${#line}
tput el
line=
;;
$bs)
if [ X${#line} != X0 ]; then
echo -n $back
tput el
line=`echo $line | rev | cut -c2- | rev`
fi
;;
"") echo
break
;; # <return> key
*) echo -n $c
line=$line$c
;;
esac
fi
done
unset IFS
# update history
if [[ ${#line} -gt 0 ]]; then
history+=("$line")
histindex=$((${#history[@]} - 1)) # set index to the last element
fi
case $line in
ns | ns\ *)
switch_ns $line
;;
ls | ls\ *)
_list $line
;;
less\ * | more\ *)
_less $line
;;
cat\ *)
_cat $line
;;
cd | cd\ *)
_cd $line
;;
context*)
_context $line
;;
clear)
debugline=0
clear
;;
history)
for ((i=0;i<${#history[@]};i++))
do
echo ${history[$i]}
done
;;
kubectl*)
($line -n $namespace)
;;
'')
;;
exit)
exit
;;
help)
_help
;;
*)
echo "Not legit: $line"
_help
;;
esac
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment