ようへいの日々精進XP

よかろうもん

Docker for Windows をあと 10 分位使ってみた(Shared Drives を触る)

tl;dr

Docker for Windows の Settings... に Shared Drives という設定があったので触ってみた。

f:id:inokara:20160807220753p:plain

どうやらホスト OS のドライブ(フォルダ)を Docker のボリュームオプションを使ってマウントする為の設定らしい。


メモ

Shared Drives を有効にする

f:id:inokara:20160807221250p:plain

コンテナからマウントして操作する

docker run のボリュームオプションを利用してホスト OS のフォルダをマウントする。

PS C:\Users\kappa> dir .\Documents\tmp\docker\


    ディレクトリ: C:\Users\kappa\Documents\tmp\docker


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----       2016/08/07     22:06                test01
d-----       2016/08/07     22:06                test02
d-----       2016/08/07     22:06                test03
-a----       2016/08/07     22:06              0 テスト.txt


PS C:\Users\kappa> docker run -v C:/Users/kappa/Documents/tmp/docker:/data alpine ls /data
PS C:\Users\kappa>
PS C:\Users\kappa> docker run -v C:/Users/kappa/Documents/tmp/docker:/data alpine ls /data
test01
test02
test03
テスト.txt

マウントしたフォルダにコンテナからファイルを作成。

PS C:\Users\kappa> docker run -v C:/Users/kappa/Documents/tmp/docker:/data alpine touch /data/test.txt
PS C:\Users\kappa> dir .\Documents\tmp\docker


    ディレクトリ: C:\Users\kappa\Documents\tmp\docker


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----       2016/08/07     22:06                test01
d-----       2016/08/07     22:06                test02
d-----       2016/08/07     22:06                test03
-a----       2016/08/07     22:17              0 test.txt
-a----       2016/08/07     22:06              0 テスト.txt

おお。

以上

プラス 10 分位使ってみたメモでした。

Docker for Windows を 15 分くらい使ってみた

tl;dr

Docker for Windows が 7/28 位に正式にリリースされたらしいので試してみたメモ。

blog.docker.com

docs.docker.com

興味深いのが Docker for Windows仮想マシンHyper-V を利用している点。普通に使う分には Hyper-V を使っていることはユーザーは意識することは無いと思うけど。

導入

要件

  • 64bit Windows 10 Pro, Enterprise and Education (1511 November update, Build 10586 or later). In the future we will support more versions of Windows 10.
  • The Hyper-V package must be enabled. The Docker for Windows installer will enable it for you, if needed. (This requires a reboot).

64 ビット版の Windows 10 で Pro / Enterprise / Education で Hyper-V が有効になっていること。

今回利用する OS は...

f:id:inokara:20160807213609p:plain

ざっくりとしたハードウェア構成は...

f:id:inokara:20160807213736p:plain

導入手順

以下のページのまま。

docs.docker.com

インストールが完了後、再起動すると Docker Engine が起動し、タスクバーに Docker アイコンが登録される。

f:id:inokara:20160807103948p:plain

右クリックすると以下のようなメニューが出てくる。

f:id:inokara:20160807105126p:plain

About Docker を選択してみる。

f:id:inokara:20160807104218p:plain

Settings.. を選択してみる。

f:id:inokara:20160807105208p:plain

色々と...PowerShell を使って触ってみる

docker version

PS C:\Users\kappa> docker version
Client:
 Version:      1.12.0
 API version:  1.24
 Go version:   go1.6.3
 Git commit:   8eab29e
 Built:        Thu Jul 28 21:15:28 2016
 OS/Arch:      windows/amd64

Server:
 Version:      1.12.0
 API version:  1.24
 Go version:   go1.6.3
 Git commit:   8eab29e
 Built:        Thu Jul 28 21:15:28 2016
 OS/Arch:      linux/amd64

docker info

PS C:\Users\kappa> docker info
Containers: 4
 Running: 0
 Paused: 0
 Stopped: 4
