tl;dr

ついカッとなってシリーズ化したい。

そんなにカッとはなっていないけど、ギョームで利用している Neustar の Web UI がたまに重かったり、負荷試験の自動化なんかを視野にいれるとコマンドラインツールとかあると嬉しいようなあと資料を見ていたら、以下のように API が提供されていたので、この API を叩いて返ってくる結果をそのまま出力するだけの雑なコマンドラインツールを作ってみたくさ。

### neustar とは

Neustar Web Performance offers load testing & website monitoring. A reliable cloud testing solution, it uses both virtual & real web browser monitoring.

www.neustar.biz

Web サイトの負荷試験を行う SaaS サービス。Selenium WebDriver にも対応した負荷試験のシナリオは JavaScript で記述することが出来たり、負荷試験の結果は SQL を使って詳細な解析を行うことが出来る…が、日本では多分、かなりマイナー。

作ったもの

github

neustar-pfm-cli - Neustar WebPerformance Management API を叩く非公認コマンドラインツール

github.com

Gem でも配ってみるという暴挙。

何が出来ると?

  • シナリオスクリプトの一覧取得
  • シナリオスクリプトの Local Validate
  • シナリオスクリプトのアップロード
  • 負荷試験一覧の取得
  • 負荷試験のスケジューリング
  • 負荷試験の削除

詳しくは…

demo

  • 事前に…API キーと Shared Secret 及び Local Validator のパスを環境変数に指定
export NEUSTAR_API_KEY="xxxxxxxxxxxxxxxxxxxxxxxxxx"
export NEUSTAR_SHARED_KEY="xxxxxxx"
export NEUSTAR_LOCAL_VALIDATOR_PATH="/path/to/local-validator-4.34.17/bin/validator"
  • シナリオスクリプトを作成
var c = test.openHttpClient();
c.setFollowRedirects(false);
test.beginTransaction();
test.beginStep("Check Website");
c.get("http://kome.inokara.com/", 200);
test.endStep();
test.endTransaction();

script.js というファイル名で保存する。

  • シナリオスクリプトをローカル環境でチェック
bundle exec bin/npc-scripting val -f path/to/script.js

以下のように出力される。

Neustar Web Performance Script Validator 4.34.17
Copyright (c) Neustar Inc - All Rights Reserved.
VNC Support is NOT Available

INFO 07/16 02:36:13 b.n.w.a.s.JavaScrip~ - LITE mode starting up
INFO 07/16 02:36:13 b.n.w.a.s.JavaScrip~ - Starting script executor 0
INFO 07/16 02:36:13 b.n.w.a.a.Webmetric~ - Using DNS Server: [192.168.24.1]
INFO 07/16 02:36:13 b.n.w.a.s.JavaScrip~ - Script complete.
INFO 07/16 02:36:13 b.n.w.v.ValidationR~ - Saving validation logs to 'validation.txt'...
INFO 07/16 02:36:13 b.n.w.v.ValidationR~ - Saving Http Archive(HAR) to 'har.js'...
  • シナリオスクリプトのアップロード
#
# -n : スクリプト名を指定
# -f : スクリプトファイルのパスを指定
# -t : タグを指定(複数指定する場合にはカンマで区切る)
# -d : スクリプトの詳細を指定
#
bundle exec bin/npc-scripting up -n demo01 -f path/to/script.js -t tag1,tag2 -d "this is sample"

以下のように出力される。

