ようへいの日々精進XP

よかろうもん

2017 年 09 月 20 日(水)

ジョギング

日課

  • (腕立て x 30 + 腹筋 x 30) x 3

馬刺し x 辛子レンコン

奥さんが熊本出張に行ったので、お土産で馬刺しと辛子レンコンを買ってきた。

早速、スライスしてもらって食べたけどサイコーだった。食べに行きたいくらい。

2017 年 09 月 19 日(火)

ジョギング

  • 香椎浜 x 2 周
  • ペースは遅いのだいぶん体がキツイ

日課

  • (腕立て x 30 + 腹筋 x 30) x 3

奥さん

朝からとても辛そうだったが、自分で病院に行って先生の話しを聞いて少し元気になった模様。

焦らずにのんびりとやっていって欲しい。

2017 年 09 月 18 日(月)

ジョギング

日課

  • (腕立て x 30 + 腹筋 x 30) x 3

志賀島

夕陽を見に行った。

志賀島で夕陽に向かってバカヤロー。

奥さん

最近、調子が良かったので少し疲れが出てしまったのかもしれない。あまり焦らずに元気になっていって欲しいと思う。

2017 年 09 月 17 日(日)

昨晩

変な夜更かしをしてしまったので、朝から体調イマイチ。

台風 18 号

福岡の北の方だと強い風は感じられなかったけど、朝から雨がずーっと降り続いていた。

ということで、ジョギングはお休み。

日課

  • (腕立て x 30 + 腹筋 x 30) x 3

CodeBuild で実行したビルドの結果を Slack に通知するヤツ(PHPUnit を実行した場合にはテスト結果もブラウザで確認出来るようにしちゃる)

CodeBuild にお願いしっぱなしでは

いけないと思ったので CodeBuild のイベントを拾って Slack に通知する Lambda ファンクションを作ってみた。

github.com

使い方

ファイル

整理出来ていないけど。

$ tree .
.
├── README.md
├── codebuild-sample.prj
├── decrypt-sample.arn
├── environment-sample.yml
├── handler.py
└── serverless.yml

0 directories, 6 files
  • codebuild-sample.prj には CodeBuild のプロジェクト名を指定
  • decrypt-sample.arn には KMS のキーを指定
  • environment-sample.ymlには Lambda ファンクションの環境変数を指定

デプロイ

Serverless Framework で楽ちん。

sls deploy --aws-profile=xxxxx --stage=xxxxx

後は CodeBuild を走らせるだけ。

こんな感じ

処理の流れ(1)

f:id:inokara:20170917233330p:plain

最初は単純に処理開始、成功、失敗、停止のみを通知するようにしていた。

処理の流れ(2)

f:id:inokara:20170918000843p:plain

前の記事で PHPUnit の結果をいい感じで HTML に吐くことが出来たので S3 に Put して PreSigned URL を発行して期間限定でブラウザから確認出来るようにしてみた。PHPUnit にも関わらず、他言語のテストフレームワークでも HTML 書き出し機能があると思うのでうまくそれを利用すれば同じようなことが出来るはず。

通知例

ビルド開始

f:id:inokara:20170917234101p:plain

地味に開始の通知は嬉しい。個人的に。

成功

f:id:inokara:20170917234358p:plain

Result URL をクリックすると HTML に書き出したテスト結果を確認出来る。

失敗

f:id:inokara:20170917234452p:plain

失敗した際も同様に Result URL をクリックすると HTML フォーマットのテスト結果を確認出来る。

f:id:inokara:20170918000633p:plain

ハマった点こととか

PreSigned URL

Lambda に付与されている IAM Role に対して S3 を操作する権限が付与されていなくても PreSigned URL が発行出来てしまうというワナ。但し、発行された URL にアクセスしても Access Denied となる。

個人的には権限が無いのなら、エラーになって欲しいと思ったり。

結果 URL の処理をどこでやるか