Images: 2
Server Version: 1.12.0
Storage Driver: aufs
 Root Dir: /var/lib/docker/aufs
 Backing Filesystem: extfs
 Dirs: 13
 Dirperm1 Supported: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
 Volume: local
 Network: null bridge overlay host
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Security Options: seccomp
Kernel Version: 4.4.15-moby
Operating System: Alpine Linux v3.4
OSType: linux
Architecture: x86_64
CPUs: 2
Total Memory: 1.952 GiB
Name: moby
ID: FZB3:32TQ:3MCG:MYMU:ES7Z:HRVA:3BQB:VDR3:7YXR:F3HL:B5S6:XSUJ
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Registry: https://index.docker.io/v1/
Insecure Registries:
 127.0.0.0/8

お、Alpine Linux が動いているのか。

仮想マシン

Hyper-V 上で動いている仮想マシンの状態を確認してみる。

PS C:\WINDOWS\system32> Get-VM

Name        State   CPUUsage(%) MemoryAssigned(M) Uptime           Status     Vers
----        -----   ----------- ----------------- ------           ------     ----
MobyLinuxVM Running 0           2048              01:34:33.4740000 正常稼働中 8.0

管理者権限で起動した PowerShellGet-VM コマンドレットで稼働中の仮想マシンを確認することが出来る。

また、Hyper-V マネージャで確認することも出来る。

f:id:inokara:20160807111739p:plain

Hello World

PS C:\Users\kappa> docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world

c04b14da8d14: Already exists
Digest: sha256:0256e8a36e2070f7bf2d0b0763dbabdd67798512411de4cdcf9431a1feb60fd9
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker Hub account:
 https://hub.docker.com

For more examples and ideas, visit:
 https://docs.docker.com/engine/userguide/

nginx コンテナ

PS C:\Users\kappa> docker run -d -p 80:80 nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx

51f5c6a04d83: Already exists
a3ed95caeb02: Already exists
51d229e136d0: Already exists
bcd41daec8cc: Already exists
Digest: sha256:0fe6413f3e30fcc5920bc8fa769280975b10b1c26721de956e1428b9e2f29d04
Status: Downloaded newer image for nginx:latest
2389477365e93f7e57ae930d2bdb351b05b032124814e050c617cb05ee8d2a0e
PS C:\Users\kappa> docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                         NAMES
2389477365e9        nginx               "nginx -g 'daemon off"   3 seconds ago       Up 2 seconds        0.0.0.0:80->80/tcp, 443/tcp   silly_roentgen

PS C:\Users\kappa>
PS C:\Users\kappa> Invoke-RestMethod -Uri "http://localhost" -outfile nginx.txt
PS C:\Users\kappa> cat nginx.txt
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

おお、普通に Docker だ。

以上

15 分位触ってみたメモでした。

Bash も使えるようになってるし、Docker も動くし、もう Windows でいいんぢゃないかなって思ったり。

福岡は Ruby に縁がある街なので、その県民として Ruby Association Certified Ruby Programmer Silver version 2.1 を受験してきた

ども、かっぱです。

tl;dr

福岡は Ruby に縁がある街だと勝手に思っているので、その県民としての義務を果たすべく Ruby Association Certified Ruby Programmer Silver version 2.1 を受験してきたのでメモ。

www.ruby.or.jp

ちなみに、福岡には以下のような Ruby の名前を冠した施設がある。

frac.jp

また、以下のような組織もある。

www.digitalfukuoka.jp

Ruby の故郷は島根県の松江かもしれないけど、第二の故郷は福岡なのかもしれない(と勝手に思っている)。


試験結果は

合否

90 点で合格。(100 点満点で 75 点以上が合格)


なんで受けたか

  • 冒頭にも書いたように福岡県民としての義務だと感じたのが一つ
  • 初老のおっさんが普通自動車免許以外にも免許が欲しかったのが一つ
  • インフラエンジニアでも Ruby 等のプログラム言語に直面する機会が増えてきたので、せめて基本は抑えておきたいと思ったのが一つ

