昨日書いた記事のなかでkuoというkubectl pluginを突貫工事でガッと作ったという話をした。
昨日の時点ではテストがなかったりして色々あれだったので、今日最低限のラインまで持っていってリリースを打つところまでやった。せっかくなので勢いのあるうちのその差分だけでも紹介できたらと思う。
機能面
kubectlサブコマンドのフラグ対応
機能の時点では以下のようなkubectl
のサブコマンドは問題なく動いていた。
$ kubectl kuo get node
======== cluster1 ========
NAME STATUS ROLES AGE VERSION
chino Ready control-plane 25d v1.25.4+k0s
maya Ready <none> 25d v1.25.4+k0s
megu Ready <none> 25d v1.25.4+k0s
======== cluster2 ========
NAME STATUS ROLES AGE VERSION
minikube Ready control-plane 122m v1.25.3
しかしながら、-o
フラグなどをつけるとcobla(というかpflagっぽい)がkuoのフラグだと解釈してしまい、定義されてないことから怒られが発生してしまった。
$ kubectl kuo get node -o wide
Error: unknown shorthand flag: 'o' in -o
そこで、kuo側ではフラグを使う予定がなかったので、全部そのまま引数として扱ってもらうようにした。
そうすることで、自然な形でkubectlサブコマンドのフラグを利用できるようになった。
$ kubectl kuo get node -o wide
======== cluster1 ========
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
chino Ready control-plane 26d v1.25.4+k0s 10.x.y.124 <none> Ubuntu 22.04.1 LTS xxxxxxxxxxxxxxxxx containerd://x.y.z
maya Ready <none> 26d v1.25.4+k0s 10.x.y.88 <none> Ubuntu 22.04.1 LTS xxxxxxxxxxxxxxxxx containerd://x.y.z
megu Ready <none> 26d v1.25.4+k0s 10.x.y.112 <none> Ubuntu 22.04.1 LTS xxxxxxxxxxxxxxxxx containerd://x.y.z
======== cluster2 ========
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
minikube Ready control-plane 22h v1.25.3 192.x.y.2 <none> Buildroot 2021.02.12 x.y.z docker://x.y.z
インストール周り
とりあえず普通にMakefileを用意して、そこでビルドと配置をするようにした。素朴な感じ。
install: ./cmd/kuo/main.go
go build -o kubectl-kuo ./cmd/kuo
mv ./kubectl-kuo /usr/local/bin/
krewから落としてこれたりするのがベストだとは思うが、登録するにもレビューが走るらしいのでそちらは保留にすることにした。
テスト
テストはとりあえずコマンドが正しく動くかどうかを確認するだけの最低限のところまでで、コマンドに値を渡して期待される応答が帰ってくるかを見ている。
func TestCommandKuo(t *testing.T) {
var out []byte
var err error
// .kuoconfigがないときはエラーになる
exec.Command("rm", "~/.kuoconfig").Run()
out, err = exec.Command("kubectl", "kuo").Output()
assert.Error(t, err)
// .kuoconfigがあるときは設定されたcontextの一覧が帰ってくる
InitializeSetContext()
out, err = exec.Command("kubectl", "kuo").Output()
assert.NoError(t, err)
assert.Contains(t, string(out), "["+CONTEXT1+" "+CONTEXT2+"]")
}
まだGoのテストの流儀みたいなのがわかっておらず、多分書き方違うんだろうなぁと思いながらとりあえず書いていた。(テストケースごとで細かくメソッド分けたほうがいいのかなと思った)
ユニットテストとかもこれから書く。(多分)
CI
これが、意外と面倒だった。
クラスタが2つある環境を用意しなければならないため、CIの環境構築に悩まされた。
最終的にたどり着いたのは、GithubActionsのhelm/kind-actionとmedyagh/setup-minikubeを同じworkflow上で動かしてそこでテストをするというもの。
- name: Set up Kind
uses: helm/[email protected]
- name: Set up minikube
uses: medyagh/setup-minikube@master
- name: test
run: |
make install
go test ./test/kuo_test.go
本当は全部入ったイメージを作るのが良いんだろうなぁと思いつつもdindでkindとminikubeを動かすのもなぁと思いこの形に落ち着いた。
ということで、今回は延長戦という形で書いてみた。
Goでちゃんとした何かを書くのは初めてなので結構楽しんでやれている。PythonもいいがGoもそれなりに書けますぐらいになれるとよいのかなぁと考えつつ、勉強がてらにちょいちょいkuoの更新をしていこうと思う。