当初は通知の Lambda ファンクション側で頑張ってみようと思ったけど、Event の内容から Artifact の URL を取得したり、XML から HTML の変換を実装することを考えたら辛かったので、今回は CodeBuild の Post Build フェーズでやってみた。これが良い判断なのかは悩ましい。

ということで

以下の二本の記事はここにたどり着く為の布石でござりんした。

inokara.hateblo.jp

inokara.hateblo.jp

お疲れさまでござりんした。

PHPUnit のテスト結果を人間に優しい感じで出力する

モチベーション

特に何もオプションを指定しない場合の PHPUnit の結果があまりにも人間に対して素っ気ない感じがしたので、テスト結果っぽい感じの出力が得られないものかを調べていた。

世の中の人たちはあの素っ気ない感じで満足されているのかと諦めかけていたころ、PHPUnit のドキュメントに貼られたリンクに気付いた。

Plugins for PHPUnit – The PHP Testing Framework

以下のリンク。

PHPUnit xslt · GitHub

この XSLT Template を噛ませば、あら素敵、テスト結果の出力がお客様が喜びそうな解りやすい感じで出力されるぢゃありませんか。

ということで

引き続き

github.com

こちらの sample を利用する。

シンプルなテスト結果

素っ気ないというとあれだけど、シンプルな出力で個人的には嫌いではない。

# php phpunit.phar tests
PHPUnit 5.7.21 by Sebastian Bergmann and contributors.

...F...                                                             7 / 7 (100%)

Time: 1.43 seconds, Memory: 12.50MB

There was 1 failure:

1) CalcTestCase::test_div
Failed asserting that 3 matches expected 2.

/opt/codebuild/tests/CalcTest.php:23

FAILURES!
Tests: 7, Assertions: 7, Failures: 1.

F は失敗したテストケースであることは何となく判る。ちなみに、.F 以外にも以下のようなステータスがある。

ステータス 意味
.(ドット) テスト成功
F テスト失敗
E テストが危険としてマーク
S テストをスキップした
I テストが未実装

ログ出力

ドキュメント を読んでいるとテスト結果を XML フォーマットでログ出力することが出来るとのこと。

# php phpunit.phar tests --log-junit post_build/result.xml
PHPUnit 5.7.21 by Sebastian Bergmann and contributors.

...F...                                                             7 / 7 (100%)

Time: 2.27 seconds, Memory: 12.50MB

There was 1 failure:

1) CalcTestCase::test_div
Failed asserting that 3 matches expected 2.

/opt/codebuild/tests/CalcTest.php:23

FAILURES!
Tests: 7, Assertions: 7, Failures: 1.

上記のように --log-junit オプションをつけてテストを起動すると JUnit XML フォーマットでテスト結果を出力してくれる。

以下のような内容になる。

<?xml version="1.0" encoding="UTF-8"?>
<testsuites>
  <testsuite name="tests" tests="7" assertions="7" failures="1" errors="0" time="0.004735">
    <testsuite name="CalcTestCase" file="/opt/codebuild/tests/CalcTest.php" tests="4" assertions="4" failures="1" errors="0" time="0.002838">
      <testcase name="test_add" class="CalcTestCase" file="/opt/codebuild/tests/CalcTest.php" line="6" assertions="1" time="0.000586"/>
      <testcase name="test_sub" class="CalcTestCase" file="/opt/codebuild/tests/CalcTest.php" line="11" assertions="1" time="0.000567"/>
      <testcase name="test_mul" class="CalcTestCase" file="/opt/codebuild/tests/CalcTest.php" line="16" assertions="1" time="0.000622"/>
      <testcase name="test_div" class="CalcTestCase" file="/opt/codebuild/tests/CalcTest.php" line="21" assertions="1" time="0.001063">
        <failure type="PHPUnit_Framework_ExpectationFailedException">CalcTestCase::test_div
Failed asserting that 3 matches expected 2.

