2010年3月26日金曜日

CentOSでTrac

スズキです。

こちらも自分メモです...

まずはパッケージのインストールです。

# yum install trac
# yum install mod_python

次にプロジェクトのディレクトリ作成です。
今回はデフォルトのSQLiteを利用するようにしており、
その場合は、"/var/www/trac/suz_lab/db"以下のオーナーとグループを、
"apache"にしておく必要があります。

# mkdir /var/www/trac
# trac-admin /var/www/trac/suz_lab initenv
# chown apache.apache -R /var/www/trac/suz_lab/db

最後に、設定ファイル(/etc/httpd/conf.d/trac.conf)です。
"PythonOption TracEnvParentDir"を上記にしています。

--------【trac.conf】--------
...
<Location /trac>
  SetHandler mod_python
  PythonInterpreter main_interpreter
  PythonHandler trac.web.modpython_frontend
  PythonOption TracEnvParentDir /var/www/trac
  PythonOption TracUriRoot /trac
</Location>
...
--------

これで、Apacheを再起動したら、

http://trac.suz-lab.com/trac/suz_lab/

で確認することができます。

ブログのペースが落ちてるなー。

--------
http://www.suz-lab.com

CentOSでSubversion

スズキです。

よくあるネタですが...

まずは必要パッケージのインストールです。

# yum install subversion
# yum install mod_dav_svn

次に、リポジトリの作成です。
Apache経由でアクセスするためオーナー/グループを
"apache"にしておくことがポイントになります。

# mkdir /var/www/svn
# cd /var/www/svn
# mkdir suz_lab
# svnadmin create suz_lab
# chown -R apache.apache suz_lab

そして、ベーシック認証に利用するファイルを作成します。

# htpasswd -c svn.passwd suz_lab

最後に、httpd.conf(/etc/httpd/conf.d/subversion.conf)の記述です。

--------【subversion.conf】--------
LoadModule dav_svn_module modules/mod_dav_svn.so
LoadModule authz_svn_module modules/mod_authz_svn.so
<Location /svn>
  DAV svn
  SVNParentPath /var/www/svn
  AuthType Basic
  AuthName "Authorization Realm"
  AuthUserFile /etc/httpd/conf/svn.passwd
  Require valid-user
</Location>
--------

これで、Apacheを再起動して、
http://svn.suz-lab.com/svn/suz_lab/
にアクセスすると、認証情報が要求され、入力すると、リポジトリの中身が確認できます。

自分メモです...

--------
http://www.suz-lab.com

2010年3月24日水曜日

yumでインストールしたパッケージとまったく同じものを他のマシンにもインストールする方法

スズキです。

こんな感じでできます。

まずは、yumコマンドでインストール済みパッケージのリストを取得します。

# yum list installed | awk '{print $1}' > packages.txt

# cat packages.txt
--------
Loaded
Installed
Deployment_Guide-ja-JP.noarch
GConf2.i386
ImageMagick2.i386
...
--------

ここで上記の最初の二行を削除します。

# cat packages.txt
--------
Deployment_Guide-ja-JP.noarch
GConf2.i386
ImageMagick2.i386
...
--------

そして、このリストを他のマシンに持っていき、下記コマンドを実行します。

# cat packages.txt | xargs yum install -y

これで、まったく同じrpmがインストール(yum経由)されたマシンが出来上がります。

こういう技、増やしていきたいなー...

--------
http://www.suz-lab.com

2010年3月23日火曜日

yumリポジトリ(CentOS)いろいろ

スズキです。

以下は、僕がCentOS環境もらったら、すぐに追加するyumリポジトリです。

▼ remi

# rpm -Uvh http://rpms.famillecollet.com/el5.i386/remi-release-5-7.el5.remi.noarch.rpm

# vi /etc/yum.repos.d/remi.repo
--------
[remi]
...
enabled=1
...
--------

▼ epel

# rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-3.noarch.rpm

# vi /etc/yum.repos.d/epel.repo
--------
[epel]
...
enabled=1
...
--------

▼ rpmforge

# rpm -Uvh http://dag.wieers.com/rpm/packages/rpmforge-release/rpmforge-release-0.3.6-1.el5.rf.i386.rpm

と思ったら、こんなエラーがでたので...
error: skipping ... - transfer failed - Unknown or unexpected error
warning: u 0x8190448 ctrl 0x8190b50 nrefs != 0 (dag.wieers.com http)

一回ダウンロードしてからです...

# curl -OL http://dag.wieers.com/rpm/packages/rpmforge-release/rpmforge-release-0.3.6-1.el5.rf.i386.rpm

# rpm -Uvh rpmforge-release-0.3.6-1.el5.rf.i386.rpm

▼ suzlab

# rpm -Uvh http://yum.suz-lab.com/5/i386/suzlab-release-5-1.noarch.rpm

最後は、自作自演です...

--------
http://www.suz-lab.com

2010年3月22日月曜日

カスタマイズしたUITableVIewCellの高さを指定

スズキです。

UITableVIewCellのカスタマイズに関しては、下記に詳しく紹介されています。

▼ Interface Builderを使ってカスタマイズしたUITableViewCellを作る方法
http://d.hatena.ne.jp/KishikawaKatsumi/20081024/1224857278

▼ Interface BuilderでカスタムUITableVIewCellを作るときの注意点
http://d.hatena.ne.jp/KishikawaKatsumi/20081027/1225114665

▼ Table View セルのカスタマイズ
http://cocoatouch.sblo.jp/article/25372371.html

しかし、"Interface Builder"で、セルの高さを変更しても、
それだけでは、実際にアプリに組み込んで表示してみると、
デフォルトの高さになってしまい、切れたりしてしまいます。

高さを合わせたい場合は、下記のように、
UITableViewControllerのメソッドをオーバーライドします。
(ここでは、80ピクセルにしています)

--------【XxxTableViewController】--------
...
- (CGFloat)tableView:(UITableView *)tableView
    heightForRowAtIndexPath:(NSIndexPath *)indexPath {
  return 80.0;
}
...
--------

これで、アプリに組み込んで表示しても、ぴったりの高さで表示させることができます。

iPhoneの記事は書きにくいなー…

--------
http://www.suz-lab.com

UITabBarControllerを横画面に固定

スズキです。

横画面に固定する方法は下記に詳しく紹介されています。
http://iphone0app.blog45.fc2.com/blog-entry-8.html

で、UITabBarControllerも基本的には同じなんですが、
注意点として、タブで表示するすべてのUIViewControllerに対して、
下記メソッドをオーバーライドする必要があります。
(一つでもオーバーライド指定ないと縦画面になってしまいます)

