clap - 簡単にツールをインストールするためのツールを作った

    多分車輪の再生産だとは思いますが、簡単にツールをインストールするための CLI ツールを作りました。 tarball や zip をダウンロードして展開して指定したパスにインストールするツールです。 https://github.com/suzuki-shunsuke/clap Go で書かれています。 ツールの名前(clap)には特別な意味や理由はなく、なんとなくです。 CI で何かしらのツールをインストールすることがままあって、そのためのシェルスクリプトを都度書くのが割と面倒なのでツール化しました。 このブログを書いている時点でバージョンは v0.1.0-1 で、最低限の機能しかありませんが、9割型ニーズを満たせるかなと思います。 使い方は以下のようになっています。 $ clap <URL> <インストールするファイルのアーカイブ内での相対パス>:<インストール先> [<インストールするファイルのアーカイブ内での相対パス>:<インストール先>...] 例えば conftest を /usr/local/bin にインストールする場合次のようになります。 CONFTEST_VERSION=0.18.2 clap install https://github.com/instrumenta/conftest/releases/download/v${CONFTEST_VERSION}/conftest_${CONFTEST_VERSION}_Linux_x86_64.tar.gz conftest:/usr/local/bin/conftest chmod a+x /usr/local/bin/conftest パーミッションの付与はやってくれないので必要に応じてやってください。 ファイルの圧縮形式は URL から自動で判別してくれます。 上記の conftest のインストールを今までは次のようなシェルスクリプトを書いていました。 #!/usr/bin/env bash set -eu CONFTEST_VERSION=0.18.2 dirpath=$(mktemp -d) pushd "$dirpath" TARFILE=conftest_${CONFTEST_VERSION}_Linux_x86_64.tar.gz curl -OL https://github.com/instrumenta/conftest/releases/download/v${CONFTEST_VERSION}/${TARFILE} tar xvzf $TARFILE mv conftest /usr/local/bin/conftest chmod a+x /usr/local/bin/conftest popd rm -R "$dirpath" 地味に面倒ですね。これをツール毎に書いて、しかも圧縮形式によって微妙に変えないといけません。

    Skaffold で特定のサービスだけ動かすためのツールを作った

    自作の CLI ツール skaffold-generator の紹介です。 プロトタイピングみたいなノリで半日くらいで割と手早く作れました。 名前が長くて適当なのでもっと良い名前ないかなと思ってます。 Skaffold に欲しい機能がないので補完する感じで作ったのですが、「それ〇〇で出来るよ」とかあったら(GitHub issue とか Twitter で)教えていただけると幸いです。 どんなツールか 設定ファイル skaffold-generator.yaml を監視して変更があったら skaffold.yaml を生成するツールです。設定ファイルでサービスの依存関係を定義できたり、コマンドライン引数で指定したサービス及びそれが依存するサービスに関連した設定だけを使って skaffold.yaml を更新します。 このツールは skaffold.yaml を生成するだけなので実際にアプリケーションをビルド・デプロイするには skaffold と組み合わせて使います。 なぜ作ったか 元々ローカルでアプリケーションを動かしながら開発するために Docker Compose を使ってるリポジトリがあるのですが、それを skaffold に移行出来ないか検証しています。 まだ skaffold を触り始めたばかりで理解が浅いのですが、 本番環境は k8s で動いてるからローカルも k8s で動かせるといいかなと思ったり、あとは変更を検知して自動でビルド・デプロイしてくれたりして便利そうかなと思いました。 まぁ結果的に移行しないことになったとしても、 Skaffold と現状の仕組みについて理解が深まればいいかなくらいのつもりです。 検証の過程で、 以下のようなことが Docker Compose だと出来るけど Skaffold だと難しそうだと思いました。 サービスの依存関係を定義すること Skaffold というより k8s の問題かとは思いますが Docker Compose だと依存するものを自動で起動してくれて便利 コマンドライン引数で指定したサービスだけ起動すること Skaffold だと skafffold.yaml で定義したものすべてがビルド・デプロイされるという認識 サービスの数が少なければ全部ビルド・デプロイでもいいですが、 マイクロサービスをモノレポで管理しているような場合、 すべてのマイクロサービスをビルド・デプロイするのは無駄が大きかったりします。

    dd-time - コマンドの実行時間を Datadog に送るツール

    コマンドの実行時間を Datadog に送る dd-time というツールを作りました。 このツールは circle-dd-bench にインスパイアされていますが、 CircleCI 以外でも需要あると思ったり、他にも幾つか改善したい部分があったので自作することにしました。 circle-dd-bench については circle-dd-bench の作者が書いたブログ https://blog.yuyat.jp/post/circle-dd-bench/ も参考にしてください。 dd-time は Go 製なので GitHub Releases からバイナリをダウンロードしてインストールすれば使えます。 使い方はシンプルで実行時間を計測したいコマンドの前に dd-time -- をつけるだけです。 例えば Docker image のビルドの時間を計測したい場合次のような感じになります。 $ dd-time -t command:docker-build -- docker build . Datadog の API key を環境変数 DATADOG_API_KEY として設定する必要があります。 こうすると Datadog の Post timeseries points API を使い、command_execution_time というメトリックス名(変更可能)でコマンドの実行時間が送られます。 メトリックスの名前や host, tags はそれぞれ --metric-name (-m), --host, --tag (-t) で指定できます。 --tag は複数回指定可能で、 key:value というフォーマットで指定します。

    go-timeout - command の timeout

    作ったのは 2ヶ月くらい前の話ですが、 Go の command の timeout を実装するためのライブラリを作ったので紹介します。 https://github.com/suzuki-shunsuke/go-timeout 基本的には https://github.com/Songmu/timeout をオススメしますが、これだと上手くいかないパターンがあったので自作しました。 Go の command の timeout に関しては https://junkyard.song.mu/slides/gocon2019-spring/#24 がとても参考になります。 上記のスライドでは 標準ライブラリの exec.CommandContext でも停止できるが、 SIGKILL で強制的に停止することになる 子プロセスが停止しない 公式見解 では、SIGKILL 以外は標準ライブラリではサポートしない。サードパーティでやればよい Songmu/timeout 使えば SIGKILL 以外でより安全に停止できる ということが丁寧に説明されています。 自分は cmdx という task runner を開発していてその中で task の実行時に timeout を設定出来るようにしました。 当初 Songmu/timeout を使って実装したのですが、問題があることに気づきました。 それは、 command の中で fzf を使うと、上手く動かないというものでした。 https://github.com/suzuki-shunsuke/cmdx/issues/52 https://twitter.com/szkdash/status/1165529415238815745 正直この辺の挙動はちゃんと理解できていないのですが、 調べてみると Songmu/timeout だと syscall.SysProcAttr の Setpgid を true に設定していて、そうすると fzf が上手く動かないようでした。

    cmdx - task runner

    最近自作した OSS, cmdx の紹介です。 https://github.com/suzuki-shunsuke/cmdx cmdx は task runner です。 task runner の定義はググってもわからなかったので、 cmdx を task runner と呼ぶのが適切かわかりませんが、 ここではプロジェクト固有のタスク 依存するライブラリのインストール ビルド テスト コード整形 lint etc などを管理するものとします。 類似するものとしては以下のようなものがあります。 Make npm scripts Task tj/robo mumoshu/variant 使い方 詳細は README を読んでください。 $ cmdx -i で設定ファイルの雛形を生成します。 そして設定ファイルに task を定義していきます。 設定に関しては README を参照してください。 そうすると cmdx -l でタスクの一覧とその説明が見れます。 例えば次は cmdx のリポジトリでの実行結果です。 $ cmdx -l init, i - setup git hooks coverage, c - test a package (fzf is required) test, t - test fmt - format the go code vet, v - go vet lint, l - lint the go code release, r - release the new version durl - check dead links (durl is required) ci-local - run the Drone pipeline at localhost (drone-cli is required) これにより新しくプロジェクトに参画した人もどのような task があるのか直ぐわかります。 例えば test を実行したければ cmdx t を実行すればいいことがわかります。 cmdx help test とすればここのタスクのより詳細なヘルプが見れます。

    Flute - Golang HTTP client testing framework

    2019-07-17 追記 プロジェクト名が変わりました https://github.com/suzuki-shunsuke/flute/issues/20 Go の HTTP client のテストフレームワークを作ったので紹介します。 https://github.com/suzuki-shunsuke/flute 執筆時点のバージョンは v0.6.0 です。 リクエストパラメータのテスト HTTP サーバのモッキング を目的としています。 比較的実践的なサンプルとして、ユーザーを作成する簡単な API client とそのテストを書いたので参考にしてください。 https://github.com/suzuki-shunsuke/flute/blob/master/examples/create_user.go https://github.com/suzuki-shunsuke/flute/blob/master/examples/create_user_test.go#L17-L53 元々自分はこの目的のために h2non/gock を使っていました。 ただ、 gock だとリクエストがマッチしなかったときに、なぜマッチしないのかがわからず、調査に困るという問題がありました。 そこで flute では request に対し、matcher と tester という概念を導入し、 matcher でマッチしたリクエストを tester でテストするというふうにしました。 テストでは内部で stretchr/testify の assert を使っており、テストに失敗したときになぜ失敗したのかが分かりやすく出力されるようになっています。 例えば以下の例は、リクエストの Authorization header にトークンがセットされていなかった場合のエラーメッセージです。 === RUN TestClient_CreateUser --- FAIL: TestClient_CreateUser (0.00s) tester.go:168: Error Trace: tester.go:168 tester.go:32 transport.go:25 client.go:250 client.go:174 client.

    Drone v0.8 の .drone.yml を v1 の .drone.jsonnet に変換するツールを作った

    Drone v0.8 の .drone.yml を v1 の .drone.jsonnet に変換するツールを作ったので紹介します。 https://github.com/suzuki-shunsuke/drone-jsonnet-generator 背景 https://docs.drone.io/user-guide/pipeline/migrating/ Drone は v0.8 から v1 で .drone.yml のフォーマットが大きく変わっています。 Drone v1 ではビルド実行時に自動で変換しているため、v0.8 の .drone.yml でもそのまま動きます(matrix builds も動きます)。 そのため、Drone v0.8 から v1 に移行する際、すぐに .drone.yml を修正しなくても問題ないのですが、 v1 独自の機能が出てきた場合 v0.8 のフォーマットの場合利用できないかもしれませんし、 いつまでも古いままだと気持ち悪いので出来るならフォーマットを変換したいです。 drone-cli ではフォーマットを変換する drone convert というコマンドが提供されています。 ただし、 drone convert は matrix build を multiple pipeline に変換するのですが、 非常に冗長になります。 そのため、jsonnet を利用することが推奨されています。 https://docs.drone.io/user-guide/pipeline/migrating/ The above syntax can be quite verbose if you are testing a large number of variations.

    go-jsoneq - 2つの値がJSONとして等しいか比較するGoライブラリ

    https://github.com/suzuki-shunsuke/go-jsoneq 2つの値がJSONとして等しいか比較するGoライブラリを開発したので紹介します。 「2つの値がJSONとして等しい」とは、2つの値をそれぞれJSON文字列に変換したら、2つが表現するデータがおなじになるという意味です。 struct { Foo string `json:"foo"` }{ Foo: "bar", } と map[string]interface{}{"foo": "bar"} を JSON に変換したらともに {"foo": "bar"} になりますね。 json.Marshaler のテストや、 実際の JSON 文字列から構造体を定義したときにちゃんと定義できているかチェックするのに使えると思います。 jsoneq.Equal でやっていることは単純です。 json.Marshal で []byte に変換 json.Unmarshal で []byte を map, array と primitive な型からなるオブジェクト(?)に変換 reflect.DeepEqual で比較 引数が []byte の場合は 1 は飛ばします。 GoDoc やサンプルを見れば使い方は簡単にわかると思います。 以上、簡単ですが、自作ライブラリの紹介でした。

    durl - 壊れたURLを検知するCLIツール

    結構前に開発したツールですが、まだ記事にしてなかったので紹介します。 https://github.com/suzuki-shunsuke/durl ファイル中の URL が壊れていないかチェックするツールです。 ファイル中の URL を抽出し、HTTPリクエストを投げてステータスコードが 2xx でないものがあった場合、異常終了します。 なお、ページ内リンク(アンカー)が壊れているものについては検知できません。 インストール Go製で、バイナリを GitHub Releases で公開しています。 https://github.com/suzuki-shunsuke/durl/releases Docker イメージ https://quay.io/repository/suzuki_shunsuke/durl busybox ベースの Docker イメージも提供しています。 CI で使うのに便利です。 使い方 durl init で設定ファイル .durl.yml を生成します。 $ durl init durl check に対象ファイルパスのリストを標準入力として渡してください。 find コマンドなどと組み合わせると良いです。 https://github.com/suzuki-shunsuke/go-errlog/blob/v0.9.0/scripts/durl.sh#L9 find . \ -type d -name node_modules -prune -o \ -type d -name .git -prune -o \ -type d -name vendor -prune -o \ -type f -print | \ grep -v package-lock.

    GraylogをTerraformで管理する

    Graylogのリソースを terraform で管理するために作った terraform provider を紹介します。 Graylogとは何かはこちらを読んでください。 Graylogには様々なリソースがあります。 User Role Input Index Set Stream Stream Rule Dashboard Alert etc これらのリソースはWeb UIから作成したり出来るわけですが、 Web UIでポチポチするのは疲れますし、ソースコードで管理したいものです(Infrastructure as Code)。 また、Web UIからでは細かな権限管理は出来ず(限られた権限管理しか出来ない)、APIを使ってする必要があります。 APIを使って管理できるツールを探したものの見つからなかったので、 APIを使ってGraylog用のterraform providerを自作しています。 https://github.com/suzuki-shunsuke/go-graylog GraylogのAPIの種類は非常に多く、残念ながらカバーできているのは一部だけですが、以下のようなものをサポートしています。 Alert Condition Alert Notification (Alarm Callback) Input User Role Index Set Stream Stream Rule Dashboard Ldap Setting Role はサポートしているので権限管理は問題なく出来ます。 Dashboard Widget もサポートしたいです。 出来れば Alert の設定も出来ると良いのですが、Alertに関するCRUD APIが提供されていない(GETのみ)ので、サポートできません。 terraform を使った管理方法 以下では自分の管理方法を紹介します。 https://github.com/suzuki-shunsuke/example/tree/master/graylog-terraform にサンプルが置いてあります。 基本はプロジェクトごとに Index Set, Stream, Role といったリソースを作成 User に Role を付与 という流れになります。