/opt/codebuild/tests/CalcTest.php:23
</failure>
      </testcase>
    </testsuite>
    <testsuite name="EmailTestCase" file="/opt/codebuild/tests/EmailTest.php" tests="3" assertions="3" failures="0" errors="0" time="0.001896">
      <testcase name="testCanBeCreatedFromValidEmailAddress" class="EmailTestCase" file="/opt/codebuild/tests/EmailTest.php" line="12" assertions="1" time="0.000612"/>
      <testcase name="testCannotBeCreatedFromInvalidEmailAddress" class="EmailTestCase" file="/opt/codebuild/tests/EmailTest.php" line="20" assertions="1" time="0.000830"/>
      <testcase name="testCanBeUsedAsString" class="EmailTestCase" file="/opt/codebuild/tests/EmailTest.php" line="27" assertions="1" time="0.000454"/>
    </testsuite>
  </testsuite>
</testsuites>

うむ、冒頭の .F の方が人間には解りやすいかもしれぬ。

phpunit.xslt を噛ますといい感じになる

再掲。

PHPUnit xslt · GitHub

前述の XML にこの XSLT を噛ましてあげると下図のように人間に解りやすい感じの出力になる。

f:id:inokara:20170917221241p:plain

具体的には以下のように XML ファイルの 2 行目に phpunit.xslt へのパスを指定してあげる。

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="https://gist.githubusercontent.com/jrfnl/3c28ea6d9b07fd48656d/raw/aaeb0b879647b1cf1dbfd461a2c4a8e292be738d/phpunit.xslt"?>
<testsuites>
  <testsuite name="tests" tests="7" assertions="7" failures="1" errors="0" time="0.004735">
    <testsuite name="CalcTestCase" file="/opt/codebuild/tests/CalcTest.php" tests="4" assertions="4" failures="1" errors="0" time="0.002838">
      <testcase name="test_add" class="CalcTestCase" file="/opt/codebuild/tests/CalcTest.php" line="6" assertions="1" time="0.000586"/>
...

もう少し踏み込んで

このログを HTML に変換して、手元のブラウザでお手軽に見ることが出来るようになれば、もっと人間に優しくなるような気がしたので PHP を使って HTML に変換するスクリプトを作ってみた。

<?php

$filename = 'result.xml';

if (! file_exists($filename)) {
    echo "$filename は存在していません." . "\n";
    exit(1);
}

$xsl = new DOMDocument();
// 事前に https://gist.githubusercontent.com/jrfnl/3c28ea6d9b07fd48656d/raw/aaeb0b879647b1cf1dbfd461a2c4a8e292be738d/phpunit.xslt からダウンロード
$xsl->load("phpunit.xslt");
$xml = new DOMDocument();
// テスト結果
$xml->load("result.xml");

$proc = new XsltProcessor();
$proc->importStylesheet($xsl);
$result_html = $proc->transformToXML($xml);
file_put_contents("result.html", $result_html);

このスクリプトを実行すると result.html が出力される。

f:id:inokara:20170917222709p:plain

何件のテストを実施して、何件のテストが Failure になっているのかが一目瞭然、Failure の原因についても個人的に見易い気がする。

以上

メモでした。

CodeBuild で PHPUnit を実行したかったので PHP のコンテナイメージを作って公開した

諸般の事情で

CodeBuild 用の PHP イメージを作って公開してみた。このコンテナイメージを利用して PHPUnit を実行する予定。

作ったもの

github.com

デモ

ビルド

build.sh を修正

ECR のリポジトリを指定する。

#!/usr/bin/env bash

DOCKER_CONTENT_TRUST=1

eval $(aws ecr get-login --no-include-email --region ap-northeast-1)

docker build -t codebuild-php .
docker tag codebuild-php:latest 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/codebuild-php:latest
docker push 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/codebuild-php:latest

ビルド

./build.sh

実行すると ECR にコンテナイメージがプッシュされる。

とりあえず手元の環境で

docker run

cd sample
docker run -t -i -v $(pwd):/opt/codebuild codebuild-php /bin/bash

PHPUnit 実行

root@2d2e13594b64:/# cd /opt/codebuild
root@2d2e13594b64:/opt/codebuild# ./run_test.sh
PHPUnit 5.7.21 by Sebastian Bergmann and contributors.

