2014年5月31日土曜日

シェルスクリプトでUnitテストをやってみた

シェルのUnitテストフレームワークに「shUnit2」というものがあります
今回はこれを使ってシェルスクリプトをテストする方法を紹介します

■環境
CentOS release 5.10 (Final)
bash 3.2.25
shUnit2 2.1.16

■shUnit2のインストール
wget https://shunit2.googlecode.com/files/shunit2-2.1.6.tgz
tar zvxf shunit2-2.1.6.tgz

※ダウンロードして解凍すれば完了です
※テストコードから参照できる場所に配置してください

■サンプルテスト
解凍した「shunit2-2.1.6」と同じ階層にサンプルテスト用のシェルスクリプト(testSample.sh)を作成します
[root@localhost work]# ls -ltr
合計 76
drwxr-xr-x 7 1001 users  4096  5月  2  2011 shunit2-2.1.6
-rw-r--r-- 1 root root  61558  5月  2  2011 shunit2-2.1.6.tgz
-rw-r--r-- 1 root root     95  5月 29 08:48 testSample.sh

testSample.shの内容は以下の通りです
#! /bin/sh

oneTimeSetUp() {
  echo "Start testSample.sh"
}

setUp() {
  echo "Start each test method"
}

testSample1() {
  assertEquals 1 1
}

testSample2() {
  cd /root && ls -ltr 2>&1 > /dev/null
  #assertEquals 0 $?
  assertEquals "This value is not 0" 0 $?
}

testSample3() {
  assertNull "This value is not null" ""
}

testSample4() {
  assertTrue "This value is not true" "[ 0 -eq 0 ]"
}

testSample5() {
  fail "This test is certainly error !"
}

tearDown() {
  echo "End of testSample.sh"
}

# load shunit2
. ./shunit2-2.1.6/src/shunit2

sh testSample.sh
と実行するとテストが実行されます

■Tips
使用できるアサート系一覧
  • assertEquals・・・等しい
  • assertNotEquals・・・等しくない
  • assertSame・・・assertEqualsと一緒
  • assertNotSame・・・assertNotEqualsと一緒
  • assertNull・・・null(空白文字列)かどうか
  • assertNotNull・・・null(空白文字列)かではない
  • assertTrue・・・trueかどうか
  • assertFalse・・・falseかどうか

assertHogehogeの第一引数に文字列を追加すると失敗した際にそのメッセージを表示してくれる

わざと失敗に倒す場合は「fail」を使用します

Setup/Teardown メソッドが使えます
「setUp」は各テストが実施される前に実行されます、oneTimeSetUpは事前に1度だけ実施されます

■参考サイト

2014年5月30日金曜日

.tmux.conf設定メモ

Here is my .tmux.conf

2014年5月29日木曜日

CentOSでJavaをインストールする方法まとめ

CentOSでJavaをインストールする方法を各種紹介します
それぞれのインストール方法でJAVA_HOMEを設定するところまで紹介します
どれでも最終的にJavaをインストールすることができますがインストールの過程や内容が大きくことなるので
自身の環境にあったインストール方法をお選びください
また、CentOSのバージョンは 5 or 6 系であることを想定しています

■yumインストール
方法としては最も簡単な方法になるかと思います
注意していただくのは、CentOS の base リポジトリにある Java は「OpenJDK」になります
Oracle が提供する公式のJavaではありません
tools.jar などを利用してJavaのコンパイル、開発がしたい場合は「-devel」がつくパッケージもインストールしなければなりません
メリットは非常に簡単にインストール・アンインストールできところかと思います
デメリットはリポジトリにあるバージョンが自動でインストールされるので好きなバージョンを選べません
(ほしいバージョンがおいてあるリポジトリを追加すればインストール可能ではありますが。。)

・インストール方法
yum -y install java-1.7.0-openjdk-devel java-1.7.0-openjdk

※openJDKのバージョンは1.5から1.7まで選択できます(2014/05/27現在)

・JAVA_HOME設定方法
export JAVA_HOME="/etc/alternatives/java_sdk"
または
export JAVA_HOME="/usr/lib/jvm/java-1.7.0"

※「/etc/alternatives」や「/usr/lib/jvm」配下にシンボリックリンクがたくさん作成されているようですが
java で始まるディレクトリを選択すればOKです(jreで始まるディレクトリはjreなのでコンパイル等ができないので注意してください)

