社内se × プログラマ × ビッグデータ

プログラミングなどITに興味があります。

Docker の仮想環境を使って yum コマンドの練習

yum とは

  • yumRPMパッケージを統合管理するシステム。
  • RPM単体でもパッケージ情報や、依存関係の情報を保持しているが管理する機能がないため、それを担うのが yum
  • DebianでのAPTの位置づけになる。
  • ディストリビューションのパッケージアップデートやパッケージの検索、追加、削除、情報表示などを行う。

とはいえ、実際に yum コマンドを実行する機会が少なかったりする(自分の開発環境を壊したくない)ので、Docker のイメージを使って試してみたい。
以下、docker はインストール済みが前提で進めていきます。

CentOS 7 のイメージを取得
docker pull コマンドで DockerHub からイメージ取得できます。
今回は公式のイメージを使いますが、あえて旧バージョン7.0を使います。

$ docker pull centos:centos7.0.1406
centos7.0.1406: Pulling from library/centos
1fc5dabcd32d: Pull complete 
Digest: sha256:e06b6eef24eaf8b531e18691f6d8af5b0610b5b637438be7151930c283b6261f
Status: Downloaded newer image for centos:centos7.0.1406
$ docker images | grep centos7
centos                     centos7.0.1406      59b15a9def8d        2 months ago        210MB

イメージを取得できました。ISOファイルだと4GBあったりするので、それに比べると随分と小さいサイズであることが分かります。

コンテナ作成・起動
コマンド指定無しで実行すると、起動出来なかったので、適当に /bin/bash を付けて起動。

$ docker run -it -d --name centos7 centos:centos7.0.1406
docker: Error response from daemon: No command specified.
See 'docker run --help'.

$ docker run -it -d --name centos7 centos:centos7.0.1406 /bin/bash
901e2adfc70d0112b37fce72671379c1cb47f1304c1f8be2cdd44b67e1e32680
$ docker ps
CONTAINER ID        IMAGE                   COMMAND             CREATED             STATUS              PORTS               NAMES
901e2adfc70d        centos:centos7.0.1406   "/bin/bash"         20 seconds ago      Up 18 seconds                           centos7

centos7 という名前のコンテナを作成し起動しました。
bash を起動して、バージョンを確認してみます。

$ docker exec -it centos7 /bin/bash
[root@2795a2a189cf /]# cat /etc/redhat-release
CentOS Linux release 7.0.1406 (Core)

CentOS の準備が出来ましたので、このコンテナに対して yum コマンドを試行していきます。

yum check-update
リポジトリのアップデートをチェック。

yum check-update
Loaded plugins: fastestmirror
base       | 3.6 kB  00:00:00     
extras     | 3.4 kB  00:00:00     
updates    | 3.4 kB  00:00:00     
(1/4): base/7/x86_64/group_gz           | 166 kB  00:00:00     
(2/4): extras/7/x86_64/primary_db        | 156 kB  00:00:00     
(3/4): updates/7/x86_64/primary_db     | 1.3 MB  00:00:02     
(4/4): base/7/x86_64/primary_db    | 6.0 MB  00:00:06     
Determining fastest mirrors
 * base: ftp.nara.wide.ad.jp
 * extras: ftp.nara.wide.ad.jp
 * updates: ftp.nara.wide.ad.jp

audit-libs.x86_64         2.8.4-4.el7          base   
bash.x86_64         4.2.46-31.el7          base   
binutils.x86_64         2.27-34.base.el7        base   
bzip2-libs.x86_64      1.0.6-13.el7          base   
ca-certificates.noarch    2018.2.22-70.0.el7_5     base   
centos-release.x86_64      7-6.1810.2.el7.centos         base   
---
yum.noarch        3.4.3-161.el7.centos         base   
yum-plugin-fastestmirror.noarch         1.1.31-50.el7       base   
zlib.x86_64    1.2.7-18.el7         base   

アップデート可能なパッケージがたくさん見つかりました。ディストリビューションそのものも(centos-release.x86_64)候補として表示されています。

yum update {package}
1つのパッケージ(ここでは audit-libs)をアップデートしてみます。

# yum update audit-libs.x86_64
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: ftp.nara.wide.ad.jp
 * extras: ftp.nara.wide.ad.jp
 * updates: ftp.nara.wide.ad.jp
Resolving Dependencies
--> Running transaction check
---> Package audit-libs.x86_64 0:2.3.3-4.el7 will be updated
---> Package audit-libs.x86_64 0:2.8.4-4.el7 will be an update
--> Finished Dependency Resolution

Dependencies Resolved

==================================================================================================================================================================================================
 Package                                          Arch                                         Version                                           Repository                                  Size
==================================================================================================================================================================================================
Updating:
 audit-libs                                       x86_64                                       2.8.4-4.el7                                       base                                       100 k

Transaction Summary
==================================================================================================================================================================================================
Upgrade  1 Package

