ようへいの日々精進XP

よかろうもん

2018 年 10 月 11 日 (木)

ジョギング

  • 山王公園往復
  • 懸垂 5 回イケた

日課

  • おやすみ

JAWS-UG 福岡もくもく会

  • みんなで集まってワイワイ技術的な話が出来るのは楽しい
  • SAP の勉強, かなり難しい...

夕飯は

とんとんで湯豆腐を食べた.

湯豆腐食べてる。

2018 年 10 月 10 日 (水)

ジョギング

  • 山王公園往復
  • 懸垂 4 回の壁が超えられない

日課

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

今朝の出来事

同じマンション住む幼い兄弟が自宅鍵を無くしたというので一緒に探してあげた. 自宅の鍵が無くなるという致命的な状況にも関わらず, 「俺と弟, そしておっちゃん (間違いなく自分のことだと思う) がいればきっと見つかるよね」って, 常にポジティブだったのが印象的だったし, なんだか大人の自分が勇気づけられた気がした. いろいろおもしろいシチュエーションもあったけど, これはまたの機会に.

マルチななんとか

お昼すぎから外出してカフェで作業. どうしても横の人たちの声が耳に入ってきて煩いなあと思っていたら, その内容がマルチなアレなアレの話っぽくて世の中怖いなあと思った次第. また, お金はコツコツ貯めて行きたいと思う.

2018 年 10 月 09 日 (火)

ジョギング

  • 山王公園往復
  • 体調がすごく悪いので 30 分くらいで引き上げた

日課

  • おやすみ

SRE 本輪読会

  • 隔週でやっている SRE 本輪読会に参加
  • 福岡の色んな企業のエンジニアが集まるので交わされる会話一つ一つが勉強になる

ビーフシチュー

  • 奥さんお得意のビーフシチューを夕飯に
  • なんかいつもよりも美味しかった

今日のトゥウィート

輪読会の後, 独りで「とんとん」に. とろろ納豆と地鶏のたたきを食べる.

どうしたんだろう. 体中がずっと痛い.

2018 年 10 月 08 日 (月)

ジョギング

  • 二日酔い気味だったけど, 佐世保市内を 40 分弱
  • 奥さんの先祖のお墓参りも出来たので良かった

日課

  • おやすみ

九十九島観光

九十九島パールシーリゾート最高だった。

なんどか佐世保まできているが, 初めて九十九島観光をしてみた. 遊覧船に乗ったり, あごだしラーメンからの佐世保バーガー食べたりと最高だった.

今日のトゥウィート

週末はスキマ時間で C 言語の初歩的な勉強を続けた. せっかくなので課題のコードについてテストを書いてみようと思ってしらべたら Unity というフレームワークが良さそうだったので Hello World 的なことをやってみた.

2018 年 10 月 07 日 (日)

ジョギング

  • 移動の為, おやすみ

日課

  • おやすみ

結婚式

素敵な式でした、末長くお幸せに❤

佐世保にて, 奥さんの従兄弟の結婚式に参加. ホントに良い式だった. 末永くお幸せに!

佐世保の夜

結婚式でやんさか楽しんだ後, 佐世保市街地に戻って奥さんのおじさんや従兄弟たちとやんさか呑んで, 喉がガラガラになるくらい色々と話が出来て楽しい夜だった. 明日の二日酔いだけが心配である.

今日のトゥウィート

ガチな「エッサッサ」には遠く及ばない感じだったが, 一応, エッサッサっぽい体の動きが出来た.

アルゴリズムとプログラミング 「第 2 章 条件分岐」の予習とまとめ

これは

放送大学教養学部の「アルゴリズムとプログラミング」という授業で使われる「アルゴリズムとプログラミング」という教材書籍を自分なりにまとめたものです.

第 2 章では, C 言語の条件分岐に関連する if 文や switch 文等の基本的な内容について触れられています. 課題については, リファクタリング的な内容だったのでテストを書いてリファクタリングしてみました.

尚, 本まとめについては, 以下の Github リポジトリで管理しており, 加筆修正はリポジトリのみ行います.

github.com

1. if 文による条件分岐

1.1 if 文

  • if 文を利用することで条件分岐が可能となる

以下の例だと, 条件式が真 (true) である場合, 処理が実行されるが, 偽 (false) である場合には実行されない.

if ( 条件式 )
  条件式が真 true だった場合の処理;

以下, C 言語の比較演算子の例.