■rpmインストール
ネット上で配布されているrpmファイルをダウンロードしてマシン上でrpmコマンドを使ってインストールする方法です
yumコマンドを使ったインストールとの違いはyumコマンド配下では管理されずrpmコマンドのみで管理される点かと思います
また、rpmコマンドでインストールする場合は「--prefix」というオプションを使ってインストール先のディレクトリを選択できます

Oracleが公式で提供しているrpmパッケージもあります
同様にOpenJDKのrpmパッケージや誰かが作成した自作Javaのrpmパッケージ等も(探せば)あります
今回はOracleが公式で配布しているrpmを使ったインストール方法を紹介します

rpmを配布しているOracle公式サイトにアクセスします
Accept License Agreement にチェックし「jdk-7u55-linux-x64.rpm」をダウンロードします
※32bitOSの場合はx86のほうをダウンロードしてください
ダウンロードしたらrpmをインストールするマシンにwinscpなりで転送してください

・インストール方法
rpm -ivh jdk-7u55-linux-x64.rpm

※インストールされてディレクトリを確認する方法は「rpm -qli jdk-1.7.0_55-fcs.x86_64」で確認できます
※特に「--prefix」を指定しない場合は/usr/java/jdk1.7.0_55/にインストールされていました

・JAVA_HOME設定方法
export JAVA_HOME="/usr/java/jdk1.7.0_55/"

■バイナリインストール
バイナリインストールと記載しましたが、configureしてmakeする流れでなく
あらかじめコンパイルされたバイナリを配置してインストール完了とする方法です
tar.gzで圧縮されたファイルを解凍して、好きな位置に配置してインストール完了です
メリットとして好きなバージョンを選択してインストールできるのとインストール先も自由に選択できます
デメリットとしてはパッケージ管理コマンドでは管理されないので、インストール済みのパッケージ一覧にでないほか
どこにインストールしたかとかアンインストールする場合はディレクトリごと削除(またはrename)するなど管理に手間がかかります

rpm同様、Oracleが提供するバイナリを利用します
バイナリを配布しているOracle公式サイトにアクセスします
Accept License Agreement にチェックし「jdk-7u55-linux-x64.tar.gz」をダウンロードします
※32bitOSの場合はx86のほうをダウンロードしてください
ダウンロードしたらrpmをインストールするマシンにwinscpなりで転送してください

・インストール方法
tar zvxf jdk-7u55-linux-x64.tar.gz
mv jdk1.7.0_55/ /usr/local/
cd /usr/local/
ln -s jdk1.7.0_55/ java

・JAVA_HOME設定方法
export JAVA_HOME="/usr/local/java"
export PATH=$PATH:$JAVA_HOME/bin

※バイナリインストールの場合、PATH上に java コマンドがないので登録します

以上です
どれが一番いいんだ?という疑問があるかと思いますが正直好みかと思います
あとは環境に依存するかと思われ、マシン自体がグローバルネットワークに出れない場合はyumインストール方式は取れないので
rpmやバイナリ方式になるかと思われます
(厳密にはグローバルに出れなくてもyumインストールする方法もありますが。。。)

個人的には好きなバージョンをインストールできるのでバイナリ方式をよく利用します
また、今回紹介した方法以外にもあるかと思いますので参考程度に見ていただけると助かります

2014年5月27日火曜日

Jenkinsでnohupなジョブを作成する方法

所謂、並列処理をJenkinsで行う場合の設定例です
自分の場合は負荷テスト用のジョブを作成したかったのでそれをケースとして紹介します

また今回はシェルスクリプトを使ったテストを想定して並列テストを実施しました

■単一のジョブによる並列処理の実装
まずは非同期処理を実行することができるシェルスクリプトのジョブの設定から
for j in `seq 1 400`
do
  echo "nohup process ${j}"
  nohup sh sampleMulti.sh &
done

sleep 60;
これは400回ループをしsampleMulti.shをバックグラウンド実行させるジョブです
sampleMulti.shの処理にもよりますが最大で400プロセスが同時にバックグランドで動作します

ポイントは最後に「sleep 60;」を入れている部分

基本的にJenkinsは1つのジョブに対して1つのスレッドが動作します
なので1つのジョブ内でマルチプロセスな処理を実行させることはできないのですが
上記のように強制的にマルチプロセスを立ち上げると裏側では複数のシェルプロセスがちゃんと立ち上がります