Total download size: 100 k
Is this ok [y/d/N]: y
Downloading packages:
Delta RPMs disabled because /usr/bin/applydeltarpm not installed.
warning: /var/cache/yum/x86_64/7/base/packages/audit-libs-2.8.4-4.el7.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID f4a80eb5: NOKEY
Public key for audit-libs-2.8.4-4.el7.x86_64.rpm is not installed
audit-libs-2.8.4-4.el7.x86_64.rpm                                                                                                                                          | 100 kB  00:00:00     
Retrieving key from file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
Importing GPG key 0xF4A80EB5:
 Userid     : "CentOS-7 Key (CentOS 7 Official Signing Key) <security@centos.org>"
 Fingerprint: 6341 ab27 53d7 8a78 a7c2 7bb1 24c6 a8a7 f4a8 0eb5
 Package    : centos-release-7-0.1406.el7.centos.2.3.x86_64 (@CentOS/$releasever)
 From       : /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
Is this ok [y/N]: y
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Updating   : audit-libs-2.8.4-4.el7.x86_64                                                                                                                                                  1/2 
  Cleanup    : audit-libs-2.3.3-4.el7.x86_64                                                                                                                                                  2/2 
  Verifying  : audit-libs-2.8.4-4.el7.x86_64                                                                                                                                                  1/2 
  Verifying  : audit-libs-2.3.3-4.el7.x86_64                                                                                                                                                  2/2 

Updated:
  audit-libs.x86_64 0:2.8.4-4.el7                                                                                                                                                                 

Complete!

改めて check-update してみると、audit-libs はリストから消えたのが分かります(アップデート済みのため)。

# yum check-update
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: ftp.nara.wide.ad.jp
 * extras: ftp.nara.wide.ad.jp
 * updates: ftp.nara.wide.ad.jp

bash.x86_64         4.2.46-31.el7          base   
binutils.x86_64         2.27-34.base.el7        base   

yum search {package}
リポジトリからパッケージを検索します。

# yum search wget 
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: ftp.nara.wide.ad.jp
 * extras: ftp.nara.wide.ad.jp
 * updates: ftp.nara.wide.ad.jp
======================================================================================= N/S matched: wget ========================================================================================
wget.x86_64 : A utility for retrieving files using the HTTP or FTP protocols

  Name and summary matches only, use "search all" for everything.

"wget" というキーワードに対して、"wget.x86_64" というパッケージが見つかりました。

yum install {package}
リポジトリからパッケージをインストールします。依存関係にあるパッケージも自動的に解決してくれます。

# yum install wget
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: ftp.nara.wide.ad.jp
 * extras: ftp.nara.wide.ad.jp
 * updates: ftp.nara.wide.ad.jp
Resolving Dependencies
--> Running transaction check
---> Package wget.x86_64 0:1.14-18.el7 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

==================================================================================================================================================================================================
 Package                                     Arch                                          Version                                              Repository                                   Size
==================================================================================================================================================================================================
Installing:
 wget                                        x86_64                                        1.14-18.el7                                          base                                        547 k

Transaction Summary
==================================================================================================================================================================================================
Install  1 Package

Total download size: 547 k
Installed size: 2.0 M
Is this ok [y/d/N]: y
Downloading packages:
wget-1.14-18.el7.x86_64.rpm                                                                                                                                                | 547 kB  00:00:00     
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : wget-1.14-18.el7.x86_64                                                                                                                                                        1/1 
install-info: No such file or directory for /usr/share/info/wget.info.gz
  Verifying  : wget-1.14-18.el7.x86_64                                                                                                                                                        1/1 

Installed:
  wget.x86_64 0:1.14-18.el7                                                                                                                                                                       

Complete!

yum info {package}
インストールされているパッケージの情報を表示します。

# yum info wget
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: ftp.nara.wide.ad.jp
 * extras: ftp.nara.wide.ad.jp
 * updates: ftp.nara.wide.ad.jp
Installed Packages
Name        : wget
Arch        : x86_64
Version     : 1.14
Release     : 18.el7
Size        : 2.0 M
Repo        : installed
From repo   : base
Summary     : A utility for retrieving files using the HTTP or FTP protocols
URL         : http://www.gnu.org/software/wget/
License     : GPLv3+
Description : GNU Wget is a file retrieval utility which can use either the HTTP or
            : FTP protocols. Wget features include the ability to work in the
            : background while you are logged out, recursive retrieval of
            : directories, file name wildcard matching, remote file timestamp
            : storage and comparison, use of Rest with FTP servers and Range with
            : HTTP servers to retrieve files over slow or unstable connections,
            : support for Proxy servers, and configurability.

yum list installed
インストールされているパッケージの一覧を表示します。

# yum list installed
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: ftp.nara.wide.ad.jp
 * extras: ftp.nara.wide.ad.jp
 * updates: ftp.nara.wide.ad.jp