どんな風に勉強したか

勉強した期間

  • トータルで一ヶ月分位

参考書籍

Ruby技術者認定試験合格教本 Silver/Gold対応 Ruby公式資格教科書

Ruby技術者認定試験合格教本 Silver/Gold対応 Ruby公式資格教科書

カスタマーレビューでは評価はイマイチだけど、受験に必要な知識がコンパクトに纏まっているし、模擬試験 50 問 + 基礎知識問題が 30 問ついているので、この本をザーッと一回読んで、模擬試験を解きまくった。

www.ruby.or.jp

上記に掲載されている模擬試験も同じように解きまくった。

模擬試験丸覚えにならない工夫

模擬試験を繰り返しているうちに答えを覚えてしまったので、自分なりに模擬試験の選択肢を pry で実行しながら誤った選択肢の挙動も確認するようにした。

やっぱり pry

模擬試験を解きながら、本を読みながら、掲載されているコードは出来るだけ pry で実行して結果を確認した。


最後に

ちょっとだけ...どんな感じで出題されたか

詳しくは書けないけど、こちらの「試験実施要項 」に書かれているように、主要なクラス(Array や Hash や String)の各メソッドの挙動については抑えておくべきだと思う。あと、演算子、これはかなり覚えるに苦労した...。今でも覚えられていないけど。

次は

メタプログラミングRuby」を読んでゴールド頑張りたい。

メタプログラミングRuby 第2版

メタプログラミングRuby 第2版

cron + α が欲しい時には ts(Task Spooler) のご利用をご検討下さいというメモ

おひさしブリーフ、かっぱです。

tl;dr

下図のように cron ジョブで定期的にスクリプトを生成して実行させようとした時、スクリプト完了する前に次の cron ジョブが走ってスクリプトが生成されて、そのスクリプトが実行されてしまうような状況に遭遇してどうしたもんかなと悩んでいたら ts というツールを見つけたので試してみた。

f:id:inokara:20160807074518p:plain


memo

ts とは

スクリプトやコマンドを ts コマンド経由で実行することで、それらをジョブとしてキューに放り込んで順次実行してくれるツール。冒頭の構成に ts を加えると下図のようになり、cron の開始時間とスクリプトの実行時間の依存関係は切り離される。

f:id:inokara:20160807082925p:plain

導入

CentOS 6 に導入するにはソースコードを取得してビルドする必要がある。

$ cat /etc/redhat-release
CentOS release 6.7 (Final)

$ sudo yum install gcc
$ wget http://vicerveza.homeunix.net/~viric/soft/ts/ts-0.7.6.tar.gz
$ tar zxvf ts-0.7.6.tar.gz
$ cd ts-0.7.6
$ make
$ mkdir ~/bin
$ cp ts ~/bin/ts

サンプル

以下のような雑なシェルスクリプトを cron で実行させる。

$ cat demo.sh
#!/bin/sh

DATE=`date +%s`
echo "echo $DATE && sleep 300" > /tmp/test.sh.$DATE
${HOME}/bin/ts logger -t ts_demo "スクリプトを作成しました"
sleep 3
logger -t ts_demo "スクリプトを実行します"
${HOME}/bin/ts sh /tmp/test.sh.$DATE
${HOME}/bin/ts -d logger -t ts_demo "スクリプトの実行が完了しました"

$ crontab -l
*/3 * * * * /home/centos/demo.sh >/dev/null 2>&1

暫く放置してから ts コマンド(ts -l でも同等)を実行すると以下のように ts コマンド経由で実行したコマンド(スクリプト)がジョブとしてキューイングされている。

$ ts
ID   State      Output               E-Level  Times(r/u/s)   Command [run=1/1]
0    running    /tmp/ts-out.b5xJat                           sh /tmp/test.sh.1470470326
1    queued     (file)                                       [0]&& logger -t ts_demo スクリプトの実行が完了しました
2    queued     (file)                                       logger -t ts_demo スクリプトを作成しました
3    queued     (file)                                       sh /tmp/test.sh.1470470342
4    queued     (file)                                       [3]&& logger -t ts_demo スクリプトの実行が完了しました