--------【XxxViewController.m】--------
...
- (BOOL)shouldAutorotateToInterfaceOrientation:
    (UIInterfaceOrientation)interfaceOrientation {
  return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
...
--------

結構、ハマってしまいました…

--------
http://www.suz-lab.com

iPhoneアプリ起動画面(Default.png)を起動後も少し表示させる

スズキです。

iPhoneアプリ起動時の画像(スプラッシュ画像)は、
ResourcesフォルダのDefault.png(320x480)となります。

この画像を起動時だけでなく、起動後も少しの間、表示したいと思い、
以下で紹介したNSTimerを利用してみました。
http://blog.suz-lab.com/2010/03/nstimeruiimageviewiphone.html

--------【XxxAppDelegate.m】--------
@synthesize window;
@synthesize tabBarController;

UIImageView *splashImageView;

- (void)applicationDidFinishLaunching:(UIApplication *)application {
  UIImage *splashImage = [UIImage imageNamed: @"Default.png"];
  splashImageView = [[UIImageView alloc] initWithImage:splashImage];
  [window addSubview:splashImageView];
  [NSTimer
    scheduledTimerWithTimeInterval:3.0
    target:self
    selector:@selector(onTimer:)
    userInfo:nil
    repeats:NO
  ];
}

- (void)dealloc {
  [splashImageView release];
  [tabBarController release];
  [window release];
  [super dealloc];
}

- (void)onTimer:(NSTimer *)timer {
  tabBarController.selectedIndex = 1;
  [window addSubview:tabBarController.view];
  [splashImageView removeFromSuperview];
  [splashImageView release];
}
--------

"applicationDidFinishLaunching"にて先ずはDefault.pngを表示して、
[window addSubview:splashImageView];
何秒か時間がたったら、メインのビューを表示しています。
[window addSubview:tabBarController.view];

もっと、いい方法があるような気がする…

--------
http://www.suz-lab.com

2010年3月18日木曜日

WorkerManagerの並行性(concurrency)

スズキです。

WorkerManagerで同時に実行できる処理の数は、下記のように"-c"オプションで指定できます。

# workermanager.pl -h
--------
...
-c : the number of concurrency (default 4).
...
--------

"/etc/init.d/workermanager"で起動する場合は、
"/etc/sysconfig/workermanager"のCONCURRENCYの値でしていできます。

# cat /etc/sysconfig/workermanager
--------
CONCURRENCY=4
WORKS_PER_CHILD=100
PROG=/usr/bin/workermanager.pl
PIDFILE=/var/run/workermanager.pid
CONF=/etc/worker.conf.yml
--------

挙動を確認するため、以下のようなコードが入ったWorkerを、
CONCURRENCYが4の場合と1の場合で、クライアントから4回連続実行してみます。

--------【Perl】--------
...
$log->debug("start - $id");
sleep(5);
$log->debug("stop - $id");
...
--------

【CONCURRENCY=4】

# cat /var/log/workermanager_error.log
--------
...
start - B
start - A
stop - B
start - D
stop - A
start - C
stop - D
stop - C
...
--------

同時に平行に実行されていることがわかります。
ちなみに"ps"の結果は下記となります。

# ps aux | grep workermanager.pl
--------
root 20450 ... perl /usr/bin/workermanager.pl -c 4 -w 100 -f
/etc/worker.conf.yml
root 20451 ... perl /usr/bin/workermanager.pl -c 4 -w 100 -f
/etc/worker.conf.yml
root 20452 ... perl /usr/bin/workermanager.pl -c 4 -w 100 -f
/etc/worker.conf.yml
root 20453 ... perl /usr/bin/workermanager.pl -c 4 -w 100 -f
/etc/worker.conf.yml
root 20454 ... perl /usr/bin/workermanager.pl -c 4 -w 100 -f
/etc/worker.conf.yml
...
--------

【CONCURRENCY=1】

# cat /var/log/workermanager_error.log
--------
...
start - A
stop - A
start - B
stop - B
start - D
stop - D
start - C
stop - C
...
--------

前の処理が終わってから、次の処理が実行されていることがわかります。
ちなみに"ps"の結果は下記となります。

# ps aux | grep workermanager.pl
--------
root 20468 ... perl /usr/bin/workermanager.pl -c 1 -w 100 -f
/etc/worker.conf.yml
root 20469 ... perl /usr/bin/workermanager.pl -c 1 -w 100 -f
/etc/worker.conf.yml
...
--------

ということで、今回は諸事情で"CONCURRENCY=1"です...

--------
http://www.suz-lab.com

Google Chrome Portable 4.1.249.1036 リリース

スズキです。

こちらでアナウンスされています。
http://portableapps.com/news/2010-03-17_-_google_chrome_portable_4.1.249.1036

早速アップデートですが、プラグインの入れなおしです...

なんかいい方法ないかなー?

--------
http://www.suz-lab.com

MySQLのログいろいろ

スズキです。

下記のように設定すると、エラーログが"/var/log/mysqld.log"に、
一般クエリログが"/var/lib/mysql/general.log"、そして、スロー クエリログが
"/var/lib/mysql/slow_query.log"に出力されるようになります。

--------【my.cnf】--------
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
symbolic-links=0
server-id=<%= ipaddress.split(".")[3] %>
log-bin=<%= hostname %>-bin
log-output=TABLE,FILE
general_log=1
general_log_file=general.log
slow_query_log=1
slow_query_log_file=slow_query.log
long_query_time=0

[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
--------

【エラーログ】
mysqldの挙動に関するログです。
--------
100317 23:45:49 [Note] Event Scheduler: Purging the queue. 0 events
100317 23:45:49 [Note] Error reading relay log event: slave SQL thread
was killed
100317 23:45:51 InnoDB: Starting shutdown...
100317 23:45:57 InnoDB: Shutdown completed; log sequence number 0 44233
100317 23:45:57 [Note] /usr/libexec/mysqld: Shutdown complete
--------

【一般クエリログ】
クエリ全般のログです。"general_log=1"で有効にし、
"general_log_file"で出力先を指定します。
--------
100318 0:08:19
194 Connect mon@suz-lab-master-2 on
194 Query set autocommit=1
194 Query SELECT NOW()
194 Quit
--------

【スロークエリログ】
実行時間の遅いクエリに関するログです。"slow_query_log=1"で有効にし、
"slow_query_log_file"で出力先を指定します。
--------
# User@Host: mon[mon] @ suz-lab-master-2 [192.168.11.12]
# Query_time: 0.000143 Lock_time: 0.000000 Rows_sent: 0 Rows_examined: 0
SET timestamp=1268838704;
SHOW SLAVE STATUS;
--------
また、"long_query_time"で出力するログの実行時間の閾値を指定できますが、
上記のように0を指定すると、すべてのクエリが出力されます。

最後に"log-output=TABLE,FILE"に関してですが、
これはログをファイルとテーブルに出力するといった設定です。

ファイルへの出力は、上述した内容なんですが、テーブルへの出力に関しては、
一般クエリログは、mysql.general_logテーブルに、スロークエリログは、
mysql.slow_logテーブルに書きこまれるようになってます。

ログローテートもしなきゃ...

--------
http://www.suz-lab.com

2010年3月17日水曜日

Puppetのコマンドのヘルプを見るにはRDocが必要

スズキです。

RDocがインストールされてないと、"puppetca -h"などとしても、ヘルプが表示されません...

ということで、以下のように、"yum"でインストールです。

# yum install ruby-rdoc

すると、今度は無事ヘルプが表示されるようになります。

Puppet、苦戦したなー...

--------
http://www.suz-lab.com

Puppetでテンプレートを使ってみた

スズキです。

近頃、Linuxの設定ファイルをPuppetで管理するようになってきたのですが、
マシンごとに設定ファイルを用意するのは面倒なので、
テンプレート機能を使ってみることにしました。

テンプレート自体は、ERBで記述でき、レプリケーション前提の
MySQLの設定ファイル(my.cnf)などは、下記のように記述することができます。

--------【my.cnf】--------
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
symbolic-links=0
server-id=<%= ipaddress.split(".")[3] %>
log-bin=<%= hostname %>-bin
log-output=TABLE,FILE
general_log=1
general_log_file=global.log

[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
--------

"server-id"は該当マシンのIPアドレスの最後の数字を利用することにし、
"log-bin"はホスト名を利用するようにしています。

利用できるマシン環境に関する変数は、下記のように"facter"で取得できるものとなります。

# facter
--------
hostname => suz-lab-master-2
ipaddress => 192.168.11.12
...
--------

このテンプレートを利用するには、マニフェスト内で下記のよう
"content => template(テンプレート名)"を使って記述します。

--------【site.pp】--------
file { '/etc/my.cnf':
  owner => 'root',
  group => 'root',
  mode => 644,
  content => template('/var/lib/puppet/files/etc/my.cnf'),
}
--------

その前に、Puppetの設定&起動も記事にしないと...

--------
http://www.suz-lab.com

EBSのスナップショット作成スクリプト(世代管理機能付)

スズキです。

以下のようなスクリプトを作ってみました。

--------【backup_ebs.sh】--------
#!/bin/sh

# 設定の読み込み
AWS_CONF=/opt/suz-lab/etc/aws.conf
. /opt/suz-lab/bin/common/load_conf.sh $AWS_CONF

# オプションの処理
while getopts n:a:s:v: opt
do
  case ${opt} in
    n) AWS_ACCOUNT_NUMBER=${OPTARG};;
    a) AWS_ACCESS_KEY=${OPTARG};;
    s) AWS_SECRET_KEY=${OPTARG};;
    v) EBS_VOLUME=${OPTARG};;
    g) EBS_GENERATION=${OPTARG};;
    \?) exit 1;;
  esac
done

# スナップショットの作成
ec2-create-snapshot \
-K $AWS_PRIVATE_KEY \
-C $AWS_CERTIFICATE \
--region $AWS_REGION \
$EBS_VOLUME

# 対象EBSのスナップショットリストを取得
SNAPSHOTS=`ec2-describe-snapshots \
-K $AWS_PRIVATE_KEY \
-C $AWS_CERTIFICATE \
--region $AWS_REGION \
| grep $EBS_VOLUME | sort -k5 -r | awk '{print $2}'`

# 世代数の管理
COUNT=1
for SNAPSHOT in $SNAPSHOTS; do
  if [ $COUNT -le $EBS_GENERATION ]; then
    # 最新順で世代数内なら残す
    echo $SNAPSHOT "remained"
  else
    # 最新順で世代数外なら削除
    ec2-delete-snapshot \
    -K $AWS_PRIVATE_KEY \
    -C $AWS_CERTIFICATE \
    --region $AWS_REGION \
    $SNAPSHOT
    echo $SNAPSHOT " deleted"
  fi
  COUNT=`expr $COUNT + 1`
done
--------

ポイントは、"ec2-describe-snapshots"で全リストを取得して、
"grep"で該当EBSの行のみにして、"sort"で作成日の降順で並べ替えて...
といったところでしょうか?

上記スクリプトで最初に読み込んでいる設定ファイルは、次の通りです。

--------【aws.conf】--------
AWS_PRIVATE_KEY=/opt/suz-lab/etc/pk.pem
AWS_CERTIFICATE=/opt/suz-lab/etc/cert.pem
AWS_REGION=us-west-1

EBS_VOLUME=vol-00000000
EBS_GENERATION=7

export EC2_HOME=/opt/ec2-api-tools
export JAVA_HOME=/usr/java/default

export PATH=/sbin:/bin
export PATH=$PATH:/usr/sbin:/usr/bin
export PATH=$PATH:/usr/local/sbin:/usr/local/bin
export PATH=$PATH:$EC2_HOME/bin
--------

以下は、上記スクリプトで利用している設定ファイルの読み込みスクリプトです。

--------【load_conf.sh】--------
#bin/sh

if [ -f $1 ]; then
  $1
else
  echo "can't find $1"
  exit 1
fi
--------

RPM化して、SUZ-LABリポジトリに置きたいなー...

--------
http://www.suz-lab.com

"yum"で"cron"のインストール(CentOS)

スズキです。

「SUZ-LAB 謹製 CenOS AMI」など
http://blog.suz-lab.com/2010/02/suz-lab-centos-ami-545_22.html
CentOSを最小構成でインストールすると、"cron"はインストールされません...

ですので、改めて"yum"でインストールするのですが、下記のように、
"cron"ではなく、"vixie-cron"というパッケージでインストールします。

# yum install vixie-cron

そろそろ、最小構成以外のAMIも作ろうかなー?

--------
http://www.suz-lab.com

2010年3月16日火曜日

Heartbeatで"mysql-mmm-monitor"

スズキです。

下記で起動している"mysql-mmm-monitor"を、
http://blog.suz-lab.com/2010/03/centos-multi-master-replication-manager.html
HAにしたかったので、Heartbeatで管理、起動するようにしてみました。

といっても、LSBスクリプト(/etc/init.d/mysql-mmm-monitor)が用意されているので、
http://blog.suz-lab.com/2010/02/lsb.html
下記のように、"haresources"を作成し、"haresources2cib.py"で変換して、...
といったいつもの方法でOKです。

--------【haresources-for-cib】--------
mysql-1 mysql-mmm-monitor IPaddr2::192.168.11.10/24/eth0
--------

MySQLのHAネタは、これが最終形かなー...

--------
http://www.suz-lab.com

CentOS で「Multi-Master Replication Manager for MySQL」(設定&起動編)

スズキです。

インストールの次は設定です。
http://blog.suz-lab.com/2010/03/centosmulti-master-replication-manager.html

今回は、2台の MySQLがインストールされたマシンを用意し、
以下のようにIPアドレスをふるようにします。

mysql-1: 192.168.11.11 (実マシンとして)
mysql-2: 192.168.11.12 (実マシンとして)
writer-0: 192.168.11.20 (マスタへの仮想IPアドレス)
reader-1: 192.168.11.21 (読み取り専用の仮想IPアドレス)
reader-2: 192.168.11.22 (読み取り専用の仮想IPアドレス)

ということで、マシンが二つとも正常な場合は、
例えば、各マシンに下記のようにIPアドレスがふられます。

MySQL1: 192.168.11.11 192.168.11.21 192.168.11.21
MySQL2: 192.168.11.12 192.168.11.22

そして、MySQL1が故障した場合は、仮想IPアドレスが下記のようにふりなおされます。

MySQL2: 192.168.11.12 192.168.11.22 192.168.11.21 192.168.11.21