Installed Packages
audit-libs.x86_64                                                                        2.8.4-4.el7                                                                      @base                   
basesystem.noarch                                                                        10.0-7.el7.centos                                                                @CentOS/$releasever     
bash.x86_64                                                                              4.2.45-5.el7                                                                     @CentOS/$releasever    
---
yum-metadata-parser.x86_64                                                               1.1.4-10.el7                                                                     @CentOS/$releasever     
yum-plugin-fastestmirror.noarch                                                          1.1.31-24.el7                                                                    @CentOS/$releasever     
zlib.x86_64                                                                              1.2.7-13.el7                                                                     @CentOS/$releasever   

yum remove {package}
インストール済みのパッケージを削除します。
インストールしたばかりですが、wget を削除します。

# yum remove wget
Loaded plugins: fastestmirror
Resolving Dependencies
--> Running transaction check
---> Package wget.x86_64 0:1.14-18.el7 will be erased
--> Finished Dependency Resolution

Dependencies Resolved

==================================================================================================================================================================================================
 Package                                     Arch                                          Version                                             Repository                                    Size
==================================================================================================================================================================================================
Removing:
 wget                                        x86_64                                        1.14-18.el7                                         @base                                        2.0 M

Transaction Summary
==================================================================================================================================================================================================
Remove  1 Package

Installed size: 2.0 M
Is this ok [y/N]: y
Downloading packages:
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
install-info: No such file or directory for /usr/share/info/wget.info.gz
  Erasing    : wget-1.14-18.el7.x86_64                                                                                                                                                        1/1 
  Verifying  : wget-1.14-18.el7.x86_64                                                                                                                                                        1/1 

Removed:
  wget.x86_64 0:1.14-18.el7                                                                                                                                                                       

Complete!

削除されているようです。

# wget --version
bash: /usr/bin/wget: No such file or directory

yum repolist all
登録済みのリポジトリ一覧を表示します。

# yum repolist all
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: ftp.nara.wide.ad.jp
 * extras: ftp.nara.wide.ad.jp
 * updates: ftp.nara.wide.ad.jp
repo id                                                                               repo name                                                                                     status
base/7/x86_64                                                                         CentOS-7 - Base                                                                               enabled: 10019
base-source/7                                                                         CentOS-7 - Base Sources                                                                       disabled
centosplus/7/x86_64                                                                   CentOS-7 - Plus                                                                               disabled
centosplus-source/7                                                                   CentOS-7 - Plus Sources                                                                       disabled
debug/x86_64                                                                          CentOS-7 - Debuginfo                                                                          disabled
extras/7/x86_64                                                                       CentOS-7 - Extras                                                                             enabled:   321
extras-source/7                                                                       CentOS-7 - Extras Sources                                                                     disabled
updates/7/x86_64                                                                      CentOS-7 - Updates                                                                            enabled:   624
updates-source/7                                                                      CentOS-7 - Updates Sources                                                                    disabled
repolist: 10964

登録されていても、無効になっているリポジトリがあります。

yum install {リポジトリ}
リポジトリを追加します。
ここでは、Remi というリポジトリを追加してみます。

# yum install http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
Loaded plugins: fastestmirror
remi-release-7.rpm                                                                                                                                                         |  15 kB  00:00:00     
Examining /var/tmp/yum-root-KhJNlg/remi-release-7.rpm: remi-release-7.6-1.el7.remi.noarch
Marking /var/tmp/yum-root-KhJNlg/remi-release-7.rpm to be installed
Resolving Dependencies
--> Running transaction check
---> Package remi-release.noarch 0:7.6-1.el7.remi will be installed
--> Processing Dependency: epel-release = 7 for package: remi-release-7.6-1.el7.remi.noarch
Loading mirror speeds from cached hostfile
 * base: ftp.nara.wide.ad.jp
 * extras: ftp.nara.wide.ad.jp
 * updates: ftp.nara.wide.ad.jp
--> Running transaction check
---> Package epel-release.noarch 0:7-11 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

==================================================================================================================================================================================================
 Package                                        Arch                                     Version                                          Repository                                         Size
==================================================================================================================================================================================================
Installing:
 remi-release                                   noarch                                   7.6-1.el7.remi                                   /remi-release-7                                    18 k
Installing for dependencies:
 epel-release                                   noarch                                   7-11                                             extras                                             15 k

Transaction Summary
==================================================================================================================================================================================================
Install  1 Package (+1 Dependent package)

Total size: 33 k
Total download size: 15 k
Installed size: 42 k
Is this ok [y/d/N]: y
Downloading packages:
epel-release-7-11.noarch.rpm                                                                                                                                               |  15 kB  00:00:00     
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : epel-release-7-11.noarch                                                                                                                                                       1/2 
  Installing : remi-release-7.6-1.el7.remi.noarch                                                                                                                                             2/2 
  Verifying  : remi-release-7.6-1.el7.remi.noarch                                                                                                                                             1/2 
  Verifying  : epel-release-7-11.noarch                                                                                                                                                       2/2 

