Quantcast
Channel: プログラミング
Viewing all articles
Browse latest Browse all 7930

kubectl の wrapper を作る際の tips (ZSH 補完など) - Unyablog.

$
0
0

kubectl に自動で namespaceや context を付与するような wrapper を作るとする。

そんなコマンドのインターフェースとして、

$ kubewrapper [...wrapper flags] [kubectl args / flags]
(例) $ kubewrapper -p staging describe pod ...

とすると

$ kubectl --context foo --namespace bar [kubectl args / flags]
(例) $ kubectl --context foo --namespace bar describe pod ...

といったコマンドが exec される、すなわちいくつかの flags を受け取って kubectl 用に変換しつつ args としては kubectl の引数をまるまる受け取るといったものが考えられる。

こういったコマンドを作るためには、補完をはじめとしていくつか注意点があるのでメモ。

外部 plugin 対応

通常の kubectl サブコマンド(getlogsなど)では、 --context や --namespace といった flag はサブコマンドの前に置いても動作する。

しかし、外部プラグインを呼ぶサブコマンドでは動作せず、サブコマンドのあとに flag をつける必要がある。

$ kubectl --context foo awesome-plugin
Error: flags cannot be placed before plugin name: --context

get, logs などは後置でも動作するので、常に後置にする(args 1つ目の直後)ように作ると良い。

上述の例でいうと、以下のようになる。

$ kubectl [kubectl 1st arg] --context foo --namespace bar [kubectl remaining args / flags]
(例) $ kubectl describe --context foo --namespace bar pod ...

kubectl の補完を利用する

kubectl では強力な補完機能を備えており、

source<(kubectl completion zsh)

すると _kubectl関数が ZSHにインストールされて、kubectl の呼び出し時に補完用関数として呼び出されるようになる。

上述した kubewrapperでの補完でも、 kubewrapper のオプションの補完もしつつ、kubectl の補完も使えるようにしたら便利だが、どうすればよいのか?

_kubectl は何をするのか

_kubectlcobraを通じて生成されているが、その中では type されたコマンドの __completeサブコマンドが呼ばれている。

($ kubectl completion zsh の結果より)
requestComp="${words[1]} __complete ${words[2,-1]}"

色々細かい処理を省略すると、$wordsには今まさに打ち込んでいるコマンドの配列となっており、ZSHは 1-index なので words[1]は実行しようとするコマンド、 ${words[2,-1}は残りの引数ということになる。

すなわち、 $ kubectl get po<tab>を打っているとき、裏では _kubectl内で $ kubectl __complete get poが呼ばれている。

_kubectl をカスタムコマンドで使う

ここで上述の kubewrapper の補完関数として _kubectlを設定するとどうなるのか。

_kubectlはあくまで今打ち込まれているコマンドを打つので、

$ kubewrapper -p staging get po<tab>

と打ったときは

$ kubewrapper __complete -p staging get po

が呼ばれることになる。

ここで kubectl の補完結果を流用するには、 wrapper 独自のオプションを消し、namespace や context flag を付加して kubectl の __complete コマンドを exec する、すなわち kubewrapper が以下を exec すれば良い。

$ kubectl __complete --context foo --namespace bar get po

※ __complete の前に namespace や context をつけると plugin 同様エラーになる

これを実現するには、wrapper の argv で __completeが 2 つめに来ていたら、$ kubectl __completeを打とうとしていると解釈すれば良い。wrapper で必須の引数が __complete の後にくることになるので、順序を入れ替えて解釈すると楽。

$ kubewrapper __complete -p staging get po
-> wrapper 内部では以下のように解釈する
$ kubewrapper -p staging __complete get po
-> そうすると wrapper の機能で自然と __complete が打たれる
$ kubectl __complete --context foo --namespace bar get po

wrapper のオプション補完

ここまで話した通り kubectl 関係の補完は _kubectlを通じて wrapper を呼び出して $ kubectl __completeに変換すればいい感じになるが、 その前に wrapper の必須 flag を埋めてもらう必要がある。

wrapper の必須 flag がなければそれを補完、満たされていれば kubectl の補完を発動させたい。

これは気合でいい感じに補完関数を書くことになる。

How do I check whether a zsh array contains a given value? - Unix & Linux Stack Exchangeを参考にしつつ、以下のようにした:

if [[ $words[(Ie)-p] == 0 ]]; then  # _arguments に wrapper の補完のみを記載する
  _arguments ...
else  # _arguments に kubectl の補完も加える
  _arguments ... \
    '(-)*:kubectl args: _kubectl'fi

(-)*は kubectl の args が現れた後は全てのハイフンの補完を無視するという意味。

zsh.sourceforge.io

こうすると、最初は wrapper に必須の flag のみが補完され、全て埋まったら wrapper の他の flags とともに kubectl の補完も表示されるようになる。


Viewing all articles
Browse latest Browse all 7930

Trending Articles