なんですが、実はsleepを入れないでしまうとジョブを実行しているメインスレッドがforループを抜けたあとに即終了してしまいます
当たり前ですが、子プロセス(ループ内のシェルプロセス)を生成する親プロセス(ジョブ自信のスレッド)が
終了してしまうといくら実行中の子プロセスが存在していても子プロセスを強制的にkillしてしまいます

なので子プロセスの400のシェルがすべて完了するまで親プロセスのジョブは処理を待つ必要があります
普通マルチスレッドプログラミングをするときには「wait」みたいな関数が用意されており子プロセスの終了を
待ってから親プロセスを終了しますが、今回はその辺の実装を全部スルーして「子プロセスは60秒経てばすべて終了する」
という(良くなく)保証を基にジョブの設定をしています

sleepではなくwaitコマンドを使うことでシェルスクロプトでもマルチスレッドプログラム的なことをできそうなので
ちゃんと実装したい場合には軽く調べれば実装できると思います

■複数のジョブによる並列処理の実装
「sh sampleMulti.sh」を10並列、同時実行するジョブの設定を考えます

単純に「sh sampleMulti.sh」を実行するジョブを10個作成します
10個のジョブを(ほぼ)同時に実行するために「Build Pipeline Plugin」をインストールします

そして同時実行をトリガーにするためのジョブを1つ作成し、そのジョブの「ビルド後の処理の追加」で「他のプロジェクトのビルド」を設定します
設定するジョブは同時並行するジョブ10個を追加します
ジョブはカンマ区切りで指定できます
同一名称のジョブを指定しても1つのジョブとして扱われるので並列実行するジョブ名はすべて別名にしてください

最後に新規ビューで「Build Pipeline View」を作成し、トリガー用として作成したジョブを指定してビューを作成すればOKです
最終的なイメージは以下のようになります





これでトリガー用のジョブをキックすればそのあとで10個のジョブが同時並行されます

ちょっと説明が文字ばかりになってしまいわかりづらい点が多かったかもしれません。。すいません。。
どちらも長所短所がありそうですが、個人的には単一のジョブで実施するほうがいいかなと思います
理由としては単純にジョブの数が少なくて済むからです(後者は並列実行される数だけジョブを作成する必要があるのでダッシュボードがカオスになりそうだからです)

他にもやりかたはあるかと思いますので参考程度に見ていただければ幸いです

2014年5月26日月曜日

redis-sentinel をやってみた

redisでmaster - slave構成を事前に構築しておいてください
構築方法はこちらをご参照ください
サーバのスペックやバージョンは同一環境で実施しております
また、redis-severですでにreplicationが動作していることを前提としております

■設定ファイル準備
・master & slave側作業
cp redis-2.8.9/src/redis-sentinel /usr/local/bin
cp redis-2.8.9/sentinel.conf /etc/
vim /etc/sentinel.conf
sentinel monitor mymaster 10.100.45.30 6379 2
logfile /var/log/sentinel.log
※IPの部分にはmaster側のIPを記載してください
※logfileは追記してください
※とりあえずあとの設定はデフォルトで問題ありません

■redis-sentinel起動
設定ファイルを引数として起動します
起動するのはmasterとslave両方で起動します

nohup redis-sentinel /etc/sentinel.conf &

tailf /var/log/sentinel.log
masterとslaveでそれぞれ起動したsentinel同士が接続したことをログで確認します
[30363] 23 May 14:41:59.831 # +monitor master mymaster 10.100.45.30 6379 quorum 2
[30363] 23 May 14:41:59.831 * +slave slave 10.100.42.181:6379 10.100.42.181 6379 @ mymaster 10.100.45.30 6379
[30363] 23 May 14:42:01.851 * +sentinel sentinel 10.100.42.181:26379 10.100.42.181 26379 @ mymaster 10.100.45.30 6379

■fail over検証
masterをkillしてみます
# pgrep redis-server
30115
# kill 30115

30秒後にmasterが落ちたというログがmaster側のsentinelに出力されます
slave側のログに「[30298] 23 May 14:45:35.169 # +switch-master mymaster 10.100.45.30 6379 10.100.42.181 6379」
と出ていればfail over完了です

slave側の情報を確認してみます

redis-cli
> info replication
# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
slaveがmasterに昇格していると思います
また、元master側はまだダウン状態でslaveとしても参加していないので「connected_slaves:0」となっていることがわかります