Installed:
  remi-release.noarch 0:7.6-1.el7.remi                                                                                                                                                            

Dependency Installed:
  epel-release.noarch 0:7-11                                                                                                                                                                      

Complete!

改めてリポジトリの一覧を見てみると、remi の名前で複数追加されているのが分かります。
主に php 関連のリポジトリであることも明白です。
※remi-safe だけが有効になっていますが、これでOKなのだろうか

# yum repolist all | grep remi
 * remi-safe: ftp.riken.jp
remi                             Remi's RPM repository for Enterp disabled
remi-debuginfo/x86_64            Remi's RPM repository for Enterp disabled
remi-glpi91                      Remi's GLPI 9.1 RPM repository f disabled
remi-glpi92                      Remi's GLPI 9.2 RPM repository f disabled
remi-glpi93                      Remi's GLPI 9.3 RPM repository f disabled
remi-glpi94                      Remi's GLPI 9.4 RPM repository f disabled
remi-php54                       Remi's PHP 5.4 RPM repository fo disabled
remi-php55                       Remi's PHP 5.5 RPM repository fo disabled
remi-php55-debuginfo/x86_64      Remi's PHP 5.5 RPM repository fo disabled
remi-php56                       Remi's PHP 5.6 RPM repository fo disabled
remi-php56-debuginfo/x86_64      Remi's PHP 5.6 RPM repository fo disabled
remi-php70                       Remi's PHP 7.0 RPM repository fo disabled
remi-php70-debuginfo/x86_64      Remi's PHP 7.0 RPM repository fo disabled
remi-php70-test                  Remi's PHP 7.0 test RPM reposito disabled
remi-php70-test-debuginfo/x86_64 Remi's PHP 7.0 test RPM reposito disabled
remi-php71                       Remi's PHP 7.1 RPM repository fo disabled
remi-php71-debuginfo/x86_64      Remi's PHP 7.1 RPM repository fo disabled
remi-php71-test                  Remi's PHP 7.1 test RPM reposito disabled
remi-php71-test-debuginfo/x86_64 Remi's PHP 7.1 test RPM reposito disabled
remi-php72                       Remi's PHP 7.2 RPM repository fo disabled
remi-php72-debuginfo/x86_64      Remi's PHP 7.2 RPM repository fo disabled
remi-php72-test                  Remi's PHP 7.2 test RPM reposito disabled
remi-php72-test-debuginfo/x86_64 Remi's PHP 7.2 test RPM reposito disabled
remi-php73                       Remi's PHP 7.3 RPM repository fo disabled
remi-php73-debuginfo/x86_64      Remi's PHP 7.3 RPM repository fo disabled
remi-php73-test                  Remi's PHP 7.3 test RPM reposito disabled
remi-php73-test-debuginfo/x86_64 Remi's PHP 7.3 test RPM reposito disabled
remi-safe                        Safe Remi's RPM repository for E enabled:  3097
remi-safe-debuginfo/x86_64       Remi's RPM repository for Enterp disabled
remi-test                        Remi's test RPM repository for E disabled
remi-test-debuginfo/x86_64       Remi's test RPM repository for E disabled

基本的なコマンドを一通り叩いてみました。
実際に叩く機会が無いとしても、仮想環境を利用して、色々なコマンドを繰り返し叩いてみることは良い経験になるかもしれません。

Java プリミティブ型のメリットって

なんでしょうか。色んな意見がありそうですが。。

1. null を許容しない
例えば、プリミティブ型の int を返すメソッドで return null と書くとコンパイルエラーになる。
個人的には、そんなに嬉しいかと言われると微妙です。
そもそも、null 許容しないなら、return null なんて書かないと思います。

2. パフォーマンスがオブジェクト型より良い

  • オブジェクト型のデータはオブジェクトを生成しなければならない。
  • また、位置情報を使ってヒープ領域のデータを参照しなければならない。
  • これらは、プリミティブ型に比べてオーバーヘッドになり得る。

昔に比べて今はメモリの使用量に関して、そこまで深刻になるケースはないかもしれません。

ただ、以下を Integer でループするかと聞かれたら”いいえ”と答えます。

for (int i=0; i<100000; i++) {
}

3. GCガベージコレクション) の対象にならない
これは上のパフォーマンスと同じような意味になります。
プリミティブ型の変数はヒープから割り当てられず、代わりにスタック領域に割り当てられる。
オブジェクト型はヒープ領域から割り当てられるため、ガベージコレクションが必要になる。

4. Effective Java に "Avoid creating unnecessary objects" と書いてある
上の for ループの例と重複しますが、以下を実行すると40秒かかるが、プリミティブ型であれば10秒以内で処理される。

public static void main(String[] args) {
    Long sum = 0L; // uses Long, not long
    for (long i = 0; i <= Integer.MAX_VALUE; i++) {
        sum += i;
    }
    System.out.println(sum);
}