ですので、writer-0, reader-1, reader-2、に対してアクセスしていれば、
どちらかのマシンが故障しても、自動でフェイルオーバーされることになります。

早速、設定に関してですが、MMMでは以下の二つのサービスプログラムを起動します。

【/etc/init.d/mysql-mmm-monitor】
稼動してるMySQLを監視するプログラムです。適当なマシンで一つ動作しておればよく、
故障を検知したときの、ファイルオーバーの決定なども行います。

【/etc/init.d/mysql-mmm-agent】
こちらは、MySQLがインストールされているマシン、一台一台で動作させる必要があります。
おそらく、"monitor"からの指示(フェイルオーバーなど)を実際に実行する
プログラムだと思います。

ですので、MySQLでは、上記二つのプログラムが利用するユーザーを、
下記のように作成する必要があります。("monitor"は"mysql-1"で起動しています)

【MySQL1】

GRANT REPLICATION CLIENT ON *.*
TO 'mon'@'mysql-1' IDENTIFIED BY 'mon!23';

GRANT SUPER, REPLICATION CLIENT, PROCESS ON *.*
TO 'agent'@'mysql-1' IDENTIFIED BY 'agent!23';

【MySQL2】

GRANT REPLICATION CLIENT ON *.*
TO 'mon'@'mysql-1' IDENTIFIED BY 'mon!23';

GRANT SUPER, REPLICATION CLIENT, PROCESS ON *.*
TO 'agent'@'mysql-2' IDENTIFIED BY 'agent!23';

ユーザーができたら、今度は設定ファイルの調整です。

まずは、共通設定ファイル(/etc/mysql-mmm/mmm_common.conf)です。
上記の仕込を設定ファイルに反映した感じになっているので、
直感的にわかるのでは、と思っています。

--------【mmm_common.conf 】--------
active_master_role writer

<host default>
  cluster_interface eth0
  pid_path /var/run/mysql-mmm/mmmd_agent.pid
  bin_path /usr/libexec/mysql-mmm/
  replication_user repl
  replication_password repl!23
  agent_user agent
  agent_password agent!23
</host>

<host mysql-1>
  ip 192.168.11.11
  mode master
  peer mysql-2
</host>

<host mysql-2>
  ip 192.168.11.12
  mode master
  peer mysql-1
</host>

<role writer>
  hosts mysql-1, mysql-2
  ips 192.168.11.20
  mode exclusive
</role>

<role reader>
  hosts mysql-1, mysql-2
  ips 192.168.11.21, 192.168.11.22
  mode balanced
</role>
--------

次に、"monitor"の設定ファイル(/etc/mysql-mmm/mmm_mon.conf))です。
といっても雛形に対して、上記で設定(定義)した、IPアドレスと
MySQLのユーザー/パスワードを書き込むだけですが...

--------【mmm_mon.conf】--------
include mmm_common.conf

<monitor>
ip 127.0.0.1
pid_path /var/run/mysql-mmm/mmmd_mon.pid
bin_path /usr/libexec/mysql-mmm
status_path /var/lib/mysql-mmm/mmmd_mon.status
ping_ips 192.168.11.1, 192.168.11.11, 192.168.11.12
auto_set_online 60
</monitor>

<host default>
monitor_user mon
monitor_password mon!23
</host>

debug 0
--------
※ "ping_ips"の"192.168.11.1"はデフォルトゲートウェイもチェックするってことです。

最後に、"agent"の設定ファイル(/etc/mysql-mmm/mmm_agent.conf)です。
"this"に対して、自分"mysql-1"を定義しています。
(当然、"mysql-2"上での設定なら、"mysql-2"を定義します)

--------【mmm_agent.conf】--------
include mmm_common.conf

this mysql-1
--------

※ 上記設定の詳しい内容は下記より参照できます。
http://mysql-mmm.org/mmm2:guide#configure_mmm

ここまで設定できたら、以下のようにサービスを起動します。

【mysql-1】
# /etc/init.d/mysql-mmm-agent start
# /etc/init.d/mysql-mmm-monitor start

【mysql-2】
# /etc/init.d/mysql-mmm-agent start

少し時間がたってから、"mysql-1"で下記コマンドを実行すると、
当初の想定どおり、IPアドレスが割り振られていることがわかります。

# mmm_control show
mysql-1(192.168.11.11) master/ONLINE. Roles: reader(192.168.11.22),
writer(192.168.11.20)
mysql-2(192.168.11.12) master/ONLINE. Roles: reader(192.168.11.21)

そして、"mysql-1"のMySQLを停止して、再度、同様のコマンドを実行すると、
下記のように、フェールオーバーされることも確認できます。

# /etc/init.d/mysqld stop
# mmm_control show
mysql-1(192.168.11.11) master/HARD_OFFLINE. Roles:
mysql-2(192.168.11.12) master/ONLINE. Roles: reader(192.168.11.21),
reader(192.168.11.22), writer(192.168.11.20)

"mmm_mon_CLUSTER.conf"って何だろう?("monitor"もクラスタにできる?)

--------
http://www.suz-lab.com

WorkerManagerが起動しなくなったら?

スズキです。

"/etc/init.d/workermanager start"で起動できず、
エラーメッセージがログにも記録されて無い場合は、
作成したワーカーモジュール(Xxx.pm)が文法エラーになっている可能性があります。

そのような場合は、WorkerManagerをデーモン化せず、
デバッグモードで起動すると発見できます。

# workermanager.pl -d -n -f /etc/worker.conf.yml
syntax error at /var/lib/workermanager/lib/Suzlab/Sample/Module.pm
line 63, near "$sweep_dir("
...

下記の通り、"-n"はデーモンかしないで起動、"-d"はデバッグモードのオプションです。

# workermanager.pl -h
usage: /usr/bin/workermanager.pl [-hdn] [-c concurrency] [-w
works_per_child] -f conf_file
-h : this (help) message
-d : debug
-n : prevent deamonize (non fork)
-c : the number of concurrency (default 4).
-w : the number of works per child process (default 100).
-f : YAML-formated file of configuration

Perlにも慣れてきたなー...

--------
http://www.suz-lab.com

2010年3月15日月曜日

MySQLでマルチマスタレプリケーション

スズキです。

二つのサーバのどちらを更新しても、そのどちらにも反映される、
MySQLのマルチマスタレプリケーションを試してみました。

ただ、マルチマスタといっても、お互いがレプリケーションしあうことで
実現しているので、当然、反映までの遅延はあり、
両サーバを同時に更新する場合は、そのあたりを考慮しなければいけません。
(AUTO_INCREMENTとかはヤバイと思います)

ということなので、結局は、どちらか一方にアクセスして、それが故障したら、
もう一方にアクセスするって用途(HA)になるんじゃないか?と思ってます。

やり方は簡単で、下記で紹介しているレプリケーションの設定を、
サーバを役割を逆にした状態でも設定するといった感じになります。
http://blog.suz-lab.com/2009/07/mysql.html

つまり、両方のサーバで、"log-bin"をとり、また、両方のサーバで、
お互いをマスタにして、"slave start"するってことになります。

実際に、一方のサーバで、以下のようなテーブルを作成するSQLを実行すると、
もう一方のサーバにも同じテーブルが作成されていることが確認でき、

--------【SQL】--------
CREATE TABLE hoge_sample (
  sample_id INTEGER NOT NULL AUTO_INCREMENT,
  sample_name VARCHAR(255) NOT NULL,
  sample_height DOUBLE NOT NULL,
  PRIMARY KEY (sample_id)
);
--------

もう一方のサーバで、以下のようなデータを挿入するSQLを実行すると、
反対のサーバにも、同じデータが挿入されていることが確認できます。

--------【SQL】--------
INSERT INTO hoge_sample (
  sample_name,
  sample_height
) VALUES (
  'suz-lab',
  165.0
);
--------

これで、MMMがすすめられる。
http://blog.suz-lab.com/2010/03/centosmulti-master-replication-manager.html

--------
http://www.suz-lab.com

CentOSで「Multi-Master Replication Manager for MySQL」(インストール編)

スズキです。

「Multi-Master Replication Manager for MySQL」とは、下記のようなソフトウェアです。

> MMM (Multi-Master Replication Manager for MySQL) is a set of flexible scripts
> to perform monitoring/failover and management of MySQL master-master
> replication configurations

MMMとは、MySQLのマルチマスタレプリケーションに関するモニタリングやフェイルオーバー、
そして、その管理などを行う柔軟なスクリプト群です。
http://mysql-mmm.org/

幸いなことに、CentOSにも以下のようにepelのリポジトリにありました。

# yum search mysql-mmm
--------
mysql-mmm.noarch : Multi-Master Replication Manager for MySQL
mysql-mmm-agent.noarch : MMM Database Server Agent Daemon and Libraries
mysql-mmm-monitor.noarch : MMM Monitor Server Daemon and Libraries
mysql-mmm-tools.noarch : MMM Control Scripts and Libraries
--------

ということで、上記の四つのパッケージをインストールです。
(どんなファイルがインストールされたかも確認しています)

# yum install mysql-mmm
# rpm -ql mysql-mmm
--------
/etc/logrotate.d/mysql-mmm
/etc/mysql-mmm
/etc/mysql-mmm/mmm_common.conf
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Common
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Common/Angel.pm
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Common/Config.pm
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Common/Log.pm
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Common/PidFile.pm
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Common/Role.pm
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Common/Socket.pm
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Common/Uptime.pm
/usr/share/doc/mysql-mmm-2.0.10
/usr/share/doc/mysql-mmm-2.0.10/COPYING
/usr/share/doc/mysql-mmm-2.0.10/INSTALL
/usr/share/doc/mysql-mmm-2.0.10/README
/usr/share/doc/mysql-mmm-2.0.10/VERSION
/usr/share/doc/mysql-mmm-2.0.10/mysql-mmm-2.0.10-1.pdf
/var/lib/mysql-mmm
/var/log/mysql-mmm
/var/run/mysql-mmm
--------

# yum install mysql-mmm-agent
# rpm -ql mysql-mmm-agent
--------
/etc/init.d/mysql-mmm-agent
/etc/mysql-mmm/mmm_agent.conf
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Agent
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Agent/Agent.pm
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Agent/Helpers
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Agent/Helpers.pm
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Agent/Helpers/Actions.pm
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Agent/Helpers/Network.pm
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Agent/Role.pm
/usr/libexec/mysql-mmm/agent
/usr/libexec/mysql-mmm/agent/check_ip
/usr/libexec/mysql-mmm/agent/clear_ip
/usr/libexec/mysql-mmm/agent/configure_ip
/usr/libexec/mysql-mmm/agent/mysql_allow_write
/usr/libexec/mysql-mmm/agent/mysql_deny_write
/usr/libexec/mysql-mmm/agent/mysql_may_write
/usr/libexec/mysql-mmm/agent/set_active_master
/usr/libexec/mysql-mmm/agent/sync_with_master
/usr/libexec/mysql-mmm/agent/turn_off_slave
/usr/libexec/mysql-mmm/agent/turn_on_slave
/usr/sbin/mmmd_agent
/usr/share/doc/mysql-mmm-agent-2.0.10
/usr/share/doc/mysql-mmm-agent-2.0.10/README
--------

