2013/07/31

FreeNAS 8.3.1 p2 インストール

CD-ROM なしで、内蔵されてる SSD に FreeNAS をインストールする手順。

  1. USBメモリに FreeNAS の (iso ではなく) img の方を書く。
  2. USBメモリから起動して、シングルユーザモードにする。
  3. # sysctl -w kern.geom.debugflags=0x10
  4. # dd if=/dev/(USBメモリ) of=/dev/(内蔵SSD) bs=1m count=2000
ハマリポイント:
  • USBメモリに iso を書いても起動できない。(あたりまえ)
  • kern.geom.debugflags = 0x10 しないと書き込みが許可されない。

FreeNAS の第 4 パーティションを広げる手順。
  1. シングルユーザモードで起動する。
  2. # sysctl -w kern.geom.debugflags=0x10
    (ここで必要かは、正直不明)
  3. # gpart resize -i 4 -s (サイズ) /dev/(SSD)
    サイズは gpart show して表示されるサイズから計算。
    今回は少し余らせた。(growfs のバグに気づかなかった為)
  4. # newfs -L FreeNASs4 /dev/(SSD)s4
  5. # mount -uw /
  6. # mkdir mnt2
  7. USBメモリ挿入。
  8. # mount /dev/(USBメモリ)s4 /mnt2
  9. # mount /dev/(SSD)s4 /mnt
  10. # cd /mnt2
  11. # cp -a * /mnt
  12. umount するなりして再起動
ハマリポイント:

この後の手順。

  1. コンソールから、ネットワークの設定。IPv6 の設定は後からGUIでやるほうが簡単。
  2. 以下GUIから、Account - Admin Account - Change Password で パスワード設定。
  3. Network - Global Configuration から Hostname 設定。
  4. Network - Interface 設定。IPv6 設定。
  5. System - Settings - General から Language, Timezone 設定。
  6. System - Settings - Email 設定。root のメールを自分宛に設定して、テスト。
  7. Storage - Volume でボリューム作る。プールとデータセット。
  8. ssh で入れるようにする。
  9. home ごにょごにょして パッチ作るとか。
  10. /boot/loader.conf に speaker_load="YES"
  11. このへんから speaker.ko をもってきて /boot/kernel/ にコピーしておく。
    ftp://ftp.jp.freebsd.org/pub/FreeBSD/releases/amd64/ISO-IMAGES/8.3/FreeBSD-8.3-RELEASE-amd64-bootonly.iso
  12. /conf/etc/base/rc.local, rc.shutdown.local でスピーカを鳴らす。
  13. CIFSなりなんなりの設定。
    共有にアクセスするユーザを制限するには、高度な設定で、
    valid users=(ユーザ)

    ハマリポイント: CIFS 設定したあとで追加したユーザは、smbcontrol smbd reload-config しても、CIFS サービスを再起動しないと passdb を再読み込みしてくれないようで、認証に失敗する。
  14. pkg_add -r php5
  15. ftp でユーザホームではなく共通ディレクトリに chroot するには、
    <Global>
     DefaultRoot (共通ディレクトリパス)
    </Global>
    を高度な設定で追加。

正直 FreeNAS 0.7 より使いにくくなってる感。
それとも、危険な操作をできなくしたってことかなあ。

困りポイント(自業自得も含まれます):
  • ファイルマネージャが無くなった。シェルに降りないと共有用のディレクトリさえ作れない。データセットをたくさん作れ、ということなのかも。
  • php がインストールされてない。pkg_add。
  • /home が存在しないディレクトリにシンボリックリンクされてる。
  • ユーザの home に /home 以下のディレクトリを指定できない。python をパッチした。(またか)
  • /mnt で始まるマウントポイントを作ると、ディレクトリ選択肢に出るけども、設定できない。
  • 起動音、終了音が鳴らない。
  • SMARTの対象に、システムを入れたディスクが指定できない。
  • GUI、見た目はともかく、機能がしょぼい。チップヘルプも少ない感。
  • ログを GUI から確認できない。
  • GUI のツリーメニューがピヨピヨしてうざい。
  • ping とか打てない。全部シェルから。えーと。
  • シェルウィンドウはいいんだけど、設定見ながらとかできないから、ssh の設定を最優先ってことでいいですか。
  • レポートメールをいつ、なにを送るかをどうやって設定するの?
    (フォーラムでも指摘されてる。)
  • cron まんまの時間指定はどうにかなりませんか。まえも cron だったけどもう少しわかりやすかった気が。
  • ZFS 採用のくせに、メモリ使用量を確認するにはグラフを下までスクロール、とか勘弁して下さい。

良い点:
  • GUI からアップグレード出来るっぽい(やってはいない)
    なにもかもなつかしい・・・

ここまでで使えることがまあ分かったが、NAS4Free にしようか考え中。


2013/06/03

TortoiseHg 対応の Exclude エクステンション書いてみた

svn の ignore-on-commit が無くてお困りの方に。
ちょっとした代替手段の提案です。