■slave側復旧
sentinelを起動している場合、元masterで今度slaveになるサーバはredis-serverのプロセスを起動するだけで勝手にslaveとして登録してくれます

・slave(元master)側作業
nohup redis-server /etc/redis.conf &
redis-cli
> info replication
# Replication
role:slave
master_host:10.100.42.181
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:31972
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

以上でsentinelを使った自動fail overの設定は完了です
fail overはこれでOKなので、あとはダウンしたサーバの処理を忘れないようにしましょう

ポイントはsentinelのプロセスを複数起動させる点かなと思います

■参考サイト

■Tips
redis-cli -p 26379
でsentinelのポートに接続すると「sentinel」という管理コマンドが使えるようになります
sentinel masters とするとsentinelの詳しい設定状況を確認することもできます

2014年5月24日土曜日

redisでmaster-slave構成を組んでみた

■環境
CentOS release 6.3 (Final)
redis 2.8.9

※master用, slave用で2台作成します
※master(192.168.0.1)、slave(192.168.0.2)とします

■redisインストール
yum -y update
yum -y groupinstall "Development Tools"
yum -y install tcl tcl-devel

wget http://www.canonware.com/download/jemalloc/jemalloc-3.6.0.tar.bz2
bzip2 -dc jemalloc-3.6.0.tar.bz2 | tar xvf -
cd jemalloc-3.6.0
./configure
make
make install

wget http://download.redis.io/releases/redis-2.8.9.tar.gz
tar zvxf redis-2.8.9.tar.gz
cd redis-2.8.9/deps
make hiredis lua jemalloc linenoise
cd ../
make
make test
make install

cp redis-2.8.9/redis.conf /etc/

■slave側設定
redisでslaveサーバを登録する場合はslave側から
「私はこのmasterのslaveになります」
というコマンドを発行します

nohup redis-server /etc/redis.conf &
redis-cli
> SLAVEOF 192.168.0.1 6379
> INFO REPLICATION
# Replication
role:slave
master_host:192.168.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:9
master_sync_in_progress:0
slave_repl_offset:267
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
と指定したmasterのスレーブとなっていることを確認します

■master側確認
特にmaster側で作業することはないですが、念のためslaveが登録されているか確認します
nohup redis-server /etc/redis.conf &
redis-cli
> INFO REPLICATION
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.0.2,port=6379,state=online,offset=366,lag=0
master_repl_offset:366
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:365
とslaveが接続されていることを確認します

■動作確認
master側のredisに対してデータを投入してみます
・master側作業
redis-cli
> set key1 value
OK
> keys *
1) "key1"

・slave側確認
redis-cli
> keys *
1) "key1"

slave側にもデータが同期されていることを確認します
また、slave側に書き込みを行おうとすると以下のようなエラーとなります
> set key2 value
(error) READONLY You can't write against a read only slave.
これはslaveがread onlyで起動しているためであり、設定によってはslave側に書き込みを行うことも可能です(今回は紹介しません)

また、今回の場合はコマンドでslave登録したのでslave側を再起動するとまたmasterに戻ってしまいます
起動するためにslaveとして登録するのは大変なので、その場合は設定ファイルにslaveの情報を記載しておくことができます

■手動fail over
masterがダウンしてしまった場合を想定してslaveをmasterに昇格させてみます
masterをkillコマンドでダウンさせてください
この状態でslave側で「INFO REPLICATION」を実行すると master_link_status:down となっていることがわかります

slaveをmasterに昇格させてみます
・slave側作業
redis-cli
> SLAVEOF NO ONE
OK
> INFO REPLICATION
# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

masterに昇格していることがわかります
ダウンした元masterサーバ次回起動時にはmasterではなくslaveとして起動、登録する必要がありますのでご注意ください

単純にredisのmaster <-> slave間でデータを同期させる方法は以上です
次回は redis-sentinel を使った、自動fail over の仕組みを試してみたいと思います

■参考サイト

2014年5月23日金曜日

redisで/var/log/messageにログを出力しないようにする

■環境
CentOS release 5.10 (Final)
redis 2.6.13
(インストールはchefのレシピでインストールしました)

■設定
emacs /etc/redis/6379.conf
syslog-enabled no

/etc/init.d/redis6379 stop
/etc/init.d/redis6379 start