さらに暫く放置してからジョブ一覧を確認すると...

$ ts -l
ID   State      Output               E-Level  Times(r/u/s)   Command [run=1/1]
6    running    /tmp/ts-out.FSSSnL                           sh /tmp/test.sh.1470470581
7    queued     (file)                                       [6]&& logger -t ts_demo スクリプトの実行が完了しました
8    queued     (file)                                       logger -t ts_demo スクリプトを作成しました
9    queued     (file)                                       sh /tmp/test.sh.1470470761
10   queued     (file)                                       [9]&& logger -t ts_demo スクリプトの実行が完了しました
11   queued     (file)                                       logger -t ts_demo スクリプトを作成しました
12   queued     (file)                                       sh /tmp/test.sh.1470470941
13   queued     (file)                                       [12]&& logger -t ts_demo スクリプトの実行が完了しました
14   queued     (file)                                       logger -t ts_demo スクリプトを作成しました
15   queued     (file)                                       sh /tmp/test.sh.1470471121
16   queued     (file)                                       [15]&& logger -t ts_demo スクリプトの実行が完了しました
0    finished   /tmp/ts-out.b5xJat   0        300.00/0.00/0.00 sh /tmp/test.sh.1470470326
1    finished   /tmp/ts-out.js0Oq6   0        0.00/0.00/0.00 [0]&& logger -t ts_demo スクリプトの実行が完了しました
2    finished   /tmp/ts-out.6Jjrf6   0        0.00/0.00/0.00 logger -t ts_demo スクリプトを作成しました
3    finished   /tmp/ts-out.fotDb6   0        300.00/0.00/0.00 sh /tmp/test.sh.1470470342
4    finished   /tmp/ts-out.8y6fdL   0        0.00/0.00/0.00 [3]&& logger -t ts_demo スクリプトの実行が完了しました
5    finished   /tmp/ts-out.lMTR8K   0        0.00/0.00/0.00 logger -t ts_demo スクリプトを作成しました

finished となっているのは完了したジョブ。logger で吐いているログを見ると...

$ sudo tail -f /var/log/messages
Aug  6 08:03:04 ip-xxx-xx-xx-xx ts_demo: スクリプトを実行します
Aug  6 08:03:49 ip-xxx-xx-xx-xx ts_demo: スクリプトの実行が完了しました
Aug  6 08:03:49 ip-xxx-xx-xx-xx ts_demo: スクリプトを作成しました
Aug  6 08:06:04 ip-xxx-xx-xx-xx ts_demo: スクリプトを実行します
Aug  6 08:08:49 ip-xxx-xx-xx-xx ts_demo: スクリプトの実行が完了しました
Aug  6 08:08:49 ip-xxx-xx-xx-xx ts_demo: スクリプトを作成しました
Aug  6 08:09:04 ip-xxx-xx-xx-xx ts_demo: スクリプトを実行します
Aug  6 08:12:04 ip-xxx-xx-xx-xx ts_demo: スクリプトを実行します
Aug  6 08:13:49 ip-xxx-xx-xx-xx ts_demo: スクリプトの実行が完了しました
Aug  6 08:13:49 ip-xxx-xx-xx-xx ts_demo: スクリプトを作成しました

ts の操作

以下は ts の主な操作。

  • ジョブの一覧確認
$ ts -l
  • 完了したジョブをジョブ一覧から削除
$ ts -C
  • ジョブの一括削除(タスクスプーラーサーバープロセスを kill する)
$ ts -K
  • 前のジョブが完了したら実行する

以下のように -d オプションをつけてジョブを登録することで、${command-1} が正常終了したら ${command-2} が実行される。

$ ts ${command-1}
$ ts -d ${command-2}
  • ジョブの標準出力を確認