# yum install mysql-mmm-monitor
# rpm -ql mysql-mmm-monitor
--------
/etc/init.d/mysql-mmm-monitor
/etc/mysql-mmm/mmm_mon.conf
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Monitor
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Monitor/Agent.pm
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Monitor/Agents.pm
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Monitor/CheckResult.pm
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Monitor/Checker
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Monitor/Checker.pm
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Monitor/Checker/Checks.pm
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Monitor/ChecksStatus.pm
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Monitor/Commands.pm
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Monitor/Monitor.pm
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Monitor/NetworkChecker.pm
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Monitor/Role.pm
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Monitor/Roles.pm
/usr/libexec/mysql-mmm/monitor
/usr/libexec/mysql-mmm/monitor/checker
/usr/sbin/mmm_control
/usr/sbin/mmmd_mon
/usr/share/doc/mysql-mmm-monitor-2.0.10
/usr/share/doc/mysql-mmm-monitor-2.0.10/README
--------

# yum install mysql-mmm-tools
# rpm -ql mysql-mmm-tools
--------
/etc/mysql-mmm/mmm_tools.conf
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Tools
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Tools/MySQL.pm
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Tools/Snapshot
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Tools/Snapshot/LVM.pm
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Tools/Snapshot/MySQL.pm
/usr/lib/perl5/vendor_perl/5.8.8/MMM/Tools/Tools.pm
/usr/libexec/mysql-mmm/tools
/usr/libexec/mysql-mmm/tools/create_snapshot
/usr/libexec/mysql-mmm/tools/remove_snapshot
/usr/sbin/mmm_backup
/usr/sbin/mmm_clone
/usr/sbin/mmm_restore
/usr/share/doc/mysql-mmm-tools-2.0.10
/usr/share/doc/mysql-mmm-tools-2.0.10/README
--------

下記の設定ファイル&コマンドが要注意、といったところでしょうか?

【mysql-mmm】
/etc/mysql-mmm/mmm_common.conf

【mysql-mmm-agent】
/etc/init.d/mysql-mmm-agent
/etc/mysql-mmm/mmm_agent.conf
/usr/sbin/mmmd_agent

【mysql-mmm-monitor】
/etc/init.d/mysql-mmm-monitor
/etc/mysql-mmm/mmm_mon.conf
/usr/sbin/mmm_control
/usr/sbin/mmmd_mon

【mysql-mmm-tools】
/etc/mysql-mmm/mmm_tools.conf
/usr/sbin/mmm_backup
/usr/sbin/mmm_clone
/usr/sbin/mmm_restore

設定編の前に、MySQLのマルチマスタレプリケーションを構築しないと...

--------
http://www.suz-lab.com

2010年3月12日金曜日

CentOSで"s3cmd"

スズキです。

ftpコマンドのS3版、といった感じのツールです。
http://s3tools.org/s3tools

下記に、日本語で詳しく紹介されており、
http://ks.typepad.jp/blog/2009/01/amazon-s3s3cmd-.html
その手順を参考にしながら、導入してみました。

まずはインストールですが、幸いyumリポジトリも公開されており、
そこからのインストールとなります。

# cd /etc/yum.repos.d/
# curl -OL http://s3cmd.org/repo/CentOS_5/s3tools.rep
# yum install s3cmd

次に、AWS情報の設定ですが、下記コマンドを実行することで、
インタラクティブに進めていくことができます。

# s3cmd --configure
--------
Enter new values or accept defaults in brackets with Enter.
Refer to user manual for detailed description of all options.

Access key and Secret key are your identifiers for Amazon S3
Access Key: XXXXXXXXXXXXXXXXXXXX
Secret Key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Encryption password is used to protect your files from reading
by unauthorized persons while in transfer to S3
Encryption password: xxxxxxxx
Path to GPG program:

When using secure HTTPS protocol all communication with Amazon S3
servers is protected from 3rd party eavesdropping. This method is
slower than plain HTTP and can't be used if you're behind a proxy
Use HTTPS protocol [No]:

On some networks all internet access must go through a HTTP proxy.
Try setting it here if you can't conect to S3 directly
HTTP Proxy server name:

New settings:
  Access Key: XXXXXXXXXXXXXXXXXXXX
  Secret Key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  Encryption password: xxxxxxxx
  Path to GPG program: None
  Use HTTPS protocol: False
  HTTP Proxy server name:
  HTTP Proxy server port: 0

Test access with supplied credentials? [Y/n] Y
Please wait...
Success. Your access key and secret key worked fine :-)

Now verifying that encryption works...
Not configured. Never mind.

Save settings? [y/N] y
Configuration saved to '/root/.s3cfg'
--------

最終的には、上記で入力した情報は暗号化された形で"/root/.s3cfg"に保管されます。

設定が終わると、下記のように利用できるようになります。

# s3cmd ls
--------
2009-10-20 06:43 s3://cdn.suz-lab.com
2009-09-15 02:32 s3://maven.suz-lab.com
2010-01-21 14:01 s3://us-east-1.ami.suz-lab.com
2010-01-18 09:01 s3://us-west-1.ami.suz-lab.com
2010-02-08 04:47 s3://yum.suz-lab.com
--------

これと"incron"を組み合わせたいんだよねー...
http://blog.suz-lab.com/2010/03/incron.html

--------
http://www.suz-lab.com

"incron"でファイルシステムの変更を検出&任意のコマンド実行(CentOS)

スズキです。

"lsyncd"に引き続き、"inotify"ネタです。
http://blog.suz-lab.com/2010/03/centoslsyncd.html

"incron"を使うと、ファイルシステムの変更を検出して
指定のコマンドを実行することができます。(下記に詳しく書かれています)

▼ファイル/ディレクトリの変更に応じて任意のジョブを実行するincron
http://sourceforge.jp/magazine/08/08/25/0131211

幸い, rpmforgeリポジトリにあったので、下記のようにインストールです。

# yum install incron

そして、"/etc/incron.d/"に、下記のように実行ルールを書いたファイルを置きます

# cat /etc/incron.d/logger
--------
/tmp IN_CREATE logger $@/$#
--------

上記は"/tmp"以下にファイルなどが作成されたら、そのフルパスをログに表示する、
といった内容です。

実際に、次のように適当なファイルを作成すると、

# touch /tmp/aaa.txt

以下のようなログが出力します。

# tail -f /var/log/messages
--------
...
Mar 13 02:07:23 suz-lab-work logger: /tmp/aaa.txt
--------

S3との同期などで使えそうだなー。

--------
http://www.suz-lab.com

2010年3月11日木曜日

"lsyncd"で双方向の同期

スズキです。

"rsync"と"lsyncd"を用いた一方向の同期は確認したので、
http://blog.suz-lab.com/2010/03/centoslsyncd.html
今度は、双方向の同期ができるかの確認です。

つまり、「サーバA」で"lsyncd"、「サーバB」で"rsync"、
そして、「サーバA」から「サーバB」に対しての同期ができたので、
さらに、「サーバA」に"rsync"、「サーバB」に"lsyncd"、を立ち上げ、
どちらのサーバでファイルの更新などをしても、もう一方に反映するか、
の確認です。

で、結論としては、できました!

やり方は、こちらと、
http://blog.suz-lab.com/2010/03/centoslsyncd.html
こちらの手順を、
http://blog.suz-lab.com/2010/03/centosrsync.html
サーバを逆にした状態でも設定する感じです。

状況によっては、負荷分散された複数のWebサーバに対する
ファイルアップロードなどに有効かもしれません。

とりあえず、今、NFS使ってるところは、置きかえられるかな?

--------
http://www.suz-lab.com

CentOSで"lsyncd"を使った同期

スズキです。

"rsync"の準備もできたので、いよいよ、"lsyncd"です。
http://blog.suz-lab.com/2010/03/centosrsync.html

"lsyncd"とは、Linuxカーネル2.6.13で利用できるようになった、
"inotify"と呼ばれるファイル・システム・イベント監視機能を利用し、
ファイルの更新などにもとづき、該当ファイルを同期先に反映してくれるコマンドです。
http://code.google.com/p/lsyncd/

幸い、CentOSでは"rpmforge"のリポジトリからインストールできます。
# yum install lsyncd

で、同期先サーバで"rsync"がデーモンモードで稼動していれば、
以下のようなコマンドで、対象ディレクトリを監視モードにできます。

# lsyncd /tmp/test/ 172.21.10.152::test
※ 第1引数は同期元ローカルディレクトリで、第2引数は同期先(rsync)です

この状態で、同期元ディレクトでファイルの更新や作成をすると、
このタイミングで、同期先にも、同様のものが反映されます。

双方向はいけるのかなー?(無限ループ?)

--------
http://www.suz-lab.com

CentOSで"rsync"のデーモンモード

スズキです。

CentOSで"rsync"をデーモンモードで使う方法です。

まずは、必要なパッケージをインストールします。

# yum install xinetd
# yum install rsync

"rsync"のデーモンモードは、"xinetd"経由で利用する形になっています。

次に、対象ファイルの作成です。

# mkdir /tmp/test
# chmod 777 /tmp/test

そして、設定ファイル("/etc/rsyncd.conf")を以下のように作成します。

--------【rsyncd.conf】--------
[test]
path = /tmp/test
hosts allow = 172.21.10.0/24
read only = false
--------

この状態で、"xinetd"を起動すると、"rsync"がデーモンモードで利用できるようになります。

# chkconfig rsync on
# /etc/init.d/xinetd start

最後に適当なサーバから、上記のサーバに対して以下のようなコマンドで、
rsyncコマンドで"rsync"のデーモンモードを利用したディレクトリ同期が確認できます。

# rsync -avx /tmp/test/ 172.21.10.152::test

これで"lsyncd"の準備も完了です。

--------
http://www.suz-lab.com

仮想インターフェース(IPエイリアス)の作成(Linux)の続き

スズキです。

以前、仮想インターフェースについたのですが、
http://blog.suz-lab.com/2010/03/iplinux.html