※設定ファイル名と起動スクリプトはインストールした状況によって異なるかもしれません
※裏側はredis-serverコマンドで起動、停止しているだけなので起動スクリプトがない場合は適宜再起動してください

2014年5月22日木曜日

PHPでマルチスレッドプログラミングをやってみた

■環境
CentOS release 5.10 (Final)
PHP 5.3.3

pcntlというモジュールが含まれている必要があります
以下のコマンドでチェックできるので含まれていない場合は「--enable-pcntl」をコンパイルオプションに指定し再度PHPをインストールし直して下さい
php -m | grep pcntl
pcntl

■サンプルコード
touch sampleMulti.php
emacs sampleMulti.php
$pscount = 0;
for ($i = 0; $i < 5; $i++) { 
    $pid = pcntl_fork();
    if ($pid == -1) {
      die('do not fork process');
    } else if ($pid) {
      // for parent process
      echo "parent process $pid \n";
      $pscount++;
    } else {
      // for child process
      echo "child process \n";
      sleep(10);
      echo "child process end \n";
      exit(0);
    }
}

while ($pscount >= 0) {
  pcntl_waitpid( -1, $status, WUNTRACED );
  $pscount--;
}

echo "end of all process \n";

★処理説明
pcntl_fork() を呼び出すと親プロセスに対して子プロセスが作成されます
子プロセスは if 文の else の方に入り 10 秒間待ちます
親プロセスは else if 分の方に入ります
$pscount は fork された子プロセスの数管理をします、子プロセスが作成されるたびに $pscount はインクリメントされていきます

pcntl はメインスレッドとは別で実行される非同期処理です、そのままだと子プロセスの終了を待たずして次の処理にどんどん進んでしまいます
なので、for の後に作成された子プロセスがすべて終了するまで待つロジックを入れてあげる必要があります
これを入れてあげないとプログラムはどんどん先に進んでしまい子プロセスが終了する前に親プロセス(実行したphpプロセス自体)が終了してしまい子プロセスが強制的に停止されてしまいます
なので子プロセス数を管理する $pscount を使って子プロセスの数が 0 になるまで待つようにしてあげています
(このあたりの待つロジックは別のサンプルもたくさんあるので実装しやすい方法で実装するといいと思います)

また、pcntl_waitpid に -1 の引数を渡すことで実行中の親プロセスにぶらさがっているすべての子プロセスの処理が完了するまで親プロセスを待たすことができます

■実行
php sampleMulti.php

実行中に pstree -ap コマンドでプロセスツリーを見てみましょう
php sampleMulti.php のコマンドの子プロセスとして5つのプロセスが存在していることがわかると思います
# pgrep php
30465
30466
30467
30468
30469
30470
# pstree -an 30465
php sampleMulti.php
  php sampleMulti.php
  php sampleMulti.php
  php sampleMulti.php
  php sampleMulti.php
  php sampleMulti.php

今回のプログラムでは約 10 秒経過したあとに「end of all process」と表示されれば子プロセスおよび親プロセスが終了したことになります

■参考サイト

2014年5月20日火曜日

simplexml_load_string(): Entity: line 1: parser error : StartTag: invalid element name

自分の場合ですが原因は以下でした

■利用シーン
system関数を利用してその返り値であるXMLをsimplexml_load_stringを使って解析する
XML自体は必ず正しいものが返ってくるものとする

■原因
system関数を利用していたため

XML内に改行コードが入っていたため

system関数は最後の1行を返すため、XML中に改行コードが入っているとXMLの最終行のみがsystem関数の返り値として返ってくるためうまくパースできなかった

■対処
sysytem関数を利用せずshell_exec関数を使用した
(同様の関数でexec関数という関数ももあるが試したところダメだったため、自分のケースでは最終的にshell_execを利用することで解決した)
また、shell_execで取得したレスポンスのXMLに対してstr_replaceを使い改行コードをすべて空白に置換した
改行コードを置換することでshell_execの返り値にXML全体が含まれるようになった
どうやらsystem関数の返り値に対してはstr_replaceでの置換がうまく動作しないようでそこに嵌った

とりあえず解決したので備忘録として残しておきます
ちなみにPHPのバージョンは5.3.3です

2014年5月18日日曜日

PHPUnitを使ってみた

■環境
CentOS release 5.10 (Final)
PHP 5.3.3
PEAR 1.9.4