$ ts -t ${JOB_ID}

その他、以下が ts のヘルプ。

$ ts -h
usage: ts [action] [-ngfmdE] [-L <lab>] [-D <id>] [cmd...]
Env vars:
  TS_SOCKET  the path to the unix socket used by the ts command.
  TS_MAILTO  where to mail the result (on -m). Local user by default.
  TS_MAXFINISHED  maximum finished jobs in the queue.
  TS_MAXCONN  maximum number of ts connections at once.
  TS_ONFINISH  binary called on job end (passes jobid, error, outfile, command).
  TS_ENV  command called on enqueue. Its output determines the job information.
  TS_SAVELIST  filename which will store the list, if the server dies.
  TS_SLOTS   amount of jobs which can run at once, read on server start.
  TMPDIR     directory where to place the output files and the default socket.
Actions:
  -K       kill the task spooler server
  -C       clear the list of finished jobs
  -l       show the job list (default action)
  -S [num] get/set the number of max simultaneous jobs of the server.
  -t [id]  "tail -n 10 -f" the output of the job. Last run if not specified.
  -c [id]  like -t, but shows all the lines. Last run if not specified.
  -p [id]  show the pid of the job. Last run if not specified.
  -o [id]  show the output file. Of last job run, if not specified.
  -i [id]  show job information. Of last job run, if not specified.
  -s [id]  show the job state. Of the last added, if not specified.
  -r [id]  remove a job. The last added, if not specified.
  -w [id]  wait for a job. The last added, if not specified.
  -k [id]  send SIGTERM to the job process group. The last run, if not specified.
  -u [id]  put that job first. The last added, if not specified.
  -U <id-id>  swap two jobs in the queue.
  -B       in case of full queue on the server, quit (2) instead of waiting.
  -h       show this help
  -V       show the program version
Options adding jobs:
  -n       don't store the output of the command.
  -E       Keep stderr apart, in a name like the output file, but adding '.e'.
  -g       gzip the stored output (if not -n).
  -f       don't fork into background.
  -m       send the output by e-mail (uses sendmail).
  -d       the job will be run only if the job before ends well
  -D <id>  the job will be run only if the job of given id ends well.
  -L <lab> name this task with a label, to be distinguished on listing.
  -N <num> number of slots required by the job (1 default).

最後に

ts の使いドコロ

  • 分散キューシステムでは無いので、一台のサーバー上でしか動かせないのは注意が必要
  • 遅延処理はしたいけど、処理の実行順序は出来るだけ守りたい場合
  • SQS や RabbitMQ 等を導入する程でもなくて、一台のサーバーで完結するようなバッチ処理

今まで知らずにすいません

本当にすいません。

AWS Game Day に参加して優勝してしまったくさ #AWSGameDayJapan‬

tl;dr

AWS Game Day というイベントに初老、初老界隈のメンバー三人で参加した。

gameday-japan.connpass.com

AWS Game Day とは...上記のサイトを抜粋。

AWS GameDayはAWS上に構築されたシステムのトラブルシュートコンテストのようなものです。
主催者より皆さんに、"ある"AWS環境を払い出します。皆さんは払い出された環境を、どんな負荷ににも耐えられる最強の環境にするコンテストです。
参加者の中で最も優れた環境に育て上げたチームがチャンピオンになります!いわば、ドラゴンボールの天下一武道会のようなものです。

詳細な内容は書くことは出来ないけど、イタズラ好きな CTO のもとで働くインフラエンジニアというシチュエーションで、高負荷に耐えうる環境を構築するミッションをそれぞれのチームで競うというもの。参加者には ISUCON 入賞者の方を擁するチームもいらっしゃたりして、我々はアルコタワーに何かちょっとした爪跡でも残せたらいいやという気持ちで挑んだところ...

優勝してしまった。

感想とか

勝因

他のチームの方からお話しを伺う限りだと、パケットキャプチャしたり、しっかりと調査を行った上で様々な対処を検討されていたので、何故、我々のチームがあんなに大きく差を付けて勝つことが出来たのか未だにナゾである。