比較演算子 比較演算子の意味 比較演算子の意味 (英語)
== 等しい equal to
!= 等しくない not equal to
> 大きい greater than
< 小さい less than
>= 大きいか等しい greater than or equal to
<= 小さいか等しい less than or equal to

複数の命令を実行したい場合には, 以下のように波括弧 (カーリーブランケット: curly brankey) の記号 { } を利用したブロック文を用いる.

if ( 条件式 ) {
  処理 1;
  処理 2;
  ...
  処理 n;
}

1.2 if-else 文

以下の例では, 条件式が真となる場合には, 処理 T が実行され, 偽の場合には処理 F が実行される.

if ( 条件式 )
  処理 T;
else
  処理 F;

複数の命令を実行したい場合には, 以下のようにカーリーブランケットを利用したブロック文を利用する.

if ( 条件式 ) {
  処理 T0;
  処理 T1;
} else {
  処理 F0;
  処理 F1;
}

2. switch 文による条件分岐

  • 式 (expression) の値に応じて多分岐を行う
  • default はどの case にも一致しなかった場合に実行される, default は省略可能, casedefault の順序は任意
  • breke はそれ以降の処理を行わずに switch 文を抜ける
  • if-else 文に置き換えることが出来る
switch ( 式 ) {
  case 定数式 0:
    処理;
    ...
    break;
  case 定数式 1:
    処理;
    ...
    break;
  case 定数式 2:
    処理;
    ...
    break;
  default:
    処理;
    ...
    break;
}

3. 条件演算子

  • 三項演算子 (ternary operator)
  • if-else 文と類似したコードを書くことが可能
  • 条件式が真であれば, 式 T の値を, 偽であれば式 F の値を返すという演算を行う
  • 式 T と式 F は同じ型の値を返す必要がある
条件式 ? 式 T : 式 F 

以下, if-else 文との比較.

// 条件演算子バージョン
result = a > b ? x : y

// if-else バージョン
if (a > b) {
  result = x;
} else {
  result = y;
}

4. goto 文

  • goto 文はコードの位置を移動させることが出来る
  • goto 文はスパゲティコードを作り出してしまう原因となる為, 多用することは推奨されていない
  • 特殊なエラー処理や多重にネストされたループから抜け出す為に使われることが稀にある
  • ループ処理や関数等の制御構造と比較して処理の流れが解りにくくなり, コードの可読性が悪くなる

以下, for 文と goto 文の比較.

# forfor ( i = 0; i < 1024; i++ ) {
  処理;
}

# goto 文
i = 0;
LABEL_A:
  if ( i < 1024 )
    goto LABEL_B;
  処理;
  i ++;
  goto LABEL_A
LABEL_B:

た, 確かに goto 文は可読性悪い...

演習問題

問 2.1

以下のコードを変更し, scanf 関数を用いて変数 x と変数 y の値を, キーボード等の標準入力から入力出来るようにしなさい.

/* code: ex2-2.c */
#include <stdio.h>

int main()
{
  int x, y;

  x = 500;
  y = 700;
  printf ("X = %d\n", x);
  printf ("Y = %d\n", y);

  if (x > y)
    printf ("X is greater than Y.\n");
  else
    printf ("X is less than or equal to Y.\n");

  return 0;
}

このコードをコンパイルして実行してみる.

$ gcc ex2-2.c -o ex2-2
$ ./ex2-2
X = 500
Y = 700
X is less than or equal to Y.

これを以下のように改修する.

/* code: q2-1.c */
#include <stdio.h>

int main()
{
  int x, y;

  printf ("Enter X Value: ");
  scanf ("%d", &x);
  printf ("Enter Y Value: ");
  scanf ("%d", &y);  
  
  printf ("X = %d\n", x);
  printf ("Y = %d\n", y);

  if (x > y)
    printf ("X is greater than Y.\n");
  else
    printf ("X is less than or equal to Y.\n");

  return 0;
}

このコードをコンパイルして実行してみる.

$ gcc q2-1.c -o q2-1
$ ./q2-1
Enter X Value: 3
Enter Y Value: 5
X = 3
Y = 5
X is less than or equal to Y.

$ ./q2-1
Enter X Value: 1000
Enter Y Value: 10
X = 1000
Y = 10
X is greater than Y.

問 2.2

以下のコードを変更し, 変数 grade が小文字のデータに対しても多分岐出来るようにしなさい.