■PHPのインストールモジュールの確認
php -m | egrep -ie 'dom|json|pcre|reflection|spl'
dom
json
pcre
Reflection
SPL

となることを確認する
モジュールが含まれていない場合はphpを再コンパイルしてインストールし直す必要があります

■PHPUnitのインストール
cd /var/tmp
wget https://phar.phpunit.de/phpunit.phar

■テストコードの作成
cd /var/tmp
touch unitTest.php
emacs unitTest.php
<?php
class unitTest extends PHPUnit_Framework_TestCase {

    public function testPushAndPop()
    {
        $stack = array();
        $this->assertEquals(0, count($stack));

        array_push($stack, 'foo');
        $this->assertEquals('foo', $stack[count($stack)-1]);
        $this->assertEquals(1, count($stack));

        $this->assertEquals('foo', array_pop($stack));
        $this->assertEquals(0, count($stack));
    }
}
?>

■テストの実行と結果の生成
通常通り実行
php phpunit.phar unitTest unitTest.php
PHPUnit 4.1.0 by Sebastian Bergmann.

.

Time: 5 ms, Memory: 4.50Mb

OK (1 test, 5 assertions)

JUnit形式のXMLファイルを結果として出力
php phpunit.phar --log-junit result.xml unitTest unitTest.php

■参考サイト

■Tips
メソッド名はtestHogehogeという形でtestで始まる必要があります
testで始まらない場合はtest用のメソッドとして認識されません

setUp(), tearDown()が使えます

テストケースはClassとして作成しなければならないのでオブジェクト指向でテスト作成できます

2014年5月17日土曜日

redisからデータを取得する方法

まずは「TYPE」でそのデータのタイプを調べまず
TYPE key

結果から得られたタイプ情報に合わせて取得するコマンドを変更します

・TYPE の結果が「string」だった場合
GET key

・TYPE の結果が「zset」だった場合
ZCARD key・・・長さを確認
ZRANGE key 0 100・・・内容を確認

・TYPE の結果が「set」だった場合
SCARD key・・・長さを確認
SMEMBERS key・・・内容を確認

・TYPE の結果が「hash」だった場合
HLEN key・・・長さを確認
HGETALL key・・・内容を確認

・TYPE の結果が「list」だった場合
LLEN key・・・長さを確認
LRANGE key 0 100・・・内容を確認

以上です
そもそもkeyの一覧がわからんという場合には
keys *
ですべてのkeyを取得することができます

■参考サイト

2014年5月16日金曜日

ListViewでonListItemClickが動作しなくなったときの対処

■環境
Target Android 19
Android SDK Tools 22.6.2

■原因
ListViewの表示にArrayAdapterでのカスタムリストを利用しており
そのカスタムリストのImageButtonが含まれていたから

■対策
以下のどちらかを実施することで対処することができました

1. ImageButtonを利用しない

2. Layout構造を利用し属性に以下を追加する
例えばArrayAdapter用のレイアウトXMLファイル内でLinerLayoutを使っている場合は以下のようにする
<LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:descendantFocusability="blocksDescendants" >

ポイントは「android:descendantFocusability="blocksDescendants"」でこれがあるとListViewの用をクリックできるようになりonListItemClickが呼ばれるようになる

■参考URL

2014年5月15日木曜日

fabricやってみた

■環境
CentOS 5.10
Python 2.6.8
easy_install 0.6.45

easy_installのインストール方法
CentOS5系でのpythonのアップデート方法

■fabricインストール
easy_install fabric

■設定ファイル作成
touch fabfile.py
from fabric.api import run

def current_ls():
  run("ls")

■実行
fab -H 192.168.0.1,host1,host2 current_ls

上記の場合fabコマンドを実行したユーザの「192.168.0.1」でのログインパスワードを聞かれます
「host1」「host2」で同じパスワードを使用している場合は続けて聞かれませんが、パスワードが違う場合は再度パスワードの入力を求められます
[root@fabhost fabric]# fab -H 192.168.0.1,host1,host2 current_ls
[192.168.0.1] Executing task 'current_ls'
[192.168.0.1] run: ls
[192.168.0.1] Login password for 'root':

■設定ファイル内に認証情報を記載する方法
from fabric.api import run, env

def current_ls():
  env.password = 'hogehoge'
  run("ls")