5. 数値の比較に == が使える
オブジェクト型の場合、.equals() を使えば比較は出来るので、特に問題はないです。
ただ、-128 から 127 までの値であれば、オブジェクト型でも == で比較が出来てしまうケースがあるややこしい一面があります。

public static void main(String[] args) {
    System.out.println(new Integer(5) == new Integer(5));  // false
    System.out.println(new Integer(500) == new Integer(500));  // false

    System.out.println(Integer.valueOf(5) == Integer.valueOf(5));  // true
    System.out.println(Integer.valueOf(500) == Integer.valueOf(500));  // false
}

こうやってみてみると、プリミティブ型が活躍しそうな(している)場面はありますね。

Couchbase cbbackup でデータをバックアップ・リストアしてみる

Couchbase server では公式のデータバックアップツールとして、cbbackup というものがある。
cbbackup | Couchbase Docs

Linux 上でインストールした Couchbase server に対して、バックアップを実行してみます。
環境
Version: 4.5.1-2844 Community Edition (build-2844)
Server Node数: 3
Bucket名: default

バックアップ前の状態
このように 100,000 件のレコードが登録されています。
f:id:blueskyarea:20181216145928p:plain
f:id:blueskyarea:20181216150103p:plain

バックアップ用コマンド

/opt/couchbase/bin/cbbackup couchbase://localhost:8091 /cb-backup -m full --single-node -u admin -p password

今回は couchbase server 上でそのままバックアップコマンドを実行するため、取得先サーバーとして、localhost を指定しています。
バックアップ先のディレクトリとして、/cb-backup を予め作成しておく必要があります。
"-m full" はフルバックアップを意味します
"--single-node" はバックアップするサーバを1台に絞ります(クラスター全体からバックアップしない)

実行すると、以下のようなメッセージが表示されます