模範解答は?

運営者が期待している模範解答を知りたかった。

教訓(もしかしたら、次の Game Day でチームに勝利をもたらすかもしれない三つの何か)を三行で

すごく当たり前のようなことなんだけど、実際にその状況が目の前にあらわれた時にちゃんと守れるかが勝敗(実務でも)の鍵だったりするのかなと。

  • インフラリソースの把握は必須、インフラだけでなくアプリケーションも出来る限り把握する
  • 慌てない、とにかくお茶でも飲んで落ち着く
  • チーム内での役割分担を明確に(司令塔、調査班、作業班)

途中、参加者には福利厚生としてアルコール類が振る舞われるが、ここでアルコールが良いガソリンとなるのか、手元や判断を狂わす劇薬になるかは貴方次第。

最後に

謝辞

  • 主催の AWS メンバーの皆さん、裏方として環境の構築等を行ってくれた Scott さん、Dave さん
  • チームロゴをその達筆な腕前で認めて下さった cloudpack の酒井さん
  • チームメンバーの cloudpack 武川さん、工藤さん
  • 東京への長期滞在を快く送り出してくれた奥さん

本当にありがとうございました。

目標とする漢、ジェイソン・ステイサムの一言

自分が目標とする漢、ジェイソン・ステイサムの一言で〆たいと思う。

Array クラス、String クラスとかパーセント記法(Ruby)

tl;dr

Array クラスのメソッドをちょろっと触ってみたメモ。

参考

メモ

delete_if メソッドと reject! メソッド

  • 要素の数だけ繰り返しブロックを実行してブロックの戻り値が真になった要素を削除
$ pry
[1] pry(main)> words = ["a", "b", "c", "d", "e"] # 配列の生成
=> ["a", "b", "c", "d", "e"]
[2] pry(main)> words.delete_if do |item| item =~ /^[ace]/ end # delete_if メソッドで要素を削除
=> ["b", "d"]

reject! メソッドも同様の結果となる。

$ pry                                                                                                                                       
[1] pry(main)> words = ["a", "b", "c", "d", "e"] # 配列の生成                                                                                                      
=> ["a", "b", "c", "d", "e"]
[2] pry(main)> words.reject! do |item| item =~ /^[ace]/ end # reject! メソッドで要素を削除
=> ["b", "d"]

但し、delete_ifreject! メソッドではレシーバ自体に変化が無かった(要素が削除されなかった)場合の挙動が以下のように異なる。

$ pry                                                                                                                                       
[1] pry(main)> words = ["a", "b", "c", "d", "e"]                                                                                                                              
=> ["a", "b", "c", "d", "e"]
[2] pry(main)> words.delete_if do |item| item =~ /^[xyz]/ end
=> ["a", "b", "c", "d", "e"] # delete_if はレシーバー自身が返る
[3] pry(main)> words.reject! do |item| item =~ /^[xyz]/ end
=> nil # reject! は nil が返る
[4] pry(main)> p words
["a", "b", "c", "d", "e"]

each_with_index

  • 要素の数だけブロックを繰り返し実行
  • ブロック引数には各要素と番号が入る
$ pry
[1] pry(main)> a = ["hage", "pika", "tsuru"]
=> ["hage", "pika", "tsuru"]
[2] pry(main)> a.each_with_index { |atama, i| print i, ":", atama, "\n" }
0:hage
1:pika
2:tsuru
=> ["hage", "pika", "tsuru"]

shift / unshift / push

  • shift ... 配列の最初の要素を削除し、その要素を返す
  • unshift ... 配列の先頭に要素を追加(引数が無い場合には何もしない)
  • push ... 配列の末尾に要素を追加