ポイントは「env」をimportするのと「env.password」でパスワードを記載するところ
current_ls を実行した場合はenv.passwordで設定したパスワードでまずSSH認証を試みます
もし、認証できない場合は先ほどのようにパスワードを入力するように促されます

envには他にも鍵情報やユーザを設定することもできます
http://docs.fabfile.org/en/latest/usage/env.html

基本的な動作は以上で完了です
これだけで複数のサーバに同時にSSH実行することができるのでだいぶオペレーションが楽になります

■Tips
sudoをimportしてrunの代わりにsudoとするとrootユーザで実行できるようになります
env.passwordにsudoのパスワードを入力しておけば実行時に省略できます、記載しなかった場合は入力を求められます

「--」を使用すると指定したコマンドをfabfile.pyを書かずとも実行できます、以下のような感じです
fab -H 192.168.0.1 -- ls

2014年5月12日月曜日

PHPからTwitterAPIを使ってフレンドの一覧を確認できるようにしてみた

過去にサンプルを動作させる記事を書きましたがこれを実行した上で以下を実施してください

cd /var/www/html/twitteroauth
git clone https://gist.github.com/262a2bc31d2a04cd5439.git
mv 262a2bc31d2a04cd5439/get_friends_list_and_remover.php .

http://hostname/twitteroauth/get_friends_list_and_remover.php
にアクセスしログインするとログインしたユーザのフレンドが表示されます

■Tips
  • フレンドは50人ずつ表示します
  • APIコールは15分で180回なので15分以内に4回ページャーするとフレンドの情報が取得できません
  • 一応50人はソースコードを修正することで変更可能ですがAPIコールの制限に引っかかるので50以下がベストです


2014年5月11日日曜日

CentOS上でSeleniumのテストを実行できるようにするまで

実行しているテストコードは自作のUIテストなので環境の構築方法を参考にしていただければと思います

■環境
CentOS release 6.3 (Final)
firefox 24.5.0
Java 1.8_20
Maven 3.1.1
tigrevnc 1.1.0-8

■必要なパッケージの準備
yum -y groupinstall "Development Tools"
yum -y install firefox
JDKのインストール
mvnのインストール

■X環境の構築
Xおよびtigervncのインストール

■Seleniumテストコードの取得と実行
git clone https://github.com/kakakikikeke/java-selenium-ui-test.git
cd java-selenium-ui-test
vim src/test/resources/config.properties
mvn clean test-compile test

■Jekins-Tips
Jenkinsから実行させる場合にはジョブの設定時に「export DISPLAY="localhost.localdomain:1"」するのを忘れないようにしてください
またmvnビルドを実行するユーザに対してexportする必要があるのでexportするビルドとmvnコマンドを実行するユーザが同じになるようにビルドを設定してください
例えばSSHログインしてシェルスクリプトを実行等のビルドを使っているとrootでログインしてmvnコマンドは別のユーザなんてことがあるので気をつけてください
自分が設定した感じだと実行ユーザではまる点が多かったのでセキュリティ上問題なければ全部rootで実行しておくと無難です

2014年5月9日金曜日

AWS Opsworksでカスタムcookbooksを設定し実行する方法

■環境
AWS Opsworks
(2014/05/08時点でのUIおよびAPIバージョンを使用)

■設定手順
1. スタックの作成
https://console.aws.amazon.com/opsworks/home?#firstrun
にアクセスします
まだスタックがない場合はダッシュボードにOpsworksの概念図が表示されます
「Add Your First Stack」をクリックしてスタックの情報を入力します


入力項目のポイントとしては
  • Region・・・スタックを作成するリージョンを選択します、ここで選択したリージョン内にインスタンスは作成することができます
  • Hostname theme・・・新しくインスタンスを作成する場合に自動で名前を付与してくれる機能です、設定したテーマに応じたインスタンス名が付与されます
  • Advanced -> Chef version・・・Opsworksのプロビジョニングはchefを使用して行われます、自分が作成したcookbooksが動作するchefのバージョンを入力しましょう
その他は好きな値を適当に入力していきます


あとで作成したスタックに対してカスタムcookbooksの設定を実施します
とりあえずはスタックを作成しましょう

2. カスタムcookbooksの設定
スタックにカスタムcookbooksを設定します
スタックの一覧に戻り先ほど作成したスタックから「Stack Settings」をクリックします


そのまま右上の「edit」をクリックします