/* code: ex2-3.c */
#include <stdio.h>

int main ()
{
  char grade;

  grade = 'B';

  switch (grade) {
  case 'A':
    printf ("excellent\n");
    break;
  case 'B':
    printf ("good\n");
    break;
  case 'C':
    printf ("fair\n");
    break;
  case 'D':
    printf ("barely passing\n");
    break;
  case 'F':
    printf ("not passing\n");
    break;
  default:
    printf ("ERROR: invalid character\n");
    break;
  }
  printf ("Your grade is %c\n", grade);
  return 0;
}

このコードをコンパイルして実行する.

$ gcc ex2-3.c -o ex2-3
$ ./ex2-3
good
Your grade is B

これを以下のように改修する.

/* code: ex2-3.c */
#include <stdio.h>

int main ()
{
  char grade;

  printf ("Enter grade: ");
  scanf ("%c", &grade);

  switch (grade) {
  case 'A':
  case 'a':
    printf ("excellent\n");
    break;
  case 'B':
  case 'b':
    printf ("good\n");
    break;
  case 'C':
  case 'c':
    printf ("fair\n");
    break;
  case 'D':
  case 'd':
    printf ("barely passing\n");
    break;
  case 'F':
  case 'f':
    printf ("not passing\n");
    break;
  default:
    printf ("ERROR: invalid character\n");
    break;
  }
  printf ("Your grade is %c\n", grade);
  return 0;
}

このコードをコンパイルして実行してみる.

$ gcc q2-2.c -o q2-2
$ ./q2-2
Enter grade: a
excellent
Your grade is a

$ ./q2-2
Enter grade: b
good
Your grade is b

$ ./q2-2
Enter grade: F
not passing
Your grade is F

$ ./q2-2
Enter grade: e
ERROR: invalid character
Your grade is e

問 2.3

以下のコードでは switch 文が使われている. switch 文を使わずに if-else 文で書き換えなさい. 論理演算子 (論理積 &&, 論理和 ||, 否定 !) 等を利用すること.

/* code: q2-3a.c */
#include <stdio.h>

int main ()
{
  int a;
  a = 3;
  switch (a) {
    case 0:
    case 1:
    case 2:
      printf ("A\n");
      break;
    case 3:
    case 4:
      printf ("B\n");
      break;
    default:
      printf ("ERROR: invalid number\n");
      break;
  }

  return 0;
}

このコードをコンパイルして実行してみる.

$ gcc q2-3a.c -o q2-3a
$ ./q2-3a
B

これを以下のように, まずはファイルの分割を行った.

/* code: q23b.c */
#include <stdio.h>
#include "q23b.h"

int main ()
{
  int num;
  num = 1;

  char res;
  res = *foobar(num);
  printf ("%c\n", res);

  return 0;
}

/* code: q23b.h */
#ifndef Q23B_H
#define Q23B_H

char *foobar(int);

#endif

/* code: foobar.c */
# include "q23b.h"

char *foobar(int num){
  switch (num) {
    case 0:
    case 1:
    case 2:
      return "A";
      break;
    case 3:
    case 4:
      return "B";
      break;
    default:
      return "ERROR: invalid number";
      break;
  }
}

その上で, foobar.c をリファクタリングしていく. リファクタリングするにあたって, Unity を使って以下のようなテストコードを書いた. C 言語のユニットテストには Unity がシンプルで良い感じだったので, 別の機会に詳細に掘り下げる予定.

/* code: tests/test_q23b.c */
#include <stddef.h>
#include "vendor/unity.h"
#include "../q23b.h"

void setUp(void)
{
}

void tearDown(void)
{
}

void test_foobar_0(void)
{
   TEST_ASSERT_EQUAL_STRING("A", foobar(0));
}

void test_foobar_1(void)
{
   TEST_ASSERT_EQUAL_STRING("A", foobar(1));
}

void test_foobar_2(void)
{
   TEST_ASSERT_EQUAL_STRING("A", foobar(2));
}

void test_foobar_3(void)
{
   TEST_ASSERT_EQUAL_STRING("B", foobar(3));
}

void test_foobar_4(void)
{
   TEST_ASSERT_EQUAL_STRING("B", foobar(4));
}

void test_foobar_5(void)
{
   TEST_ASSERT_EQUAL_STRING("ERROR: invalid number", foobar(5));
}