$ pry
[1] pry(main)> words = ["one", "two", "three"]
=> ["one", "two", "three"]
[2] pry(main)> words.shift
=> "one"
[3] pry(main)> words.shift
=> "two"
[4] pry(main)> words.unshift
=> ["three"]
[5] pry(main)> words.push("four")
=> ["three", "four"]
[6] pry(main)> p words
["three", "four"]
=> ["three", "four"]
[7] pry(main)> words.unshift("two")
=> ["two", "three", "four"]

concat / compact / uniq

  • concat ... 要素を連結
  • compact ... nil を削除(非破壊的メソッド)
  • uniq ... 重複している要素を削除(非破壊的メソッド)
$ pry
[1] pry(main)> a = [:a, :a, :b, :c] # 配列を生成
=> [:a, :a, :b, :c]
[2] pry(main)> a[5] = :e # 配列の要素を追加
=> :e
[3] pry(main)> a.concat([:a, :b, :c]) # 配列を連結
=> [:a, :a, :b, :c, nil, :e, :a, :b, :c]
[4] pry(main)> a.compact # 配列から nil から削除(但し非破壊的)
=> [:a, :a, :b, :c, :e, :a, :b, :c]
[5] pry(main)> a.uniq # 重複している要素を削除(但し非破壊的)
=> [:a, :b, :c, nil, :e]
[6] pry(main)> p a # 結果として a.concat([:a, :b, :c]) と同じ出力となる
[:a, :a, :b, :c, nil, :e, :a, :b, :c]
=> [:a, :a, :b, :c, nil, :e, :a, :b, :c]

find / detect

  • find ... 要素を探して取り出し、ブロックが真となったら処理を中断する(該当する要素があれば処理を中断する)
  • detect ... find の別名
$ pry
[1] pry(main)> words = ["ab", "bc", "cd", "de"]
=> ["ab", "bc", "cd", "de"]
[2] pry(main)> words.find do |word| word =~ /c/ end
=> "bc"
[3] pry(main)> words.detect do |word| word =~ /c/ end
=> "bc"

パーセント記法

以下の記事がとても参考になった。

blog.toshimaru.net

slice

  • 引数で指定した位置の要素を取り出す
$ pry
[1] pry(main)> a = [1,2,3,4,5]
=> [1, 2, 3, 4, 5]
[2] pry(main)> p a.slice(1,3)
[2, 3, 4]
=> [2, 3, 4]
[3] pry(main)> p a.slice(1..3)
[2, 3, 4]
=> [2, 3, 4]

index

  • 文字列の中に第一引数で指定した文字が含まれていれば、その開始位置を整数で返す
  • 第二引数が指定されている場合、その位置から検索する
$ pry                                                                                                                                       
[1] pry(main)> p "oe!oe!oe!oe!oe!oe".index("!", 3)                                                                                                                            
5
=> 5
[2] pry(main)> p "oe!oe!oe!oe!oe!oe".index("!")                                                                                                                               
2
=> 2

chop / chomp

  • chop ... 末尾の一文字を削除(非破壊的)
  • chomp ... 末尾の改行を削除(非破壊的)(※改行が無ければ何もしない)
[3] pry(main)> x = "Hello world.\n"
=> "Hello world.\n"
[4] pry(main)> x.chop # \n を削除(非破壊的)
=> "Hello world."
[5] pry(main)> x.chop # \n を削除(非破壊的)
=> "Hello world."
[6] pry(main)> x.chomp # \n を削除(非破壊的)
=> "Hello world."
[7] pry(main)> p x # 結局南極 chop や chomp は非破壊的メソッドな為、x の値は変化なし
"Hello world.\n"
=> "Hello world.\n"

引き続き、色々とメモる予定。

配列の & 演算子と | 演算子と + 演算子と - 演算子(Ruby)

tl;dr

これもよく記憶が飛んでしまうので...メモ。「愛しさと切なさと心強さと」みたいなタイトルですいません。

メモ

& 演算子

  • 両方に含まれる要素を配列で返す
$ ruby
[1] pry(main)> a = [1,2,3]  # 配列の生成
=> [1, 2, 3]
[2] pry(main)> b = [1,3,5]  # 配列の生成
=> [1, 3, 5]
[3] pry(main)> p a & b      # 比較
[1, 3]
=> [1, 3]