...                                                                 3 / 3 (100%)

Time: 1.92 seconds, Memory: 12.00MB

OK (3 tests, 3 assertions)

ちなみに run_test.sh の中身は以下の通り。

#!/usr/bin/env bash

php phpunit.phar --bootstrap src/Email.php tests/EmailTest --log-junit post_build/result.xml

テストコードはこちらより拝借。

CodeBuild では…

イメージの指定

下図のように指定することで、ECR に push したコンテナイメージを利用することが出来る。

f:id:inokara:20170917191039p:plain

実行結果

f:id:inokara:20170917190156p:plain

buildspec.yml とかは sample 以下のファイルを確認されたし。

以上

メモでした。

だいぶん、色々と端折ってごめんくさい。

2017 年 09 月 16 日(土)

ジョギング

  • 50 分くらい、距離にして 10 キロ強
  • 香椎周辺をトコトコと
  • 右足の痛みは走り始めると和らぐのでちょっと安心

日課

  • (腕立て x 30 + 腹筋 x 30) x 3

夕飯

久しぶりによし本。

俺の郷 〜 尾崎亜美、鈴木亜美、時東ぁみもみんな一緒に EC2 AMI を作成、削除するツールを作ってリリースした 〜

オリビアを聴きながら

リリースした。

github.com

AMI を管理する時の個人的な課題

  • AMI に紐付いた Snapshot を忘れてしまう(特に AMI を削除する場合)
  • マネジメントコンソールからの作成が面倒でしかも CLI がサクッと出てこない

ということで amiCtrl を作ってみた

Be Together(導入)

wget とかでバイナリを取得する。

wget https://github.com/inokappa/amiCtrl/releases/download/v0.0.1/amiCtrl_darwin_amd64 \
  -O ${HOME}/bin/amiCtrl
chmod 755 ${HOME}/bin/amiCtrl

ヘルプ

$ ${HOME}/bin/amiCtrl -h
Usage of /path/to/bin/amiCtrl:
  -ami string
        AMI ID を指定.
  -create
        タグをインスタンスに付与.
  -delete
        タグをインスタンスから削除.
  -describe
        タグを詳細を確認.
  -endpoint string
        AWS API のエンドポイントを指定.
  -instance string
        Instance ID を指定.
  -name string
        AMI Name を指定.
  -noreboot
        No Reboot オプションを指定. (default true)
  -profile string
        Profile 名を指定.
  -region string
        Region 名を指定. (default "ap-northeast-1")

AMI 作成

./amiCtrl -instance=i-xxxxxxxxxxxxxxxxx -name=suzuki-ami-desu -create

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

+-----------------+--------------+--------------------------------+
|    AMI NAME     |    AMI ID    |          SNAPSHOT ID           |
+-----------------+--------------+--------------------------------+
| suzuki-ami-desu | ami-1234567x | snap-123456789a1234567         |
|                 |              | snap-123456789b1234567         |
+-----------------+--------------+--------------------------------+

AMI を確認

./amiCtrl -instance=i-xxxxxxxxxxxxxxxxx -ami=ami-12345678

以下のように出力されるので、悩みどころだった AMI と Snapshot の関連付けについてもいい感じで確認出来る(個人的に)。

+-----------------+--------------+--------------------------------+
|    AMI NAME     |    AMI ID    |          SNAPSHOT ID           |
+-----------------+--------------+--------------------------------+
| suzuki-ami-desu | ami-1234567x | snap-123456789a1234567         |
|                 |              | snap-123456789b1234567         |
+-----------------+--------------+--------------------------------+

AMI に関連した SNAPSHOT ID まで確認することが出来る。

AMI を削除

./amiCtrl -instance=i-xxxxxxxxxxxxxxxxx -ami=ami-12345678 -delete

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