int main(void)
{
   UnityBegin("tests/test_q23b.c");

   RUN_TEST(test_foobar_0);
   RUN_TEST(test_foobar_1);
   RUN_TEST(test_foobar_2);
   RUN_TEST(test_foobar_3);
   RUN_TEST(test_foobar_4);
   RUN_TEST(test_foobar_5);

   return (UnityEnd());
}

テストは make で実行出来るように, 以下のような Makefile も用意した.

CFLAGS  = -std=c99
CFLAGS += -g
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -pedantic
CFLAGS += -Werror

VFLAGS  = --quiet
VFLAGS += --tool=memcheck
VFLAGS += --leak-check=full
VFLAGS += --error-exitcode=1

test: tests.out
        @./tests.out

memcheck: tests.out
        @valgrind $(VFLAGS) ./tests.out
        @echo "Memory check passed"

clean:
        rm -rf *.o *.out *.out.dSYM *.dSYM

tests.out: q23b.c foobar.c tests/vendor/unity.c tests/test_q23b.c
        @echo Compiling $@
        @$(CC) $(CFLAGS) foobar.c tests/vendor/unity.c tests/test_q23b.c -o tests.out

build:
        @$(CC) $(CFLAGS) q23b.c foobar.c -o q23b

試しにテストを走らせてみる.

$ make test
Compiling tests.out
tests/test_q23b.c:47:test_foobar_0:PASS
tests/test_q23b.c:48:test_foobar_1:PASS
tests/test_q23b.c:49:test_foobar_2:PASS
tests/test_q23b.c:50:test_foobar_3:PASS
tests/test_q23b.c:51:test_foobar_4:PASS
tests/test_q23b.c:52:test_foobar_5:PASS

-----------------------
6 Tests 0 Failures 0 Ignored
OK

いい感じ. 以下のようにリファクタリングを行った.

/* code: foobar.c */
# include "q23b.h"

char *foobar(int num){
  if (num == 0 || num == 1 || num == 2) {
    return "A";
  } else if (num == 3 || num == 4) { 
    return "B";
  } else {
    return "ERROR: invalid number";
  }
} 

試しにテストを走らせる.

$ make test
tests/test_q23b.c:47:test_foobar_0:PASS
tests/test_q23b.c:48:test_foobar_1:PASS
tests/test_q23b.c:49:test_foobar_2:PASS
tests/test_q23b.c:50:test_foobar_3:PASS
tests/test_q23b.c:51:test_foobar_4:PASS
tests/test_q23b.c:52:test_foobar_5:PASS

-----------------------
6 Tests 0 Failures 0 Ignored
OK

いい感じ.

以上

感じたことなど.

  • goto 文は出来る限り「使うな」
  • 三項演算子が出てきた (Ruby も C も同じ書き方なんだな)
  • switch 文にて, 条件が複数になる場合 case 文は縦に並べて書く必要があるのは辛い
  • 教材には掲載されていないが, コード分割の雰囲気を掴むことが出来た
  • C のテストはとりあえず Unity で書いていこうと思う (Unity はググらビリティ悪いよな)

2018 年 10 月 06 日 (土)

ジョギング

  • 台風の為, 朝のジョギングはお休み
  • 夕方から山王公園往復, 快調に飛ばすおじさん達が多い印象 (あ, 俺もおじさんか)
  • 懸垂 4 回, だんだん慣れてきた
  • 足のあっちこっちが痛い

日課

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

台風

  • 朝から台風 25 号が直撃していて強い風の轟音とともに午前中は過ごした

豚の生姜焼き

  • 実は豚の生姜焼きはあまり好きではない
  • でも, 奥さんが作る豚の生姜焼きは生姜もしっかり擦ってあって, 豚肉のジューシーさが失われずにいてとても美味しい

今日のトゥウィート

いろいろと勉強になったのでまとめた.

明日は

FTP ユーザーの振る舞いをテストをする rspec-ftp を試した + 抹茶を追加しました

tl;dr

以前に以下のような記事を書きました.

inokara.hateblo.jp

この時には自前の Ruby スクリプトを使って, ftp ユーザーの振る舞い (ログイン出来るか, chroot になっているか, 読み書き, 削除出来るか等) をチェックしていました.

今回, 以下の Gem を拡張して Rspec を介してチェック出来るようにしてみました.

github.com

尚, 自分がチェックしたかった振る舞いに対応するマッチャーが実装されていなかったので, 追加で実装してプルリクエストしています.

github.com

マージされると嬉しいなあ.