Mercurial の Exclude エクステンション
http://mercurial.selenic.com/wiki/ExcludeExtension
を改造して、TortoiseHg に対応してみました。

対象: TortoiseHg 2.8, Mercurial 2.6
他のバージョンでは確認していないし、動く可能性も低いと思います。

ここからダウンロード
http://www.codebox.rni.jp/hgext/exclude.py

使用方法:
元の ExcludeExtension をインストールして、exclude.py を差し替えて下さい。
設定方法は元のものと同じです。

TortoiseHg の ciexclude(除外ファイル)とは以下の点が違います。

  • syntax 指定が使えます。(.hgignore と同じ書式です。)
  • exclude されたファイルは、コミットペインに表示されません。 (ciexclude はチェックが外れるだけです。)

Tips:
svn の changeset のように複数のセットを直接定義することはできませんが、カスタムツールと合わせて .hgexlcude を変更することで、(かなり遠いけれどこれまでよりは)近い雰囲気を実現できます。

まずファイルを2つ作っておきます。


.hgexclude.empty
(空のファイル)


.hgexclude.ignore-on-commit
syntax:glob
*/AssemblyInfo.cs



と用意しておいて、

cmd /c copy "{ROOT}¥.hgexclude.ignore-on-commit" "{ROOT}¥.hgexclude"

を実行するカスタムツールと、

cmd /c copy "{ROOT}¥.hgexclude.empty" "{ROOT}¥.hgexclude"

を実行するカスタムツールをそれぞれ作成します。

ボタンを押してから、更新ボタンを押します。


2013/05/27

Mercurial 運用開始までのメモ

この文書は無保証です。

要約

svn 単独で運用していた環境から、svn をメインリポジトリサーバとして使用したままで、hg を使った 分散リポジトリ環境に移行した。

キーワード

hgsubversion 拡張, largefiles 拡張, hg graft コマンド

環境と前提条件


OShg
PC1Mac OS X 10.6hg 2.5.2
PC2Windows7 Professional SP1 x86 (32bit)Tortoisehg 2.8, Mercurial 2.6
  1. PC1 と PC2 のユーザは別人である。
  2. svn サーバへアクセス出来るのは PC1 のみである (SSH 鍵の都合上)。
  3. PC2 からのコミットを検証して、PC1 から svn サーバに push する。
  4. 透過的コミットは、はなから目的としない。

結論

概要

  1. svn サーバからは必要な svn ブランチのみ clone すること。svn ブランチ間のマージは諦める。(svn でやる)
  2. svn のタグは諦める。
  3. svn との連係は default ブランチ、hg 側は base ブランチと決める。
  4. repoB は連係専用とし、repoB で通常の編集作業は行わない。 これを守ることで、repoB の default と base の間の同期作業で、graft 時にローカル変更との衝突が発生しない。

構築手順(svn ブランチごとに行う)

  1. repoB の構築
    1. hgsubversion 拡張を enable する。
    2. largefiles 拡張を enable する。
    3. hg clone svn://svnserver/repoA/svnbranch repoBS
    4. hg lfconvert repoBS repoB
    5. cd repoB
    6. cp ../repoBS/.hg/hgrc .hg/hgrc
      (済んだら repoBS は消して良い)
    7. hg svn rebuildmeta
    8. hg up
    9. hg branch base
    10. hg commit -m 'create base branch'
    11. hg serve --port 8881
      ポート番号はブランチごとによしなに決める。
  2. repoC の構築
    1. hg clone repoB repoC
    2. hg up -r base
  3. repoD の構築
    1. hgsubversion 拡張を enable する。
    2. largefiles 拡張を enable する。
    3. hg clone http://PC1:8881/ repoD
    4. hg up -r base

運用手順

  1. repoB から svn に push する
    1. hg up -r base
    2. よしなに確認する。
    3. hg up -r default
    4. hg graft -r 'branch(base)'
    5. hg outgoing
      最終確認する
    6. hg push
  2. repoB に svn repoA から pull する
    1. hg up -r default
    2. hg incoming
    3. hg pull
    4. hg up -r base
    5. hg graft -r 'branch(default)'
  3. repoC, repoD での通常作業
    1. base ブランチに対してcommit。base ブランチからさらにブランチしてもよい。 base ブランチの内容だけが svn への push 候補となる。
    2. 普通に push, pull する。

知識とは失敗である、その手順

失敗: largefiles 拡張が必要

まずなにも考えず hg clone で svnリポジトリ全体をクローンする。

  1. PC1
    1. hgsubversion 拡張を enable する。
    2. hg clone svn://svnserver/repo1 repo1
      →成功。2時間ぐらいかかった。
    3. cd repo1
    4. hg serve --port 8881
  2. PC2
    1. hg clone http://PC1:8881/ repo1
      →数十分後に OutOfMemory の Python 例外