# /opt/couchbase/bin/cbbackup couchbase://localhost:8091 /cb-backup -m full --single-node -u admin -p password
  [####################] 100.0% (33332/estimated 33332 msgs)
bucket: default, msgs transferred...
       :                total |       last |    per sec
 byte  :              2629467 |    2629467 |   300695.6
2018-12-16 01:38:07,871: mt could not find index server:0
done

バックアップ先に指定したディレクトリを見てみると、以下のようなファイルが生成されています。
実行時のタイムスタンプから、対象のバケット名やサーバ名など、思っていたよりも深いディレクトリ構造になっています。

# ls -alth cb-backup/2018-12-16T013759Z/2018-12-16T013759Z-full/bucket-default/node-172.26.0.3%3A8091/
total 4.8M
-rw-r--r-- 1 root root 3.9K Dec 16 01:38 seqno.json
drwxr-xr-x 2 root root 4.0K Dec 16 01:38 .
-rw-r--r-- 1 root root 4.8M Dec 16 01:38 data-0000.cbb
-rw-r--r-- 1 root root 5.6K Dec 16 01:38 snapshot_markers.json
-rw-r--r-- 1 root root  18K Dec 16 01:38 failover.json
drwxr-xr-x 3 root root 4.0K Dec 16 01:37 ..

データのクリア
一旦、すべてのデータをクリアします。
f:id:blueskyarea:20181216150145p:plain

リストア用コマンド

/opt/couchbase/bin/cbrestore /cb-backup couchbase://localhost:8091 -b default

実行すると以下のようなメッセージが表示されます。

# /opt/couchbase/bin/cbrestore /cb-backup couchbase://localhost:8091 -b default
  [####################] 100.0% (33332/estimated 33332 msgs)
bucket: default, msgs transferred...
       :                total |       last |    per sec
 byte  :              2629467 |    2629467 |   964675.8
done

リストア後の状態
f:id:blueskyarea:20181216150202p:plain
なんと、元あったデータの3分の1しか復元されていませんでした。
cbbackup 実行時に --single-node オプションをつけていた為、3台中1台分しかバックアップされていなかったようです。

改めて --single-node なしでバックアップ

# /opt/couchbase/bin/cbbackup couchbase://localhost:8091 /cb-backup -m full -u admin -p password
  [####################] 100.0% (100000/estimated 100000 msgs)
bucket: default, msgs transferred...
       :                total |       last |    per sec
 byte  :              7888890 |    7888890 |   293045.8
2018-12-16 05:51:27,091: mt could not find index server:0
done

ノード毎に3台分ディレクトリが生成されています。

# ls -alth /cb-backup/2018-12-16T055100Z/2018-12-16T055100Z-full/bucket-default/
total 20K
drwxr-xr-x 2 root root 4.0K Dec 16 05:51 node-172.26.0.3%3A8091
drwxr-xr-x 2 root root 4.0K Dec 16 05:51 node-172.26.0.1%3A8091
drwxr-xr-x 2 root root 4.0K Dec 16 05:51 node-172.26.0.2%3A8091
drwxr-xr-x 5 root root 4.0K Dec 16 05:51 .
drwxr-xr-x 3 root root 4.0K Dec 16 05:51 ..

改めてリストア
全てのデータがリストアされました。
f:id:blueskyarea:20181216150223p:plain

非常に基本的なバックアップを取得するつもりでしたが、オプションの意味を勘違いしていたことで、意図しない結果が得られました。
自分のドキュメント理解力も残念なところがありますが、試してみることが大切であると改めて感じます。

java.util.stream のソースを読んでみる filter 編

stream については、package java.util.stream; の JavaDoc には以下のように書かれています。

 * A sequence of elements supporting sequential and parallel aggregate
 * operations.

並んでいる要素に対して、直列または並列処理をサポートするみたいなイメージでしょうか。

そもそも、Java8 ではなぜ List から stream() を使って Stream に変換が出来るのだろう?
> Collection インタフェースに stream() が用意されていて、List ではそれを継承しているようです。
https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html

では、filter の JavaDoc を見てみます。

    /**
     * Returns a stream consisting of the elements of this stream that match
     * the given predicate.
     *
     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
     * operation</a>.
     *
     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
     *                  <a href="package-summary.html#Statelessness">stateless</a>
     *                  predicate to apply to each element to determine if it
     *                  should be included
     * @return the new stream
     */
    Stream<T> filter(Predicate<? super T> predicate);

うーん。Predicate ですか。
では、Predicate の JavaDoc を見てみます。

/**
 * Represents a predicate (boolean-valued function) of one argument.
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #test(Object)}.
 *
 * @param <T> the type of the input to the predicate
 *
 * @since 1.8
 */

これだけでは、ピンと来なかったですが、用意されているメソッドを見てみると、test(T t) というものがあります。

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);

与えられた引数が条件(直訳だと述語?)に一致した場合は、true 一致しない場合は false を返します。
interface Predicate は他にもメソッドが定義されていますが、最終的にこの test(T t) が呼ばれるようです。

つまり、Stream filter(Predicate predicate); の中の Predicate predicate に関しては
与えたデータ型 T が boolean に変換されるとも捉えられるので、
Stream filter(T -> boolean);
こんな感じに変換(おおざっぱに)捉えることにします。

例として、

List<String> before = Arrays.asList("a", "b", "c");
List<String> after = before.stream().filter(e -> e.equals("b")).collect(Collectors.toList());
after.forEach(System.out::println); // b

filter(T -> boolean) と filter(e -> e.equals("b")) のような関係にこじつけられます。

JGiven のレポート機能を試す(Java, JUnit)

JGiven ではいくつかのレポート機能が用意されているようです。

テキストのレポートを無効にする

デフォルトでは、コンソール上にテキストのレポートが表示されます。

 Something should happen

   Given サーバーが止まっている時に
    When プログラムを実行すると
    Then エラーになる

しかしながら、これを Java system property にて無効化することが出来ます。

$ mvn test -Djgiven.report.text=false

わざわざ無効化する用途は思い当たらないのですが。

JSON のレポートを無効にする

デフォルトでは、jgiven-reports ディレクトリ以下に JSON ファイルでテスト結果のレポートが出力されます。
私の環境では、eclipse 上からテストを実行した場合、project/jgiven-reports にレポートが出力されました。
mvn test でテストを実行した場合、target/jgiven-reports/json にレポートが出力されました。
後者については、Maven surefire plugin を用いた場合の挙動になるようですが、あまり理解できていません。
しかしながら、これも無効にすることが出来ます。

$ mvn test -Djgiven.report.enabled=false

この property を指定した場合、コンソール上へのテキスト形式のレポートも表示されなくなります。
※レポート機能自体が無効化される
これも、わざわざ無効化する用途は思い当たらないのですが。

JSON のレポート出力先を変更する

/tmp に変更しています。json のテキストファイルが直接出力されます。

$ mvn test -Djgiven.report.dir=/tmp

HTML のレポートを出力するために

このような感じのレポートが出力できるようです。
まず、JSON のレポート出力は必須とのこと。
そして、Given report generator と呼ばれるツールを html フォーマットを指定して実行すれば出力してくれるようです。
このツールは、jgiven-html5-report と呼ばれるモジュールの一部らしいです。

java com.tngtech.jgiven.report.ReportGenerator \
  --format=html \
  [--sourceDir=<jsonreports>] \
  [--targetDir=<targetDir>] \

maven プラグインを使えば、このようなコマンドを別途実行してあげる必要もなさそうです。
pom ファイルで指定するためには、

<build>
  <plugins>
    <plugin>
      <groupId>com.tngtech.jgiven</groupId>
      <artifactId>jgiven-maven-plugin</artifactId>
      <version>0.17.0</version>
      <executions>
        <execution>
          <goals>
            <goal>report</goal>
          </goals>
        </execution>
      </executions>
      <configuration>
        <format>html</format>
      </configuration>
    </plugin>
 </plugins>
</build>

注意点は、reporting の配下ではなくて、build の配下に設置すること。

そして、mvn verify コマンドを実行しますと、以下のようにレポートが target/jgiven-reports/html 配下に自動的に生成されます。

[INFO] --- jgiven-maven-plugin:0.17.0:report (default) @ practiceJava ---
[INFO] JGiven HTML report source directory: /home/xx/workspace/Java/target/jgiven-reports/json
[INFO] JGiven HTML report output directory: /home/xx/workspace/Java/target/jgiven-reports/html
[INFO] Generating HTML reports to /home/xx/workspace/Java/target/jgiven-reports/html...
[INFO] Generating HTML5 report to /home/xx/workspace/Java/target/jgiven-reports/html/index.html
[INFO] Written 1 scenarios to data0.js
[INFO] Cannot read /home/xx/workspace/Java/src/test/resources/jgiven/custom.css, skipping
[INFO] Cannot read /home/xx/workspace/Java/src/test/resources/jgiven/custom.js, skipping
[INFO] -------------------------------------------------------------------
[INFO] Generated JGiven HTML reports to directory /home/xx/workspace/Java/target/jgiven-reports/html
[INFO] -------------------------------------------------------------------

ブラウザで開いてみると、こんな感じに見れます。

f:id:blueskyarea:20181128233126p:plain
sample_jgiven_report

まとめ

レポート機能は HTML (ブラウザで確認)のためにあるような印象です。
今までテスト結果をコンソール上や、IDE上でのみか確認出来なかった場合、外部向けに説明するには何らかの加工をしてあげる必要がありましたが、ブラウザ上でのレポートであれば見やすく、外部向けにも説明がしやすくなると思います。
ついでに、テストを書くのが楽しくなれば良いと思います。

JGiven をユーザーガイド見ながら試す(Java, JUnit)

JGiven とは

公式サイト から引用すると

JGiven は、開発者にフレンドリーで実用的な Java の BDD ツールです。
ドメインエキスパートにとって読みやすいレポートを生成してくれます。

JGiven を使おうとしたきっかけ

Java のプロジェクトに関しては、普段 JUnit を使用してテストを書いていますが、以下のような問題に悩まされています。
1. 既存テストの要点を掴むのが難しいことがある
他人が書いたテストコードはもちろんのこと、自分で書いたテストですら数ヶ月も経つと、テストの要点(目的)などが分かり難くなってしまっていることがあります。
テスト内でテストデータを作ったり、条件を作ったりしていると、それをトレースするのが大変になったりします。

2. テストのレポートがわかりにくい
JUnit でテストを実行した結果、例えその結果が全てパス(成功)だったとしても、どういった仕様を満たしているのかわかりにくい場合があります。
特にテストケースが数十、百以上になってきたりすると、どのようなテストケースがあるのか把握するのが難しくなります。

3. 開発者(プログラマー)しか読めない
上記と類似することですが、テストの仕様を理解するのに、プログラム(ソースコード)を読まなければならない場合があるため、開発者以外が仕様を理解することが難しくなります。
場合によっては、開発者以外のために、別途ドキュメントを用意する必要があります。

結局のところ、以下の2点が満足できれば、これらの問題を解消する手助けになりそうです。
1. 読みやすいテストが書けること
2. 分かりやすいレポートが出力されること
これらが、JGiven フレームワークに期待しているポイントになります。

ユーザーガイド

それでは、ユーザーガイドに沿って、インストールから最初の実行までやってみます。
JGiven User Guide

インストール

JUnitmaven を使用しているので、以下を pom に指定してあげます。

<dependency>
	<groupId>com.tngtech.jgiven</groupId>
	<artifactId>jgiven-junit</artifactId>
	<version>0.17.0</version>
	<scope>test</scope>
</dependency>

JUnit テストクラスを作る

何はともあれ、テストクラスがなければ話が始まらないので作ります。
JUnit の場合は、ScenarioTest を継承する必要があるようです。
更に ScenarioTest は3種類のパラメータを要求しており、それぞれ Given-When-Then と呼ばれます。

import com.tngtech.jgiven.junit.ScenarioTest;

public class MyShinyJGivenTest
        extends ScenarioTest<GivenSomeState, WhenSomeAction, ThenSomeOutcome> {
}

日本語で言うと、以下のようなステージ構成になるようです。
Given : 何かの状態のとき
When : 何かをしたら
Then : 何かの結果になる

これを上手く表現することが出来れば、そのまま仕様のように読み取れるかもしれません。

Given, When, Then クラスを作る

それぞれのステージを構成するためのクラスを生成します。
Given

import com.tngtech.jgiven.Stage;

public class GivenSomeState extends Stage<GivenSomeState> {
    public GivenSomeState some_state() {
        return self();
    }
}

When

import com.tngtech.jgiven.Stage;

public class WhenSomeAction extends Stage<WhenSomeAction> {
    public WhenSomeAction some_action() {
        return self();
    }
}

Then

public class ThenSomeOutcome extends Stage<ThenSomeOutcome> {
    public ThenSomeOutcome some_outcome() {
        return self();
    }
}

Stage クラスの継承を必須としているわけではないそうですが、and() や self() などの有用なメソッドが提供されているため、推奨されているようです。
※何が有用なのか現時点では不明ですが

テストシナリオを書く

それではいよいよテストシナリオを書いていきます。
最初に作ったテストクラスに追記しています。

public class MyShinyJGivenTest extends ScenarioTest<GivenSomeState, WhenSomeAction, ThenSomeOutcome> {
    @Test
    public void something_should_happen() {
        given().some_state();
        when().some_action();
        then().some_outcome();
    }
}

ScenarioTest を継承したことにより、given(), when(), then() がそれぞれ指定したクラスのインスタンスに紐づいているようです。
なので、インスタンス.メソッド名 という形でメソッドの呼び出しが可能となっています。

実行してみる

実行してみると、以下のような結果が出力されました。
Given, When, Then は固定で、some xxx は、メソッド名(some_state など)から来ているようです。

Test Class: test.java.practice.bdd.jgiven.MyShinyJGivenTest

 Something should happen

   Given some state
    When some action
    Then some outcome

なので、例えば日本語でメソッド名を作成してみた場合、こんな感じの出力が期待できます。
どんなテストをやっているのか分かりやすいですね。

   Given サーバーが止まっている時に
    When プログラムを実行すると
    Then エラーになる

もし ScenarioTest を継承することができない場合

すでに他のクラスを継承しているなどで、ScenarioTest を継承することができない場合は、JGiven の JUnit rule を使用すれば良いとのこと。
具体的には、JGivenClassRule と JGivenMethodRule を定義すること。
Given-When-Then それぞれのクラスを @ScenarioStage アノテーションを用いて注入してあげること。

public class UsingRulesTest {

    @ClassRule
    public static final JGivenClassRule writerRule = new JGivenClassRule();

    @Rule
    public final JGivenMethodRule scenarioRule = new JGivenMethodRule();

    @ScenarioStage
    GivenSomeState someState;

    @ScenarioStage
    WhenSomeAction someAction;

    @ScenarioStage
    ThenSomeOutcome someOutcome;

    @Test
    public void something_should_happen() {
        someState.given().サーバーが止まっている時に();
        someAction.when().プログラムを実行すると();
        someOutcome.then().エラーになる();
    }
}

ScenarioTest のソースを見てみると、似たようなことをしているので、継承する代わりに自分たちで定義してあげるような格好になっていると思われます。

public class ScenarioTest<GIVEN, WHEN, THEN> extends ScenarioTestBase<GIVEN, WHEN, THEN> {
    @ClassRule
    public static final JGivenClassRule writerRule = new JGivenClassRule();

    @Rule
    public final JGivenMethodRule scenarioRule = new JGivenMethodRule( createScenario() );

    @Override
    public Scenario<GIVEN, WHEN, THEN> getScenario() {
        return (Scenario<GIVEN, WHEN, THEN>) scenarioRule.getScenario();
    }
}

まとめ

以上、ユーザーガイドに沿って試行してみましたが、当初期待していた2点
> 1. 読みやすいテストが書けること
> 2. 分かりやすいレポートが出力されること
について、JGiven が手助けになる可能性を感じることができました。
もちろん現時点では、テストケースも少なくシンプルなので分かりやすいですが、実際にシナリオが増えてきた場合に、上手くシンプルな状態を保ったまま管理が出来るかは分かりません。
とは言え、テスト結果が以下のように表示されるだけでも強力です。

   Given サーバーが止まっている時に
    When プログラムを実行すると
    Then エラーになる

たとえば、以下のように Given だけ差し替えることも容易に出来ると思われます。

   Given ネットワークが止まっている時に
    When プログラムを実行すると
    Then エラーになる

レポート出力に関しては、機能が充実しているようなので、機会があれば試行してみたいと思います。

terminator(端末)が起動しなくなった except (KeyError,ValueError)

Ubuntu14.04 上でいつの間にか terminator が起動しなくなりました。
デスクトップ上のランチャーを叩いても、何の応答もありません。
仕方なく、他の端末(XTerm)を起動し、/usr/bin/terminator を直接実行してみたところ、以下のエラーが表示。

  File "/usr/bin/terminator", line 103
    except (KeyError,ValueError), ex:

SyntaxError: invalid syntax

SyntaxError ? なぜ、terminator のソースをさわってもいないのに突然そのようなエラーが出るのか。
答えは、python 3 をデフォルトに設定していたためでした。
※確かに、この問題が発生する直前に変更していました

/usr/bin/terminator の1行目に、#! /usr/bin/python と指定されています。
そのため、python 3 で terminator を起動するようになったと思われますが、それが互換性がなくて SyntaxError になってしまったと思われます。

回避策として、1行目を #! /usr/bin/python2 として、python2を適用することを明示すれば、問題なく起動するようになりました。
この問題は初めて遭遇しましたが、前々からよくありそうですし、報告されています。
bugs.launchpad.net