FTP ユーザーの振る舞いをテストする

なぜ, FTP ユーザーの振る舞いをテストしたいのか

そもそも, FTP のようないにしへの技術を未だに利用しているのかと突っ込まれそうな気がしていますが, 実際のところ FTP を利用したいというニーズはあります. その中でサーバーの構築というよりは FTP を利用するユーザーの追加や削除という作業に多くの時間を割かれます. 当然, これらの作業はコード化していますが, 作成した FTP ユーザーが正しくログイン出来るか, ファイルの追加や削除は行えるか, 意図しないディレクトリへのアクセスは許可されていないか等を確認した上で依頼主にエビデンスとして共有する必要があると考えています. また, この確認を自作のスクリプトではなく, 既存のテストフレームワーク上で実行することで汎用性を高め, 自作スクリプトという属人化しやすい部分を廃していくことを目的としています.

ということで, 今回は rspec-ftp を利用して FTP サーバーに作成したユーザーをテストする環境を以下のサンプルに用意してみましたので, これを利用して FTP ユーザーの振る舞いテストの雰囲気を紹介致します.

サンプルはこちらから

github.com

サンプル実行

想定する FTP サーバー, FTP ユーザー

  • FTP サーバーは vsftpd を利用
  • FTP サーバーの IP アドレスは 172.26.0.6 (コンテナ間は vsftpd-server という名前でアクセスすることが出来る)
  • パッシブモードで起動し, パッシブポートは 21200 から 21210 ポートを利用
  • FTP ユーザー名は ftpuser, FTP ユーザーパスワードは supersecret

環境構築

docker-compose up -d

以下のように vsftpd サーバーと Ruby 環境が 3 環境起動します.

$ docker-compose up -d
Creating network "rspec-ftp-sample_my_sample_net" with driver "bridge"
Creating rspec-ruby23  ... done
Creating rspec-ruby25  ... done
Creating vsftpd-server ... done
Creating rspec-ruby24  ... done

ユーザー名, パスワードを secret.yml に定義する

以下のように secret.yml を定義します.

vsftpd-server:
  users:
    - username: ftpuser
      password: supersecret

フォーマットは以下の通りです.

IP アドレス又はホスト名:
  users:
    - username: ユーザー名
    - password: パスワード

このファイルはリポジトリにうっかりアップしてしまわないように .gitignore に登録しておくと良いでしょう.

$ cat .gitignore
secret.yml

テストを実行する...その前に

テストは rake コマンドを介して実行することを想定している為, rake -T を実行してタスクの一覧を確認しておきます.

bundle exec rake -T

以下のように出力されることを確認します.

$ docker-compose exec rspec-ruby25 bundle exec rake -T
rake ftpcheck:vsftpd-server:ftpuser  # Run ftpcheck to vsftpd-server by ftpuser

気を取り直して, テスト実行

以下のように rake コマンドを利用してテストを実行します. 一応, Ruby のバージョンに応じて以下のようにコマンドが別れています.

# Ruby 2.5.x 環境で実行する
docker-compose exec rspec-ruby25 bundle exec rake ftpcheck:vsftpd-server:ftpuser

# Ruby 2.4.x 環境で実行する
docker-compose exec rspec-ruby24 bundle exec rake ftpcheck:vsftpd-server:ftpuser

# Ruby 2.3.x 環境で実行する
docker-compose exec rspec-ruby23 bundle exec rake ftpcheck:vsftpd-server:ftpuser

以下のように出力されることを確認します.

$ docker-compose exec rspec-ruby25 bundle exec rake ftpcheck:vsftpd-server:ftpuser
/usr/local/bin/ruby -I/usr/local/bundle/gems/rspec-core-3.8.0/lib:/usr/local/bundle/gems/rspec-support-3.8.0/lib /usr/local/bundle/gems/rspec-core-3.8.0/exe/rspec spec/ftp_spec.rb

#be_accessible (real server)
  can login valid user and password

#be_chroot (real server)
  check chroot enabled

#be_writable (real server)
  check writable with active mode

#be_removable (real server)
  check removable

Finished in 0.09052 seconds (files took 0.18992 seconds to load)
4 examples, 0 failures

# Summary by Type or Subfolder

| Type or Subfolder  | Example count | Duration (s) | Average per example (s) |
|--------------------|---------------|--------------|-------------------------|
| ./spec/ftp_spec.rb | 4             | 0.07874      | 0.01968                 |