| 演算子

  • どちらかに含まれる要素を配列で返す
$ pry
[1] pry(main)> a = [1,2,3]  # 配列の生成
=> [1, 2, 3]
[2] pry(main)> b = [1,3,5]  # 配列の生成
=> [1, 3, 5]
[3] pry(main)> p a | b      # 比較
[1, 2, 3, 5]
=> [1, 2, 3, 5]

+ 演算子

  • 要素を連結(ガッチャンコ)して配列で返す
$ pry                                                                                                                                       
[1] pry(main)> a = [1,2,3]  # 配列の生成
=> [1, 2, 3]
[2] pry(main)> b = [1,3,5]  # 配列の生成
=> [1, 3, 5]
[3] pry(main)> p a + b      # ガッチャンコ
[1, 2, 3, 1, 3, 5]
=> [1, 2, 3, 1, 3, 5]

- 演算子

  • 対象の要素を取り除いた配列を返す
$ pry
[1] pry(main)> a = [1,2,3]  # 配列の生成
=> [1, 2, 3]
[2] pry(main)> b = [1,3,5]  # 配列の生成
=> [1, 3, 5]
[3] pry(main)> p a + b      # ガッチャンコ
[1, 2, 3, 1, 3, 5]
=> [1, 2, 3, 1, 3, 5]
[4] pry(main)> c = [2,3,4]  # 配列の生成
=> [2, 3, 4]
[5] pry(main)> p a + b - c  # 引き算
[1, 1, 5]
=> [1, 1, 5]

以上

メモでした。

配列の添字演算子メモ(Ruby)

tl;dr

すぐに混乱するのでメモ。

memo

$ pry
[1] pry(main)> a = [1,2,3,4,5]     # 配列生成
=> [1, 2, 3, 4, 5]
[2] pry(main)> p a[0,5]            # a[0] から 5 つの要素
[1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
[3] pry(main)> p a[0..4]           # a[0] から a[4] まで
[1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
[4] pry(main)> p a[0..1]           # a[0] から a[1] まで
[1, 2]
=> [1, 2]
[5] pry(main)> p a[0,2]            # a[0] から 2 つの要素
[1, 2]
=> [1, 2]
[6] pry(main)> p a[0..-1]          # a[0] から a[-1] まで
[1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]

以上、以下、未満

そう言えば、先日、「以上」、「以下」、「未満」を派手に混同して使っていて恥ずかしい思いをしたので、こちらもメモっておく。

  • 100 円以上であれば... 100 円を含む
  • 100 円以下であれば... 100 円を含む
  • 100 円未満であれば... 100 円を含まない

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

tl;dr

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

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


neustar とは

www.neustar.biz

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


作ったもの

github

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}}}
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 でも負荷試験がスケジューリングがされている。

f:id:inokara:20160716115609p:plain

  • 負荷試験一覧から任意の負荷試験の情報を取得する
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 にアクセスすると以下のように試験が開始されている。

f:id:inokara:20160716120706p:plain

  • 任意の負荷試験の情報を取得する
 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 を多分初めて利用してみたけど、とても簡単にコマンドラインツールが作れることに感動した。

2016 年 07 月 10 月(日)

tl;dr

参議院議員選挙だった。

  • vim の snippet について勉強
  • ゴルフ中継の煽りをうけてガンダムとジューオージャーは休止、仮面ライダーゴーストだけ見る
  • 車の掃除
  • ジョギングシューズを新調したのでウキウキウォッチングで走ってきた、いい感じ

  • どん兵衛とおにぎりでランチ
  • Docker のストレージドライバを devicemapper から overlayfs に変えたらコンテナの起動が早くてビビったのでブログにしたい

  • ソファで寝落ち
  • neustar の Scripting API と Load Testing API について勉強、Ruby で簡単なサンプルを作って遊ぶ