+-----------------+--------------+--------------------------------+
|    AMI NAME     |    AMI ID    |          SNAPSHOT ID           |
+-----------------+--------------+--------------------------------+
| suzuki-ami-desu | ami-1234567x | snap-123456789a1234567         |
|                 |              | snap-123456789b1234567         |
+-----------------+--------------+--------------------------------+
上記の AMI を削除しますか?(y/n): y
AMI を削除します...
AMI を削除しました.

終わり

Describe Image して Snapshot の ID が取れることを知らなかったので…

今まで全く知らなかったこと。(知ったかぶりしていたこと。)

Describe Image の内容に Snapshot ID が含まれていたこと。

{
    "Images": [
        {
...
            "BlockDeviceMappings": [
                {
                    "DeviceName": "/dev/sda1",
                    "Ebs": {
                        "DeleteOnTermination": true,
                        "SnapshotId": "snap-1234567890abcdef0",
                        "VolumeSize": 8,
                        "VolumeType": "standard"
                    }
                }
            ],
...
        }
    ]
}

知らなかったので、AMI と Snapshot の関連付けを確認する為に、以下のように Describe Snapshot の Description に含まれる AMI ID を利用していた。

{
    "Snapshots": [
        {
            "Description": "Created by CreateImage(i-xxxxxxxxxxxxxxxxx) for ami-1234567x from vol-xxxxxxxxxxxxxxxxx",
...
        }
    ]
}

docs.aws.amazon.com

API ドキュメントを見ると、以下のようにレスポンスに Snapshot ID が含まれているので

<DescribeImagesResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
  <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId> 
  <imagesSet>
    <item>
...
      <blockDeviceMapping>
        <item>
          <deviceName>/dev/sda1</deviceName>
          <ebs>
            <snapshotId>snap-1234567890abcdef0</snapshotId>
            <volumeSize>15</volumeSize>
            <deleteOnTermination>false</deleteOnTermination>
            <volumeType>standard</volumeType>
          </ebs>
        </item>
      </blockDeviceMapping>
...
  </imagesSet>
</DescribeImagesResponse>

ずっと昔から Describe Image だけで Snapshot ID を確認することが出来ていたのかもしれない。

gox を初めて使った

github.com

以下のように実行するだけでクロスコンパイルがサクッと出来てしまって泣いた。

gox -output "pkg/amiCtrl_{{.OS}}_{{.Arch}}"

-output を指定しない場合にはカレントディレクトリにバイナリが出力される。

$ gox -output "pkg/amiCtrl_{{.OS}}_{{.Arch}}"
Number of parallel builds: 3

-->      netbsd/arm: amiCtrl
-->      darwin/386: amiCtrl
-->       linux/arm: amiCtrl
...
-->       linux/386: amiCtrl
-->    darwin/amd64: amiCtrl
-->     linux/amd64: amiCtrl

ghr も初めて使った

github.com

バイナリを Github Release ページにアップロードしてみたかったので ghr を初めて利用した。

事前に GitHub Token を払い出して環境変数に定義するか、コマンドラインオプション(-t)に設定する必要があるが、以下のように簡単に Release ページの作成からバイナリのアップロードを完了することが出来た。

ghr -u inokappa -r amiCtrl v0.0.1 ./pkg/

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

$ ghr -u inokappa -r amiCtrl v0.0.1 ./pkg/
==> Create a new release
--> Uploading: amiCtrl_darwin_amd64
--> Uploading: amiCtrl_windows_amd64.exe
--> Uploading: amiCtrl_freebsd_amd64
--> Uploading: amiCtrl_darwin_386
...

以下のように Release ページ作成されている。

f:id:inokara:20170916234940p:plain

おお、お手軽過ぎる。

以上

メモでした。

時東ぁみ」の代表的な楽曲は知らないので本文中には出てきていないが悪しからず。

2017 年 09 月 15 日(金)

ジョギングと日課

  • 昨晩が遅かったこともありお休み
  • 右足のふともも股関節から痛みが続く
  • 日課も休み

何してたんだか

わからない位あっという間に過ぎた一日だった。

ホント何やってたんだろう。