# Summary by File

| File               | Example count | Duration (s) | Average per example (s) |
|--------------------|---------------|--------------|-------------------------|
| ./spec/ftp_spec.rb | 4             | 0.07874      | 0.01968                 |

いい感じでテストが PASS しました. ちなみに, chroot が適切に設定されていない場合には...

$ docker-compose exec rspec-ruby25 bundle exec rake ftpcheck:xxx.xxx.xxx.xxx:user1
...
Failures:

  1) #be_chroot (real server) check chroot enabled
     Failure/Error: expect(ENV['TARGET_HOST']).to be_chroot.user(property['username']).pass(property['password'])
       expected "xxx.xxx.xxx.xxx" to be chroot
     # ./spec/ftp_spec.rb:11:in `block (2 levels) in <top (required)>'

Finished in 2.06 seconds (files took 0.20194 seconds to load)
4 examples, 1 failure
...

上記ようにテストはものの見事に失敗します. この時に vsftpd.log を確認すると以下のように上位ディレクトリを参照してしまっていることが確認出来ます.

...
Sat Oct  6 15:02:41 2018 [pid 1410] [user1] FTP command: Client "111.222.333.444", "CWD ../"
Sat Oct  6 15:02:41 2018 [pid 1410] [user1] FTP response: Client "111.222.333.444", "250 Directory successfully changed."
Sat Oct  6 15:02:41 2018 [pid 1410] [user1] FTP command: Client "111.222.333.444", "PWD"
Sat Oct  6 15:02:41 2018 [pid 1410] [user1] FTP response: Client "111.222.333.444", "257 "/home""
Sat Oct  6 15:02:41 2018 [pid 1412] CONNECT: Client "111.222.333.444"
...

意図した通りです. これをずーっとやりたかったんです.

余談

余談という言い方もアレですが

実装するにあたって色々と勉強になったことのメモを書いていきます. 色々と気付きがあったので, 思い出したら追記していきたいと思います.

FTP について

  • アクティブモードとパッシブモードについて理解が曖昧だったので, 改めてこれらについて理解を深める良い機会になった
    • TCP 20 番ポートはデータ転送用, TCP 21 番ポートは制御用
    • アクティブモードはサーバーが TCP 20 番ポートに対してデータの転送を行う
    • パッシブモードはデータ転送ポートは不定で, サーバー側から明示的に範囲を指定された中のポートに対してデータ転送を行う

下図の解説が解りやすかった為, 引用させて頂きました.

r10zu04.gif

インターネット・プロトコル詳説(11):FTP(File Transfer Protocol)~後編 より引用.

抹茶の追加

以前にも rspec のカスタムマッチャの追加方法は勉強しました.

inokara.hateblo.jp

Rspec::Matchersdefine メソッド内に処理を書いていきます. また, メソッドチェーンは chain メソッド内にチェーンしたいメソッドを定義していきます.

Specinfra の property と set_property を利用する

FTP ユーザー名, パスワードの情報を secret.yml を切り出しておいて, テストで利用する方法の一つとして, Serverspec (厳密には specinfra) の tips で紹介されている property と set_property メソッドを spec_helper 内で利用してみました.

require 'rspec'
require 'rspec-ftp'
require 'specinfra/properties'
require 'yaml'

def property
  Specinfra::Properties.instance.properties
end

def set_property(prop)
  Specinfra::Properties.instance.properties(prop)
end

properties = YAML.load_file('secret.yml')
host = ENV['TARGET_HOST']
ftpuser = ENV['FTP_USER']
set_property properties[host]['users'].first {|u| u['username'] == ftpuser }

Travis CI で docker-compose を使う

元々の rspec-ftp にもテストは書かれていましたが, 今回いくつかのマッチャを追加するにあたり, Docker コンテナで立てた FTP サーバーに対してテストを実行したいと考えました. このような場合, docker-compose を利用するのが良いと考えていますが, 今まで Travis CI で docker-compose を使えることを知りませんでした.

ところが, 確認したところ, ずいぶん前から docker-compose は利用可能な状態になっていたことが判ったので, 以下のような docker-compose.yml を作成してテストを行うようにしました. 特に Travis CI で実行する為に特別な設定は行っておらず, 手元の端末でも docker-compose up -d で一発起動します.