{"name":"demo01","scriptBody":"var c = test.openHttpClient();nc.setFollowRedirects(false);ntest.beginTransaction();ntest.beginStep("Check Website");nc.get("http://kome.inokara.com/", 200);ntest.endStep();ntest.endTransaction();n","tags":["demo","test"],"description":"description"}
{"result":"OK","data":{"script":{"id":"1234567890xxxxxxxxxxxxxxxxxxxxxxxxxxx","accountId":"xxxxxxxxxxxxxxxxxxxxxxxxxx","name":"demo01","description":"description","scriptType":"VirtualUser","validationState":"VALIDATING","validationBypassed":false,"lastValidated":null,"lastValidationAttempted":"2016-07-16T02:39:42.544+0000","validationResults":null,"numRequests":0,"pageViews":0,"stepCount":0,"txTime":0,"hasScreenshot":false,"hasScreenVideo":false,"logFileAvailable":false,"harFileAvailable":false,"transactionFileAvailable":false,"maxBps":0,"created":"2016-07-16T02:39:39.195+0000","deleted":false,"versionId":"h9OBnizehhH89yVZkKDA2aKGPBvw05la","format":"JavaScript","scriptBody":"var c = test.openHttpClient();nc.setFollowRedirects(false);ntest.beginTransaction();ntest.beginStep("Check Website");nc.get("http://kome.inokara.com/", 200);ntest.endStep();ntest.endTransaction();n","scriptUploaded":true,"screenshotUrl":null,"screenVideoUrl":null,"harFileUrl":null,"logFileUrl":null,"transactionFileUrl":null,"scriptExecutionTimeout":0,"versionHistory":[{"versionId":"h9OBnizehhH89yVZkKDA2aKGPBvw05la","modifiedByUsername":"xxxxx@xxxx.com","lastModified":"2016-07-16T02:39:42.513+0000","validated":false,"stepLabels":null,"validationBrowser":null,"validationQueue":null}],"tags":["test","demo"],"availableFormats":["JavaScript"],"maxBpsOverride":0,"maxTotalTimeOverride":0,"monitorCount":0,"loadTestCount":0,"updateMonitors":false,"regOptIn":false}}}
  • アップロードしたシナリオスクリプト名と ID を取得
bundle exec bin/npc-scripting ls | jq '.data.items[]|{name,id}|select(contains({name:"demo"}))'

JSON のパースは jq におまかせ。以下のように出力される。

{
  "id": "1234567890xxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "name": "demo01"
}
  • 負荷試験定義ファイルを作成

負荷試験の定義は YAML ファイルで書くようにした。

# 負荷試験名を指定
name: "myloadtest"

# ソースとなるリージョンを指定
region: "AP_NORTHEAST"

# 試験で利用するシナリオスクリプトの ID と割合を指定
scripts:
  - percentage: 100
    scriptId: "1234567890xxxxxxxxxxxxxxxxxxxxxxxxxxx"

# ワークロード(という言い方が合っているか判らないけど)を指定(duration = 5 min / maxUsers = 10 / type = RAMP)
parts:
  - duration: 5
    maxUsers: 10
    type: "RAMP"

この定義ファイルを loadtest.yml という名前で保存しておく。

  • 負荷試験をスケジューリング
bundle exec bin/npc-loadtest sc -f loadtest.yml

以下のように出力される。

{"name":"myloadtest","region":"AP_NORTHEAST","scripts":[{"percentage":100,"scriptId":"1234567890xxxxxxxxxxxxxxxxxxxxxxxxxxx"}],"parts":[{"duration":5,"maxUsers":10,"type":"RAMP"}]}
{"data":{"loadTest":{"name":"myloadtest","id":275822,"state":"SCHEDULED","type":"VirtualUser","region":"AP_NORTHEAST","end":"2016-07-16T03:05:14.000+0000","parts":[{"type":"RAMP","duration":5,"maxUsers":10}],"accountId":"xxxxxxxxxxxxxxxxxxxxxxxx","start":"2016-07-16T03:00:14.000+0000","scripts":[{"percentage":100,"scriptId":"1234567890xxxxxxxxxxxxxxxxxxxxxxxxxxx"}],"overrideCode":null,"numTransactions":0,"numFailures":0,"launchedUsers":0,"privateUrl":"https://load.wpm.neustar.biz/load/test/275822","publicUrl":"https://load.wpm.neustar.biz/load/test/share/xxxxxxxxxxxxxxxxxxxxxxxxxxx","durationFormatted":"5 minutes","numScripts":1,"numParts":1}},"result":"OK"}

Nuestar の WebUI でも負荷試験がスケジューリングがされている。

20160716115609

  • 負荷試験一覧から任意の負荷試験の情報を取得する
bundle exec bin/npc-loadtest ls | jq '.data.items[]|{name,id,privateUrl,state,numTransactions}|select(.name=="myloadtest")'

以下のように出力される。

{
  "numTransactions": 102,
  "state": "RUNNING",
  "privateUrl": "https://load.wpm.neustar.biz/load/test/1234567",
  "id": 1234567,
  "name": "myloadtest"
}

privateUrl にアクセスすると以下のように試験が開始されている。

20160716120706

  • 任意の負荷試験の情報を取得する
bundle exec bin/npc-loadtest get -i 123456 | jq '.data.loadTest|{name, state, numTransactions, numFailures}'

以下のように出力される。

{
  "numFailures": 0,
  "numTransactions": 16435,
  "state": "FINISHED",
  "name": "myloadtest"
}

最後に

自分以外は誰も使うことが無いであろう…

ちなみに、Thor というコマンドラインツールが簡単に使える Gem を多分初めて利用してみたけど、とても簡単にコマンドラインツールが作れることに感動した。

元記事はこちら

ついカッとなって Neustar のコマンドラインツールを作ってみたくさ