この設定だと、外部につながらなくなってしまいました...
("ping www.yahoo.com"などの反応がなくなってしまいます)

ですので、やっぱり、ネットマスクとブロードキャストを指定して、再設定です。

# ifconfig eth0:0 10.32.10.150 netmask 255.255.255.0 broadcast 10.32.10.255

今度は"ping www.yahoo.com"もOKです。

これで、yumが使えるようになった...

--------
http://www.suz-lab.com

2010年3月10日水曜日

GStreamerで動画のタグ取得(FFmpeg連携)

スズキです。

MP3のタグ情報取得に続き、
http://blog.suz-lab.com/2010/03/gstreamermp3.html

今度は動画も試してみました。

MP4はこんな感じでです。

# gst-launch filesrc location=input.mp4 ! decodebin ! fakesink -t
Setting pipeline to PAUSED ...
Pipeline is PREROLLING ...
FOUND TAG : found by element "qtdemux0".
  video codec: H.264 / AVC
FOUND TAG : found by element "qtdemux0".
  audio codec: MPEG-4 AAC audio
Pipeline is PREROLLED ...
Setting pipeline to PLAYING ...
New clock: GstSystemClock
Got EOS from element "pipeline0".
Execution ended after 724906045 ns.
Setting pipeline to PAUSED ...
Setting pipeline to READY ...
Setting pipeline to NULL ...
FREEING pipeline ...

調子に乗って、MTSも試してみましたが、

# gst-launch filesrc location=input.mts ! decodebin ! fakesink -t
Setting pipeline to PAUSED ...
Pipeline is PREROLLING ...
ERROR: from element /pipeline0/decodebin0: A MPEG-2 Transport Stream
demuxer plugin is required to play this stream, but not installed.
Additional debug info:
gstdecodebin.c(845): close_pad_link (): /pipeline0/decodebin0:
No decoder to handle media type 'video/mpegts'
ERROR: pipeline doesn't want to preroll.
Setting pipeline to NULL ...
FREEING pipeline ...

こちらはエラーになってしまいました。

しかし、下記でインストールしたことを思いだし、
# yum install gstreamer-ffmpeg

以下のFFmpeg関連のドキュメントを見ながら試行錯誤したところ、
http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-ffmpeg-plugins/html/

以下のように、MTSも成功しました。

# gst-launch filesrc location=input.mts ! ffdemux_mpegts ! fakesink -t
Setting pipeline to PAUSED ...
Pipeline is PREROLLING ...
FOUND TAG : found by element "ffdemux_mpegts0".
  video codec: H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10
FOUND TAG : found by element "ffdemux_mpegts0".
  audio codec: ATSC A/52A (AC-3)
FOUND TAG : found by element "ffdemux_mpegts0".
  audio codec: ATSC A/52A (AC-3)
Pipeline is PREROLLED ...
Setting pipeline to PLAYING ...
New clock: GstSystemClock
Got EOS from element "pipeline0".
Execution ended after 77135625 ns.
Setting pipeline to PAUSED ...
Setting pipeline to READY ...
Setting pipeline to NULL ...
FREEING pipeline ...

そんなこんなで、GStreamerの感触はつかめてきた感じです。

本命はGStreamer使ったPerlでの音合成なんだけど...

--------
http://www.suz-lab.com

GStreamerでタグ情報(MP3)の取得

スズキです。

GStreamerはマルチメディアフレームワークと呼ばれているもので、
音声や動画に対して、さまざまな処理ができるものです。
http://gstreamer.freedesktop.org/

CentOSのyumリポジトリにもあったので、下記のようにインストールしてみました。
(よくわかってないので、それっぽいもの、すべてインストールです)

# yum install gstreamer
# yum install gstreamer-tools
# yum install gstreamer-ffmpeg
# yum install gstreamer-plugins-base
# yum install gstreamer-plugins-good
# yum install gstreamer-plugins-ugly
# yum install gstreamer-plugins-bad

で、早速、利用例の一つである、MP3のタグデータを取得してみました。

# gst-launch filesrc location=test.mp3 ! id3demux ! fakesink -t
Setting pipeline to PAUSED ...
Pipeline is PREROLLING ...
FOUND TAG : found by element "id3demux0".
  title: XXXXXXXX
  artist: XXXXXXXX
  album: XXXXXXXX
  date: 2009-01-01
  comment: XXXXXXXX
  track number: 1
  genre: XXXXXXXX
  ISRC: XXXXXXXX
  track count: 4
  discid: XXXXXXXX
Pipeline is PREROLLED ...
Setting pipeline to PLAYING ...
New clock: GstSystemClock
Got EOS from element "pipeline0".
Execution ended after 36584697 ns.
Setting pipeline to PAUSED ...
Setting pipeline to READY ...
Setting pipeline to NULL ...
FREEING pipeline ...

標準出力に、MP3のタグ情報が表示されているのがわかります。

実践投入は、まだまだ先だなー...

--------
http://www.suz-lab.com

NSTimerで定期的にUIImageViewの画像を入れ替える(iPhone)

スズキです。

iPhoneで、下記100個の画像ファイルを0.1秒おきに差し替えるやり方です。

image_00000.jpg
image_00001.jpg
...
image_00099.jpg

実装方法は、NSTimerを利用して0.1秒ごとに、
UIImageViewのimageを差し替える感じです。

主要クラスのリファレンスは次の通りです。
【NSTimer】
http://developer.apple.com/iphone/library/documentation/Cocoa/Reference/Foundation/Classes/NSTimer_Class/Reference/NSTimer.html
【UIImageView】
http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIImageView_Class/Reference/Reference.html
【UIImage】
http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIImage_Class/Reference/Reference.html

最終的なコードは下記のようになりました。

--------【Objective-C】--------
#import "Test02ViewController.h"
@implementation Test02ViewController
@synthesize imageView;
NSTimer *timer = nil;
int sequence = 0;

- (void)viewDidLoad {
  [super viewDidLoad];
  NSLog(@"start");
  [NSTimer
    scheduledTimerWithTimeInterval:0.1
    target:self
    selector:@selector(onTimer:)
    userInfo:nil
    repeats:YES];
}

- (void)didReceiveMemoryWarning {
  [super didReceiveMemoryWarning];
}

- (void)viewDidUnload {
}


- (void)dealloc {
  [super dealloc];
}

- (void)onTimer:(NSTimer *)timer {
  NSString *imageName = [NSString stringWithFormat: @"image_%05d", sequence];
  NSString *imagePath = [
    [NSBundle mainBundle] pathForResource:imageName
    ofType:@"jpg"
  ];
  UIImage *image = [[UIImage alloc] initWithContentsOfFile:imagePath];
  imageView.image = image;
  [image release];
  sequence++;
  if (sequence > 100 && [timer isValid]) {
    [timer invalidate];
    NSLog(@"stop");
  }
}

@end
--------

メモリ管理系は、結構、理解してきたなー…

--------
http://www.suz-lab.com

WinSCP 4.2.7 リリース

スズキです。

適当にバグフィックスしてる感じです。
http://winscp.net/eng/docs/history#4.2.7

とりあえず、アップデートです。
(日本語リソースはこちらから)
http://winscp.net/eng/translations.php

ペースを、もとに戻さないと...

--------
http://www.suz-lab.com

「バースト」と「スパイク」(ネットワーク)

スズキです。

一時的なアクセス増で、ネットワークトラフィックが一時的に、
そして急激に増大するさまを、どのような言葉で表すべきか?、です。

経験的に、「バースト」と「スパイク」という言葉が頭に浮かび、
どちらが正式(?)なのか?、もっとふさわしい言葉があるのか?、
いろいろ調べて(ググって)みたのですが、決定的なものは無いようでした...

ということで、なけなしの情報をもとに、SUZ-LAB的に以下のように定義です。

【バースト】
突発的にトラフィックが増える現象。

【スパイク】
結果的に、とがった波形を持つ、トラフィックデータ。

まあ、結果的には同じような現象を指すことになるとは思いますが、
「バースト」は現象にた、「スパイク」はデータの様子に対して、
使えばいいのかな?、と...

--------
http://www.suz-lab.com

2010年3月9日火曜日

仮想インターフェース(IPエイリアス)の作成(Linux)

スズキです。

以前、"/etc/sysconfig/network-scripts/ifcfg-eth0:1"を
使ったものを紹介しましたが、
http://blog.suz-lab.com/2009/02/blog-post.html

今回は、ifconfigコマンドで直接作成する方法です。

といっても、下記の通りです。

# ifconfig eth0:0 10.32.10.150

上記を実行することで、仮想インターフェースが作成されていることが、
以下の通り、確認することができます。

# ifconfig -a
eth0
  Link encap:Ethernet HWaddr 00:40:CA:86:61:95
  inet addr:10.32.10.151 Bcast:10.32.10.255 Mask:255.255.255.0
  UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
  RX packets:366831 errors:0 dropped:0 overruns:0 frame:0
  TX packets:354882 errors:0 dropped:0 overruns:0 carrier:0
  collisions:0 txqueuelen:1000
  RX bytes:198431746 (189.2 MiB) TX bytes:172734237 (164.7 MiB)
  Interrupt:193 Base address:0x4000
eth0:0
  Link encap:Ethernet HWaddr 00:40:CA:86:61:95
  inet addr:10.32.10.150 Bcast:10.255.255.255 Mask:255.0.0.0
  UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
  Interrupt:193 Base address:0x4000

ブログのペースが乱れてる...

--------
http://www.suz-lab.com

2010年3月8日月曜日

「SUZ-LAB FEED」で「AWS+」のサポーター(?)フィードを作成(その2)

スズキです。

「その1」でフィードができたので、次は、そのフィードを読み込んで表示する部分です。
http://feed.suz-lab.com/feed.xml/aws-plus_news

今回は"Google AJAX FEED API"を利用して、お手軽に作ってみました。
http://code.google.com/intl/ja/apis/ajaxfeeds/documentation/

コードは下記のような感じです。

--------【JavaScript】--------
<script type="text/JavaScript" src="/js/jquery.js"></script>
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">google.load("feeds", "1");</script>
<script>
$(function() {
  var url = "http://feed.suz-lab.com/feed.xml/aws-plus_news";
  var feed = new google.feeds.Feed(url);
  feed.setNumEntries(20);
  feed.load(function(result) {
    if(!result.error) {
      var html = "";
      $.each(result.feed.entries, function() {
        var date = new Date(Date.parse(this.publishedDate));
        html += "<dt>";
        html += date.getFullYear();
        html += ".";
        html += ("0" + (date.getMonth() + 1)).slice(-2);
        html += ".";
        html += ("0" + date.getDate()).slice(-2);
        html += "</dt>";
        html += "<dd>";
        html += "<a target='_blank' href='" + this.link + "'>";
        html += this.title;
        html += "</a>";
        html += " [" + this.author + "]";
        html += "</dd>";
      });
      $("#entry").html(html);
    }
  });
});
</script>
--------

実際に動いてるものは、こちらになります。
http://www.aws-plus.com/

「SUZ-LAB FEED」の二つ目の事例です。

--------
http://www.suz-lab.com

jQueryでJSONP(Twitter)

スズキです。

以前、JSONPが使える"Web API"をまとめましたが、
http://blog.suz-lab.com/2010/01/jsonpweb-api.html
その一つである、TwitterをjQuery(JSONP)で利用する方法です。
http://apiwiki.twitter.com/Twitter-API-Documentation

TwitterでJSONPを利用するには、例えば、以下のようなリクエストをします。
http://search.twitter.com/search.json?callback=foo&q=twitter

ポイントは、callbackパラメータで、指定した名前(foo)に応じて、
下記のようなレスポンスが返るようになっています。
foo(JSONデータ);

ということをふまえて、jQueryを使ったコードを書くと、以下のような感じになります。

--------【JavaScript】--------
<script type="text/javascript"
  src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js">
</script>
<script type="text/javascript">
var url = "http://search.twitter.com/search.json?callback=?";
var param = {q: "jquery"};
$.getJSON(url, param, function(json) {
  for(var i = 0; i < json.results.length; i++) {
    alert(json.results[i].text);
  }
});
</script>
--------

つまり、"$.getJSON"でJSONPも扱うことができる、ということです。
ポイントは、"callback=?"です。おそらく、「?」があるかないかで、
JSONかJSONPか切り替えてるような気がします。

上記を実行すると、Twitterへのリクエストは、
http://search.twitter.com/search.json?callback=jsonp1267977402483&q=jquery
となり、当然レスポンス次のようになっています。
jsonp1267977402483(JSONデータ);

このことから、実際には"callback=?"の「?」には
jQueryが自動的に作成する関数名(jsonp1267977402483)が差し込まれることがわかります。

あとは、いつもの"$.getJSON"のように、指定した関数内で、
JSONデータ(json)として扱っていくことができます。

"jQuery + JSONP"は手軽すぎるなー。

--------
http://www.suz-lab.com

2010年3月7日日曜日

「SUZ-LAB FEED」で「AWS+」のサポーター(?)フィードを作成(その1)

スズキです。

下記「AWS+」サイトの"New Entry"に表示するフィードを作りました。
http://www.aws-plus.com/

この"New Entry"はAWS+のサポートしてくれている人たちのブログで
"AWS"に関連する記事のみピックアップして表示するものとなっています。

現在は直接手書きで運用していますが、以下で紹介した「SUZ-LAB FEED」を用いて、
http://blog.suz-lab.com/2010/02/gaej.html
複数のブログの特定のカテゴリの記事だけ集めたフィードを作成し、
サイトのほうで、それを読み込んで、"New Entry"を作成するつもりでいます。

実際のフィードのURLは次のとおりです。
http://feed.suz-lab.com/feed.xml/aws-plus_news

現状は、本ブログの"AWS"カテゴリの記事と、
klogさんの"amazonwebservices"カテゴリの記事をまとめたものにしています。
http://5net.com/blog/

ということで、明日、サイトのほうも実装します。

--------
http://www.suz-lab.com

2010年3月6日土曜日

ScanSnap(S300)復活!

スズキです。

以前購入した自動給紙方式のスキャナ、ScanSnap(S300)ですが、
http://blog.suz-lab.com/2009/01/scansnaps300.html
引越しのときに、PCからはずして、今日までそのままになってました...

たまたま、書類のスキャンを依頼され、つなぐだけで、すぐにできるだろうと思い、
軽い気持ちで引き受けたのですが、非常に時間がかかってしまいました。

原因は、ドライバのインストールです。

下記、サポートページからダウンロードできるだろうと、たかをくくっていたのですが、
http://scansnap.fujitsu.com/jp/downloads/
アップデートプログラムのみで、実際のドライバは付属CDからのインストールしか
手段がない状態でした。

ということで、付属CDの大捜索が始まりました...
...
...
...
そして、奇跡的に見つけることができました。

ただ、そのCDも汚れすぎており、何度も洗剤で洗い、
そこそこピカピカしてきたら、恐る恐るドライブに入れ、無事認識といったところです...

あとは、普通のインストール作業で復活です!

CD、捨てないで本当に良かった...

--------
http://www.suz-lab.com

Image::Magickで画像に任意の文字をのせる

スズキです。

以下のようにAnnotateメソッドで可能です。

--------【Perl】--------
use Image::Magick;
...
my $image = Image::Magick->new;
$image->Read($input_file); もと画像の読み込み
$image->Annotate(
  font => "/usr/share/fonts/japanese/TrueType/sazanami-gothic.ttf", # フォントファイル
  pointsize => 20, # フォントサイズ
  fill => "white", # 文字の色
  text => "suz-lab", # のせる文字列
  x => 0, # 文字の位置(x座標)
  y => 20 # 文字の位置(y座標)
);
$image->Write($output_file); # 文字がのった画像の書き出し
...
--------

日本語は未検証です...

--------
http://www.suz-lab.com

XnView Portable 1.97.2 リリース

スズキです。

近頃サーバサイドでの画像、動画処理やっており、確認用に重宝しているので
間髪いれず、アップデートです。
http://portableapps.com/news/2010-03-04_-_xnview_portable_1.97.2

職業がら、画像、動画関係のツールは充実させないといけないんだけど、
本職に比べると、まだまだだなー...(勝手にポータブル縛りもあるし...)

--------
http://www.suz-lab.com

「第0回 AWS User Group - Japan 勉強会」のLT資料まとまってます

スズキです。

本家のページで、まとめて公開(リンク)されています。
http://jaws-ug.jp/

僕が作成した、こちらも、載せていただいてます。
http://blog.suz-lab.com/2010/02/ltjaws-ug.html

次の勉強会も楽しみです。

--------
http://www.suz-lab.com

PHPでコマンドの終了ステータスを取得

スズキです。

system関数を利用した場合、第二引数を指定すると、
そこに終了ステータスが入るようになっています。

詳しくは、こちらです。
http://www.php.net/manual/ja/function.system.php

サンプルコードはこんな感じです。

--------【PHP】--------
<?php
  system("check_movie.pl " . escapeshellarg("0000000001.mp4"), $status);
  print($status);
?>
--------

久しぶりのPHPです。

--------
http://www.suz-lab.com

Image::ExifToolで動画の大きさと尺のチェック

スズキです。

Image::ExifToolは画像だけでなく、動画に関しても、メタデータが取れます。
動画の場合は、例えば、下記のように取得できます。

$VAR1 = {
  'AudioSampleRate' => '44100',
  'SelectionTime' => '0 s',
  'OpColor' => '0 0 0',
  'TrackVersion (1)' => 0,
  'TrackVolume (1)' => '100.00%',
  'SourceImageHeight' => 360,
  'MIMEType' => 'video/mp4',
  'FileType' => 'MP4',
  'AudioBitsPerSample' => 16,
  'MediaHeaderVersion (1)' => 0,
  'TrackLayer (1)' => 0,
  'TrackCreateDate (1)' => '0000:00:00 00:00:00',
  'ExifToolVersion' => '8.00',
  'MediaModifyDate' => '0000:00:00 00:00:00',
  'Directory' => '/var/www/html/master/src/city/01',
  'Version' => 0,
  'ImageHeight' => 360,
  'PreferredRate' => '1',
  'TrackID (1)' => 2,
  'TrackVolume' => '0.00%',
  'CompatibleBrands' => 'isom, iso2, avc1, mp41',
  'PreferredVolume' => '100.00%',
  'BitDepth' => 24,
  'SelectionDuration' => '0 s',
  'NextTrackID' => 3,
  'MediaTimeScale (1)' => 30000,
  'Duration' => '13.25 s',
  'Rotation' => '0',
  'HandlerDescription (1)' => 'VideoHandler',
  'MajorBrand' => 'MP4 Base Media v1 [IS0 14496-12:2003]',
  'PreviewDuration' => '0 s',
  'TrackLayer' => 0,
  'MinorVersion' => '0.2.0',
  'MediaDuration' => '13.17 s',
  'SourceImageWidth' => 640,
  'ModifyDate' => '0000:00:00 00:00:00',
  'MediaTimeScale' => 44100,
  'MatrixStructure' => '1 0 0 0 1 0 0 0 1',
  'ImageSize' => '640x360',
  'ImageWidth' => 640,
  'AudioFormat' => 'mp4a',
  'HandlerType' => 'Audio Track',
  'TimeScale' => 1000,
  'PosterTime' => '0 s',
  'CurrentTime' => '0 s',
  'VideoFrameRate' => '29.97',
  'MatrixStructure (1)' => '1 0 0 0 1 0 0 0 1',
  'TrackDuration' => '13.25 s',
  'GraphicsMode' => 'srcCopy',
  'CompressorID' => 'avc1',
  'FileName' => '0000000001.mp4',
  'XResolution' => '72',
  'HandlerType (1)' => 'Video Track',
  'MatrixStructure (2)' => '1 0 0 0 1 0 0 0 1',
  'MediaCreateDate (1)' => '0000:00:00 00:00:00',
  'TrackModifyDate' => '0000:00:00 00:00:00',
  'CreateDate' => '0000:00:00 00:00:00',
  'MediaLanguageCode (1)' => 'und',
  'HandlerDescription' => 'SoundHandler',
  'FileModifyDate' => '2010:01:22 03:14:08+09:00',
  'TrackVersion' => 0,
  'MediaHeaderVersion' => 0,
  'MediaLanguageCode' => 'und',
  'MediaDuration (1)' => '13.25 s',
  'MediaModifyDate (1)' => '0000:00:00 00:00:00',
  'TrackID' => 1,
  'FileSize' => '656 kB',
  'Balance' => '0',
  'AudioChannels' => 2,
  'YResolution' => '72',
  'TrackModifyDate (1)' => '0000:00:00 00:00:00',
  'MediaCreateDate' => '0000:00:00 00:00:00',
  'TrackDuration (1)' => '13.17 s',
  'PreviewTime' => '0 s',
  'TrackCreateDate' => '0000:00:00 00:00:00'
};

で、以下のように動画、静止画の大きさ(尺)をチェックする
スクリプトを作成してみました。
(閾値未満のものは0以外のステータスが返ります)

--------【Perl】--------
#!/usr/bin/env perl

use strict;
use warnings;
use Data::Dumper;
use Image::ExifTool;
use Log::Dispatch;

use constant WIDTH => 800;
use constant HEIGHT => 450;
use constant DURATION => 4;

my $log = Log::Dispatch->new(outputs => [[
  "Screen",
  min_level => 'debug',
  stderr => 1,
  newline => 1
]]);

my $file = $ARGV[0];
my $tool = new Image::ExifTool;
my $exif = $tool->ImageInfo($file);

if(defined $exif->{ImageHeight}) {
  $log->debug("ImageHeight: " . $exif->{ImageHeight});
  if($exif->{ImageHeight} < HEIGHT) {
    $log->debug("Height is short");
    exit 11;
  }
} else {
  $log->debug("Height is undefined.");
  exit 1;
}

if(defined $exif->{ImageWidth}) {
  $log->debug("ImageWidth: " . $exif->{ImageWidth});
  if($exif->{ImageWidth} < WIDTH) {
    $log->debug("Width is short");
    exit 12;
  }
} else {
  $log->debug("Undefined Width.");
  exit 2;
}

if(defined $exif->{Duration}) {
  $log->debug("Duration : " . $exif->{Duration});
  chop($exif->{Duration});
  chop($exif->{Duration});
  if($exif->{Duration} < DURATION) {
    $log->debug("Duration is short");
    exit 13;
  }
} else {
  exit 0;
}
--------

次は、PHPでコマンドの終了ステータスを取得してみよう

--------
http://www.suz-lab.com

2010年3月4日木曜日

CentOSにてImage::Magickでサムネール作成(WorkerManager)

スズキです。

"CentOS & WorkerManager"ネタも、これで一段落でしょうか...

とりあえずyumで調べてみると、別々のリポジトリに
ImageMagickとImageMagick2というものが見つかりました。

# yum info ImageMagick
...
Version : 6.2.8.0
...
Repo : base
...

# yum info ImageMagick2
...
Version : 6.5.5.6
...
Repo : remi
...

上記のように、詳しく調べると、ImageMagick2のほうがバージョンが高かったので、
こちらをインストールすることにしました。

# yum install ImageMagick2-perl

実際には、下記のように(サムネールの作成)利用することができます。

> use Image::Magick;
> ...
> my $image = Image::Magick->new;
> $image->Read($src_file);
> $image->Thumbnail(width => 100, height => 100);
> $image->Write($jpg_file);

WorkerManagerでのコード(全体)は次のような感じです。

--------【Perl】--------
use strict;
use warnings;
use base qw(TheSchwartz::Worker);
use TheSchwartz::Job;
use Image::Magick;
use Log::Dispatch;
use constant BASE_PATH => "/var/www/html/master";

sub work {

  # ログの設定
  my $log = Log::Dispatch->new(outputs => [[
    "Screen",
    min_level => 'debug',
    stderr => 1,
    newline => 1
  ]]);

  # パラメータの取得
  my $class = shift;
  my TheSchwartz::Job $job = shift;
  my $material_id = $job->arg->{material_id};
  my $material_ext = "jpg";

  # サムネール作成元画像
  my $src_file = BASE_PATH . "/" . $material_id . "." . $material_ext;
  $log->debug("src_file: " . $src_file);
  # サムネール作成先画像
  my $jpg_file = BASE_PATH . "/" . $material_id . ".jpg";
  $log->debug("jpg_file: " . $jpg_file);

  # サムネールの作成
  my $image = Image::Magick->new;
  $image->Read($src_file); # 元画像の読み込み
  $image->Thumbnail(width => 100, height => 100); # サムネールの作成
  $image->Write($jpg_file); # サムネールの書き出し
  $job->completed();

}

sub max_retries { 3 }
sub retry_delay { 20 }

1;
--------

明日には、iPhone開発にもどりたいなー...

--------
http://www.suz-lab.com

FFmpeg::Commandで動画から静止画の切り出し(WorkerManager)

スズキです。

今度は、動画から静止画の切り出しです。

一つ前の記事の「動画の切り取り」と同じような感じですが、
http://blog.suz-lab.com/2010/03/ffmpegcommandworkermanager.html
コードは下記のようになります。

--------【Perl】--------
use strict;
use warnings;
use base qw(TheSchwartz::Worker);
use TheSchwartz::Job;
use FFmpeg::Command;
use Log::Dispatch;
use constant BASE_PATH => "/var/www/html/master";

sub work {

  # ログの設定
  my $log = Log::Dispatch->new(outputs => [[
    "Screen",
    min_level => 'debug',
    stderr => 1,
    newline => 1
  ]]);

  # パラメータの取得
  my $class = shift;
  my TheSchwartz::Job $job = shift;
  my $material_id = $job->arg->{material_id};
  my $material_ext = "mp4";

  # 画像切り出し元の設定
  my $src_file = BASE_PATH . "/" . $material_id . "." . $material_ext;
  $log->debug("src_file: " . $src_file);
  my $ffmpeg = FFmpeg::Command->new();
  $ffmpeg->input_options({
    file => $src_file,
  });

  # 画像切り出し先の設定
  my $jpg_file = BASE_PATH . "/" . $material_id . ".jpg";
  $log->debug("jpg_file: " . $jpg_file);
  $ffmpeg->output_options({
    file => $jpg_file,
  });
  $ffmpeg->options(
    "-y", # FFmpegの問い合わせに自動でYesで返答
    "-an", # 音声の処理はしない
    "-ss" => 0, # 0秒時点を静止画に
    "-f" => "image2", # 画像として出力
    "-vframes" => 1 # 対象フレーム数
  );

  # FFmpegの実行
  if(!$ffmpeg->exec()){
    $log->debug("Failed:\n" . $ffmpeg->stderr());
    $job->failed($ffmpeg->stderr());
    return;
  }
  $log->debug("Completed:\n" . $ffmpeg->stderr());
  $job->completed();

}

sub max_retries { 3 }
sub retry_delay { 20 }

1;
--------

ポイントも、一つ前の記事と同様、下記となります。

> $ffmpeg->options(
>   "-y", # FFmpegの問い合わせに自動でYesで返答
>   "-an", # 音声の処理はしない
>   "-ss" => 0, # 0秒時点を静止画に
>   "-f" => "image2", # 画像として出力
>   "-vframes" => 1 # 対象フレーム数
> );

PerlでImageMagickまで終わったら、ちょっと気が楽になるなー、がんばろう...

--------
http://www.suz-lab.com

FFmpeg::Commandで動画の切り取り(WorkerManager)

スズキです。

こちらと、
http://blog.suz-lab.com/2010/01/ffmpeg.html
こちらの、
http://blog.suz-lab.com/2010/01/theschwartz-ffmpegcommand.html
合わせ技です。

コードはこんな感じになります。

--------【Perl】--------
use strict;
use warnings;
use base qw(TheSchwartz::Worker);
use TheSchwartz::Job;
use FFmpeg::Command;
use Log::Dispatch;
use constant BASE_PATH => "/var/www/html/master";

sub work {

  # ログの設定
  my $log = Log::Dispatch->new(outputs => [[
    "Screen",
    min_level => 'debug',
    stderr => 1,
    newline => 1
  ]]);

  # パラメータの取得
  my $class = shift;
  my TheSchwartz::Job $job = shift;
  my $material_id = $job->arg->{material_id};
  my $material_ext = "mp4";

  # 変換元動画
  my $src_file = BASE_PATH . "/" . $material_id . "." . $material_ext;
  $log->debug("src_file: " . $src_file);
  # 変換先動画
  my $flv_file = BASE_PATH . "/" . $material_id . ".flv";
  $log->debug("flv_file: " . $flv_file);

  # FFmpegの設定
  my $ffmpeg = FFmpeg::Command->new();
  $ffmpeg->input_options({
    file => $src_file,
  });
  $ffmpeg->output_options({
    file => $flv_file,
    format => "flv" # 出力フォーマットはFLV
  });
  $ffmpeg->options(
    "-y", # FFmpegの問い合わせに自動でYesで返答
    "-an", # 音声の処理はしない
    "-ss" => 0, # 最初から切り取る
    "-t" => 4 # 4秒間切り取る
  );

  # FFmpegの実行
  if($ffmpeg->exec()) {
    $log->debug("Completed");
    $job->completed();
  } else {
    $log->debug("Failed: " . $ffmpeg->errstr);
    $job->failed($ffmpeg->errstr);
  }

}

sub max_retries { 3 }
sub retry_delay { 20 }

1;
--------

ポイントは、まさに、下記です。

> $ffmpeg->options(
>   "-y", # FFmpegの問い合わせに自動でYesで返答
>   "-an", # 音声の処理はしない
>   "-ss" => 0, # 最初から切り取る
>   "-t" => 4 # 4秒間切り取る
> );

FFmpegネタ、もう一つやったら今日は寝よう...

--------
http://www.suz-lab.com

Log::Dispatchでログ出力(Perl)

スズキです。

ログ出力モジュールをCPANで探してみたら、
非常に多くのモジュールが見つかったのですが、
Log::Dispatchを使ってみることにしました。

まずは、yumでインストールです。

# yum install perl-Log-Dispatch

そして、下記のようなコードでログを出力します。

--------【Perl】--------
use Log::Dispatch;
...
my $log = Log::Dispatch->new(outputs => [[
  "Screen",
  min_level => 'debug',
  stderr => 1,
  newline => 1
]]);
...
$log->debug("Logging!");
--------

上記は、画面(STDERR)にログを出力するようにしています。
("stderr => 0"にするとSTDOUTに出力します)
"newline => 1"はログ出力($log->debug)ごとの改行です。

もう少し、Perlモードだなー...

--------
http://www.suz-lab.com

2010年3月3日水曜日

"perl-FFmpeg-Command"をSUZ-LABリポジトリ(yum)に追加

スズキです。

CentOS5.4で"yum search"しても、見当たらなかったので、
以下のようにRPMを作成して、SUZ-LABリポジトリ(yum)に追加しました。

まずは、ソースの取得です。

# cd /usr/src/redhat/SOURCES
# curl -OL http://search.cpan.org/CPAN/authors/id/M/MI/MIZZY/FFmpeg-Command-0.13.tar.gz

次に、SRPMを作成して、そこからspecファイルを取り出します。

# cpanflute2 FFmpeg-Command-0.13.tar.gz
# rpm -Uvh perl-FFmpeg-Command-0.13-8.src.rpm
# rm perl-FFmpeg-Command-0.13-8.src.rpm

そして、そのspecファイルに対して「Release: 1.el5.suzlab」と修正し、
"ffmpeg"のパッケージに依存するように「Requires: ffmpeg」を追記します。

specファイルが完成したら、RPMとSRPMの作成です。

# cd ../SPECS
# rpmbuild -ba perl-FFmpeg-Command.spec

最後に下記の手順のように、作成したRPMとSRPMをリポジトリに配置して、
http://blog.suz-lab.com/2010/02/suz-labyumrpm.html
再度"yum search"を行うと、
今度は"perl-FFmpeg-Command"のパッケージが見つかります。
("yum clean all"でキャッシュクリアしておいたほうがいいかも)

Enjoy!

--------
http://www.suz-lab.com

「君子は和して同せず、小人は同して和せず。」

スズキです。

忘れたころのMaximです。

集団行動の苦手な僕の言い訳です。
http://ameblo.jp/jitenfeti/entry-10007627447.html

でも孔子の言葉なので、そこそこ、説得力はあるかな、と。

--------
http://www.suz-lab.com

CentOSとSUZ-LABリポジトリ(yum)でWorkerManager(TheSchwartz)

スズキです。

CentOSでSUZ-LABリポジトリ(yum)を利用して、
WorkerManagerの環境を作成する手順です。

(1) リポジトリの登録です。
# rpm -Uvh http://yum.suz-lab.com/5/i386/suzlab-release-5-1.noarch.rpm

(2) WorkerManagerのインストールです。
# yum install perl-Worker-Manager

(3) MySQLにアカウントとデータベースを作成します。
# mysql -u root
mysql > GRANT ALL PRIVILEGES ON theschwartz.*
-> TO theschwartz@localhost IDENTIFIED BY 'theschwartz!23'
mysql > create database theschwartz character set utf8;

(4) TheSchwartzで利用するテーブルを作成します。
# mysql -u theschwartz -p theschwartz <
/usr/share/doc/perl-TheSchwartz-1.07/doc/schema.sql

(5) 設定ファイル(/etc/worker.conf.yml)の記述(DB)を上記にそった形に変更します。
--------【worker.conf.yml】--------
workers:
 - Sandbox::Worker::A
 - Sandbox::Worker::B
worker_options:
 prioritize: 1
 databases:
  dsn: dbi:mysql:theschwartz
  user: theschwartz
  pass: theschwartz!23
inc_path:
 - /usr/share/doc/perl-Worker-Manager-0.01/examples/lib
pidfile: /var/run/workermanager.pid
logfile: /var/log/workermanager.log
errorlogfile: /var/log/workermanager_error.log
--------

(5) サーバを起動します。
# service workermanager start

実際には、用途に応じて"worker.conf.yml"の"workers"や"inc_path"を
プロジェクトのものに変更して運用することになります。

これで、次から5分でセッティングできる!?

--------
http://www.suz-lab.com

2010年3月2日火曜日

「AWS+」オープン

スズキです。

下記サイトのオープンのお手伝いをしました(まだ、しています)。
http://www.aws-plus.com/

簡単に紹介すると、「AWS+」はEC2をはじめとする、
"amazon web services"の導入/運用をサポートするサービスです。

当然、このサイトもEC2上で稼動しており、そのAMIに、
下記のような"SUZ-LAB謹製 CentOS AMI"が利用されています。
http://blog.suz-lab.com/2010/02/suz-lab-centos-ami-545_22.html

また、画像、CSS、JavaScriptに関しては、
以下の方法でCloudFrontを利用するようにしています。
http://blog.suz-lab.com/2010/03/modextfilterurlcloudfront.html

そして、まだ実装中ですが、トップページのニュースには、
「SUZ-LAB FEED」(http://feed.suz-lab.com/)を用いて、
複数人のAWSに関する記事一覧を表示するようにします。

ぜひ、ビジネスとしても、成功していただきたいと思ってます。

SUZ-LABのポートフォリオが作れるぞ!

--------
http://www.suz-lab.com

"mod_ext_filter"で画像などのURLをCloudFrontのものに

スズキです。

こちらで紹介されている方法を、"perl"ではなく"sed"で試してみました。
http://vkgtaro.jp/2009/04/05/mod_ext_filter

まず、"sed"用の変換ルールを定義したファイルを用意します。

【cdn.sed】
s/"\/img\//"http:\/\/cdn.suz-lab.com\/img\//g
s/"\/css\//"http:\/\/cdn.suz-lab.com\/css\//g
s/"\/js\//"http:\/\/cdn.suz-lab.com\/js\//g

今回は、画像が"img"の下、CSSが"css"の下、
JavaScriptが"js"の下に配置されているとして、これらのファイルを、
CloudFrontに置き、"mod_ext_filter"でHTML上のURLを
CloudFrontのものに書き換えるようにします。

そして、"httpd.conf"は以下のようになります。

【httpd.conf】
ExtFilterDefine cdn mode=output intype=text/html cmd="/bin/sed -f /etc/httpd/conf/cdn.sed"
<Location />
  SetOutputFilter cdn
</Location>

どうせなら、"mod_cloudfront"みたいなもの、作っておきたいなー。
--------
http://www.suz-lab.com

"NSMutableArray"とか"stringWithFormat"とか...

スズキです。

そろそろ、Objective-Cの文法や基本的なAPIも
わかって無いと通用しなくなってきたので...

やりたいことは、下記で紹介した、静止画のアニメーション表示で、
http://blog.suz-lab.com/2010/03/uiimageviewiphone_01.html
静止画のファイル名を配列にハードコードしていたところを、
繰り返しを用いて、もう少しスマートにできたら、って感じです。

必要な道具としては、動的に追加できる配列(のようなもの)と、
数字から、"00003"みたいな文字列を生成する、"sprintf"みたいな機能です。

調べてみると、動的に追加できる配列はNSArrayのサブクラスである、
NSMutableArrayが用意されていました。

また"sprintf"に関しては、NSStringクラスのstringWithFormatメソッドで、
同様のことが可能でした。

ということで、こんな感じのコードでやりたいことが実現できました。

--------【Objective-C】--------
NSMutableArray *images = [[NSMutableArray alloc] init];
for(int i = 0; i < 30; i++) {
  NSString *file = [NSString stringWithFormat:@"test_%05d.jpg", i];
  [images addObject: [UIImage imageNamed: file]];
}
imageView.animationImages = images;
imageView.animationDuration = 1.0f;
imageView.animationRepeatCount = 1;
[imageView startAnimating];
--------

どっかで、メモリ管理もしっかり勉強しなきゃ...

--------
http://www.suz-lab.com

2010年3月1日月曜日

UIImageViewでアニメーション(iPhone)

スズキです。

以下を発展させた内容ですが、
http://blog.suz-lab.com/2010/03/uiimageviewiphone.html
UIImageViewには連続画像をアニメーションとして表示する機能があります。

下記のようなコードで、00.png〜14.pngまでの画像を、
0.5秒でアニメーションし、さらに、それを10回繰り返すことができます。
(画像を普通に表示するコードと対応させています)

--------【画像を普通に表示】--------
- (void)viewDidLoad {
  [super viewDidLoad];
  imageView.image = [UIImage imageNamed:@"test.png"];
}
--------【画像をアニメーションと表示】--------
- (void)viewDidLoad {
  [super viewDidLoad];
  imageView.animationImages = [NSArray arrayWithObjects:
    [UIImage imageNamed:@"00.png"],
    [UIImage imageNamed:@"01.png"],
    [UIImage imageNamed:@"02.png"],
    [UIImage imageNamed:@"03.png"],
    [UIImage imageNamed:@"04.png"],
    [UIImage imageNamed:@"05.png"],
    [UIImage imageNamed:@"06.png"],
    [UIImage imageNamed:@"07.png"],
    [UIImage imageNamed:@"08.png"],
    [UIImage imageNamed:@"09.png"],
    [UIImage imageNamed:@"10.png"],
    [UIImage imageNamed:@"11.png"],
    [UIImage imageNamed:@"12.png"],
    [UIImage imageNamed:@"13.png"],
    [UIImage imageNamed:@"14.png"],
    nil
  ];
  imageView.animationDuration = 0.5f;
  imageView.animationRepeatCount = 10;
  [imageView startAnimating];
}
--------

ポイントは下記の通りです。
(1) animationImagesにUIImageの配列を代入。
(2) 上記配列の最後の要素はnilでなければならない。
(3) アニメーションの時間はanimationDurationで指定。
(4) アニメーションの繰り返し回数はanimationRepeatCountで指定。
(5) animationRepeatCountを0にすると永遠に繰り返す。
(6) [imageView startAnimating]でアニメーション開始。

2月のブログの記事数が、目標より下回ってしまった…

--------
http://www.suz-lab.com

UIImageViewで画像の表示(iPhone)

スズキです。

iPhone開発の記事は、テキストベースのブログでは表現しにくいのですが...

まず、"View-based Application"プロジェクト(Test02)を作成します。

次にヘッダファイルを以下のように、UIImageViewを宣言した形で作成します。

--------【Test02ViewController.h】--------
#import <UIKit/UIKit.h>
@interface Test02ViewController : UIViewController {
  UIImageView *imageView;
}
@property(nonatomic, retain) IBOutlet UIImageView *imageView;
@end
--------

対応する実装ファイルは、"viewDidLoad"のところで、
表示したい画像(test.png)を指定したUIImageを、
UIImageView(imageView)のimageに代入するようにします。
("test.png"はプロジェクト直下に置いてあります)

--------【Test02ViewController.m】--------
#import "Test02ViewController.h"
@implementation Test02ViewController
@synthesize imageView;
- (void)viewDidLoad {
  [super viewDidLoad];
  imageView.image = [UIImage imageNamed:@"test.png"];
}
- (void)didReceiveMemoryWarning {
  [super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
}
- (void)dealloc {
  [super dealloc];
}
@end
--------

最後にInterface Builder"の処理です。

Resources下にある、Test02ViewController.xibを選択し、
"Interface Builder"を立ち上げます。

そして、Libraryの"Image View"(UIImageView)をViewウィンドウに
ドラッグアンドドロップします。

その後、ドロップされたUIImageViewは"File's Owener"(Test02ViewController)の
Inspector上にあるOutletsの一つである"imageView"と結びつけます。
("imageView"の右端の丸をCtrl押しながら結びつけます)

これでシミュレーターなどの画像で実行すると、
"test.png"がiPhone上に表示されるはずです。

上記の説明で、未来の自分はわかるのかなー?

--------
http://www.suz-lab.com