version: "2"
services:
    vsftpd-server:
      image: fikipollo/vsftpd
      container_name: vsftpd-server
      environment:
        - FTP_USER=ftpuser
        - FTP_PASS=supersecret
        - ONLY_UPLOAD=NO
        - PASV_ENABLE=YES
        - PASV_ADDRESS=172.26.0.6
        - PASV_MIN=21200
        - PASV_MAX=21210
      ports:
        - "21:21"
        - "21200-21210:21200-21210"
      networks:
        my_sample_net:
          ipv4_address: 172.26.0.6
... 略 ...
    rspec-ruby23:
      image: ruby:2.3
      build: ./spec/docker/rspec
      container_name: rspec-ruby23
      volumes:
        - .:/work
      command: tail -f /dev/null
      networks:
        my_sample_net:
          ipv4_address: 172.26.0.3
networks:
  my_sample_net:
    driver: bridge
    ipam:
     driver: default
     config:
       - subnet: 172.26.0.0/16
         gateway: 172.26.0.1

networks を利用しているのは, vsftpd で PASV_ADDRESS の IP アドレスをコンテナの IP アドレスに固定する必要があった為です.

引き続き, Travis CI で docker-compose を使いつつ, 複数のコマンドを並列して実行する

複数の Ruby バージョンを使って並列してテストを走らせる為には, matrix を利用して, 環境変数 TEST_TARGET に対象の Ruby バージョンコンテナ名を入れてあげれば良いようです. 以下は実際に利用している .travis.yml です.

sudo: required
matrix:
  include:
  - name: "Ruby 2.5"
    env: TEST_TARGET=rspec-ruby25
  - name: "Ruby 2.4"
    env: TEST_TARGET=rspec-ruby24
  - name: "Ruby 2.3"
    env: TEST_TARGET=rspec-ruby23
services:
  - docker
before_install:
  - docker-compose build ${TEST_TARGET}
  - docker-compose up -d
install:
before_script:
script:
  - docker-compose exec ${TEST_TARGET} rspec
after_script:
notifications:

これを利用することで, 下図のように複数の Ruby バージョンにおいて並列でテストが走ることを確認しました.

f:id:inokara:20181006161310p:plain

以上

FTP という由緒正しいいにしへの技術が今後も使われ続けるのであれば, rspec-ftp を通して FTP について理解を深めていく必要があると感じました. また, 今回のようにインフラの振る舞いをテストするツールとしては infrataster と連携 (もしくはプラグイン化) 出来ないか考えてみたいと思います.

2018 年 10 月 05 日 (金)

ジョギング

  • 山王公園往復
  • 懸垂 4 回
  • 引き続き, 右足に違和感, これはストレッチとかしながら付き合っていくしかないのかな

日課

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

今日も鍋

  • 手羽中の鍋
  • 手羽中は事前にごま油で炒めてから煮込む, 人参等の根野菜も一緒に煮込むとさらに美味しくなる
  • 久しぶりの柚子胡椒も良かった

今日のトゥウィート

12 回目もやります.

明日は

台風が直撃しそう.

2018 年 10 月 04 日 (木)

ジョギング

  • 山王公園往復
  • 懸垂 3 回, 4 回目にいく勇気がほしい
  • 引き続き, 右足に違和感

日課

  • お休み

JAWS-UG 福岡 もくもく会 11 回目

  • 今回はさくらインターネットさんの福岡オフィスで
  • JAWS-UG 会津の方も緊急参戦して頂いた
  • AWS Loft の話題で特に盛り上った
  • もくもくは rspec-ftp を弄って, 自分が欲しかった matcher を追加してプルリクエストを送った (JAWS-UG でやるネタじゃないかもしれないけど...)

とんとん

  • もくもく会の帰りにとんとんで一杯
  • 常連 5 級くらいにはなってきたもしれない
  • 地鶏のタタキとタコの唐揚げ, このくらいで十分お腹いっぱいになる

今日のトゥウィート

「もじゃべ」じゃないらしい.

夢が広がる. ただ, Ruby の複数のバージョンを使ったテストとかしたい場合どうするんだろう.

そう言えば, もくもく会でも似たような話が出た. コンテナを使ったことが無いという層に対して k8s のハンズオンをしても響かない. ちゃんとコンテナを理解すべきだという話をされていて, ホンコレ, なぜ k8s だけが一人歩きしているんだろうなあと改めて考えてしまった. ま, 自分はコンテナもちゃんと理解出来ていないし, k8s なんて全く解ってないのでこれから勉強しなきゃという感じ.