この記事は、富士通クラウドテクノロジーズ Advent Calendar 2020 の 11日目 の記事です。
10日目は @nashikさんの PowerPointで絶対にプレゼンの時間を遵守させるツールを作る の記事でした。
パワポVBAでこんなこともできるのですね。興味深い記事でした。(ウサギ実行という関数名が素敵です)
本日はIaaS APIの開発をしている私が、開発をする上で役立ちそうなツールについて紹介したいと思います。
はじめに
最近API開発でとあるシミュレーター(ステートフルなMockサーバーのようなもの)を使っています。そのシミュレーターをテストコード内で呼び出すときに、起動と終了をテストケースごとに行えれば実装がシンプルになります。
事前処理や事後処理内でプロセスを直接呼びだしても良いのですが、そんなヘビーなことをテストコード内でやりたくありませんね・・
CLIを制御するようなHTTP API生えてきてくれないかな と思っていたら簡単に生やす方法がありそうなので見てみたいと思います。
shell2http
shell2http は名前の通りシェルコマンドをHTTP越しで実行するためのツールです。
Go製でStar数は2020/12/09現在 666 です。
今回はこちらのツールを利用してAPI化してみたいと思います。
インストール
Install に書いてある手順のどれかでインストールできます。
Goが使えれば下記が楽かと思います。
go get -u github.com/msoap/shell2http
# set link to your PATH if needed:
ln -s $(go env GOPATH)/bin/shell2http ~/bin/shell2http
使ってみる
とりあえずHTTP経由でdateコマンドを実施したいと思います。
API公開は下記のコマンドを実施するだけです。Go製のツールだけあってさくっと一瞬で起動します。
- ターミナル1
- サーバー起動
$ shell2http /date "date"
- ターミナル2
- HTTPリクエスト
$ curl http://localhost:6000/date
Wed Dec 9 18:12:32 JST 2020
ターミナル1でlocalhostの /hello
にechoコマンドがバインドされたサーバーが起動したため、ターミナル2でcurlで取得できるようになりました。
指定可能なオプションについて
$ shell2http -help
で指定可能なオプションが見れます。
-port
でのサーバーポート指定や -form
でのリクエストパラメータ指定はよく使うかと思います。
$ shell2http -help
usage: shell2http [options] /path "shell command" /path2 "shell command2"
-add-exit
add /exit command
-basic-auth string
setup HTTP Basic Authentication ("user_name:password")
-cache int
caching command out (in seconds)
-cert string
SSL certificate path (if specified -cert/-key options - run https server)
-cgi
run scripts in CGI-mode
-export-all-vars
export all current environment vars
-export-vars string
export environment vars ("VAR1,VAR2,...")
-form
parse query into environment vars, handle uploaded files
-host string
host for http server
-include-stderr
include stderr to output (default is stdout only)
-key string
SSL private key path
-log string
log filename, default - STDOUT
-no-index
don\'t generate index page
-no-log-timestamp
log output without timestamps
-one-thread
run each shell command in one thread
-port int
port for http server (default 8080)
-shell string
custom shell or "" for execute without shell (default "sh")
-show-errors
show the standard output even if the command exits with a non-zero exit code
-timeout int
set timeout for execute shell command (in seconds)
-version
get version
shell2httpでCLIツールの制御用コマンドをAPI公開する
先述した通り、CLIツールの起動、終了をAPI経由で叩けるようにしてみます。
サンプルではvcsimというvCenterのシミュレーターツールの起動・終了コマンドをAPI公開したいと思います。
APIサーバー起動
vcsimを制御する下記のような3つのAPIを起動してみます。
-
/start
- vcsimを起動する(リクエストパラメータでオプションを指定可能)
-
/kill
- 起動中のvcsimプロセスを強制終了する
-
/status
- vcsimが動作していることを確認する
下記でサーバーを起動します。
$ shell2http -form -port 5000 \
/start "vcsim $v_options" \
/kill "killall vcsim" \
/status "env GOVC_URL=https://user:pass@127.0.0.1:8989/sdk govc find -k ."
/start
をHTTPリクエストしてvcsimを起動
オプションパラメータを指定しつつ起動します。
$ curl -m 1 http://localhost:5000/start --data-urlencode "options=-cluster 2"
※ フォアグラウンドで起動しますので -m
オプションクライアント側からタイムアウトしています。
※ options
として指定したリクエストパラメーターが $v_options
の形でshell2http側で変換されます。
/status
をHTTPリクエストしてvcsimの状態を確認
起動できたことを確認します。シミュレーターがVMっぽいものを起動していますね。
$ curl http://localhost:5000/status
/
/DC0
/DC0/vm
/DC0/vm/DC0_H0_VM0
/DC0/vm/DC0_H0_VM1
...
/kill
をHTTPリクエストしてvcsimを終了
起動できましたので今度はシャットダウンしてみます。
$ curl http://localhost:5000/kill
/status
をHTTPリクエストしてvcsimの状態を再確認
終了しているかどうかを確認するため、もう一度状態を確認してみます。確認時にエラーが発生していることを確認できます。
$ curl http://localhost:5000/status
exec error: exit status 1%
以上のようにすればコマンドの起動、終了、状態確認をHTTP経由で実施できます。
curlで行っているリクエストをそれぞれのプログラミング言語のHTTPクライアントで実装するだけで、簡単にテストが書けますね!
サンプルとしてはvcsimを用いていますが、他のツールでも同様の手順でAPI公開できるかと思います。
(おまけ) HTTPメソッドについて
今回は簡単にすべてGETメソッドで実現しましたが、一般的に /kill
や /start
はPOSTメソッドで実現するかと思いますのでそんなときはshell2httpの起動コマンドを下記のようにパスの前にメソッドを指定すればよいです。こうしておくことで /kill
がブラウザで補完されてうっかり消してしまうことはなくなるでしょう。
$ shell2http -form -port 5000 \
POST:/start "vcsim $v_options" \
POST:/kill "killall vcsim" \
GET:/status "env GOVC_URL=https://user:pass@127.0.0.1:8989/sdk govc find -k ."
(おまけ) shell2httpをコンテナ化
テストコードで扱う上ではshell2http自体はコンテナを起動するだけで実行できるとさらに良いですね。
vcsimの場合例えば下記のようにDockerfileを書くことで同様の挙動を期待できます。
FROM nimmis/vcsim
EXPOSE 8989 443 80 8080
# shell2httpで制御用コマンドをAPI公開する
COPY --from=msoap/shell2http /app/shell2http /usr/local/bin/shell2http
EXPOSE 5000
ENTRYPOINT ["/usr/local/bin/shell2http", "-form", "-port", "5000","/spawn", "hostname | xargs -I {} vcsim -l {}:8989 $v_options", "/killall", "killall vcsim --wait -q", "/govc_find", "hostname | xargs -I {} env GOVC_URL=https://user:pass@{}:8989/sdk govc find -k ."]
まとめ
シェルコマンドをHTTP API化する方法を紹介しました。
今回はテスト用途での利用を想定しましたが、他にも活用の幅は広いツールかと思いますのでぜひご活用ください。
※ ちなみに本番環境で使うのであれば、リクエストパラメーターでのOSコマンドインジェクションの脆弱性がないか、認証は十分か等セキュリティ対策が十分に必要ですので、お手軽に使いたいのでしたらあくまで検証、開発用のある程度閉じた環境で使うことをお勧めします。
明日は @tily さんの2020年のFJCTエンジニアタスクフォースの活動報告記事です。
今年はどのような活動をしたのでしょうか。ぜひご覧ください!
参考文献
-
https://github.com/ansible/vcenter-test-container
- vcsimをコンテナ化しflaskでラッパーしたもの(本記事はこれをより汎用的に使う方法を考えた結果です)
- shell2httpでAWS FargateやSSHレスの運用を少しだけ楽にする
- 類似ツール
-
webhook
- jsonでより細かく設定できる。どちらかというとパッケージ名通りwebhook的用途向き。
-
websocketd
- コマンドをwebsocketで公開できる。面白そう。
-
webhook