一番下の方に「Use custom Chef cookbooks」という欄があるのでトグルをYesにします
するとcookbooksが配置してあるリポジトリを設定する項目が表示されますので入力します


今回はcookbooksはGithubで公開しているので、GithubのURLを記載します
  • Repository type・・・Git
  • Repository URL・・・https://github.com/kakakikikeke/cookbooks-for-automation.git
cloneにSSHを利用する場合は鍵情報を入力します
Branch/Revisionは指定しなければmasterの最新から取得します、特定のブランチやコミット情報を取得したい場合はブランチ名やコミット情報を入力します

今回使用するカスタムcookbooksの細かい説明はしませんが、PHPでmemcachedライブラリを使用するための準備をしています
CustomJsonをここでは設定しません、特定のレイヤーでのみcookbooksを実行させたいのでレイヤーに設定します
CustomJsonの設定方法は後ほど記載します

gitの設定が完了したら「Save」をクリックします

3. PHPレイヤーの作成
スタック内にまだ1つもレイヤーが存在しない場合には右ペインに作成のフローが表示されます
「Add a layer」をクリックしてレイヤーを追加します


今回はPHPレイヤーを追加します
Layer Typeに PHP App Server を選択します
すでにec2上にELBを作成している場合はELBを設定することもできます
レイヤーには特に名称等を指定する部分もないのでタイプを選択したら「Add Layer」をクリックします

4 PHPレイヤー内で実行するレシピの設定
スタックに設定したカスタムcookbooksをPHPレイヤー内で実行させるための設定をします
レイヤーの一覧に戻り先ほど作成したレイヤーから「Recipes」をクリックします


そのまま右上の「edit」をクリックします


レイヤーの設定画面の真ん中あたりに「Custom Chef Recipes」という項目があります
Setupの部分に実行するレシピ名を入力します(今回は「php-memcached-sample」というレシピを実行されるのでphp-memcached-sampleと入力します
入力したら横の「+」ボタンをクリックします
入力が完了したら「Save」します


これでPHPレイヤー内で実行するカスタムcookbooksの準備が整いました

5. インスタンスの作成
インスタンスを作成して実際にカスタムcookbooks内のレシピが実行されるか確認しましょう
レイヤーの一覧に戻り「Add Instance」をクリックします

作成するインスタンスの設定をします
スタック等に設定されているデフォルトの情報を引っ張ってくるので特に設定する必要はありませんが
インスタンス個別に設定を変更したい場合はここで変更します
OSやSSHの鍵情報、インスタンスのタイプを変更することができます
入力が完了したら「Add Instance」をクリックします


Opsworksではこれだけではインスタンスが作成されません
左メニューの「Instances」をクリックしインスタンスの一覧を表示します
インスタンスの一覧の右側に「start」とあるのでこれをクリックするとインスタンスが作成されます
Opsworksはこの段階で初めて課金されます


あとはインスタンスが作成されるまで待ちます
設定したカスタムcookbooksもこの段階で自動で実行されることになります
インスタンスのステータスがbootingからonlineになればインスタンスの作成が完了となります

6. 動作確認
サーバ内にログインしてカスタムcookbooksが実行されているか確認します
今回のカスタムcookbooksはpeclでmemcahcedのライブラリがインストールされていればOKなので
「pecl list」のコマンドの結果でmemcahcedがインストールされていることを確認してください

またサーバにログインしなくともchefの実行ログを確認することができます
インスタンスの詳細画面に「Logs」という項目があるのでそこからログを閲覧できるURLをクリックするとブラウザ上でchefのログを確認することができます
ここでcookbooksが正常に動作しているか確認することもできます

■Tips
今回サンプルとして利用しているcookbooksはCentOS用に作成したcookbooksなのでOSは Amazon Linux でしか動作しません

Githubにあるカスタムcookbooksの階層は、cookbooksリポジトリ -> cookbooks名 -> recipesという階層でないといけません
リポジトリの直下にrecipesディレクトリ等がある場合はもう1つリポジトリを作成してそのリポジトリのサブモジュールとして登録してあげると使えるようになります
Opsworksはサブモジュールも動作します

今回はsetupというところでカスタムcookbooks内のレシピを実行しましたが、setupじゃなくても問題ないです
Opsworksにはライフサイクルという概念があり、好きなライフサイクルでカスタムcookbooksを実行することが可能です