2つのContextを同時に操作するkubectlプラグインを作った – 延長戦

昨日書いた記事のなかで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-actionmedyagh/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の更新をしていこうと思う。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA