2010/08/30

VirtualBoxでのCentOSインストールの自動化

Mac(Mac mini; MacOS X 10.6.4)で動いているVirtualBoxで、kickstartの仕組みを使ってCentOSのインストールを自動化しようとしてみました。

ただ手続きが多いので、基本的な動きを確認するためにVMを起動すると自動でCentOSのインストールが開始するところまでを確認しました。

全体の流れ

Kickstartを自動で開始するディスクの作成

mkisofsコマンドをmacportなどで導入すればMacでも可能そうでしたが、面倒なのでここだけはlinux(Ubuntu 10.04 LTS)で作業しています。

$ sudo mount -o loop CentOS-5.5-x86_64-netinstall.iso /mnt/iso
$ mkdir centos55netinst
$ cd  centos55netinst

/mnt/iso以下はread-onlyなので、作成したディレクトリにコピーを作成します。

$ rsync -av /mnt/iso/. .

自動的にKickstartを開始するようにisolinux.cfgファイルを編集します。

$ vi isolinux/isolinux.cfg

isolinux/isolinux.cfgファイル

default linux
prompt 1
timeout 10
display boot.msg
F1 boot.msg
F2 options.msg
F3 general.msg
F4 param.msg
F5 rescue.msg
label linux
  kernel vmlinuz
  append initrd=initrd.img ks=hd:fd0:/ks.cfg
label local
  localboot 1
label memtest86
  kernel memtest
  append -

isolinux.cfgだけを変更したISOイメージを ../centos55netinst.img に作成します。

$ sudo mkisofs -R -J -no-emul-boot -boot-load-size 4 -boot-info-table -o ../centos55netinst.img -c isolinux/boot.cat -b isolinux/isolinux.bin .

mkisofsのオプションは使い方によって、 -T , -p といったオプションを工夫しても良いかもしれません。

ks.cfgファイルの準備

一度は手動でCentOSを入れると配置される /root/anaconda-ks.cfg ファイルをベースにしました。

サーバにするために不要なものをいろいろ省くと次のようになります。

ks.cfgファイル

# Kickstart file automatically generated by anaconda.
install
url --url http://rsync.atworks.co.jp/centos/5.5/os/x86_64
lang en_US.UTF-8
keyboard us
network --device eth0 --bootproto dhcp --hostname centos.vb.localdomain
rootpw --iscrypted $1$./9drDbb$nWXlnh/h4517xgxRZBTsS/
firewall --enabled --port=22:tcp
authconfig --enableshadow --enablemd5
selinux --permissive
timezone --utc Asia/Tokyo
bootloader --location=mbr --driveorder=sda
text
halt
# The following is the partition information you requested
# Note that any partitions you deleted are not expressed
# here so unless you clear all partitions first, this is
# not guaranteed to work
clearpart --all --drives=sda --initlabel
part /boot --fstype ext3 --size=100 --ondisk=sda
part pv.2 --size=0 --grow --ondisk=sda
volgroup VolGroup00 --pesize=32768 pv.2
logvol / --fstype ext3 --name=LogVol00 --vgname=VolGroup00 --size=1024 --grow
logvol swap --fstype swap --name=LogVol01 --vgname=VolGroup00 --size=512 --grow --maxsize=1024

%packages
@base
@core
@network-server
@server-cfg
@text-internet
@web-server
keyutils
trousers
fipscheck
device-mapper-multipath
openssh-server

起動すると自動的にパーティションの削除から開始するため、意図せずにディスクの内容を削除してしまう可能性がそれなりにある点に注意してください。

フロッピーイメージの作成

Mac上でフロッピーイメージを作成するには、いくつかの方法がありましたが、今回は自動化するためにコマンドラインで出来る方法を採用しました。

カレントディレクトリにks.cfgがあると仮定して、floppy.imgを作成し、その中にks.cfgをコピーするところまでを試しています。

$ dd if=/dev/zero of=floppy.img bs=1024 count=1440
$ hdiutil attach -nomount floppy.img | while read dev
do
  newfs_msdos -f 1440 -v centos55 $dev
  hdiutil detach $dev 
done
$ hdiutil mount floppy.img | while read dev fs
do
  cp ks.cfg $fs
  hdiutil detach $dev
done

さいごに

作成したファイルを使って、VirtualBoxのインスタンスを起動すると自動的にインストールが完了しました。

とはいえ、インスタンスの設定ではいくつか必要な操作があります。

  • 起動順から「フロッピー」を削除
  • 「フロッピーコントローラ」の追加
  • 「フロッピーコントローラ」直下のks.cfgを含むfloppy.imgの追加

あとはVirtualBoxにインスタンスの構成を行なって、カスタマイズしたks.cfgを作成すれば自動的にインスタンスを増やす事は何とかなりそうです。

2010/08/24

MacでVirtualBoxをコマンドラインから操作してみる

MacOS X 10.6上のVirtualBoxをコマンドラインから操作してみようと、VirtualBox SDKを触り始めました。

SDKのリファレンスにあるサンプルを少し動かそうとしただけで、Macだと戸惑うところがでてきます。

サンプルプログラムの起動

SDK付属のPDFファイルにある「2.1 The object-oriented web servvice for JAX-WS」に従って進めていきます。

作業はコマンドラインが必要で、ターミナルでも良いと思いますが、 iTermを使いました。

JAX-WSを使うためにJDK 6の確認

MacOS X 10.6では普通にJDK 6が使えるので、確認だけしておきます。

$ java -version
java version "1.6.0_20"
Java(TM) SE Runtime Environment (build 1.6.0_20-b02-279-10M3065)
Java HotSpot(TM) 64-Bit Server VM (build 16.3-b01-279, mixed mode)
vboxwebsrvコマンドの起動

マニュアルではコマンドのある場所に移動して、$ ./vboxwebsrv -vとタイプするように書かれています。

ただ素直に場所を探そうとすると、地味に面倒だったりします。

MacOS Xの場合はFinderから起動するプログラムはディレクトリで、必要なリソースのパッケージになっています。 そのため普通に画面右上のspotlightウィンドウでコマンド名を検索しても隠されてしまい表示されません。

こんな場合は、linux同様にlocateコマンドですが、macの場合は最初にデータベースをアップデートするようにメッセージが表示されます。

$ sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.locate.plist

データベースが作成されるのを待ってから、locateコマンドを打ってみます。

$ locate vboxwebsrv
/Applications/VirtualBox.app/Contents/MacOS/vboxwebsrv
/Applications/VirtualBox.app/Contents/MacOS/vboxwebsrv-amd64
/Applications/VirtualBox.app/Contents/MacOS/vboxwebsrv-x86
/usr/bin/vboxwebsrv

マニュアルにはコマンドのある場所に移動するよう書かれているので、次のようなコマンドを実行しました。

$ cd /Applications/VirtualBox.app/Contents/MacOS
$ vboxwebsrv -v

ちなみにmdfindを使うとスポットライトと同じような出力になるはずですが、次のように少し違った結果になります。

$ mdfind vboxwebsrv
/Users/user01/Programming/VirtualBoxSDK/bindings/webservice/java/jax-ws/samples/metrictest.java
/Users/user01/Programming/VirtualBoxSDK/docs/SDKRef.pdf
/usr/bin/vboxwebsrv

どちらの結果でも、標準的な場所にvboxwebsrvコマンドを見つける事ができますが、後で実験したところ単純にホームディレクトリでvboxwebsrvを実行すると問題が起こりました。

コマンドの実行

マニュアルにある通り、makeコマンドを打つと、 show vms の結果が表示されるはずです。

しかし実際にはプログラムの中にユーザ名とパスワードの組が書かれているため、そのまま実行すると次のようなエラーメッセージで失敗します。

Exception in thread "main" javax.xml.ws.WebServiceException: org.virtualbox_3_2.InvalidObjectFaultMsg: VirtualBox error: Invalid managed object reference ""
        at com.sun.xml.ws.commons.virtualbox_3_2.IVirtualBox.getVersion(IVirtualBox.java:56)
        at clienttest.<init>(clienttest.java:47)
        at clienttest.main(clienttest.java:291)
Caused by: org.virtualbox_3_2.InvalidObjectFaultMsg: VirtualBox error: Invalid managed object reference ""
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
        at com.sun.xml.internal.ws.fault.SOAPFaultBuilder.createException(SOAPFaultBuilder.java:130)
        at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:108)
        at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:78)
        at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(SEIStub.java:107)
        at $Proxy33.iVirtualBoxGetVersion(Unknown Source)
        at com.sun.xml.ws.commons.virtualbox_3_2.IVirtualBox.getVersion(IVirtualBox.java:53)
        ... 2 more
make: *** [run16] Error 1

修正した部分の差分は次のようになりました。

--- clienttest.java.orig        2010-08-24 14:23:05.000000000 +0900
+++ clienttest.java     2010-08-24 14:24:49.000000000 +0900
@@ -43,7 +43,7 @@
     public clienttest()
     {
         mgr = new IWebsessionManager("http://localhost:18083/");
-        vbox = mgr.logon("test", "test");
+        vbox = mgr.logon("username", "password");
         System.out.println("Initialized connection to VirtualBox version " + vbox.getVersion());
     }

必要な修正をして準備が出来たら、次のように実行します。

$ make run16
java -cp ../lib/vboxws_java16.jar:./gen16 clienttest show vms
Initialized connection to VirtualBox version 3.2.8
Machine 0:  [a2c4fdbc-86c1-4480-806d-fbe6b77005b7] - ubuntu804.x86_64
Machine 1:  [d1b95e67-3005-4279-bb9b-f723433fbe0b] - CentOS
Logged off.

もしホームディレクトリでvboxwebsrvを起動してしまうと、次のようなエラーが表示されます。

$ make run16
java -cp ../lib/vboxws_java16.jar:./gen16 clienttest show vms
Exception in thread "main" javax.xml.ws.WebServiceException: org.virtualbox_3_2.InvalidObjectFaultMsg: VirtualBox error: Invalid managed object reference ""
        at com.sun.xml.ws.commons.virtualbox_3_2.IVirtualBox.getVersion(IVirtualBox.java:56)
        at clienttest.<init>(clienttest.java:47)
        at clienttest.main(clienttest.java:291)
Caused by: org.virtualbox_3_2.InvalidObjectFaultMsg: VirtualBox error: Invalid managed object reference ""
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
        at com.sun.xml.internal.ws.fault.SOAPFaultBuilder.createException(SOAPFaultBuilder.java:130)
        at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:108)
        at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:78)
        at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(SEIStub.java:107)
        at $Proxy33.iVirtualBoxGetVersion(Unknown Source)
        at com.sun.xml.ws.commons.virtualbox_3_2.IVirtualBox.getVersion(IVirtualBox.java:53)
        ... 2 more
make: *** [run16] Error 1

この時のvboxwebsrv側のエラーメッセージは次のとおりです。

2010-08-24 14:05:47 [ P ] Request 1 on socket 9 queued for processing (1 items on Q)
2010-08-24 14:05:47 [  1] New SOAP thread started
2010-08-24 14:05:47 [  1] Processing connection from IP=127.0.0.1 socket=9 (0 out of 1 threads idle)
2010-08-24 14:05:47 [  1] -- entering __vbox__IWebsessionManager_USCORElogon
2010-08-24 14:05:47 [M  ] Pumping COM event queue
2010-08-24 14:05:47 [M  ] Pumping COM event queue
2010-08-24 14:05:47 [  1] external authentication library is 'VRDPAuth'
2010-08-24 14:05:47 [  1] authenticate() Failed to load external authentication library. Error code: VERR_FILE_NOT_FOUND
2010-08-24 14:05:47 [  1] Could not resolve VRDPAuth2 or VRDPAuth entry point2010-08-24 14:05:47 [  1] -- leaving __vbox__IWebsessionManager_USCORElogon, rc: 0x0
2010-08-24 14:05:47 [  1] -- entering __vbox__IVirtualBox_USCOREgetVersion
2010-08-24 14:05:47 [  1]    findRefFromId(): looking up objref 
2010-08-24 14:05:47 [  1] -- leaving __vbox__IVirtualBox_USCOREgetVersion, rc: 0xFFFFEF33 (-4301)

エラーメッセージのポイントはauthentication()の呼び出しで VERR_FILE_NOT_FOUND が発生しているところかと思われます。

その他のサンプル

PDFには$ java clienttestの引数を変えて実行すると、コマンドの振舞いが変ると書かれていますが、細かい実行方法には振れられていません。 まぁそれぐらい分かる人が相手なんでしょうけどね。

ここでは$ make run16の出力をコピーして、必要なクラスパス(-cp)の設定を使って、試す事にします。

$ java -cp ../lib/vboxws_java16.jar:./gen16 clienttest list hostinfo
Initialized connection to VirtualBox version 3.2.8
Processor count: 2
Processor #0 speed: 2260MHz
...
Logged off.

さいごに

目的はコマンドラインでkickstartを使ってCentOSを導入するところなのですが、長くなったのでとりあえず次回にすることにします。

2010/08/20

GUI版Emacs用の設定まとめ

もはや、わざわざ「GUIなEmacs」とかいうと変な目でみられそうです。

今回使った(if window-system ...というコードも、なぜ必要なのか説明しても分かってもらえないかもしれないですね。

さてLispなどの関数系言語では、BASIC同様に関数をいくら覚えられるかが勝負のようなところがあって、 いろいろメモを残しておかないと二度手間な作業が多く発生します。

ということで、Emacsのカスタマイズしたことをメモにしておきます。

ウィンドウサイズの変更方法

普通はウィンドウの位置やX Window System (X11)の環境では geometry オプションでサイズ(<width>x<height>+<x>+<y>)を指定します。

$ emacs -geometry 110x50-110+0

他にもxrdbを使ってX11のResource Managerの仕組みを使う事もできますが、システムの/etc/X11/Xsession辺りの設定によって読み込まれるファイルが変化したりするので、あまりお勧めできなさそうです。

ただ設定されているリソース自体は確認しておいた方が良いかもしれません。

$ xrdb -all -query

さて、 geometry を使うのは、いろいろなスクリプトからemacsを起動するようにしているので変更箇所が多くなってしまいそうです。 そこで~/.emacsで好みの画面サイズを指定しようと思いました。

結論からいえば、フォントの設定を含めて次のようなコードを~/.emacsに追加しました。

~/.emacsファイルから抜粋


;; GUI mode setting
(if window-system
  (progn
    ;; set font size
    (set-default-font "7x14")
    
    ;; set window size
    (setq initial-frame-alist
      (append initial-frame-alist
        (list
          '(left . -120)
          '(width . 110)
          '(height . 50)
         )))
      
    ;; end of progn
   )
  ;; for non-x11 environment
  (setq initial-frame-alist
    (list
      '(menu-bar-lines . 0)
      '(tool-bar-lines . 0)
    )))

最後の部分はif文のelse節に相当する部分で、キャラクタ端末上でemacsを動かした時に最上部に1行表示されるメニューを消しています。

手元の~/.emacsでは(load-file "~/.emacs-skk")のようなモード別に設定ファイルを分けてロードしているので、画面設定も別ファイルにしようかと思ったのですが、いまのところ~/.emacsに含めています。

大学の頃はmuleとemacs19を使い分けるために、設定ファイルは別々で、大学がデフォルトで配布していた~/.emacsファイルはシンプルなものでした。

環境によっては~/.emacsが適当な設定ファイルでない環境も、まだあるんでしょうね。

2010/08/19

プレゼント用のペンケースを探して、市内散策。

あまり実生活についての投稿はしないのですが、ほぼ一日を費してしまったのでまとめておきます。

普段、自分で使う文房具は100円ショップなり、カインズホームなんかのPB商品で十分なのですが、プレゼントにしようとすると、ビニールとか、キャラクターものっていうわけにはいかないものです。

特にペンケースなんていうのは、自分で使うならビニールポーチぐらいで代用してしまいますから、お店にもそれほど数が並んでいません。

デザインと値段のバランスを考えると、コクヨのペンケースシリーズぐらいでも良いのですが、それすら揃えているお店はないですね。

目的のペンケースの条件

条件はペンが7本ぐらいに定規、消しゴム、シャープペンの芯ケース、定規ぐらいは十分に入ること。

今回は以前プレゼントしたバーバリーのペンケースのリプレース用なので、17mmx10mmぐらいのサイズが最低でも必要です。

さらに革製品である必要性はなくて、実用的で作りの良いものにしようと思いました。

市内でプレゼント的な文房具を売っているお店

新潟や関東、中部圏にあるアピタという商業施設が会津若松にありますが、プレゼントにできるような入れ物は、鞄とお財布ぐらいしか扱っていないのが悲しいところです。

市内でブックカバーとかペンケースとか、古典的な文房具を買おうと思えば「オサダ」という以前からある文具店が、ほぼ唯一といっていい選択肢だと思います。

ただ万年筆やボールペンを入れるだけの小さいものや、薄いものはあるのですが、ある程度の容積があってプレゼントにも向くようなものは見つけられませんでした。 革製品は見た目にはリッチですが、伸縮はしないので幅や入口が狭いものを却下すると、ほとんど選択肢がありませんでした。

Webでペンケースを探してみた

地元経済のためには手近なお店で買い物ができると良かったのですが、Amazonやら楽天やらで検索してみました。

どうも値段が高めのものはサイズが小さかったり、入口の作りが見た目に狭かったり、実用性を考えるといまいちなものが目立ちました。しっかりはしているんでしょうけどね。

革製品でファスナーが広く付けられているものは、日本製でもむしろ値段が安いぐらい。

でも革にしろ布にしろ生地がペナペナだと困ってしまうので、通販だとそこら辺が確認できないのがちょっと不安でした。

最終的に選んだペンケースは…。

普段使っている ブックカバーがUNITED BEES製なのですが、探しているうちにペンケースも売っていることが分かったのでそれに決めました。

ブックカバーとしては生地がとてもしっかりしているのが気に入っていたので、懸念はありませんでした。 最終的にはサイズいくつか選べるところが決め手になりました。

プレゼントには値段的にも素材的にも少し迷ったのは事実ですが、長く使えて実用的なものという点では満足しています。実際にどれくらい使えるかは、しばらく様子見ですけどね。

それにしても会津若松市内で文房具を買うのに苦労するとは思いませんでした。 プレゼントにする雑貨ならいくつかお店があるんですけどね。

プレゼントは足を使って探すしかないんですよね。 インターネットで手に入るとはいっても、その商品がどういうものかある程度知っていないと怖いところがあるなと感じました。

この記事で取り上げた品々

2010/08/01

一人で開発しているSVNリポジトリで必要な操作

subversionを使う場合は、一応標準的な使い方としてトップディレクトリに trunk , tags , branches のディレクトリを配置する使い方が良く説明されています。

とはいえ、実際にはただのディレクトリなので、いきなりトップレベルにmain.cppやらのファイルを作成することもありました。

そんな風に開始したプロジェクトが案外規模が膨らんできたので、リリース毎にコードをまとめたいと思い、 trunktags ディレクトリをトップレベルに作成することにしました。

trunk, tagsディレクトリの追加

トップディレクトリで開発をしている場合には、後からsvn copyを使ってプロジェクト全体のコピーを作る事が難しくなります。

svn copyを実行して出来るものはただのディレクトリなので、サブディレクトリに含める事もできますが、いたずらにコードサイズが増えることになるのと、管理単位として性質の違うものが同居するのは避けたいところです。

既存ファイルのtrunkディレクトリへの集約

まずは全てのファイルをSVNの管理下に置き、コミットしておきます。

必要であれば後述するignoreプロパティを適切に設定して、svn statusを実行して何も表示されない状態にしてから作業を開始します。

$ mkdir trunk tags
$ svn add trunk tags
$ svn commit -m 'added directories for version control.' 

次に漏れのないようにtrunk, tags以外のファイル、ディレクトリを trunk ディレクトリに移しました。

$ svn move README.txt *.cpp *.h *.ui *.pro trunk
$ svn commit -m 'Moved all files into the trunk directory.'
タグを付ける

最後にtagsディレクトリに現在の最新版のコピーを作成し、バージョンを付けます。

$ svn copy trunk/. tags/release-0.1a
$ svn commit -m 'Tagging the 0.1a release'

Googleでsvn move(svn mv)コマンドの使い方を調べてみると、URLでリポジトリを指定してサーバ側で作業をする方法が紹介されています。

svn moveコマンドに関しては手元で作業をしてコミットしても、多少の無駄はあるかもしれませんが、問題にはならないのではないでしょうか。

tagsとdiffを取ってみる。

svn diffコマンドを使ってtags/以下の特定のバージョンと、最新版の比較をしようと思った場合には、サーバ側のリポジトリを指定して実行する必要があります。

手元のコードと、過去の特定バージョンとの比較は次のようにします。

$ cd trunk/
$ svn diff --old http://svn.localdomain/svn/proj01/tags/release-0.1/. --new .

ただし、次のコマンドは失敗します。

$ cd trunk/
$ svn diff --old ../tags/release-0.1/. --new .

差分を取るには、過去のある時点のリポジトリをURLベースで指定する事が必要です。

無視するファイルの設定

一律 *~ ファイルを無視するようなルールは、個別に設定する必要がないので ~/.subversion/config ファイルに記述することができます。

~/.subversion/confiファイルへの無視ファイルルールの追加

[miscellany]
global-ignores = *.bak *.o *.lo *.la #*# .*.rej *.rej .*~ *~ .#* .DS_Store *.log *.pyc

問題は特定のディレクトリにあるファイルの中で、svnに無視させたいファイルがある場合の設定方法です。

もしファイルが一つであればsvn propsetコマンドを使います。

$ svn propset svn:ignore blog.rnc .
複数ファイルにsvn:ignore属性を追加する

言葉で書くと上のような表記になりますが、正確には「カレントディレクトリのsvn:ignore属性に複数ファイルを追加する」です。

例えば次のようなコマンドは常に最後に実行したファイルだけが優先されます。

$ svn propset svn:ignore blog.rnc .
$ svn propset svn:ignore blog.xsd .

コミットせずに現状を調べてみます。

$ svn status
 M      .
?       blog.rnc

本当はblog.rnc と blog.xsdの2つのファイルを無視したかったのですが、実際に無視されているのは最後のコマンドで指定したblog.xsdのみです。

複数のファイルを設定するには、propeditを使いましょう。

$ svn propedit svn:ignore .

コマンド実行後にエディタが開いた直後の様子

blog.xsd

この状態からファイルを追加して、保存し終了します。

編集後の

blog.xsd
blog.rnc

他にも無視させたいファイルがあれば1行1ファイルのパターンで、どんどん追加していけます。

この状態で先ほどと同じようにして、ちゃんと無視されているかコミット前に確認しておきましょう。

$ svn status
 M      .

けど、ここでviが開いて驚いたりする人っていないんですかね。 自分のスキルに合わせてEDITOR環境変数を適切に設定しておきましょう。