調べたり聞いたりしたところによると、hg が想定しているファイルサイズは <10MB だそうで。 ファイルを全部メモリに展開するみたいで、32bit OS では Python のアドレス空間が不足する。

Twitter で愚痴を言ってみたところ、、、

@flyingfoozy さんご親切にありがとうございました。

というわけで largefiles 拡張が要るとのこと。
→やりなおし

失敗: hg lfconvert + hg svn rebuildmeta の罠

  1. PC1
    1. largefiles 拡張を enable する。
    2. hg clone svn://svnserver/repo1 repo1S
    3. hg lfconvert repo1S repo1
    4. cd repo1
    5. hg pull
      →エラー。paths の設定は lfconvert で引き継がれていない、というか hgrc がコピーされない。
    6. cp ../repo1S/.hg/hgrc .hg/hgrc
    7. hg pull
      →svn のリビジョンをもう一度全部 pull して来ようとする。

lfconvert したリポジトリは repo1S とは全く別のリポジトリで、ハッシュ値も全く違うものになる。 なのでリポジトリ内の clone した時のリビジョンと、svn の対応リビジョンの情報が一致しなくなり、 hg pull (incoming) で見える svn 側のリビジョンは別のものとして扱われてしまう。

→hg svn rebuildmeta

失敗: hgsubversion default ブランチの罠

hgsubversion 拡張は default ブランチを svn との連係に使用するが、svn にはマージリビジョンの 概念がないので、マージリビジョンがあると push できない。

さらに

  • うっかりローカル変更があると、svn 側と衝突したときのマージが面倒。
  • commit 後、svn に push するとハッシュ値やユーザ名が svn 側のものに変わる。
    →push するまでハッシュが確定しない。したがってリビジョンを参照する(ログに関連リビジョンのハッシュを記載する)ことは不可能。

世の中を見ると、merge - commit - revert する方法が提案されていて、確かに可能だが、

  • 複数のコミットで構成されるマージの場合、コミットがまとめられてしまう。
  • 一つ一つのコミットを svn に送信したい場合は、一つづつ merge - commit - revert しなければならない。
  • commit ログをもう一回入力しなければならない。
  • リビジョングラフの形が気持ち悪い。
    (イマイチ理解していないのでどこか間違ったのかもしれない)

さらに世の中には rebase する方法も提案されているが、試すより先に graft を思いついたので試していない。

default には merge するな、あそこは svn なのだ

解決策

  • default ブランチは svn との連係専用にしてここで編集しない。
  • repoC, repoD でのコミットは、base ブランチに行う。default は(過去ログ以外)見ない。
  • graft を使う。この場合、default ブランチと base ブランチはリビジョングラフ上で交差しない。
    これは嫌な人には嫌だろうが、今回のケースでは svn に push したコミットの author が書き換えられるため、 同じ変更でも別のコミットに見えてくれる方が都合が良く、怪我の功名。

graft は今回の用途には非常に都合よくできていて

  • マージリビジョンは無視される。
  • graft したリビジョンは記録されていて、何回も graft されるようなことはない。
  • コミットログはそのままコピーされる。

失敗: 非標準レイアウトの罠

非標準レイアウトの場合 hgsubversion は全てのブランチとタグを通常のディレクトリとして svn から取得する。

これは svn の ブランチとタグが只のコピーと区別がつかないせいだが、clone したディレクトリが 恐ろしく肥大化してしまい、何をしても時間がかかるようになってしまう。

解決策

  • 個別のブランチを svn から取り出す。svn ブランチ間マージは hg では実行しない。

2013/05/13

Mercurial at Win7 x86 の Out Of Memory error

pulling from http://x.x.x.x:y/
searching for changes
adding changesets
adding manifests
adding file changes
transaction abort!
rollback completed
Traceback (most recent call last):
  File "mercurial¥dispatch.pyo", line 88, in _runcatch
  File "mercurial¥dispatch.pyo", line 771, in _dispatch
  File "mercurial¥dispatch.pyo", line 540, in runcommand
  File "mercurial¥dispatch.pyo", line 866, in _runcommand
  File "mercurial¥dispatch.pyo", line 837, in checkargs
  File "mercurial¥dispatch.pyo", line 766, in 
  File "mercurial¥util.pyo", line 506, in check
  File "mercurial¥extensions.pyo", line 143, in wrap
  File "mercurial¥util.pyo", line 506, in check
  File "hgext¥largefiles¥overrides.pyo", line 733, in overridepull
  File "mercurial¥util.pyo", line 506, in check
  File "mercurial¥commands.pyo", line 4543, in pull
  File "mercurial¥localrepo.pyo", line 1692, in pull
  File "mercurial¥localrepo.pyo", line 58, in wrapper
  File "mercurial¥localrepo.pyo", line 2330, in addchangegroup
  File "mercurial¥revlog.pyo", line 1244, in addgroup
  File "mercurial¥revlog.pyo", line 1115, in _addrevision
  File "mercurial¥revlog.pyo", line 1026, in compress
MemoryError
abort: out of memory