6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

富士通クラウドテクノロジーズAdvent Calendar 2020

Day 11

shell2httpを使ってお手軽にCLIツールをHTTP API化する

Last updated at Posted at 2020-12-10

この記事は、富士通クラウドテクノロジーズ Advent Calendar 202011日目 の記事です。
10日目は @nashikさんの PowerPointで絶対にプレゼンの時間を遵守させるツールを作る の記事でした。
パワポVBAでこんなこともできるのですね。興味深い記事でした。(ウサギ実行という関数名が素敵です)

本日はIaaS APIの開発をしている私が、開発をする上で役立ちそうなツールについて紹介したいと思います。

はじめに

最近API開発でとあるシミュレーター(ステートフルなMockサーバーのようなもの)を使っています。そのシミュレーターをテストコード内で呼び出すときに、起動と終了をテストケースごとに行えれば実装がシンプルになります。

事前処理や事後処理内でプロセスを直接呼びだしても良いのですが、そんなヘビーなことをテストコード内でやりたくありませんね・・

CLIを制御するようなHTTP API生えてきてくれないかな :angel_tone2: と思っていたら簡単に生やす方法がありそうなので見てみたいと思います。

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を起動 :sunrise:

オプションパラメータを指定しつつ起動します。

$ curl -m 1 http://localhost:5000/start --data-urlencode "options=-cluster 2"

※ フォアグラウンドで起動しますので -m オプションクライアント側からタイムアウトしています。
options として指定したリクエストパラメーターが $v_options の形でshell2http側で変換されます。

/status をHTTPリクエストしてvcsimの状態を確認 :eyes:

起動できたことを確認します。シミュレーターがVMっぽいものを起動していますね。

$ curl http://localhost:5000/status
/
/DC0
/DC0/vm
/DC0/vm/DC0_H0_VM0
/DC0/vm/DC0_H0_VM1
...

/kill をHTTPリクエストしてvcsimを終了 :waxing_gibbous_moon:

起動できましたので今度はシャットダウンしてみます。

$ curl http://localhost:5000/kill

/status をHTTPリクエストしてvcsimの状態を再確認 :eyeglasses:

終了しているかどうかを確認するため、もう一度状態を確認してみます。確認時にエラーが発生していることを確認できます。

$ 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を書くことで同様の挙動を期待できます。

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エンジニアタスクフォースの活動報告記事です。
今年はどのような活動をしたのでしょうか。ぜひご覧ください!

参考文献

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?