ペンギンと愉快な機械の日々 http://d.palmtb.net/ I use technology to make life more convenient. en-us Sun, 26 Mar 2017 00:00:00 +0900 http://d.palmtb.net/2017/03/26/my_daughter_began_playing_scratch_on_debian.html http://d.palmtb.net/2017/03/26/my_daughter_began_playing_scratch_on_debian.html <![CDATA[My daughter began playing Scratch on Debian]]> My daughter began playing Scratch on Debian

先日、こんな tweet をしました。

昨夜、おまめ一号が私のMacBook Pro を時々覗き込みながら何か描いているなと思ってたら「パパと同じパソコン作ってるの」と。 誕生くらいでデビューだ!と妄想したが早すぎて保留にしていたDebian デビュー、そろそろ頃合いかも。古いMacBookにSidインストールするか。

ということで、おまめ一号に使っていない古いMacBookを与えてみました。

../../../_images/omame-20170326_01.jpg

testing 用のCDイメージ を CD-RWに書き込み、グラフィカルモードでおまめ一号と一緒にインストールをしました。といってもおまめ一号にやらせたのは、

  • Enterキーを押す
  • 自分のユーザー名の設定
  • パスワードの設定

くらいですが。

インストールに関する余談

今回、おまめ一号にあげた MacBookは、Jessieがまだ次期stable だったときにSid化していたので、クリーンインストールする前にアップグレードを試してみました。

APT Lineを unstable から jessieに変更し、stableとして一度 update, dist-upgradeし、testing, unstableとステップ踏んでアップグレードしてみたのですが、途中余計なパッケージをお掃除しながらやっていたのもあったせいか、Xは起動しないは、systemd-fsckがコケるので起動時にメンテナンスモードに入ってしまう、という問題がありました。

なので、結局クリーンインストールで逃げました。Palm Pre用にPalm SDKをインストールしていて、このパッケージの依存関係が壊れてアンインストールできなくなったり、私が使っていたデータが残っていたりするので、子供に遊ばせるにはどのみちクリーンインストールの方が都合がいいので。

すでにメンテナンスされていない rEFIt から LILO 経由で Debianを bootしていたので、 rEFInd にしたほうが良いかなぁと思ったものの、そのままインストールして、特に問題なかったのでそのまま rEFItを使っています。

インストールに関する備忘録

次回やるときにまた忘れそうな箇所のメモ

  • Broadcomの無線LANのファームウェアは Debianインストーラーには含まれていないのでとりあえず無視
  • Disk Partitioning で、boot (/dev/sda3) は、EFI boot パーティショニングになっていたので、 ext3ファイルシステムに、マウントポイント
  • GRUBのインストールは /dev/sda3に指定、EFIリカバリディスクはチェック入れておいたけど、まぁとりあえず今回は関係ないかな
  • nVidia絡みは最新のDebianインストーラーだと、とくに設定不要でXを起動できる(楽になったもんだ)

Scratchインストールして遊ばせてみた

デスクトップ環境は私と同じ Awesomeにしようかな、と思ったけどやめておいてMATEにしました。ログイン後が若干もっさりしている感じはあるもののまぁ子供に使わせるには良さげ。 DebianパッケージでScratchをインストールをインストールした後、遊ばせる前に以下を教えました。

  • 電源アダプターの接続、RJ-45ポートにイーサネットケーブルを接続
  • 電源の入れ方
  • ログイン方法(インストール時に自分でユーザー名、パスワードを設定させたのはこのため)
  • Scratchの起動方法
  • Scratchでのプロジェクトの保存方法
  • Scratchの終了方法
  • 画面ロック方法(おまめ二号が勝手にいじるのを防ぐため)
  • 画面ロックの解除方法
  • シャットダウン方法
  • 片付け方
  • やってはいけないこと(物理的に壊すこと)

セキュリティに関することは追々教える感じですかね。

私自身がScratchを使ったことがないので、最初は一緒にちょっと操作方法を見て、あとは勝手に遊ばせてみたのですが、どこから見つけるのかちょっとテンプレートの画像を開いて勝手に遊んでいて、子供はすごいなぁと思いました(小並感)

../../../_images/omame-20170326_02.jpg
]]>
Sun, 26 Mar 2017 00:00:00 +0900
http://d.palmtb.net/2017/01/03/aspiration_of_the_2017.html http://d.palmtb.net/2017/01/03/aspiration_of_the_2017.html <![CDATA[Aspiration of the 2017]]> Aspiration of the 2017

あけましておめでとうございます。今年もよろしくお願いします。

今回の年末年始の休みは割と予定通り以上に家事等をこなせました。良かった良かった。 しかし悲報。明日から仕事です。マンションのシャトルバスも明日はまだ休みなのに。シクシク。

今年の抱負

昨年末の振り返りでも書きましたが、大病こそしなかったものの体調崩したり、仕事の比率が高くなって家庭に悪影響を及ぼしてしまったことなどがありました。今春、おまめ二号が幼稚園入園し、一号二号とも幼稚園でこれからいよいよ元気真っ盛りです。一方自分や妻の体力的な回復はますます遅くなってきています。20代の頃と違って、一時的に無理をすると、そのいっときは良いのですが、その後の回復に時間がかかります。長期的に見ると非常に無駄です。家庭も仕事もプライベートも一定のペースで継続することがますます重要だと感じています。恒常的に成果を出しつづけるのは、一時の頑張りで成果を出すよりも難しいものですし。

ということで、公私とも恒常的に成果を出していくために、「 無理しない。体調を崩さない。適度に体力増進に努める 」を抱負にします。

(KP)T

目標としては昨年末に振り返りをしたKP(T)を踏まえてのTryとして挙げてみます。

  • 8時間睡眠および朝型生活の維持
  • 残業しない
    • 気づくとつい30分〜1時間くらい残業してしまうことがあるので、これは本当に気をつけないと
  • 英語の学習再開、継続
    • 先日のMini Debian Conference Japan 2016の運営で、このままではあかん、と思いました
    • 前職ではまだ同じチームに英語で話をする外国人の同僚がいたのですが、今は全く使わないので本当にまずい
  • プライベートでのコーディングの時間確保のやり方を変える
    • フリーソフトウェアのコーディングに費やす時間は、以前は30分ないし1時間単位で確保していました。が、これを10分単位で確保し、その単位で手を動かせるように変えてみることにします
    • 今までMacBook Pro 15’を使っていましたが、これも携帯性を重視したものに変更しようかなぁ。職場のPCと2台持ち歩くのはしんどいし。
    • メンテナンスしているDebianパッケージ以外で、自分がよく使っているソフトウェアでも、お手伝いする時間を作ってみようかなと、今回の年末年始のお休みでちょっと思ったり
  • Debian JP Projectのサーバー移行の残作業
    • やらんとなぁ…
]]>
Tue, 03 Jan 2017 00:00:00 +0900
http://d.palmtb.net/2016/12/29/review_the_2016.html http://d.palmtb.net/2016/12/29/review_the_2016.html <![CDATA[Review the 2016]]> Review the 2016

昨日で(在宅勤務でしたが)仕事納めでした。短いですが今日から休みです。年末年始ってやること多くて休んだ気にならないのが悩みの種です。

さて、恒例ですが今年の振り返りをしてみました。

2016年の抱負はこちら。 Aspiration of the 2016

今年の抱負は実現できましたか?

今年の抱負は「家族皆健康第一、短い時間できっちり成果出す」でした。

私自身の健康

私は昨年よりあまり病院行っていないような気がしていたのですが、家計簿見たら、季節の変わり目に体調崩したり、持病が悪化したりして、通院したりで、 掛かった 医療費は昨年とあまり変わりません でした。

生活習慣としては次の二点を変えました。 眼鏡を常用するようになった こと、食事だけでなく 睡眠時の姿勢を気をつけるようになった こと。

もともと視力は両目で0.7はあったので、運転時以外の普段は眼鏡を掛けていなかったのですが、乱視があるなら常用した方が良いと指導されました。このおかげで、 夕方になると酷くなっていた緊張性頭痛や、偏頭痛がほとんどなりました 。もっと早くから眼鏡掛けていれば良かったですね。

後者は3,4年前からある持病が時々酷くなり、その都度通院して服薬する、という状況なのですが、 睡眠時の姿勢を気をつけることで、だいぶ体調が良くなりました

家族の健康

家族では、というと は年末に感染症胃腸炎で寝込み、 長女のおまめ一号 は今年も幼稚園の運動会のときに風邪を引いて参加できませんでしたが、それ以外は 概ね良好 でした。

次女のおまめ二号 は、昨年見つかった病気の治療は終わり、それによる症状は中程度から軽度に改善しました。一方、そのうち出るかもしれないと言われていた別の症状が年明けすぐくらいに見つかりました。これは毎日服薬することで症状は治まっています。もう一つ、昨年くらいからもしかして?と思っていた別の症状が年末に確定したものの、恒常性ではないので現時点では様子見で良さそうです。子供(特におまめ二号)はいろいろあり大変ですね。

そして、もう一匹の家族である、 こまめ 。2月に 胆管炎 で2ヶ月ほど自宅で点滴治療を行い、そして11月末にまた 嘔吐症から胆管炎と膵炎を発症 し、1ヶ月弱ほど点滴治療を行っていました。主治医によると、シャルトリューという猫種自体が、この病気が多いそうです。

短い時間で成果を出す

「短い時間」というのは基準が曖昧で、評価しづらいなぁと振り返ってみて反省。「決めた予定以内で」と読み替えてみると、仕事では概ね予定どおりに成果出せていたかなぁと思います。

昨年11月に転職してから職場にも慣れたこと、同じチームの同僚のコードを見たりコードレビューを受けたりでRubyやRailsにもだいぶ慣れたことが大きいですね。

一方、特に6〜10月で仕事で多忙だったのでプライベートで使える時間が減ってしまって、特に家庭内で問題が増えてしまって悩ましい状態でした。今はちょっと改善傾向です。

KP(T)

Keep

  • 7-16時勤務の朝型生活は維持
  • 睡眠時間を増やして体調は改善傾向
  • 仕事面は割と順調
    • しかしバランスは難しい
  • 「妻と一緒に娘のことで悩んだり決断したことを、なんらかの形にする」は達成
    • 無理のない形で継続できています
  • Debian JP Projectのメーリングリストの移行完了
    • お手伝い頂いた皆様ありがとうございました
  • Mini Debian Conference 2016 開催
    • 私自身は運営としてあまり活動できませんでしたが、開催できてよかったですね
  • 今年もふるさと納税した
    • 控除金額上限の計算は割と面倒ですねぇ

Problem

  • 睡眠時間を増やした代わりに自分の時間が減って、毎朝コーディングができなくなってしまった
  • 家計簿は相変わらず時間かかる(処理を溜めると特に)
  • 仕事の比率増えて、全体のバランス悪くなっている
    • 自分に余裕がなくなると悪化する、というのは分かっていたのに一定に保てませんでした
  • Tryで立てたことは、娘のこと以外はほとんどできなかった

Try

これは年明けの「新年の抱負」で書きます。

まとめ

今年も良いことも悪いこともいろいろありましたが、良い年を迎えられそうです。 年賀状の印刷と大掃除がまだ残っている ので、やりきって新年を迎えるぞ!

ということで、良いお年を。

]]>
Thu, 29 Dec 2016 00:00:00 +0900
http://d.palmtb.net/2016/12/23/updates_for_tex_live_2016.html http://d.palmtb.net/2016/12/23/updates_for_tex_live_2016.html <![CDATA[Updates for TeX Live 2016]]> Updates for TeX Live 2016

年々準備が遅くなっている年賀状ですが、ようやく来年の年賀状を書くか、と重い腰を上げ、 出す枚数を確定し年賀状を購入してきました。

ページサイズがおかしい問題に遭遇

毎年、年賀状印刷で最初にやることは、 宛名印刷用のPDFの生成ツール の動作確認です。更新したCSVから、TeXファイル経由でPDFを生成しているのですが、指定したページサイズが効かずにA4サイズになってしまう、という問題に遭遇しました。

年賀状なので、下記のように100mm × 148mmにしているのですが、これが正常に機能しません。

\documentclass[12pt]{jarticle}
\usepackage[dvipdfmx]{graphicx}
\usepackage{verbatim}
\usepackage{plext}
\pagestyle{empty}
\setlength{\textwidth}{100truemm}
\setlength{\hoffset}{0in}
\setlength{\voffset}{0truemm}
\setlength{\headheight}{0truemm}
\setlength{\headsep}{0truemm}
\setlength{\oddsidemargin}{0truemm}
\setlength{\textheight}{148truemm}
\setlength{\topmargin}{0truemm}
\advance\oddsidemargin -1in
\advance\topmargin -1in
\setlength{\footskip}{0truemm}
\begin{document}
\setlength{\unitlength}{1truemm}

{{#address}}

\begin{picture}(100,148)(0,0)

dvipdfmx.defの変更が原因だった模様

TeX Live 2016にしたらページサイズがおかしくなります 」から、 こちらのスレッド を確認し、下記のように [dvipdfmx] オプションを [nosetpagesize] オプションに変更することで解消できました。

diff --git a/template/address.mustache b/template/address.mustache
index 513ee90..948eb3c 100644
--- a/template/address.mustache
+++ b/template/address.mustache
@@ -1,5 +1,5 @@
 <U+FEFF>\documentclass[12pt]{jarticle}
-\usepackage[dvipdfmx]{graphicx}
+\usepackage[nosetpagesize]{graphicx}
 \usepackage{verbatim}
 \usepackage{plext}
 \pagestyle{empty}

ということで

年賀状作成するぞ。

]]>
Fri, 23 Dec 2016 00:00:00 +0900
http://d.palmtb.net/2016/12/08/openblocks_and_debian_gnu_linux.html http://d.palmtb.net/2016/12/08/openblocks_and_debian_gnu_linux.html <![CDATA[自宅サーバから始まったDebianとのお付き合い]]> 自宅サーバから始まったDebianとのお付き合い

この記事は「 自宅サーバの思い出 Advent Calendar 2016 」、 8日目 のエントリです。

いろいろ記憶が曖昧なところがありますが、思い出を振り返ってみました。


自宅サーバ事始め

自宅サーバを始めたのは、社会人になった頃、仕事と関係なくJavaとかXMLとかを独学で勉強しながら、なんか作って公開したいな、と思ったのがきっかけでした。当時、Windows 2000をデスクトップで使っており、ライセンス的に無理だったので、ベアボーンで RedHat 9か VineLinuxあたりをインストールしたような記憶。GNU/Linuxを使い始めたのもこれが最初。いくつかディストリビューションを試して、インストーラーと、パッケージ管理の操作性が簡単だったことから、VineLinuxを使うようになった記憶。もう15年くらい前になると記憶が定かではないですね。

サーバ公開するのにセキュアなサーバにするのはどうしたら良いんだろう?と思ったことから、趣味も仕事もセキュリティに興味を持ち、そこからサーバやネットワーク絡みの構築&運用が中心になっていったのは余談。 [1]

ベアボーンにする、のはやめた

当初は、ベアボーンで使うときだけ起動していました。で、じきに常時稼働を始めようとして、すぐにやめました。理由は、 うるさいから 。当時1Kロフト付きのアパートに住んでおり、ロフトで寝ていたのですが、狭いのでファンがうるさいので眠れないわけです。さらに、消費電力考えると電気代もかさみます。ということですぐにやめました。

OpenBlockSとの出会い

はじめて購入したマイクロサーバーは、 ぷらっとホームのOpenBlockS 266 (64MBモデル)でした。オンラインショップだったのか、今は亡き、秋葉原にあった店舗だった [2] のか、どちらで先に購入したのかは覚えていません。どちらで?というのは、その後OpenBlockS 266は順調に5台まで増えるからです。

OpenBlockSを選んだ理由は、消費電力が小さいこと、ファンレスだったこと、Linuxだったことです。その後OpenBlockS以外のマイクロサーバーとしては、

自分で購入したのが

譲っていただいたのが

という感じで順調に増えました。 今でも、Armadillo-J、OpenBlockS 600は現役です。(他は休眠中)

当初はセルフビルドだったんだ

OpenBlockS 266を使うにあたり、SSD/Linuxが割と使いやすかったのでそのまま、クロスコンパイルを環境を作ろうとしました。

もともとWindows 2000を入れていたPCをデュアルブートにして、何らかのGNU/Linuxディストリビューションをインストールしていました。多分、当時は巡りめぐって結局Vine Linuxを使っていたように記憶しています。が、ライブラリのバージョン絡みでうまくできなかったので、OpenBlockS自体でセルフビルド行っていました。

ApacheとかPostfix、SpamAssassin、Hobbitはまあそんなに時間がかからなかったのですが、PostgreSQLが確か6〜8時間、NET-SNMPが12時間オーバーだったような。ビルドしている間は放置していたのですが、まぁ、そんなのにいつまでも耐えられるわけはありません。

そしてDebianとの出会い

ちょうどそんなときにぷらっとホームからDebianのHDDイメージが公開されました。多分2005年ごろ。

VineLinuxで(APT-RPMの) 「apt-get 便利だわー。お、DebianでもAPT使えるのかー、これは使うしかないわー」と思い、OpenBlockS 266でDebianを使い始めたのがDebianとの出会い。APT-RPMがDebianのAPTから派生したものだと知るのはこの後の話です。

でちょうど同じくらいのタイミングで、OSC Tokyoで東京エリアDebian勉強会を知り、参加するようになり、OpenBlockSだけでなく、PCもDebianに変更し、という感じで基本Debianだけを使うようになりました。

自宅サーバの最初の転機

その後、アパートから今のマンションに引っ越し、前述の通り順調にマイクロサーバーも増えていくのですが、最初に訪れた転機は妻と結婚してから猫(こまめ、こまちゃん)を飼いだしたこと。飼いだした当初はまだ生後3ヶ月程度で、色々噛むので電源コードなどを噛んで感電しないように、という対策を打つようになりました。 [3]

こまちゃん対策ではさらに、3.11のとき、妻と二人して帰宅できなかったことから、OpenBlockS 600を使って、こまちゃん監視カメラを作りました。

自由に置けなくなる

次の転機としては、長女(おまめ一号)が産まれ、ママ友が自宅を訪れるようになってからです。 前述のこまちゃん監視カメラは、こまちゃんの滞在時間が一番長いリビングに設置していたのですが、これが「監視されているようで嫌だ」と不評で、撤去する羽目に。 [4]

さらに次女(おまめ二号)が産まれ、僅かなスペースと僅かな電力消費の節約で台数削減ということで、停止して片付けて台数減らしました。

グローバルIPアドレスが使えなくなった

今のマンションに入居して結構時間が経ち、マンション全体で加入している回線の帯域が狭いこともあり、ISPの切り替えに伴い、NAT下でのプライベートIPアドレスになりました。数年前から公開サーバ自体は主にVPSにしていることもあり、特に困らないのですが、なんか書いていたらちょっとさみしくなってきました。

そして今

現状動かしているのは、Armadillo-JでDHCPサーバとOpenBlockS 600でルーターを動かしています。マンションの回線入れ替え前までは、PoEで動かせるOpenMicroServerをルーター兼ファイアウォールとして動かしていたのですが、スループットの問題でOpenBlockS 600に切り替えました。

ちなみに目的が目的なので、これらはDebianではありません。現在、Debianは(公私問わず)開発環境としてのワークステーションと、公開用のサーバとしてVPSにつかっています。

OpenBlockS 600でもNAPTすると速度がかなり遅くなるので、YAMAHAルーターあたりが欲しいなぁ、と思う今日この頃です。

Footnote

[1]前職でプライベートクラウドの開発を行って、現職では認証や管理機能の開発をやっています。
[2]2台目以降は店舗で購入していた記憶です。理由は、ジャンクパーツの Xeonのヒートシンクをおまけでもらえたので。これをOpenBlockS 266に載せて、扇風機を当てるだけで10℃近く冷却できるのでした。
[3]ちなみに噛んで感電というと、大学の卒業研究で在籍していた研究室で、実験用ラットをトレッドミルで走らせていたのですが、そのうちの一匹が電極を噛んで感電死したことを思い出します。
[4]動体検知での監視が目的なので、そりゃそうなんですけどね。
]]>
Thu, 08 Dec 2016 00:00:00 +0900
http://d.palmtb.net/2016/07/13/how_to_use_plantuml_mode.html http://d.palmtb.net/2016/07/13/how_to_use_plantuml_mode.html <![CDATA[How to use plantuml-mode]]> How to use plantuml-mode

PlantUMLを使うことになったので、EmacsでPlantUMLを使うための設定をしたのでそのメモ。

パッケージインストール

$ sudo apt-get install plantuml

plantuml-modeの設定

まずは git clone

$ cd .emacs.d/vendor
$ git clone https://github.com/zwz/plantuml-mode.git

.emacsに下記を追記

(setq plantuml-jar-path "/usr/share/plantuml/plantuml.jar")
(load-file "~/.emacs.d/vendor/plantuml-mode/plantuml-mode.el")

以上。

]]>
Wed, 13 Jul 2016 00:00:00 +0900
http://d.palmtb.net/2016/05/09/repaired_windows_tablet.html http://d.palmtb.net/2016/05/09/repaired_windows_tablet.html <![CDATA[Repaired Windows tablet]]> Repaired Windows tablet

昨年、飯山市へのふるさと納税でもらったマウスコンピューターの Windows tablet を Windows 10にアップグレードしておくか、と久々に妻に代わって [1] 起動してみたら、BIOS画面のあとすぐエラー画面が表示されて何もできない問題が発生しました。この連休入ってすぐのこと。

../../../_images/win-tablet0.png ../../../_images/win-tablet1.png

なんともしようがないの連休明けくらいに返信来ればいいかなとマウスコンピューターのサポートに問い合わせしてみたらすぐ返事きて、結果的修理対応になりました。

なお、最初上記の写真を文章だけで、表示されているメッセージを伝えたのですが、どうもそれだと正確に伝わらなかったらしく、 マウスコンピューターのロゴが表示されてから起動しない場合の手順を案内されました。最初から写真にしておけば良かったですね。

んで、センドバックで送付して、これまた1週間位かかるのかなぁと勝手に思っていたら、修理と発送含めて4日で戻ってきました。速い!

原因はマザーボードの故障とのことでした。今朝、妻の代わりに初期設定やったら、完了後に勝手にWindows 10へのアップグレードが始まって、正常に完了したので、面倒なことやらずに済んで助かりました。 [2] あとは家のどこかに紛失した Office のプロダクトキーの発掘か…。

Footnote

[1]妻がほしいというので、妻用にもらったものの、メンテナンス自体は私がやる、という…。
[2]故障前は Windows 10へのアップグレードが全然表示されなかったので、micro SDをわざわざ購入して、アップグレード用のISOイメージダウンロードしてアップグレードしようかと思っていたので。タイミングの問題だと思いますが。購入した micro SD はもともとアップグレード完了後にカーナビで使う予定だったので特に問題なし。
]]>
Mon, 09 May 2016 00:00:00 +0900
http://d.palmtb.net/2016/03/23/appends_platforms_metadata.html http://d.palmtb.net/2016/03/23/appends_platforms_metadata.html <![CDATA[Appends platforms metadata]]> Appends platforms metadata

Ansible 2.0がリリースされて 二ヶ月経ちました。その後からくらいから、私がメンテしているAnsible moduleがAnsible Galaxyにインポートできなくなっていました。解決したのでメモ。Ansible 2.0がリリースされたのと関係あるのかは知りません。

対応していなかった言い訳

インポートできなくなって、対応していなかったのは、公開済みのモジュールについては ansible-galaxy install コマンドでインストールできたからです。

原因

platformsというメタデータが必須になったためでした。

ということで、 meta/main.ymlgalaxy_info の下に platforms とその値を追加して終わり。platformsに使える値は、 ansible-galaxy init パッケージ名 でrole scafolldingを生成し、その meta/main.yml を参考にすればよろし。

なぜplatforms を設定していなかったのか

他の人のモジュールを参考にして、roleを作成していたので知らなかった、というオチ。

]]>
Wed, 23 Mar 2016 00:00:00 +0900
http://d.palmtb.net/2016/02/29/i_cannot_use_e_tax_this_year.html http://d.palmtb.net/2016/02/29/i_cannot_use_e_tax_this_year.html <![CDATA[I cannot use e-Tax this year]]> I cannot use e-Tax this year

今朝、自宅近所で証明写真を撮って [1] 、市役所に行ってみたらマイナンバーの特設会場が予想外に混んでいました。よくよく聞いてみると、交付用の特設会場に変わっていたので、市民課で代わりに手続き。

手続き自体は15分くらいで終わったので良かったのですが、結局国から郵送されてくるまでに1〜3ヶ月かかるそうなので、今年(2015年分)の確定申告はe-Tax使えないことが決定。

救いは、市役所で確定申告書類の預かりをやっていることを教えてもらったこと。提出自体も本人でなくても大丈夫ということで、e-Taxでの提出用に作ったデータを、郵送形式に変更して妻に提出しにいってもらうことにしました。

e-Taxじゃないおかげで一つ面倒だなぁと思っているのが、医療費控除での交通費。 子どもの通院の場合、医療証の提出で自己負担がありません。それは助かるものの、そのおかげで領収書を発行してくれない病院があるのですが、そこの交通費の申請って、金額だけの申告で大丈夫なのかなぁ? e-Taxだと領収書の提出省略できるので、掛かった公共料金の日数分を申請するだけで済んでいたのですが。

と思って検索してみたらどうやら 大丈夫みたい 。正確を期すためには税務署に聞いてみるのがよさそう。

Footnote

[1]今800円もするのね、高い。と思ったけど6枚になっていた。昔4枚で600円くらいだった気がするので、枚数増やして一枚あたりの単価と総金額を上げたのか。6枚も使わないけどねー。
]]>
Mon, 29 Feb 2016 00:00:00 +0900
http://d.palmtb.net/2016/02/28/my_jpki_certificate_had_expired.html http://d.palmtb.net/2016/02/28/my_jpki_certificate_had_expired.html <![CDATA[My JPKI certificate had expired]]> My JPKI certificate had expired

確定申告の書類作成、今年は普段から医療費控除の領収書をまとめておいたこともあって、今日だけで終わりました。

しかし、さてe-Taxで電子申告するかと、念の為公的個人認証(JPKI)の証明書のチェックをやってみたら、今年の2/19で有効期限が切れている、だと!?

有効期限切れるの、てっきり来年(2017年)だと思っていたので、家計簿で公的個人認証の更新をしたのがいつだったのかを確認してみたら、2013年2月20日でした。そりゃそうだよねぇ…。orz

仕方ないので、明日、個人番号カードの交付手続きと、交付までに要する日数を確認市に市役所に寄ってから出勤することにしました。

なんで来年だと思い込んでいたんだろう…。

]]>
Sun, 28 Feb 2016 00:00:00 +0900
http://d.palmtb.net/2016/02/22/bootstrap_python_package.html http://d.palmtb.net/2016/02/22/bootstrap_python_package.html <![CDATA[bootstrap Python package]]> bootstrap Python package

以前、Pythonパッケージ生成用のテンプレートをシェルスクリプトで作ったのですが、Pythonで一から書き直して bootstrap-py としてPyPIで公開しました。

できること

  • そのままPyPIに登録可能な形でPythonパッケージを生成
  • PyPIで登録されている名前を事前チェック
  • Toxを使ってユニットテストとテストツールを実行
    • pytest-covによるカバレッジの計測
    • pytest-pep8 コーディング規約のチェック
    • pytest-flakes による文法チェック
    • pytest-pylint によるコードチェック
    • PyChecker によるバグ検出
    • docstringのチェック
    • ユニットテストの実行順をランダム化
    • 前回以前のテスト実行時の古いバイトコードを削除
    • Sphinxでのドキュメントビルドチェック
  • Sphinxとautomoduleによるドキュメント自動生成
  • ClassifiersからのOSI Approved LICENSESとdevelopment statusの選択
  • GitHubアカウントを指定した場合に、Travis-CI, Coveralls, ReadTheDocsのステータスボタンをREADMEに設定
  • GitPythonで上記が設定した状態でGitリポジトリを生成し、user.name, user.email およびremote originを設定し、Initial commitを作成

Python 2.7以上、Python3.3以上、PyPy 2.4.0以上で初期コミット状態でtoxが通ります。(生成されたリポジトリでのPythonコードは実質setup.pyだけ、というのもありますが)

使い方などはREADMEにありますのでそちらを参照ください。

リポジトリは、 こちら

GitPython久しぶりに使った

約3年半前に ネタで書いたコード で使って以来、久しぶりにGitPythonを使いました。あー、便利。だけど、早速バグを見つけてしまった(commit時に、.git/HEADに \n が最後に付加されない)ので、バグ報告しておこう。

余談

以前はこれの拡張で、Django + django REST framework + Django絡みのベストプラクティスと言われるようなのを予め反映させるテンプレート(それもやはりシェルスクリプト)を作ったのですが、最近Djangoは使っていないのでとりあえず予定はありません。

おわり。

]]>
Mon, 22 Feb 2016 00:00:00 +0900
http://d.palmtb.net/2016/01/09/activate_0_sim_by_so_net.html http://d.palmtb.net/2016/01/09/activate_0_sim_by_so_net.html <![CDATA[Activate 0 SIM by so-net]]> Activate 0 SIM by so-net

12/25に会社のオフィス近所の書店 [1] で購入していた デジモノステーション 2月号 の付録の 0 SIM by so-net をアクティベートしました。接続確認は昔購入して使わなくなった、 b-mobile WiFiルータ を使ったのですが、本誌の記事や So-netの設定用の FAQマニュアル動画 にはダイヤル番号が載っていなくて困ったのですが、 他のFAQ に載っていました。備忘のため、記載しておきます。

b-mobile WiFiルータでの設定

プロファイル名
任意の名前。so-netとしておいた
APN
so-net.jp
ダイヤル番号
*99#
DNS
自動
認証方法
PAP or CHAP。無論CHAPにした [2]
ユーザー名
nuro
パスワード
nuro

まとめ

SORACOM SIM買って、b-mobile WiFiルータでIntel Edisonで遊ぼうと思っていたのですが、0 SIM使えば運用コストほぼ0円で済みそうなのでお財布的に助かるなぁと。

Footnotes

[1]ちょうどその前日に移転していたのですが、移転前のオフィスのあったビル一階にある書店で、昼休みに探しに行ったら結構売っていました。五反田の国道1号線沿いの他の大きめの書店では売り切れていたので、あそこならありそう、という読みは当たってました。ちなみに会社の同僚数名も同じ書店で購入していました。
[2]理由が分からなければ調べてみましょう。
]]>
Sat, 09 Jan 2016 00:00:00 +0900
http://d.palmtb.net/2016/01/03/aspiration_of_the_2016.html http://d.palmtb.net/2016/01/03/aspiration_of_the_2016.html <![CDATA[Aspiration of the 2016]]> Aspiration of the 2016

あけましておめでとうございます。今年もよろしくお願いします。

そして悲報。今日で休みも終わりです。 妻にとっても悲報です。まだ幼稚園はお休みです。

今回の年末年始のお休みは

  • Debian JP Projectのサーバーリプレース作業の準備(とりあえず一段落)
  • おまめ一号と温泉の回数券使い切るタスク(おまめ一号はソフトクリーム目当て)
  • おまめ二号のアデノウイルス感染症で可哀想&辛い(おまめ一号とこまちゃん以外は眠れない日々)
  • 久々に大掃除した(妻の家事力がパワーアップしていて助かりました)
  • ディズニーランドに行く計画は中止(子連れだと基本日にち指定は買わないのでいいんだけど)
  • 年賀状作成に追われる(今回も年明け…)
  • Amazon定期便の事前通知のあと調整忘れる(必要なくてキャンセルする必要のあったのまで発送されて涙目)
  • 実家に行って、妹の結婚絡みの話が長引いておまめ一号と一泊して帰宅(日帰りの予定だった)
  • 実家帰りのその足で法定一年点検(ワイパーブレードとエアコンフィルター交換で思わぬ出費)

という感じでした。いつもよりむしろ休んでないよね。

今年の抱負

昨年もそういえば、おまめ二号はこの時期風邪を引いていました。昨年の振り返り(Review the 2015)でも書いたとおり、11月に職場も仕事も変わり、サーバーサイドはRailsで実装しているサービスのお仕事をすることになりました [1] 。2ヶ月かかってようやく慣れてきたところで新年を迎えられました。ということを踏まえ、

「家族皆健康第一、短い時間できっちり成果出す」

を今年の抱負にします。

年末の振り返りから再度KPTは以下。

Keep

  • 7-16時勤務の朝型生活
    • これからの繁忙期も維持できるのか分からないですが、この辺はマネージャーと話をちゃんとしよう
  • 毎日コーディング
  • Debian の活動が減っているので無理ない程度に増やす

Problem

  • おまめ一号のDebianデビュー
  • 妻にPythonを教える

Try

  • 英語を使う機会が減っているのでまず習慣化する
  • 娘たちとのコミュニケーションを改善する
  • 年明けてこの三日間はとりあえず良好
  • 自分に余裕がなくなると悪化する、というのはわかっているので、仕事、健康、家庭、自分の時間と、如何に一定に保つか、が重要
  • 環境や条件が変わっても一定に保つってのが一番難しいので
  • おまめ一号のキーボード操作レクチャー
  • 中断したHaskellの勉強の再開&何か作る
  • C++の勉強継続、何か作る
  • 一昨年、昨年と妻と一緒に娘のことで悩んだり決断したことを、なんらかの形にする

Footnotes

[1]遠回しに言ってますが、要は転職しました。例のリストは こちら です。常時Welcomeです。
]]>
Sun, 03 Jan 2016 00:00:00 +0900
http://d.palmtb.net/2015/12/31/review_the_2015.html http://d.palmtb.net/2015/12/31/review_the_2015.html <![CDATA[Review the 2015]]> Review the 2015

あと30分弱で新年ですが今年の振り返りをしてみました。

Aspiration of the 2015

「家族皆健康第一」は?

12/30におまめ二号が発熱し、大晦日もぐったりしていたので病院に連れて行ってみたところ、アデノウイルス感染症で終わった一年でした。 それとは別に、今後どう向き合う、というか付き合っていくか、ということを何度も考えたり、決断をすることが多かった一年ではあったのですが概ね健康で過ごせたかなと思います。

その他の目標

  • 7-16時勤務の朝型生活
    • 11月から職場を変えたので、一時期維持するのが難しかったのですが現在は概ね戻せて来た感じです。
  • 毎日コーディング
    • 概ね達成できてます。最近はアウトプットだけでなくインプットも増やしてます。
  • Debian の活動が減っているので無理ない程度に増やす
    • とりあえず現状維持。
  • 英語を使う機会が減っているのでまず習慣化する
    • 未達成。要見直し。
  • おまめ一号とのコミュニケーションを改善する
    • おまめ二号も自我が出てきて、さらに環境も変わって、むしろ悪化している気がする…。
  • おまめ一号のDebianデビュー
    • 未達成。字をようやく覚え始めたのでキーボード操作はまだその後かなという感じ。
  • 妻にPythonを教える
    • 「私には無理」と拒絶。別のアプローチが必要
  • 中断したHaskellの勉強の再開&何か作る
    • これは未達成だったものの、仕事上、Python&GoだったのがRuby&Railsを扱うことになりました。
    • プライベートではC++の勉強をはじめました
  • (2015年)4月からおまめ一号の幼稚園でさらに支出が増えるので、収支の改善方法を検討&実行する
    • 私および妻ともに、auからIIJ mioに切り替えることで月々の電話料金の削減は達成 * 育児用品や生活用品などの購入をAmazon Primeと楽天だけだったのをヨドバシや他のサイトを利用することになったことで、定期的な購入費用は割と改善できた感じ
    • コストコや楽天などでの大量購入の頻度を上げる
    • 高速道路の利用頻度が増えたので、ETC導入
    • 基本未着手分を増額するなど、予算の立て方変更

まとめ

書き始めたのが遅かったので書き終えたら年越しちゃったよ。

]]>
Thu, 31 Dec 2015 00:00:00 +0900
http://d.palmtb.net/2015/12/25/a_sequel_to_pull_request_for_ansible_ldap.html http://d.palmtb.net/2015/12/25/a_sequel_to_pull_request_for_ansible_ldap.html <![CDATA[A sequel to pull request for ansible-ldap]]> A sequel to pull request for ansible-ldap

昨日の記事(ansible-ldap is very simple and useful)で、ansible-ldap のAnsible Galaxy 対応のPRを送ったところ、早速返事がありました。

If you’d like to publish these on Ansible Galaxy, feel free. You don’t need anything from me.

Ansible Galaxyでの公開はしないそうですが、公開そのものはご自由にどうぞ 、ということでした。

ということで、 fork版として公開 しました。

今後の方針

現状、テストコードがなく、Ansible 2.0も未対応なのでその対応を行う予定です。 [1] upstream側での変更が今後されるのかわかりませんが、可能であれば追従していくつもりです。

インストール方法

ansible-galaxy コマンドでインストールできます。

$ ansible-galaxy install -p library mkouhei.ldap

Mercurial から Gitへの変換

オリジナルはMercurialのリポジトリとしてBitbucketで公開されています。一方、Ansible Galaxyで公開するにはGitHubで公開する必要があります。 そこで、次の手順でMercurialからGitに変換しました。

  1. hg-fast-exportをインストール
$ sudo apt-get intall hg-fast-export
  1. インポート先のGitリポジトリを作成
$ mkdir ansible-role-ldap
$ cd ansible-role-ldap
$ git init
  1. MercurialからGitに変換
    • 変換元のMercurialのリポジトリは、却下されたPull requestを作成するためにfeature branchを作ったローカルリポジトリを使いました。
$ hg-fast-export -r /path/to/ansible-ldap
master: Exporting full revision 1/6 with 4/0/0 added/changed/removed files
master: Exporting simple delta revision 2/6 with 0/2/0 added/changed/removed files
master: Exporting simple delta revision 3/6 with 0/2/0 added/changed/removed files
for-ansible-galaxy: Exporting simple delta revision 4/6 with 1/0/0 added/changed/removed files
for-ansible-galaxy: Exporting simple delta revision 5/6 with 2/0/2 added/changed/removed files
for-ansible-galaxy: Exporting simple delta revision 6/6 with 0/2/0 added/changed/removed files
Issued 6 commands
git-fast-import statistics:
---------------------------------------------------------------------
Alloc'd objects:       5000
Total objects:           28 (         3 duplicates                  )
      blobs  :           11 (         2 duplicates          6 deltas of         11 attempts)
      trees  :           11 (         1 duplicates          5 deltas of         11 attempts)
      commits:            6 (         0 duplicates          0 deltas of          0 attempts)
      tags   :            0 (         0 duplicates          0 deltas of          0 attempts)
Total branches:           2 (         2 loads     )
      marks:           1024 (         6 unique    )
      atoms:              8
Memory total:          2344 KiB
       pools:          2110 KiB
     objects:           234 KiB
---------------------------------------------------------------------
pack_report: getpagesize()            =       4096
pack_report: core.packedGitWindowSize = 1073741824
pack_report: core.packedGitLimit      = 8589934592
pack_report: pack_used_ctr            =          7
pack_report: pack_mmap_calls          =          3
pack_report: pack_open_windows        =          1 /          1
pack_report: pack_mapped              =      19729 /      19729
---------------------------------------------------------------------

$ git branch
  for-ansible-galaxy
* master
  1. GitHubにリモートリポジトリを作成
  2. git push
$ git remote add origin git@github.com:mkouhei/ansible-role-ldap.git
$ git push --mirror
  1. for-ansible-galaxy ブランチを master にマージ
  2. Ansible Galaxyでインポート、公開

footnotes

[1]先日公開した include_csv もですが。
]]>
Fri, 25 Dec 2015 00:00:00 +0900
http://d.palmtb.net/2015/12/24/ansible_ldap_is_very_simple_and_useful.html http://d.palmtb.net/2015/12/24/ansible_ldap_is_very_simple_and_useful.html <![CDATA[ansible-ldap is very simple and useful]]> ansible-ldap is very simple and useful

OpenLDAP と仲間たち Advent Calendar 2015 24日目、クリスマスイブですね。一昨日(12/22)にEngineer All Handsという社内のイベントでLTをすることになり、「LDAPと私」というネタで ansible-ldap というモジュールの話を軽くしました。ついでにブログにでもちゃんと書いておこうかなと思い、昨日アドベントカレンダーの予定を見てみたら、空いていたので参加してみました。

概要

この記事の要点としては以下のとおりです。これを読んで理解できる方はその後を読む必要はありません。モジュールのソースコード内のドキュメントを読みましょう。

  • ansible-ldapの ldap_entry および ldap_attr モジュールだけで LDAPのエントリーの追加・削除、エントリーの属性の追加、削除、置換を冪等に行うことができる
  • ldapi:// にも対応しているので slapd-config(5)の設定もできる
  • Ansible Galaxy には登録されてないのでパッチ書いてPR送った (mergeされるかは別の話)

あと、LDAPには直接関係ありませんが、

ansible-ldapとは

django-otpdjango-auth-ldapmockldap などの作者の Peter Sagerson 氏が開発された Ansib用の LDAP モジュールです。django-auth-ldapやmockldapには前職でとてもお世話になってました。 [1]

ldap_entryldap_attr の2つのモジュールがあります。 前者はLDAPのDITに対し、entryを追加または削除を、後者はすでに存在するエントリーの属性を追加、削除、もしくは置き換えを行うためのモジュールです。

fumiyasuさん が一日目にslapd.conf(5)を使ったPlaybookの 記事 を書かれていますが、ansible-ldapモジュールを使う場合は、slapd-config(5)を使います。DebianやUbuntuのOpenLDAPサーバのパッケージである、slapdパッケージはslapd-config(5)がデフォルトです。slapd-config(5)絡みの記事は 以前書いたものある ので、そちらもご参照ください。

使い方

これらのモジュールを使った サンプルのPlaybook を作ったのでそれを例にして説明します。

ldap_entry

まずはシンプルに memberof モジュールを追加する例です。

- name: be sure memberof module
  ldap_entry:
    dn: cn=module{1},cn=config
    state: present
    objectClass: olcModuleList
    olcModulePath: /usr/lib/ldap
    olcModuleLoad: memberof.la
dn
必須項目です。エントリーの追加時、 {1} とあるindex番号は必要に応じて自動的に付加されます。しかし、 cn=module,cn=configcn=module{1},cn=config は別のdnになります。そのためエントリー追加後、同様にindexを指定しないで属性の変更や、エントリーの削除を行おうとすると、エントリーが見つからないためエラーになります。変更するエントリーのindexを把握しておく必要があるのでサンプルで明示的に指定しています。
state
デフォルトは present で存在しなければ作成し、存在すれば何もしません。削除するときは absent を使います。これはAnsibleの他モジュールと同じ挙動です。 ldap_entry には変更という操作はありません。つまり ldapadd コマンドと ldapdelete コマンドに相当する操作だけです。 ldapmodify コマンドに相当する操作は ldap_attr で行います。
objectClass 及びその他の属性
必要な場合は設定します。 slapd-config(5)の属性の名称はslapd.conf(5) の設定オプション名とは微妙に異なるので、man slapd-config(5)GLOBAL CONFIGURATION OPTIONS 以降のセクションを参照しましょう。

次に、suffixが dc=example,dc=org のLDAPディレクトリに対し、oganizational unitを追加する例を見てみます。

- ldap_entry:
    dn: "ou={{ item }},{{ suffix }}"
    objectClass: organizationalUnit
    ou: "{{ item }}"
    bind_dn: "cn=admin,{{ suffix }}"
    bind_pw: "{{ admin_pw }}"
    state: present
  with_items:
    - People
    - Groups
    - SUDOers
server_uri
この例では省略していますが、これはデフォルトでは ldapi:/// になります。リモートホストのLDAPサーバを対象にする場合には、LDAPのURLを指定する必要があります。
start_tls
StartTLS LDAPを使うときはこのオプションを true にします。デフォルトでは false です。
bind_dnbind_pw
slapd-config(5) の設定の時は省略することで EXTERNAL mechanism でアクセスしますが、特定のDITの操作を行うには、デフォルトでは認証が必要になります。bind用のDNを bind_dn で、パスワードを bind_pw で指定します。slapd自体の設定し、特定のsuffix のDITに対し変更を行う場合、つい忘れがちなので気をつけましょう。

ldap_attr

アクセス権限を設定する例を見てみます。

- name: olcAccess are absent.
  ldap_attr:
     dn: "olcDatabase={1}{{ backend | lower }},cn=config"
     name: olcAccess
     state: absent
     values:
       - '{0}to attrs=userPassword by self write by anonymous auth by * none'
       - '{1}to attrs=shadowLastChange by self write by * read'
       - '{2}to * by * read'

- name: olcAccess are present.
   ldap_attr:
     dn: "olcDatabase={1}{{ backend | lower }},cn=config"
     name: olcAccess
     state: present
     values:
       - '{0}to attrs=userPassword,shadowLastChange
          by self write
          by anonymous auth
          by dn="cn=admin,{{ suffix }}" write
          by * none'
       - '{1}to dn.base=""
          by * read'
       - '{2}to *
          by dn="cn=admin,{{ suffix }}" write
          by * read'
       - '{3}to dn.subtree="{{ suffix }}"
          by self read
          by * read'
       - '{4}to *
          by * none'

この2つのタスクでは、 absent でslapdインストール時にデフォルトで設定されるアクセス設定を一度削除し、 present で新しく設定しています。

このやり方は面倒ですね。代わりに exact を使えばひとつのタスクで変更できます。

- name: override olcAccess exactly
  ldap_attr:
    dn: "olcDatabase={1}{{ backend | lower }},cn=config"
    name: olcAccess
    state: exact
    values:
      - '{0}to attrs=userPassword,shadowLastChange
         by self write
         by anonymous auth
         by dn="cn=admin,{{ suffix }}" write
         by * none'
      - '{1}to dn.base=""
         by * read'
      - '{2}to *
         by dn="cn=admin,{{ suffix }}" write
         by * read'
      - '{3}to dn.subtree="{{ suffix }}"
         by self read
         by * read'
      - '{4}to *
         by * none'

name で 変更する属性を指定し、 values で一つもしくは一つ以上の値を指定します。複数設定できるか否かは、設定するattributeのスキーマ次第です。他のパラメータは基本的には ldap_entry と同じです。

Note

backend には MDB を指定しています。MDBは LMDB をバックエンドとするためのdebconfのパラメータです。DNでは小文字になるため、lowerフィルターを使って小文字に変換しています。

ansible-ldapのインストール方法

現状、ansible-ldapは Ansible Galaxyには登録されてません。また、Ansible Galaxyで公開できる形式になっていないため、requirements.yml に

- src: https://bitbucket.org/psagers/ansible-ldap
  name: ldap
  scm: hg

のように記述し、 ansible-galaxy install -p library -r requirements.yml と実行してもインストールできません。手動で hg clone を実行し、playbookのlibraryディレクトリを以下にモジュールをコピーする必要があります。とても面倒です。ということで、パッチ書いてPRを送っておきました。

マージされるまでの間 [2] は、下記のように記述することで ansible-galaxy install コマンドでインストールすることができます。ただし、 --no-deps オプションが必要ですので気をつけましょう。

- src: https://bitbucket.org/mkouhei/ansible-ldap
  name: ldap
  scm: hg
  version: for-ansible-galaxy

さらにもしAnsible Galaxyに登録されたら、おそらくこんな記述になることでしょう。

- src: psagers.ldap

C bindingとPure Python

今回紹介した django-auth-ldap、mock-ldapは OpenLDAPライブラリの C bindingと実装された Python-LDAP やそのPython3対応としてのforkの pyldap に依存してします。 ansible-ldapもPython-LDAPに依存しています。 [3] Pure PythonでのLDAPクライアントの実装としての ldap3 は使用されていません。今回紹介する ansible-ldap も やはり Python-LDAPに依存しています。

今までに何度かLDAP用のAnsibleモジュールを書こうかな、と思ったことも何度かあったのですが [4] 、slapdの設定変更に必要なのは ldapi:// (LDAP over IPC) でアクセス、操作できることなので、少なくともこの10月末まではC bindingのPython-LDAP / pyldapしかその機能があるPythonモジュールはありませんでした。 Pure Pythonのldap3では本当にこの最近(2015-11-15)、 v0.9.9.3 として LDAPIの機能が実装された ようです。

一方、このansible-ldapは 昨年の11月に基本機能を実装して公開されていた いたので、ldap3を使っていないのは当然といえます。

DebianシステムではPython-LDAPは python-ldap パッケージとして提供されていますが、pyldapはDebianパッケージとして提供されていません。ldap3 は python-ldap3 (Python2版) および python3-ldap3 (Python3版) として提供されています。Ansible は Python3はまだ正式対応されていないので現状では playbook の中で、

- apt: pkg=python-ldap state=present

python-ldap パッケージをインストールすればよいですが [5] 、Ubuntu の次のLTSではPython3だけになるので、pyenvなどでPython2.7を構築するタスクを書いた上 [6]

- apt:
    pkg={{ item }}
    state=present
  with_items:
    - build-essential
    - libldap2-dev
  - pip: name=Python-LDAP

として、slapdを動かすホスト上でPython-LDAPのコンパイルも必要な上、ansible-ldapでは現状任意の PYTHONPATH を指定することができないので、 /usr/local/lib/python2.7/dist-packages の下にPython-LDAPをインストール必要があります。

(おまけ) CSVからvarsを読み込むモジュールを作りました

サンプルのPlaybookではユーザーの作成や、SSH公開鍵を登録するための タスク もあるのですが、ユーザー作成用のパラメータや公開鍵をいちいちYAMLで記述するのはとても億劫です。なので、CSVで記述したものをvarsとして読み込むことのできる include_csv というモジュールもついでに作りました。使い方としては、コアモジュールの include_vars のような使い方になります。詳しくはAnsible GalaxyのREADMEのページを参照してください。

まとめ

今までは、Ansibleらしくない書き方でslapdの構築を行い、それが故に冪等にすることが難しいため変更はAnsibleで行わない、という運用になってしまっていましたが、このansible-ldapモジュールのおかげで冪等性を保つことができるようになりました。個人的には ldapvi コマンド、Python-LDAPに続く、LDAPの運用・利用が非常に楽になるツールが登場したと思ってます。勝手に三種の神器と呼びたい。

また、include_csv も便利そうという意見ももらったので結構うれしいですね。 [7]

footnotes

[1]11月からRuby on Railsの仕事をすることになり、業務では現時点ではPythonもLDAPも使っていません。
[2]マージされるかはわかりませんが。
[3]ansible 2.0.0-0.8.rc3 も試してみましたが、現状ではまだ ansible-galaxy コマンドが Python3 に対応していませんでした。
[4]頻度の問題で、結局作らずに済ませてしまってきたのですが…。
[5]Debianシステムの場合。
[6]今回の話と少しずれるので省略します。
[7]ちなみに今回、初Ansible Galaxy、つまり初のAnsible モジュール作成、初のアカウント作成、初のRole登録、初の ansible-galaxy コマンド利用、と初ものづくしでした。
]]>
Thu, 24 Dec 2015 00:00:00 +0900
http://d.palmtb.net/2015/10/18/changed_the_display_manager_to_slim_instead_of_gdm3.html http://d.palmtb.net/2015/10/18/changed_the_display_manager_to_slim_instead_of_gdm3.html <![CDATA[Changed the display manager to slim instead of gdm3]]> Changed the display manager to slim instead of gdm3

一週間ほど前(2015/10/12)から、stretch/sidでパッケージのアップデートを行うと、次回のOS起動時にDisplay managerが起動せず、ttyのログインプロンプトが延々と明滅してまともにログインすらできない問題に遭遇しました。

私物のMacBook ProのVirtualBox上で動かしているSidは、VirtualBox用のカーネルモジュールを再作成してやることで回避できました。

$ sudo dpkg-reconfigure virtualbox-guest-dkms

しかし、仕事で使っているMacBook ProのVirtualBox上のSid [1] ではこれでは解決せず、recovery modeで/var/log/Xorg.0.logを確認してみたところ、

(EE) dbus-core: error connecting to system bus: org.freedesktop.Dbus.Error.FileNotFound (Failed to connect to socket /var/run/dbus/system_bus_socket: No such file or directory

というログが出ていたのでパッケージを確認してみたら、 libdbus-c++-10v5 パッケージが無く、これをインストールすると、 startx コマンドでX Window systemが起動するようにはなりました。 [2]

ところが、これでもgdm3は起動しません。そこで、現在Debianでサポートされている Display manager を確認して、slimに変更してみました。これは正常に起動できました。

デフォルトのセッションがawesomeではなかったので、 /etc/slim.conflogin_cmd

diff --git a/slim.conf b/slim.conf
index c82f73b..413e111 100644
--- a/slim.conf
+++ b/slim.conf
@@ -33,8 +33,9 @@ authfile           /var/run/slim.auth
# NOTE: if your system does not have bash you need
# to adjust the command according to your preferred shell,
# i.e. for freebsd use:
-# login_cmd           exec /bin/sh - ~/.xinitrc %session
-login_cmd           exec /bin/bash -login /etc/X11/Xsession %session
+#login_cmd           exec /bin/sh - ~/.xinitrc %session
+#login_cmd           exec /bin/bash -login /etc/X11/Xsession %session
+login_cmd           exec /bin/bash -login /etc/X11/Xsession awesome

# Commands executed when starting and exiting a session.
# They can be used for registering a X11 session with

と直接指定しています。 [3]

普段、Gnomeではなくawesomeしか使っていないので、別に gdm3を使う理由も無いので、とりあえずこれで良しとします。問題のなかった私物の環境の方もslimに変更しようかな。

footnotes

[1]このSidのイメージはもともと自宅で使っているSidのイメージを使っているのですが、まぁ年月経つと大分環境にも差異が出ますよね。
[2]ちなみに xinit パッケージもインストールされていませんでした。Display manager使っていたら普段必要ないのですけど。
[3]ちなみに ~/.xinitrcsession=awesome を設定し、 exec /bin/sh - ~/.xinitrc %session を有効にする方法だと、gdmの時と同様の問題が発生してしまいました。
]]>
Sun, 18 Oct 2015 00:00:00 +0900
http://d.palmtb.net/2015/10/17/rewrote_the_sctipt_of_openssh_authorizedkeyscommand_for_ldap_public_key.html http://d.palmtb.net/2015/10/17/rewrote_the_sctipt_of_openssh_authorizedkeyscommand_for_ldap_public_key.html <![CDATA[Rewrote the sctipt of OpenSSH AuthorizedKeysCommand for LDAP public key]]> Rewrote the sctipt of OpenSSH AuthorizedKeysCommand for LDAP public key

OpenSSH 6.2以上で実装された AuthorizedKeysCommand を使って、LDAPでの公開鍵認証用のシェルスクリプトを Golang で書き換えました。その理由などはいいからコードはよ、という方は、 次のリンク先からドキュメントと合わせてどうぞ。

背景

現状、下記のようなシェルスクリプトを /etc/ssh/searchkey.sh として用意し、

#!/bin/sh -e

uri="ldap://ldap.example.org"
search_base="ou=People,dc=example,dc=org"
uid=$1
search_filter="(&(objectClass=posixAccount)(uid=${uid})(description=limited))"

ldapsearch -x -LLL -H $uri -b $search_base $search_filter sshPublicKey |\
grep -v '^dn:' | sed '
s/sshPublicKey: //g
s/^ //g
' | tr -d '\n'

このスクリプトのパスを sshd_configAuthorizedKeysCommand に設定することで、 openssh-lpk.schema を使ったLDAPでの公開鍵認証を行っています。ちなみにその前(Ubuntu PreciseやDebian Wheezy)では OpenSSHのソースパッケージにopenssh-lpkパッチを適用して、カスタムビルドパッケージを配布していました。 [LPK0] [LPK1] [LPK2]

問題発生

Trusty, Jessieから AuthorizedKeysCommand でのシェルスクリプトに切り替えてから、しばらく問題がなかったのですが、あるタイミングから公開鍵認証ができなくなりました。 [1]

原因は2つ。一つは sshPublicKey の値が base64 encodeされている場合。上記のスクリプトだとdecodeしていないため、authorized keysとして機能しません。 もうひとつは、複数の公開鍵が登録されている場合。複数行あった場合の処理も行っておらず、複数のエントリがあった場合は一行に連結されてしまいます。

対応検討

最初、シェルスクリプトで対応しようかと思ったのですが、厄介なのが、複数キーを登録しているユーザで、ある鍵は base64 encodeされておらず、ある鍵はencodeされている、というケースが存在すること。シェルスクリプトだとテストコードも書きづらかったこともあり、ピュアGoで書かれている go-ldapGosh で試してみたら、base64 encodedの値も自動的にdecodeしてくれるので、Golangで書き換えることにしました。

openssh-ldap-pubkey での実装

go-ldapでエラー処理など省いて書くと実質的には下記のようになります。

c, _ := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "<host>", "<port>"))
defer c.Close()
bindRequest := ldap.NewSimpleBindRequest("", "", nil)
c.SimpleBind(bindRequest)
searchRequest := ldap.NewSearchRequest(
        l.base, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases,
                0, 0, false,
                fmt.Sprintf("<filter>", "<uid>"), []string{sshPublicKeyName}, nil)
sr, _ := c.Search(searchRequest)
for _, pubkey := range sr.Entries[0].GetAttributeValues("sshPublicKey") {
             fmt.Println(pubkey)
}

ただ、Goで書き換えても、 openssh-ldap-pubkey コマンドのラッパースクリプトを用意して、LDAPサーバや search baseを指定するのはひと手間増えます。これは避けたいなと思いました。通常LDAPを使っている環境では nslcd も併用していることが多いので、初期リリースとしては /etc/nslcd.conf があればそこから設定を読み込むようにしました。 nslcd.confとopenssh-ldap-pubkeyコマンドのオプションの対応表はドキュメントに記載 してあります。なお、もしnslcd を利用していない場合はラッパースクリプトを用意する必要があります。この場合も ドキュメントに記載 しておきました。

RHEL系は?

皆大好きRHELベースのディストロでは、そもそも openssh-ldap というパッケージが用意されているので、 AuthorizedKeysCommand を使う必要がありません。設定を合わせたい、という場合には同じやり方でできます。

SSSDの対応は?

DebianシステムでもSSSDパッケージは用意されています。ただ、デフォルトではSSSDになっておらず、個人的にもまだ使っていないので、こちらは未対応です。要望があれば対応するかも or パッチウェルカムです。

IPv6 only host in Dual stack でハマった

今の環境は、IPv4/IPv6の dual stackの構成で、IPv6がデフォルトで、ホストはIPv6 onlyまたはIPv4/IPv6のdual stackを選べるようになっています。なのでDNSは基本IPv6のアドレスに問い合わせする構成にしています。LDAPサーバはIPv4しか使えないネットワーク機器も利用するので、例えばldap.example.orgはAAAAレコードとAレコードを設定しています。通常、ldapsearchを行うと基本IPv6経由で行ってくれるので問題ありませんが、今回使ったgo-ldapはdual stackの場合、IPv4で名前解決をしてしまい、アクセスできないとそこで処理を中断してしまうことが分かりました。go-ldapの方を修正して、パッチを投げるのが筋でしょうが、とりあえず、今回はopenssh-ldap-pubkey側で net.LookupHost を使って、IPv6 onlyのホストでも正常に接続できるように 回避策 をとりました。

まとめ

やっつけで作るときはシェルスクリプトやAWK, Sedスクリプトは楽なのですが、メンテナンスを考えると結構しんどいので、テストコード書けるプログラミング言語で実装するほうがやはり良いですね。 2年位前だったら、今回のような場合、Pythonで実装していたと思いますが、クライアントに配布するようなユーティリティで、ディストリビューションの公式パッケージにしていない場合、Golangはシングルバイナリで配布できるのでやはり圧倒的に便利です。

あと、今回のユーティリティは主にDebianシステムが対象なのと、go-ldapは 公式Debianパッケージになって いるのでDebianパッケージ化しておくと、Ubuntu 16.04やDebian Stretch以降で便利です。気が向いたら ITPするかもしれません。

参考文献

[LPK0]OpenSSH LDAP public key
[LPK1]Applying openssh-lpk to Wheezy
[LPK2]How to build custom Debian package automatically by Jenkins

footnotes

[1]と言ってもカスタムビルドパッケージを使ったPreciseやWheezyでは問題が無く、現環境ではCentOSに比べ、Ubuntuを使っている人そもそも少ないこと、後述のbase64 encodeされているのも一部のユーザであるため、気づいている人が少ないのが現状でした。
]]>
Sat, 17 Oct 2015 00:00:00 +0900
http://d.palmtb.net/2015/10/07/upgraded_to_os_x_el_capitan.html http://d.palmtb.net/2015/10/07/upgraded_to_os_x_el_capitan.html <![CDATA[Upgraded to OS X El Capitan]]> Upgraded to OS X El Capitan

会社用のMacBook Pro(Retina, 15-inch, Early 2013)と私物のMacBook Pro 8,2(15-inch)をEl Capitanにアップグレードしてみました。 一部、騒がれているような問題にも特に遭遇することもなく、2台とも正常にアップグレードできました。

メイン環境のVirtualBox上のSidさんは今日も日常通りです。VirtualBoxをフルスクリーンでしか基本使ってないのですけどね。

VirtualBox入れてない、Mac miniは問題が落ち着いた頃にアップグレードしてみます。

そろそろ私物のMacBook Pro (15-inch)、新しいの欲しいなぁ。

Mac miniといえば

先日、ようやく妻の古いWindowsからiTunesのデータをMac miniに移行しました。まだiTunesに登録してないCDが結構あるので、USB接続のDVDドライブ見てみたら、(使用頻度を考えると)結構高いのですね。うーん。

]]> Wed, 07 Oct 2015 00:00:00 +0900 http://d.palmtb.net/2015/09/01/i_have_user_registration_to_hp_helion_public_cloud_in_order_to_use_the_swift.html http://d.palmtb.net/2015/09/01/i_have_user_registration_to_hp_helion_public_cloud_in_order_to_use_the_swift.html <![CDATA[I have user registration to HP Helion Public Cloud in order to use the Swift]]> I have user registration to HP Helion Public Cloud in order to use the Swift

自分で作っているバックアップ用のツール(backup2swift)とそのライブラリ(swiftsc)のIdentity API v3対応のため、KeyStoneとSwiftの環境を作るのが面倒だったのでHP Helion Public Cloudに登録してみました、という使ってみた系のお話です。

結論からいうと、 OpenStack Days Tokyo 2015 で個人情報と引き換えにもらった

OpenStackクラウドインテグレーション オープンソースクラウドによるサービス構築入門

この本の最初の方で紹介されているHP Helion Public Cloudの登録方法を見れば分かるはずだと思います。 [1]

手間取った点

ユーザーアカウント登録時

一つは、ユーザーアカウント登録の時。まず、contact infoの登録で住所の部屋番号を間違えて登録した記憶がありました。 その後支払い情報を登録するときにも、住所を登録する必要があります。この時には正しく入力しました。 その登録直後に表示されたメッセージには、セキュリティ上の問題があるやらなんやらで確認するのにしばらくかかるよ、みたいな内容が表示されました。なので住所間違えたのがまずかったかな?と思ったわけですが、しばらく(10分くらい?)したらaccount activatedのメールが来たので、メール来るまでの間、なんか面倒なことになってないだろうか嫌だなぁ、ともやもやしていただけで、結果的には杞憂に過ぎませんでした。 [2]

Identity API用の情報確認

Identity API v2.0 とv3とで、エンドポイント以外に、認証に必要な情報が異なるため、Helionのダッシュボードから探すのに手間取りました。 前者ではユーザー名はユーザーアカウント登録時に設定した User Name 、パスワード、および自動生成される Project Name 、後者では User Nameと対で自動生成される User ID と自分で設置したパスワード、および やはり自動生成される Project ID となんか微妙に異なります。ぱっとみ Project NameProject ID-Project というSuffixを付与すればええんだな、と思ってよく見たら実は違うし。

そういえば、Horizonの画面触ったのはEssex以来で、今同じ部門で進んでいるOpenStackの導入にはまーったく絡んでいないですし [3] 。 あとIdentity API v3を触ってたのも v3 がリリースされる前の時だったしなぁ、という言い訳をしておきます。

ConoHaは?

Helion登録する前に ConoHa by GMO でもよいかなと思ったのですが、こちらは まだ Identity API v2.0のみでv3には対応していません でした。残念。

気になっている点

アカウント削除後、再登録できるのか?

Helion は3ヶ月は無料となっているのですが、既に 対応済んだ ので、ほったらかして忘れてしまい課金されてた!というのを避けるために、もう解約しようと思っているのですが、また何らかの理由で必要になったときに、再度新規登録すればまた使えるのかなぁ、というところですね。無料試用期間も復活するとさらに良いのですが。

そういえば日本語情報無いですね

HP Helion関係の日本人エンジニアの方、いると思っているのですが日本語ブログとか無いなぁ、と気づいたのですが、HP Helion Pubilc Cloudを売るのが仕事ではないからなんでしょうかね、と勝手にトスを上げてみて、終わります。

footnote

[1]職場で同僚に貸してしまっていて、手元に無いので実際に登録するときにはこの本見てません。
[2]実際にこの後contact infoを確認したらやっぱり住所間違えていました。
[3]私はというと、5月から引き継いだシステムのいわゆる「技術的負債の返済」を先週までやっていました。
]]> Tue, 01 Sep 2015 00:00:00 +0900 http://d.palmtb.net/2015/07/28/bulk_apple_85w_magsafe_a1343_mc556j_b.html http://d.palmtb.net/2015/07/28/bulk_apple_85w_magsafe_a1343_mc556j_b.html <![CDATA[Bulk Apple 85W Magsafe A1343 MC556J/B]]> Bulk Apple 85W Magsafe A1343 MC556J/B

自宅で使っているMacBook Proの電源アダプターが気がついたら、こんな酷い事に。

../../../_images/mbp_power0.png

Apple Storeやヨドバシで普通に購入すると税込みで一万円以上します。高い。 一方、サポート切れていても電源アダプターの場合、Apple Storeに持ち込むと修理費用で交換してもらえた旨の情報も見かけたのですが、それでも一万弱はするようでした。

とAmazonで調べてみたら純正のバルク品が4,280円であったので即購入しました。

届いた品

../../../_images/mbp_power1.png ../../../_images/mbp_power2.png

レビューを事前に確認したら異音がするとか、正規品よりも発熱するとかいうケースも見られたのですが、実際購入して使っている感じでは特にそういうことはなく、発熱も正規品と大差ありません。 唯一違っていたのは、充電中のLEDランプが正規品のそれより小さく見える、というくらいで充電完了時は同じでした。

というわけで結果的には良い買い物でした。

現在は残念ながら

購入したAmazonマーケットプレイスの 店舗では在庫切れですでに取り扱っていない様子 です。

7,000円弱では現在もまだ扱っているところもあるようです。

]]> Tue, 28 Jul 2015 00:00:00 +0900 http://d.palmtb.net/2015/07/27/third_time_lucky.html http://d.palmtb.net/2015/07/27/third_time_lucky.html <![CDATA[Third time lucky]]> Third time lucky

matsuu さんから さらにツッコミアドバイス を頂いて [1]いくつかコードの修正 を行うことで、正常に http://app.example.org ドメインでドメインのrewriteとカスタムドメイン用のAレコードの設定をせずにアクセスできるようになりました。

matsuu さん、いろいろありがとうございました!

footnote

[1]設定はほぼ matsuu さんのGistのまんまなので今回は掲載しません。
]]>
Mon, 27 Jul 2015 00:00:00 +0900
http://d.palmtb.net/2015/07/24/change_the_reverse_proxy_upstream_of_nginx_without_lua.html http://d.palmtb.net/2015/07/24/change_the_reverse_proxy_upstream_of_nginx_without_lua.html <![CDATA[Change the reverse proxy upstream of Nginx without Lua]]> Change the reverse proxy upstream of Nginx without Lua

前回の記事(Change the reverse proxy upstream of Nginx by time zone) を見て、 matsuu さん が下記のような設定をGistに掲載されていたので試してみました。

結果、問題なくできたので前回の設定は次のようにシンプルになりました。

map $time_iso8601 $upstream {
    default "app-b.example.org";
    "~T(0|1[01])" "app-a.example.org";
}

server {
    server_name app.example.org;
    rewrite ^ $scheme://$upstream$request_uri permanent;
}

upstream app-a.example.org {
    server app-a.example.net;
}

server {
    server_name app-a.example.org;
    access_log /var/log/nginx/app-a.access.log;
    location / {
        proxy_pass http://app-a.example.org/;
    }
}

upstream app-b.example.org {
    server app-b.example.net;
}

server {
    server_name app-b.example.org
    access_log /var/log/nginx/app-b.access.log;
    location / {
        proxy_pass http://app-b.example.org/;
    }
}

matsuu さん、どうもありがとうございました。

]]>
Fri, 24 Jul 2015 00:00:00 +0900
http://d.palmtb.net/2015/07/17/change_the_reverse_proxy_upstream_of_nginx_by_time_zone.html http://d.palmtb.net/2015/07/17/change_the_reverse_proxy_upstream_of_nginx_by_time_zone.html <![CDATA[Change the reverse proxy upstream of Nginx by time zone]]> Change the reverse proxy upstream of Nginx by time zone

諸事情 により、VPSでNginxで運用しているリバースプロキシで、下記のように、時間帯によって振り分け先を変更させるようにしてみました。 [1]

時間の判定には HttpLuaModuleset_by_lua を使いました。nginx-extrasパッケージのインストールが必要です。

$ sudo apt-get install nginx-extras

ここ を参考にNginxに下記の設定を行いました。

(snip)

upstream app-a.example.org {
    server app-a.example.net;
}

server {
    server_name app-a.example.org;
    access_log /var/log/nginx/app-a.access.log;
    location / {
        proxy_pass http://app-a.example.org/;
    }
}

upstream app-b.example.org {
    server app-b.example.net;
}

server {
    server_name app-b.example.org;
    access_log /var/log/nginx/app-b.access.log;
    location / {
        proxy_pass http://app-b.example.org/;
    }
}

server {
    server_name app.example.org;
    access_log /var/log/nginx/app.access.log;
    set $access_a_zone 0;
    set_by_lua $access_a_zone '
        local time = os.date("*t")
        if 0 <= time.hour and time.hour < 12 then
             return 1
        end
    ';

    if ($access_a_zone = 1) {
        rewrite ^ $scheme://app-a.example.org$request_uri permanent;
    }
    rewrite ^ $scheme://app-b.example.org$request_uri permanent;
}

http://app.example.org でアクセスすると、0-11時台は http://app-a.example.net にリダイレクトし、12-23時台は http://app-b.example.net にリダイレクトするだけの設定です。変数access_a_zoneは当初リンク先同様、下記のようにbooleanにしようとしましたが、Ubuntu TrustyのNginx 1.4.6だと期待通りに判定されず、最後のrewriteが実行されてしまうので、0, 1を設定することにしました。

set_by_lua $access_a_zone '
    local time = os.date("*t")
    local access_a_zone = false
    if 0 <= time.hour and time.hour < 12 then
        access_a_zone = true
    end
    return access_a_zone
';

if ($access_a_zone) {
(snip)

カスタムドメインを使う場合、上記の app-a.example.orgapp-b.example.orgCNAME レコードか ALIAS レコードを設定する必要がありますが、今回はリバースプロキシの IPアドレスを app.example.org, app-a.example.org, app-b.example.org それぞれ A レコードとして設定しました。少なくとも現時点ではこの方法でもアクセスできます。

まとめ

リダイレクトしてしまうので、ドメイン名も午前と午後で変わるので、ドメインも変わらないようにするなら app.example.org をリダイレクトし、カスタムドメインをAPIで定時で削除&追加でするとできます。一瞬アクセスできない時間ができてしまいますが。

今のところ解析結果をMemcachedに入れているだけで、特にデータ更新も行わないお遊びのサイトなので今回の方法を取りました。 無料の範囲内で遊ぶために2つもリソース使って、本末転倒じゃないかという内容なので、いろいろお察し下さい…。

footnote

[1]制約超えると通知されるメールが増えてきたので…。
]]>
Fri, 17 Jul 2015 00:00:00 +0900
http://d.palmtb.net/2015/07/04/drawing_tool_of_the_python_package_digraph.html http://d.palmtb.net/2015/07/04/drawing_tool_of_the_python_package_digraph.html <![CDATA[Drawing tool of the Python package digraph]]> Drawing tool of the Python package digraph

ふと Heroku で遊んでみようと思い、 「Webブラウザで Python パッケージの依存関係を表す有向グラフ」を描画するツール を作ってみました。

誰得で、またつまらぬモノを作って公開してしまった、が後悔はしていない。 機能的には個人的には欲しかったモノなのと、最小構成の無料の範囲で遊べているので。

特徴

  • ナビゲーションバーの”Example“をクリックするとpgraphの最新バージョンの依存関係を描画します
  • search packages のフォームから検索すると、 PyPI のAPIでの検索したパッケージ一覧の結果を表示します
  • 描画されたグラフは、ノードをクリックしてドラッグして、グリグリ動かしたり、グラフの拡大・縮小ができます

グリグリ動かす?拡大・縮小?

グラフをグリグリ動かしたり、拡大・縮小するのに使っているのは、 Linkdraw というライブラリです。ご存知でしょうか?

元同僚の mtoshi さんが開発したトポロジを描画するツールで、大統一Debian勉強会 2013発表されました 。ここ数年、一番感銘を受けたソフトウェアで、「mtoshiスゲー!!」を引き起こした一番のシロモノです。

このツールは、ネットワークのトポロジを描画するものなので、今のところ Wiki から辿れる サンプルデモ くらいしか表に出ているものが無いので、他の活用例があると良いなぁと思い、今回使ったという次第です。

pgraphのexample

上記のExampleのリンクから pgraph のグラフを表示すると、pgraph 自体はパッケージの依存関係が多いため、パッケージのノードを動かすとモッサリすることもあります。これはJavaScriptでSVGを処理しているので完全にクライアントのリソース次第です。Linkdraw自体は有向グラフではないので、依存関係の方向性はlineのdescriptionに -> を表示しています。これは py-deps というライブラリで生成しています。Pythonパッケージの依存関係を調べ、各種グラフに変換するために実装したライブラリです。 [1]

pgraphの構成

Webフレームワークには Pyramid [2] 、パッケージの検索、依存関係の分析および Linkdraw用のデータ生成には、自作の py-deps、py-depsに依存関係の分析を実行させる処理は Celery でタスクキューに投げ非同期で実行し、分析した結果はキャッシュに格納します。ローカルで実行する時と、Herokuで実行する時とで、それぞれCeleryのBrokerとキャッシュのバックエンドを変更できるようにしています。

py-depsの機能

パッケージの検索には PyPIの XML-RPC メソッド を使っています。パッケージの依存関係の分析には pip のライブラリを使いました。 [3] パッケージによっては、依存パッケージが多く、パッケージのダウンロードに時間が掛かることもあるので、前述の通りCeleryを使っています。キャッシュはPickleでのファイルキャッシュかMemcachedをpy-depsで選べるようにしています。

今回ハマったこと

Herokuでも当初ローカルと同様の構成にしようと、Celeryのバックエンドには CloudAMQP 、キャッシュはPickleでのファイルキャッシュにしていましたが、いろいろ問題がありました。また、Linkdrawでパッケージの依存関係を表示すること自体にも問題がありました。最後にそれらをまとめて紹介します。

Linkdrawでノードとエッジが離れて動いたりする問題

現在のLinkdrawの仕様で一部の使えない文字が原因でした。このため、setuptoolsのextras_requireを表示するのに、 foo[bar]foo____bar と変換しています。

なお、使用できない文字は ドキュメントに追記して おいてもらいました。

celerydが起動しているように見えるのに、タスクが登録されない問題

これは単に、Herokuではworkerがデフォルトでは起動しない、というのを私が知らなかっただけなので、

$ heroku ps:scale worker=1

で起動することで解決しました。

キャッシュファイルが作成されない問題

Herokuではpipでパッケージをインストールできるのだから、アプリから一時ファイルの生成もできるんじゃないか、と誤解していたため、当初依存関係の結果をPickle化してファイルキャッシュとしていました。

しかし、実際に作ってからHeroku上で動かしたところ、ファイルは作成できてもすぐに削除されることを知り、キャッシュのバックエンドには pylibmc を使って、Memcachedを使えるようにしました。 [4]

HerokuではAddonの Memcached Cloud を使っています。

pylibmcがビルドできない問題

pylibmcは libmemcachedの C bindingのPythonパッケージなので、Herokuで使うには build-pack-python を使ってビルドを行う必要があります。build-pack-pythonは requirements.txt にビルド対象のパッケージが記載されていることをトリガーにして、ビルドを実行します。

で、これでハマりました。

普段、Pythonパッケージを作るとき、requirements.txtはsetup.pyの install_requies から自動生成するようにしています。今回も同様にしていました。しかしこれが原因でpylibmcがビルドされない問題に当たりました。setup.pyでのrequirements.txtの生成は、build-packによるビルドより先に実行されることを期待していました。しかし実際にはbuild-packでのビルドの方が先であり、build-packでのビルド時にはrequirements.txtが無いため、pylibmcがビルドされないということでした。

この問題は、Heroku用のブランチのみrequirements.txtをindexに追加することで解決しました。

CloudAMQPのメッセージがすぐ上限に達しそうな問題

当初、パッケージ依存関係を分析するタスクをCloudAMQPに登録していましたが、タスクの結果を celery.result.AsyncResult でチェックするだけでメッセージカウンターが上がってしまうのでした。。最小構成での無料の範囲で動かそうとすると、CloudAMQPの一ヶ月のメッセージの上限が100万なのに一週間で上限の7割に達してしまいました。これはアカン。

ということで、Celeryのバックエンドを Heroku Postgres に変更することで回避しました。

Heroku Postgresの最小構成の制限はメッセージ数ではなく、1万行までのデータなので、CeleryのBrokerとして使うのであればタスクが正常に完了するか、あるいは失敗してrevokeさせれば、レコードは削除されます。ですのでメッセージ数はもちろん、レコード数の制約も特に気にする必要がありません。

Price planが変わった問題

遊びだしてからSpin downしないように New Relic APM を使って polling していたのですが、なんか Heroku からメールが来るなぁと思ったら、 DynosのPricingが変更されて おり、最低6時間はSleep が必要になっていました。

とりあえず、誰得ツールなので polling するのをやめれば大丈夫でしょう。

終わりに

特にまとめはありませんが、ぜひグリグリ遊んでみてください。

footnote

[1]開発自体はpy-depsの方が先です。現状、Linkdrawと NetworkX だけに対応しています。 blockdiag にもそのうち対応する予定です。
[2]仕事では Flask, Django および django REST framework が多かったのでたまには別のものも使ってみるか、というノリです。
[3]pip コマンドではありません。
[4]ローカルで動かす場合にはPickleを使う構成に現在もできます。なお、手元でmemcachedをバックエンドにしてテストするときには、普段yrmcdsをインストールしているのでそっちを使っています。
]]>
Sat, 04 Jul 2015 00:00:00 +0900
http://d.palmtb.net/2015/01/09/released_gosh_0_2_0.html http://d.palmtb.net/2015/01/09/released_gosh_0_2_0.html <![CDATA[Released Gosh 0.2.0]]> Released Gosh 0.2.0

Golang用の対話形式シェル Gosh0.2.0 をリリースしました。

前回のブログ(Interactive shell for Golang)の時は、 0.1.5 でしたので、そこからの変更点をまとめると次の通りです。

  • main関数の宣言を省略可能にしました
  • 型および関数の宣言のパーサーの機能強化しました
  • 関数宣言の再宣言可能にしました
  • Go 1.2のサポート廃止しました
  • 各種バグの修正

などです。実装としてはregexpパッケージの正規表現から、go/scanner, go/tokenパッケージを利用した字句解析に変更しています。

main関数の省略

README にも記載していますが、簡単に紹介します。

Goshの実行方法

$ $GOPATH/bin/gosh

fmt.PrintlnでのHello world

>>> fmt.Println("Hello world")
Hello world
>>>

変数の宣言と演算

>>> var i = 10
>>> i++
>>> fmt.Println(i)
11
>>>

省略形式の変数宣言でも大丈夫です。

>>> i := 10
>>> i += 100
>>> fmt.Println(i)
111
>>>

パッケージのインポート

Goshを作ったそもそもの動機である、パッケージのインポートはもちろん使えます。 次は github.com/bitly/go-simplejson を使った場合の例です。

>>> import "github.com/bitly/go-simplejson"
>>> r, _ := http.Get("http://d.palmtb.net/_static/glaneuses.json")
>>> defer r.Body.Close()
>>> j, _ := simplejson.NewFromReader(r.Body)
>>> fmt.Println(j)

表示は省略しましたが、simplejson.Json型のデータが出力されます。

main関数の宣言のリセット

>>> func main(){}

とするとmain関数の宣言を省略して宣言した変数はクリアされます。

fmt.Print*の実行は一回のみ

fmt.Println("hello") などを実行後、その後に他の入力を続けても、最初に実行された fmt.Println("hello") は実行されないようにしました。つまり、次のようになります。

>>> i := 1
>>> fmt.Println(i)
1
>>> i++
>>> fmt.Println(i)
2

既知の問題

  • main関数を入力した後、Enterをもう一度入力しないとプロンプトが表示されない [1]
    • 0.2.2 で修正しました(2015-01-14追記)
  • 型の再宣言ができない

余談

前のブログでは matsuu さんの tweet やHacker Newsへの 投稿 でかなりStarsがつきました。海外の方が多いのは結構モチベーションが上がりますね。matsuuさん、ありがとうございました。

あとは、実際に使ってissues登録やpull requestしてくれる方が出てくると嬉しいですね。

Footnotes

[1]上記の例で空白行を掲載しているのはそのためです。
]]>
Fri, 09 Jan 2015 00:00:00 +0900
http://d.palmtb.net/2015/01/02/aspiration_of_the_2015.html http://d.palmtb.net/2015/01/02/aspiration_of_the_2015.html <![CDATA[Aspiration of the 2015]]> Aspiration of the 2015

あけましておめでとうございます。今年もよろしくお願いします。 [1]

今年の抱負

今朝見た初夢は

  • 仕事の前に昼飯のつもりで買ったケーキが、ホールで一人で食べきれずに諦めて持って帰ることにして、外に食べに行ったらやたら混んでいて、通された席がトイレの前で辛い
  • 泳いでいたら、プクプクみたいなのに棘を口から吹きつけられて、刺さってチクチク痛い

というよく分からん内容でした。とりあえず食べ過ぎと怪我には気をつけろ、ということなんでしょうかね。また、元日早々、おまめ二号の風邪がうつり、喉が痛かったり、おまめ二号の風邪も長いので [2]

「家族皆健康第一」を今年の抱負にします。

KPT

その他細かい目標は以下。

Keep

  • 7-16時勤務の朝型生活
  • 毎日コーディング

Problem

  • Debianの活動が減っているので無理ない程度に増やす [3]
  • 英語使う機会減ってるのでまず習慣化する
  • おまめ一号とのコミュニケーションを改善する [4]

Try

  • おまめ一号のDebianデビュー&妻にPython教える
  • 中断したHaskellの勉強の再開&何か作る
  • 4月からおまめ一号の幼稚園でさらに支出が増えるので、収支の改善方法を検討&実行する

Footnotes

[1]昨年は喪中でしたので書きませんでした。
[2]昨年11月末にRSウィルス感染症で気管支炎が重症化して入院したので、風邪引くと咳や痰が続くのです…。
[3]昨年は大統一Debian勉強会を結局できなかったし…。
[4]まだ3歳前にもかかわらず、「パパ嫌い」とお風呂一緒に入るのを嫌がられているで、そう言われないように…。
]]>
Fri, 02 Jan 2015 00:00:00 +0900
http://d.palmtb.net/2014/12/31/review_the_2014.html http://d.palmtb.net/2014/12/31/review_the_2014.html <![CDATA[Review the 2014]]> Review the 2014

今年は昨年と違って(Review the 2013 and aspiration of the 2014)、 余裕があったので年内に振り返りをしてみました。

抱負であった「健康第一」に対して

今年も昨年同様「健康第一」を抱負にしていました。10月に5年ぶりくらいに右肩脱臼してしまい、今もリハビリを続けてはいるものの、昨年に比べると体調が良く、病院に行く回数も非常に少なかったので達成できたと実感できる一年でした。これは2月の次女出産に伴う生活の変化が大きな要因でした。 [1]

次女(おまめ二号)の誕生と生活の変化

昨年の11月末に妻が切迫早産の危険が出てきたため、寝たきりにさせる必要がありました。結局、出産後の1ヶ月頃(2月下旬頃)までは長女(おまめ一号)は保育園の一時保育もしくは妻の両親に預かってもらい、在宅勤務をする、という生活を送っていました。

おまめ二号が産まれてからは、朝5-6時頃に起床し、ラジオ体操と朝食以外は、出勤で9時頃家を出るまでの間、昨年目標にした朝のコーディングを続けていました。

10月中旬頃から、諸事情により生活習慣と仕事のやり方を変える必要が出てきました。現在は、3時から4時半ごろに起床、早朝コーディングと朝食の後、5時半過ぎには出勤、7-16時を定常勤務として、17時過ぎには帰宅、21-22時には家族皆で就寝、という生活になりました。

この生活リズムに変更したことによるメリットは次の4つです。

  • 体調が良くなった
  • 子供たちと接する時間が増えた
  • 仕事の効率が良くなった
  • 朝のコーディングの時間が増えた

特に仕事面では、7時出勤だとほぼ他に人がおらず、一人で集中できる時間がとても長いので、とてもおすすめです。

仕事

今年行った割と効果の高かった内容としては、

あたりでしょうか。

Debian

今年の活動としては、

あたりです。少ない…。

プログラミング

年初にGolangの勉強を行ってから、Python以外でGolangでコーディングすることが増えました。 年末現在、プライベートではGolangとPythonの比率だと7:3くらいになりました。仕事でもEC2上で使うツールには、デプロイの関係上Golangで書いたりしています。しかし、前述の脚注の通り、仕事ではPythonとDjangoで開発に使う言語とフレームワークを統一したので、もっぱらPython漬けです。

年初に目標にした、早朝コーディングは大晦日現在毎日続けており、今年のGitHubのContributionsは下記のようになりました。

../../../_images/github-contributions-2014.png

昨年が閑散たる有り様でしたので、結構良い状況です。

../../../_images/github-contributions-2013.png

コーディング時にハマるケースが少なくなったり、実装に掛かる時間が短くなったり、などの実感の違いが出てきている気がします。 [6]

その他

ブログ書かなくなったなーという。ブログ書くより、コード書く方が楽しいからなんですけどね。

まとめ

まとめなし、オチ無し。来年の抱負は年明けに。

Footnotes

[1]昨年の年始の段階では「諸事情」としていました。
[2]開発に使う言語とフレームワークを、Pythonと、Djangoおよびdjango REST frameworkに統一したため。
[3]Debianパッケージ版のオートビルドシステムをちょっとカスタマイズして、GitHub Enterprise、Jenkins、devpi & devpi-ldapを連携して作った簡単なお仕事です。
[4]Debianには直接関係ないのですが、今年初めて家族を連れてOSCに参加しました。
[5]SurfのDebianパッケージ化しようとしていましたが、Build-Dependsで必要なBSON用のライブラリが含まれるMongo用のドライバのビルドが通らない問題でJessie入りは断念しました。
[6]個人の感想です
]]>
Wed, 31 Dec 2014 00:00:00 +0900
http://d.palmtb.net/2014/11/17/interactive_shell_for_golang.html http://d.palmtb.net/2014/11/17/interactive_shell_for_golang.html <![CDATA[Interactive shell for Golang]]> Interactive shell for Golang

Golang用の対話形式シェル Gosh を作りましたよ、というお話です。

Golangでコードを書き始めた今年の年初くらいから、iPythonのような対話形式のシェルがほしいなと思っていました。気になるライブラリをちょっと試してみたいときに、 go get して、Emacsでコード書いて、 go run を実行する、というのは億劫で、 import したらそのまま go get して実行できれば良いな、と思っていました。 そういったツールが無いかと調べて、go-evaligoGo playground [1] にはたどり着いたのですが、パッケージをインポートする機能がないので自分の欲しい機能とは違う、ということでエイヤっと作ってみました。

特徴

現在の特徴としては次のとおりです。

  • Go 1.2 以上対応
  • 対話形式のシェル
  • package main の入力省略可 [2]
  • 標準ライブラリの import 省略可
  • 標準ライブラリ以外のライブラリの import[3]
  • import 文の重複入力を無視
  • import しても未使用のパッケージを無視
  • Ctrl + d で終了

やっていることとしては、単に入力したコードからを、一時ファイル作って go run を実行するだけの簡単な内容です。

インストール方法や使い方は、 README を読んでください。

今後

  • main() を入力しないと実行できないので省略できるようにする
  • タブ補完
  • DebianパッケージなどでシステムグローバルにインストールしたGolangライブラリなどの import を省略できるようにする

などを考えています。良かったら使ってみて下さい。

Footnotes

[1]ブラウザで実行したいわけではないので、Go Playgroundだと更に自分のほしいのと違うのですよね。
[2]入力を省略できる、というか、入力するとエラーになります。 修正しました。(2014-11-18 追記)
[3]import example.org/foo/bar のように実行すると、 go get します。
]]>
Mon, 17 Nov 2014 00:00:00 +0900
http://d.palmtb.net/2014/09/09/changed_to_jetdrive_420.html http://d.palmtb.net/2014/09/09/changed_to_jetdrive_420.html <![CDATA[Changed to JetDrive 420]]> Changed to JetDrive 420

普段プライベートではMacBookPro 8,2 [1] でVirtualBox上で、Debian GNU/Sidを使っています。購入時に128GB SSDに変更したのですが、パッケージメンテナンスしたり、コード書いたり、家計簿つけたりしているSidだけで90GB-100GBくらい使っていて、そろそろ容量増やしたいなと思っていたら、今年の春にTranscendから JetDrive が出ました。

出た当初はまだ高いなぁ、と思って様子見していましたが、最近チェックしたら 480GBのJetDrive 420が約20%価格ダウン していたので、価格動向見て今が買いどきだな、ということで購入しました。

交換方法

一応、日本語で書かれたマニュアルも添付しているのですが、かなり端折っているので、上記の製品ページの動画を見るのがベストです。90GB弱の使用率で128GBのSSDをリストアするのに要した時間は約1時間半強でした。寝ている間か、風呂かメシ食っている間にやるのが良いですね。

私の使っているモデルのMacBookProの場合、裏蓋を開けるのには少し注意が必要でした。ネジがそれぞれ垂直ではなく、少し斜めになって止められています。気づかずに付属のドライバーでまっすぐ回そうとすると、ねじ山を潰してしまいます。また、ネジを全て外し終わっても、裏蓋自体も外しにくいので、少し隙間を開けたら、本体からまっすぐ持ち上げるのがよいでしょう。

こま毛に気をつけろ!

裏蓋を開けてびっくりしたのは、こま毛だらけだったことです!どうやって、こんな奥にまでこま毛が入ったものかというくらい、結構入り込んでいました。あ、こま毛ってのは、こまちゃん [2] の毛のことです。早朝、朝練や家計簿つけていると餌をねだりにやってきてます。定時 [3] よりも早かったら、後でね、と放置プレーしているとMacBookProの背後に回りこむ、あいつの毛です。ハンドクリーナーとガムテープで丁寧に取っておきました。

まとめ

特に技術ネタも何もないお話でした。ポイントは、「こま毛に気をつけろ!」ということです。容量増えてとりあえず一安心ですね。

Footnotes

[1]15-inch Early 2011, MC721xx/Aを英語キーボード、ノングレア液晶ディスプレイ、128GB SSD, Memory 8GBにしています。
[2]久々に登場の我が愛猫こまめさん。
[3]朝晩とも6時が餌の定時。
]]>
Tue, 09 Sep 2014 00:00:00 +0900
http://d.palmtb.net/2014/08/23/clean_build_rpm_with_mock_as_like_git_buildpackage.html http://d.palmtb.net/2014/08/23/clean_build_rpm_with_mock_as_like_git_buildpackage.html <![CDATA[Clean build RPM with mock as like git-buildpackage]]> Clean build RPM with mock as like git-buildpackage

DebianパッケージのビルドシステムはTrustyでJenkinsとpbuilder & cowbuilder & git-buildpackage を使って実装している、という話を 7月のDebian勉強会 でお話しました。

一方、RPMについては、2年ほど前にFlaskとCouchDBで実装したパッケージ管理システムを作成しました。Webブラウザ経由でRPMbブラウザでアップロードすると、ローカルリポジトリに登録されるようなシロモノです。個人的にはRPM使わないのでまぁ良いのですけど、ブラウザ経由でアップロードとか面倒ですね。 [1] また、Upstreamが配布しているRPMはまだしも、カスタムパッケージの場合、Debianパッケージでのpbuilderなどのように、mockでクリーンビルドを行っていないと、「オレの環境ではビルドできるんだけど?」という、「これはヒドイ」パッケージが配布されます。 [2]

そこで、前述のDebianパッケージのビルドシステム同様に、Debian上でmockを使ってGitリポジトリからクリーンビルドすることができないかを検証してみました。

環境

検証した環境は次のとおりです。Trustyのmockパッケージも1.1.33で、後述のJenkinsでの実行は、Trusty上での実行をサンプルリポジトリを使って確認済みです。

  • Debian GNU/Linux Sid
  • mock 1.1.33
  • chrootターゲット epel-6-x86_64 (CentOS6用) [3]
    • chrootのターゲットは、/etc/mock以下の .cfgファイルから選びます。mock(1)には、デフォルトでは、/etc/mock/default.cfgというファイルが選択される、とあるのですがDebianパッケージにはこのファイルはありません。必要ならユーザが用意する必要があります。

また、site-wideの設定として/etc/mock/site-default.cfgが使用されます。こっちは後述のGit関連のオプションを指定する際に内容を確認しました。

環境準備

  1. mockパッケージのインストール:

    $ sudo apt-get install mock
    
  2. mockグループの作成:

    $ sudo addgroup mock
    
  3. 実行ユーザをmockグループに追加:

    $ sudo adduser mkouhei mock
    
  4. chroot用ディレクトリの作成:

    $ sudo install -g mock -m 2775 -d /var/lib/mock
    
  5. chrootツリー作成:

    $ mock -r epel-6-x86 --init
    

これを実行しなくても、初回のビルド実行すると、chrootツリーがなければ作成されます。 /var/lib/mock/epel-6-x86_64/rootに作成されます。

Source RPMをリビルド

まずは普通にSource RPMをリビルドしてみました。:

$ mock -r epel-6-x86_64 rebuild /path/to/example-0.1-1.src.rpm

実行すると、ログと正常に実行された場合に生成されるRPMファイルが/var/lib/mock/epel-6-x86_64/result以下に生成されます。生成されるファイルは下記の通りです。

  • available_pkgs
  • build.log
  • installed_pkgs
  • root.log
  • state.log
  • example-0.1-1.src.rpm
  • example-0.1-1.x86_64.rpm

root.log, state.log, build.logでビルドに問題無いかを確認できます。mock自体はPythonで書かれていて、実行時にエラーになるとPythonのログを吐いてくれるので、原因は割と追っかけやすいです。

chrootツリーは生成されるとepel-6-x86_64の場合約432MB、キャッシュが/var/cache/mock/epel-6-x86_64以下に約327MB、/var/cache/yum以下に約71MB程度できます。キャッシュは依存するパッケージなどによって増減するでしょうけど、まぁ最低1GB程度あれば事足りそうです。

Gitリポジトリからビルド

git-buildpackageと同様に、Gitリポジトリからビルドするには、 –scm-enable オプションおよび –scm-option オプションを使います。

mock(1)のサンプルでは、 –scm-option の引数には:

mock -r fedora-14-i386 --scm-enable --scm-option package=pkg

とだけあり、他のkey-valueが分からないのですが、ここで前述の/etc/mock/site-defaults.cfgが参考になります。次のような記述があります。

#
# Things that must be adjusted if SCM integration is used:
#
# config_opts['scm'] = True
# config_opts['scm_opts']['method'] = 'git'
# config_opts['scm_opts']['cvs_get'] = 'cvs -d /srv/cvs co SCM_BRN SCM_PKG'
# config_opts['scm_opts']['git_get'] = 'git clone SCM_BRN git://localhost/SCM_PKG.git SCM_PKG'
# config_opts['scm_opts']['svn_get'] = 'svn co file:///srv/svn/SCM_PKG/SCM_BRN SCM_PKG'
# config_opts['scm_opts']['spec'] = 'SCM_PKG.spec'
# config_opts['scm_opts']['ext_src_dir'] = '/dev/null'
# config_opts['scm_opts']['write_tar'] = True
# config_opts['scm_opts']['git_timestamps'] = True

# These options are also recognized but usually defined in cmd line
# with --scm-option package=<pkg> --scm-option branch=<branch>
# config_opts['scm_opts']['package'] = 'mypkg'
# config_opts['scm_opts']['branch'] = 'master'

この中で実質上必須のオプションは次の通りです。 これらのkey毎に –scm-option で指定する必要があります。

  • package
  • git_get
  • spec
  • wirte_tar

まず、 git_get を指定しないと上記の例がデフォルト設定になっているため、 git://localhost/package.git からcloneしようとします。 git clone をつけないといけないのと、既にclone済みのディレクトリをそのまま使えないのがイケてないですね。 ただ、後者については、 git_get=git clone /path/to/repo と指定すれば、clone済みのリポジトリからcloneできます。 [4] また git_get でcloneすると、自動的にchroot内のローカルリポジトリにchdirします。

spec の指定はローカルリポジトリのディレクトリをrootとし、そこからの相対パスで指定できます。なので、upstreamのGitリポジトリにrpm用のspecファイルが含まれている場合、specファイルの相対パスを指定してビルドすることができます。簡便であるという点では良いのですが、Debianパッケージのように、upstreamのソースコードとメンテナスクリプトを分離する概念がmockしないため、第三者のFLOSSのGitリポジトリからforkしてパッケージ管理するとコミットログが混じってしまって混ぜるな危険な感じではあります。あるいは、自分で git-buildpackage のように upstream ブランチと master ブランチを分けて管理する、という方法も取れますが、自分で一からやるのは面倒ですね。

write_tar は、specファイルの中で Source タグを指定している場合、 True を指定します。デフォルトは False です。 True を指定するとchroot内の /builddir/build/SOURCES ディレクトリ以下にGitリポジトリから tar czf で生成されたtarballが配置されます。 [5] これが生成されないと、mockでの rpmbuild 実行中にコケます。

実際にGitリポジトリからビルドするには次のように実行します。:

$ mock -r epel-6-x86_64 --scm-enable --scm-option package=example --scm-option git_get="git clone git@remote/example.git" --scm-option spec=rpm/example.spec --scm-option write_tar=True

ローカルミラーやローカルリポジトリを使う場合

カスタムパッケージなどに依存するパッケージを作るには、ローカルリポジトリが必要になります。 chroot環境で参照するyumリポジトリは、 -r オプションで指定した、 epel-6-x86_64.cfg に記述があります。

config_opts['root'] = 'epel-6-x86_64'
config_opts['target_arch'] = 'x86_64'
config_opts['legal_host_arches'] = ('x86_64',)
config_opts['chroot_setup_cmd'] = 'groupinstall buildsys-build'
config_opts['dist'] = 'el6' # only useful for --resultdir variable subst

config_opts['yum.conf'] = """
[main]
cachedir=/var/cache/yum
debuglevel=1
reposdir=/dev/null
logfile=/var/log/yum.log
retries=20
obsoletes=1
gpgcheck=0
assumeyes=1
syslog_ident=mock
syslog_device=

# repos
[base]
name=BaseOS
enabled=1
mirrorlist=http://mirrorlist.centos.org/?release=6&arch=x86_64&repo=os
failovermethod=priority

[updates]
name=updates
enabled=1
mirrorlist=http://mirrorlist.centos.org/?release=6&arch=x86_64&repo=updates
failovermethod=priority

[epel]
name=epel
mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=epel-6&arch=x86_64
failovermethod=priority

[testing]
name=epel-testing
enabled=0
mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=testing-epel6&arch=x86_64
failovermethod=priority

[local]
name=local
baseurl=http://kojipkgs.fedoraproject.org/repos/dist-6E-epel-build/latest/x86_64/
cost=2000
enabled=0

[epel-debug]
name=epel-debug
mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=epel-debug-6&arch=x86_64
failovermethod=priority
enabled=0
"""

なので、ローカルミラーやローカルリポジトリを使う場合にはここを変更すればよいでしょう。なお、デフォルトでgpgcheckは無効になっています。 [6] gpgcheckを有効にして、ローカルリポジトリのGPG公開鍵を追加する場合は、/var/cache/mock/epel-6-x86_64/root_cache/cache.tar.gz を修正し、chrootツリーを作成しなおす必要があります。

Jenkinsでmockを実行する

Jenkinsでmockを実行する場合、ssh経由でしか git clone できないリポジトリを使う場合には、private keyのパスフレーズの入力面倒です。なので、JenkinsのGitプラグインを使って、JenkinsのWORKSPACEにcloneしたローカルリポジトリを使ってビルドすることになります。 ところが、前述の通り、mockは git_getgit clone する必要があります。なので、

  1. JenkinsのGitプラグインで git clone する
  2. mockに –scm-option git_get=’git clone ${WORKSPACE}/repo’ オプションで、JenkinsのWORKSPACEから更に git clone する

という2段階の git clone を行えば使えることになります。 なんかダサいですね。

Bitbucketに用意した サンプルリポジトリ を使うと、Jenkinのジョブ設定は下記のようになります。

mock -r epel-6-x86_64 \
    --resultdir=${WORKSPACE}/result \
    --scm-enable \
    --scm-option package=example \
    --scm-option git_get="git clone ${WORKSPACE}/example" \
    --scm-option spec=rpm/example.spec \
    --scm-option write_tar=True

–resultdir オプションで${WORKSPACE}/result を指定すると、ワークスペース下にresultディレクトリが生成されます。

残タスクとしては、生成するRPMにGPGで署名すること、ローカルリポジトリにpush & createrepoを実行することですね。

まとめ

以上で、Debian/UbuntuでJenkinsを使って、RHEL系のシステムのRPMの自動ビルドもできるようになりました。普段Debianシステムしか使ってないのに、やんごとなき事情でRPM作らざるを得なくなっても、Debianシステムだけで基本的には完結できますね。

Footnotes

[1]自分で作って&メンテしておきながら、これはヒドイ。
[2]他の人が作ったspecファイルを今回の検証に使ったらそうだったのです。
[3]デフォルトでは、CentOSとFedoraの各バージョン用のファイルが用意されています。この辺はpbuilder/cowbuilderよりも親切で便利ですね。
[4]CVS、SVNも対応できるようにするため、とは言え、 コマンドを書かないとアカン のは微妙ですね。
[5]git archive コマンド ではない のです。これもCVS, SVNも対応するためでしょう。
[6]upstream自体で無効 にされています
]]>
Sat, 23 Aug 2014 00:00:00 +0900
http://d.palmtb.net/2014/06/13/segfault_occurs_when_executing_celery_worker_with_librabbitmq1.html http://d.palmtb.net/2014/06/13/segfault_occurs_when_executing_celery_worker_with_librabbitmq1.html <![CDATA[Segfault occurs when executing celery worker with librabbitmq1]]> Segfault occurs when executing celery worker with librabbitmq1

Ubuntu Trustyのpython-celeryパッケージを使って、celery workerを実行すると、プロセスが突然死ぬ、という現象に遭遇しました。 原因は、AMQPクライアントライブラリであるlibrabbitmq1がsegfaultを起こしていたためでした。

[881933.805893] celery[12704]: segfault at 0 ip 00007f23cd79f6ab sp 00007fff5afe3f70 error 4 in librabbitmq.so.1.1.1[7f23cd797000+10000]

celerybeatを使うと、segfaultは起きないものの、RabbitMQにジョブだけたまり、ちっとも処理されない、という現象が発生します。

Sidで開発していたときには発生しなかった問題だったので、比較してみたらSidではlibrabbitmq1とこのライブラリに依存するpython-librabbitmqは使っておらず [1] 、python-amqpを使っていました。依存関係としては下図のようになります。

python-amqpもインストールされていたのですが、python-librabbitmqがインストールされているとこちらが優先されるようです。

workaround

librabbitmq1とpython-librabbitmq [2] をアンインストールすると、この問題は解決します。ちなみにSidでこれらのパッケージをインストールしてみましたが再現しなかったのでTrusty(のパッケージのバージョン)だけでの問題のようです。

Footnotes

[1]パッケージ自体インストールしていませんでした。
[2]librabbitmq1パッケージをアンインストールすれば、依存関係でpython-librabbitmqも自動的にアンインストールされます。
]]>
Fri, 13 Jun 2014 00:00:00 +0900
http://d.palmtb.net/2014/05/28/i_made_debsign_of_python_libary_that_can_be_run_without_a_tty.html http://d.palmtb.net/2014/05/28/i_made_debsign_of_python_libary_that_can_be_run_without_a_tty.html <![CDATA[I made debsign of Python libary that can be run without a TTY]]> I made debsign of Python libary that can be run without a TTY

この辺の話の続きです。

諸事情で、ローカル環境でDebianパッケージをbackportsしたり、 オリジナルのパッケージを諸事情で公式パッケージではなく、非公開パッケージとして、 それらをローカルアーカイブに突っ込むのに、Jenkinsで全て完結させたいなと思い、 [1] いろいろ試行錯誤したところ、どう頑張っても debsing で署名することだけはできないことが分かりました。

debsign コマンド自体がつぎのように標準入力からパスフレーズを受け取ってプロンプトで代入する、ということができません。

$ echo -e "passphrase\npassphrase\n" | debsign some.changes

同じように試行錯誤している人はいるみたいですが、解決している人はいなさそうでした。 一方、 gpg コマンドは、 –batch および –no-tty というオプションがあります。 で、GnuPGのPythonバインディングである python_gnupg はこの機能を使えることが分かりました。

debsign コマンドの挙動としては、まず.dscファイルを署名し、署名後のファイルサイズとmd5, sha1, sha256のチェックサムを取得し、.changesのエントリを書き換え、.changesファイルを署名します。 で.changesファイルを sed コマンドなどで書き換えるのはちょいと面倒だなと思っていたら、.changesファイルを扱う、deb822というモジュールがありました。これは、python-debianパッケージとして提供されています。 [2] これを使うと、.changesファイルの情報をDictに似たデータとして扱えます。

で、これらを使って、pydebsignというPythonライブラリを作りました。

このライブラリで debsign と同等の処理を、JenkinsなどのCIで実行させることができます。 そのサンプルが、 これ です。

このコードでJenkinsでパッケージビルド&署名&reprepro管理のローカルアーカイブへの登録まで全部自動で行えるようになりましたよ、 というお話でした。 [3]

footnote

[1]一からソースパッケージを作るところの自動化は除く。
[2]PyPI でも公開されています。 https://pypi.python.org/pypi/python-debian
[3]リンク先のGistのコードを使うために、JenkinsおよびRepreproにも設定が必要なのですが、それはまた別の話。
]]>
Wed, 28 May 2014 00:00:00 +0900
http://d.palmtb.net/2014/05/22/difflib_ndiff___and_assertmultilineequal___are_very_useful.html http://d.palmtb.net/2014/05/22/difflib_ndiff___and_assertmultilineequal___are_very_useful.html <![CDATA[difflib.ndiff() and assertMultiLineEqual() are very useful]]> difflib.ndiff() and assertMultiLineEqual() are very useful

Gitでdiffを行うとデフォルトでは、GNU diffの diff -u と同じ挙動なので行単位での差異がでます。 文章のdiffを取りたい場合には –word-diff というオプションをつけると、 [-word-]{+word+} という形式で違う箇所が表示されるので便利です。

さて本題。Pythonでテストコードを書いて、文字列の比較に assertEqual() を使うと、

_____________________________________ DebbuildTests.test_generate_batch_script ______________________________________

self = <debbuild.tests.test_debbuild.DebbuildTests testMethod=test_generate_batch_script>

    def test_generate_batch_script(self):
        """ unit test of generate_batch_script """
        debbuild.generate_batch_script(self.params)
        # self.assertMultiLineEqual(self.batch_content,
        self.assertEqual(self.batch_content,
>                        debbuild.generate_batch_script(self.params))
E       AssertionError: '#!/bin/sh -x\nexport DEBFULLNAME="Dummy Maintainer"\nexport DEBEMAIL=dummy@example.org\napt-get -y install curl devscripts quilt patch libdistro-info-perl fakeroot\napt-get -y build-dep shello\ndget -d http://example.org/debian/pool/main/s/shello/shello_0.1-1.dsc\ndpkg-source -x shello_0.1-1.dsc\n(\ncd shello-0.1\ndebuild -us -uc\n)\ncp -f shello_0.1-1.debian.tar.gz  shello_0.1.orig.tar.gz shello_0.1-1.dsc /home/mkouhei/debbuild/temp/\n' != '#!/bin/sh -x\nexport DEBFULLNAME="Dummy Maintainer"\nexport DEBEMAIL=dummy@example.org\napt-get -y install curl devscripts quilt patch libdistro-info-perl fakeroot\napt-get -y build-dep shello\ndget -d http://example.org/debian/pool/main/s/shello/shello_0.1-1.dsc\ndpkg-source -x shello_0.1-1.dsc\n(\ncd shello-0.1\ndebuild -us -uc\n)\ncp -f shello_0.1-1.debian.tar.gz shello_0.1.orig.tar.gz shello_0.1-1.dsc /home/mkouhei/debbuild/temp/\n'

tests/test_debbuild.py:220: AssertionError

とエラーは検出できてもどこが間違っているのか解読するのは困難です。なので、 assertMultiLineEqual() を使うとこの問題を解決できます。

(snip)
>                        debbuild.generate_batch_script(self.params))
E       AssertionError: '#!/bin/sh -x\nexport DEBFULLNAME="Dummy Maintainer"\nexport DEBEMAIL=dummy@exam [truncated].
.. != '#!/bin/sh -x\nexport DEBFULLNAME="Dummy Maintainer"\nexport DEBEMAIL=dummy@exam [truncated]...
   E         #!/bin/sh -x
   E         export DEBFULLNAME="Dummy Maintainer"
   E         export DEBEMAIL=dummy@example.org
   E         apt-get -y install curl devscripts quilt patch libdistro-info-perl fakeroot
   E         apt-get -y build-dep shello
   E         dget -d http://example.org/debian/pool/main/s/shello/shello_0.1-1.dsc
   E         dpkg-source -x shello_0.1-1.dsc
   E         (
   E         cd shello-0.1
   E         debuild -us -uc
   E         )
   E       - cp -f shello_0.1-1.debian.tar.gz  shello_0.1.orig.tar.gz shello_0.1-1.dsc /home/mkouhei/debbuild/temp/
   E       ?                                  -
   E       + cp -f shello_0.1-1.debian.tar.gz shello_0.1.orig.tar.gz shello_0.1-1.dsc /home/mkouhei/debbuild/temp/

上記の通り、cpコマンドの2つ目の引数の後ろにスペースが一つ余計に入っていることが、”-” で示してあるので分かりやすいです。 最近までこのメソッドの存在に気づいていませんでした。ちゃんとリファレンス読め、ワシ…。

自分で同様の処理を行うなら、 difflib.ndiff() を使うとできます。次のような関数を定義すれば assertMultiLineEqual() の代わりに通常のコードの中でも使えます。

import difflib

def worddiff(string1, string2):
    diff = difflib.ndiff(string1.splitlines(1), string2.splitlines(1))
    print(''.join(diff))

ググるとndiff()については結構ブログで書かれているみたいなのですが、assertMultiLineEqualの方はあまり見当たらないですね。

]]>
Thu, 22 May 2014 00:00:00 +0900
http://d.palmtb.net/2014/04/25/infinite_loop_using_chord_of_celery.html http://d.palmtb.net/2014/04/25/infinite_loop_using_chord_of_celery.html <![CDATA[Infinite loop using chord of Celery]]> Infinite loop using chord of Celery

Cronのような使い方としては、既に Celery を使っていたのですが、複数のキューを並列実行かつ、各キュー自体はFIFOで処理させられないかなと、チュートリアルを順にやっていた時に見つけたバグです。 チュートリアル にある下記のコードを実行すると、

>>> from celery import chord
>>> from proj.tasks import add, xsum

>>> chord((add.s(i, i) for i in xrange(10)), xsum.s())().get()

次のようなログが出て無限ループします。:

[2014-04-25 00:04:45,623: INFO/MainProcess] Received task: celery.chord_unlock[dba8e0f8-cb96-4c91-948c-2acd5ccc3ae8] eta:[2014-04-25 00:04:46.620008+09:00]

Debian GNU/Linux Sidの今のCeleryのパッケージ(python-celery)のバージョンが、3.1.9なのですが、 このバグが修正されているのは、3.1.11に含まれる コミット です。

3.1.9から3.1.11の間には、他にもchordに関するバグが結構修正されているので、3.1.11をパッケージにしてもらうように、 BTSに登録して おきました。

なお、group()の方は問題ないので、3.1.11未満で同じことをしたければ、

>>> (group(add.s(i, i) for i in xrange(10)) | xsum.s())().get()

の方を使えば大丈夫です。

このコミットのパッチ を適用したdebdiffの結果も送付しようかと思ったのですが、現在の環境では、これとは別でテストがコケるFTBFSも存在したので それを報告して おきました。

]]>
Fri, 25 Apr 2014 00:00:00 +0900
http://d.palmtb.net/2014/04/17/manage_multiple_distributions_with_reprepro.html http://d.palmtb.net/2014/04/17/manage_multiple_distributions_with_reprepro.html <![CDATA[Manage multiple distributions with reprepro]]> Manage multiple distributions with reprepro

本日Trustyがリリースされるということで、職場で使っているrepreproにTrusty用のローカルアーカイブを追加しました。 Preciseの設定をコピーして列挙すればよいだけですね。

設定内容

conf/distributions

preciseの部分をtrustyに変えて追記するだけ。

Origin: myrepo
Label: myrepo
Suite: precise
Codename: precise
Architectures: amd64 i386 source
Components: custom
UDebComponents: custom
Description: my repository for Ubuntu precise
SignWith: yes

Origin: myrepo
Label: myrepo
Suite: trusty
Codename: trusty
Architectures: amd64 i386 source
Components: custom
UDebComponents: custom
Description: my repository for Ubuntu trusty
SignWith: yes

conf/incoming

distributionsと同じ。

Name: precise
IncomingDir: incoming
TempDir: tmp
LogDir: log
Allow: precise
Default: precise

Name: trusty
IncomingDir: incoming
TempDir: tmp
LogDir: log
Allow: trusty
Default: trusty

conf/options

これは変更なし。

verbose
basedir /var/lib/debpkg-custom/ubuntu
ask-passphrase

DB生成

PreciseやWheezy用のローカルアーカイブには、私のメンテナンスしているパッケージやその依存パッケージをバックポートしたり、 社内で開発&利用しているツールをDebianパッケージにして管理しています。 私のメンテナンスしているパッケージはひと通りTrustyに入っているので、とりあえず必要ないので空のDBを生成します。

$ pwd
/var/lib/debpkg-custom/ubuntu
$ reprepro export trusty

余談。

Wheezy用には、パス自体分けて(/var/lib/debpkg-custom/debian)運用していたのですが、 なんか分けないで混ぜていても良かったなぁと思いました。が、まぁ特に困らないのでいいや。

]]>
Thu, 17 Apr 2014 00:00:00 +0900
http://d.palmtb.net/2014/04/16/retrieve_and_generate_debian_package_of_oracle_jdk.html http://d.palmtb.net/2014/04/16/retrieve_and_generate_debian_package_of_oracle_jdk.html <![CDATA[Retrieve and generate debian package of Oracle JDK]]> Retrieve and generate debian package of Oracle JDK

I have written script for retrieving Oracle JDK tarball automatically, why I wanted to retrieve and make debian package with make-jpkg command on Jenkins.

  1. Retrieve JDK 7 and JDK 8 download page urls from Oracle JDK Download site.
  2. Retrieve JDK tarball URL.
  3. Check the save file local directory.
  4. Download with “wget” command.

Requirements

  • python-requests
  • python-query
  • wget
  • java-package

Prepare as following script for Jenkins.

#!/bin/sh

python retrieve_jdk.py -j $1
echo -e '\n\n' | make-jpkg $(ls -1 jdk-*-linux-x64.tar.gz | tail -1)
]]>
Wed, 16 Apr 2014 00:00:00 +0900
http://d.palmtb.net/2014/04/12/how_to_build_custom_debian_package_automatically_by_jenkins.html http://d.palmtb.net/2014/04/12/how_to_build_custom_debian_package_automatically_by_jenkins.html <![CDATA[How to build custom Debian package automatically by Jenkins]]> How to build custom Debian package automatically by Jenkins

以前、OpenSSH LDAP Public key パッチ(openssh-lpk)を、Ubuntu 12.04 LTS(Precise)とDebian GNU/Linux WheezyのそれぞれのOpenSSHに適用したカスタムビルドパッケージを作りました。 [1] [2] OpenSSHのパッケージが更新される度に、

  1. このパッチを適用し
  2. pbuilderを使ってPrecise, Wheezyでビルド
  3. 実環境にインストールしてテスト
  4. GPG key sign
  5. reprepro管理下のローカルアーカイブに登録

するという作業を行っています。といっても、PreciseやWheezyでもOpenSSHのパッケージ自体のアップデートが最近までほとんどなかったので、手動でメンテナンスを行っていたのですが、この1ヶ月くらいで何回かアップデートがあったことや、先日Jenkinsを作ったこと (Issue deploying Jenkins to Tomcat7 Debian package in Wheezy)もあったこと、職場で私以外に作業できる人がいない、という問題があるので、Jenkinsでビルドするようにしました。

OpenSSHパッケージのDebianバージョンとOpenSSH LPKパッチの関係

これを図にすると下記のようになります。 Debianのパッケージが更新されるたびに、”+cust1”を付加したバージョンをリリースするわけです。

digraph changelog { node [fontsize="10"]; edge [fontsize="10"];  w2c[label="1:6.0p1-4+deb7u2+cust1", style=dotted, fontcolor="#888888"]; w2[label="1:6.0p1-4+deb7u2", style=dotted, fontcolor="#888888"]; w1c[label="1:6.0p1-4+deb7u1+cust1"]; w1[label="1:6.0p1-4+deb7u1"]; w0c[label="1:6.0p1-4+cust1"]; w0[label="1:6.0p1-4"]; w2 -> w2c [style=dotted, label="apply openssh-lpk"]; w1 -> w1c [label="applied openssh-lpk"]; w0 -> w0c [label="applied openssh-lpk"]; w2 -> w1 [style=dotted, dir=back]; w1 -> w0 [dir=back]; {rank = same; w0; w0c} {rank = same; w1; w1c} {rank = same; w2; w2c} }

Preciseの場合も基本的に同じです。

digraph changelog { node [fontsize="10"]; edge [fontsize="10"];  u4c[label="1:5.9p1-5ubuntu1.4+cust1", style=dotted]; u4[label="1:5.9p1-5ubuntu1.4", style=dotted]; u3c[label="1:5.9p1-5ubuntu1.3+cust1"]; u3[label="1:5.9p1-5ubuntu1.3"]; u2c[label="1:5.9p1-5ubuntu1.2+cust1"]; u2[label="1:5.9p1-5ubuntu1.2"]; u1c[label="1:5.9p1-5ubuntu1.1+cust1"]; u1[label="1:5.9p1-5ubuntu1.1"]; u0c[label="1:5.9p1-5ubuntu1+cust1"]; u0[label="1:5.9p1-5ubuntu1"]; u4 -> u4c [label="apply openssh-lpk", style=dotted]; u3 -> u3c [label="applied openssh-lpk"]; u2 -> u2c [label="applied openssh-lpk"]; u1 -> u1c [label="applied openssh-lpk"]; u0 -> u0c [label="applied openssh-lpk"]; u4 -> u3 [style=dotted, dir=back]; u3 -> u2 -> u1 -> u0[dir=back]; {rank = same; u0; u0c} {rank = same; u1; u1c} {rank = same; u2; u2c} {rank = same; u3; u3c} {rank = same; u4; u4c} }

pbuilderのイメージ準備

Jenkinsを動かしているのは前回の通りWheezyなので、Wheezy用のbase.tgzは次のように作成します。

$ sudo pbuilder --create --distribution wheezy --basetgz /var/cache/pbuilder/wheezy-base.tgz

一方、Precise用のbase.tgzは、別途Preciseをインストールしたサーバ上で同様に作成し、そのtarballを/Jenkins用のサーバに転送&配置します。 [3]

WheezyやPrecise用のbase.tgzのAPT Lineにはupdatesやsecurityのものは含まれていないので、

$ sudo pbuilder --login --save-after-login --basetgz /vat/cache/pbuilder/wheezy-base.tgz

でchroot環境にログインし、変更しておきます。 [4] また、合わせて、repreproで作成したローカルアーカイブ用のGPG公開鍵をapt-key addコマンドで追加しておきます。

パッチ置き場と一次ビルドの出力先の作成

openssh-lpkパッチと、debian/rulesのパッチをを任意のWebサーバにWheezy用、Precise用とそれぞれ用意しました。下記のようなURLです。

また、一次ビルドで出力するソースパッケージは、/var/tmp/resultディレクトリを作成し、後述のスクリプトでそこに出力するようにします。

$ sudo install -d -o tomcat7 -g tomcat7 --mode 0700 /var/tmp/result

一次ビルド、といっているのはパッチを適用した状態で、一度debuildを実行して出力されるソースパッケージのことです。その出力されたソースパッケージを用いて、pbudilerでクリーンビルドする、という流れです。

ソースツリーからpbuilderを実行するpdebuildコマンドを使えば、そんな面倒なことをする必要はありません。が、Wheezy上でPreciseの公開鍵をインポートしなくてはいけない点と、PreciseとWheezyとで基本的に同じ手順で行いたい、という二点から、pbuilderを2回実行する形にしました。

ジョブ用のスクリプト

Wheezy, preciseとで基本同じなので、先頭の2行のみを環境に合わせて変更します。Wheezyの場合は、codenameをwheezy, distroにはstableにしますが、Preciseの場合には両方共preciseです。 [5]

codename=wheezy
distro=stable
bin_package=openssh-server
src_package=openssh
arch=$(dpkg-architecture -qDEB_HOST_ARCH)

# check version
cat << EOF > check_version.sh
apt-cache show $bin_package | grep Version: | sort | tail -1 | grep -v +cust > /var/tmp/result/${BUILD_ID}.txt
exit 0
EOF
sudo pbuilder --update --basetgz /var/cache/pbuilder/${codename}-base.tgz
sudo pbuilder --execute --basetgz /var/cache/pbuilder/${codename}-base.tgz --bindmounts "/var/tmp/result" -- check_version.sh
test -s /var/tmp/result/${BUILD_ID}.txt || exit

deb_version=$(awk -F: '{print $3}' /var/tmp/result/${BUILD_ID}.txt)
orig_version=$(echo $deb_version | awk -F"-" '{print $1}')

# retrieve source package and patches
cat << EOF > build.sh
apt-get -qq -y install curl devscripts quilt patch libdistro-info-perl fakeroot libldap2-dev
apt-get -qq -y build-dep $bin_package

apt-get source $src_package

curl -O http://repo.example.org/${codename}/openssh-lpk.patch
curl -O http://repo.example.org/${codename}/rules.patch
(
export DEBFULLNAME="Auto Build"
export DEBEMAIL=autobuild@example.org

cd ${src_package}-${orig_version}
echo "### applying patch ###"
patch -p1 --dry-run < ../openssh-lpk.patch || exit 1
patch -p1 < ../openssh-lpk.patch

echo "### commiting patch ###"
echo | dpkg-source --commit . openssh-lpk.patch ../openssh-lpk.patch

echo "### update Build-Depends ###"
sed -i 's/^\(Build-Depends: .*\)$/\1, libldap2-dev/' debian/control

echo "### update compile options ###"
patch -p1 --dry-run < ../rules.patch
patch -p1 < ../rules.patch

echo "### update changelog ###"
dch -l+cust -D${distro} "Applied OpenSSH LPK patch."

echo "### build package ###"
debuild -us -uc
)

cp -f ${src_package}_${deb_version}+cust1.debian.tar.gz ${src_package}_${orig_version}.orig.tar.gz ${src_package}_${deb_version}+cust1.dsc /var/tmp/result/
EOF

sudo pbuilder --execute --basetgz /var/cache/pbuilder/${codename}-base.tgz --bindmounts "/var/tmp/result" -- build.sh

# clean build
sudo pbuilder --build --basetgz /var/cache/pbuilder/${codename}-base.tgz /var/tmp/result/${src_package}_${deb_version}+cust1.dsc

# installing test
sudo piuparts -b /var/cache/pbuilder/${codename}-base.tgz -d $codename --keep-sources-list /var/cache/pbuilder/result/${src_package}_${deb_version}+cust1_${arch}.changes

大まかな流れとしては次のとおりです。

  1. カスタムビルドパッケージよりも更新されたバージョンがリリースされていないかのチェック
  2. pbuilderを使い、chroot環境内でのソースパッケージとパッチの取得・適用及びビルド
  3. ビルドして生成されたソースパッケージを用い、pbuilderでクリーンビルド
  4. クリーンビルドしてできたパッケージを、piupartsでインストールテスト

公式パッケージで更新されてパッチ適用したバージョンよりも新しいバージョンがリリースされている場合、このジョブを実行すると、パッチ適用してビルドされたパッケージが、Jenkinsサーバの/var/cache/pbuilder/resultディレクトリ下に作成されます。

後は別のジョブでdebsignでGPG key signし、repreproのincomingディレクトリにpushすれば良いわけです。 [6]

この記事のオチ

さて、これで自動ビルドできるようになったので楽できるわー、と思ったら、このジョブを仕込んた翌日に、 OpenSSH 6.2 以降で

  • AuthorizedKeysCommand
  • AuthorizedKeysCommandUser

というオプションが使えるようになったことを同僚に教えてもらいました。つまり、「もはやOpenSSH LPKなんて不要になった!」ワケです。素晴らしい。

来週リリース予定のUbuntu 14.04 LTS(Trusty)ではOpenSSH 6.6ですし、WheezyでもBackportsに6.5にあるのでわざわざこんな手の混んだことをしなくても、ミラーをすればよいのです。 なので、このジョブそのものはたった一日で不要になってしまいました。

ただし、Precise用にはWheezyのBackportsのソースパッケージをリビルドする必要があるので、今回やった事自体は役立ちそうです。このジョブに比べたら(リビルドさえちゃんと確認できれば)なんてこと無いですね。

もっと簡単にマルチディストリビューション向けに自動(カスタム)クリーンビルドする方法があれば、どなたか教えて下さい。

追記

  • check_version.shに exit 0 を忘れていたので、ローカルアーカイブの方にパッチ適用済みのパッケージが存在すると、ジョブがコケてしまう、ので修正しました。
  • @mizuno_as さんに複数環境向けにビルドするならpbuilder-distの方が便利ですよ、と教えてもらったので、後日検証しようと思います。

追記2

  • –bindmounts オプションを /var/tmp/result /tmp としていたのですが、pbuilderのbindmountsオプションの挙動を勘違いしていました。こうするとホストの/var/tmp/resultとchroot内の/var/tmp/result、そしてホストの/tmpとchroot内の/tmpがbind-mountされるので、今回であれば/var/tmp/resultだけを記述すれば良かった、ということでした。(修正済み)

Footnotes

[1]OpenSSH LDAP public key
[2]Applying openssh-lpk to Wheezy
[3]cowbuildreを使うことも検討したのですが、Precise上で cowbuilder –create すると失敗するためpbuilderを使うことにしました。
[4]exitコマンドではなく、Ctrl + dでログアウトすると、”–save-after-login” オプションをつけていても変更が保存されないようです。
[5]Wheezyでは、dchコマンドの”-D”オプションでのディストリビューションの指定には、Ubuntuと違ってコードネームの”wheezy”ではなく、”stable”でないとエラーになります。
[6]今回はdebsign, repreproへのpushについては書きませんが。
]]>
Sat, 12 Apr 2014 00:00:00 +0900
http://d.palmtb.net/2014/03/27/issue_deploying_jenkins_to_tomcat7_debian_package_in_wheezy.html http://d.palmtb.net/2014/03/27/issue_deploying_jenkins_to_tomcat7_debian_package_in_wheezy.html <![CDATA[Issue deploying Jenkins to Tomcat7 Debian package in Wheezy]]> Issue deploying Jenkins to Tomcat7 Debian package in Wheezy

travis-ciはよく使っているのですが、JenkinsはあのWeb UIに馴染めなくて今まで使っていませんでした。が、この度仕事でJenkinsを用意する必要が出てきたの [1] で、Debian GNU/Linux Wheezyでサーバを用意することにしました。

用意するにあたり、upstreamからwarファイルをダウンロードし、直接実行する方法で、まず全体設定やセキュリティ関連の設定を試しました。そのあとで、DebianパッケージのTomcat7上で動かそうとした際にちょっとハマりました。これはそのメモです。ググった限りでは同様の問題にハマっている人は多分いないのでしょう。

直接実行の場合

OpenJDKを使うため、default-jre-headless パッケージをインストールします。あとは、warファイルをダウンロードして直接実行するだけです。

$ sudo apt-get intall default-jre-headless
$ wget http://mirrors.jenkins-ci.org/war/latest/jenkins.war
$ java -jar jenkins.war

検証途中で、権限周りの設定をしている時に間違えてEnterを打ってしまい、何もできなくなるというエライことに。きっと これよくある問題 なんでしょうね。

DebianパッケージのTomcat上で動かす場合

本題です。Tomcat7をまずDebianパッケージでインストールします。

$ sudo apt-get install tomcat7 tomcat7-admin

インストールしたら自動的にTomcatが起動しますが、何の権限も無くてtomcatのweb管理画面にもアクセスできないので、/etc/tomcat7/tomcat-users.xmlを変更し、下記を<tomcat-users>の子要素として追加します。ユーザ名、パスワードは適当に設定して下さい。

<tomcat-users>
    (snip)
        <role rolename="manager"/>
        <role rolename="manager-gui"/>
        <role rolename="admin-gui"/>
        <user username="tomcat" password="passw0rd" roles="manager,manager-gui,admin-gui"/>
</tomcat-users>

設定したら、tomcat7を再起動します。

$ sudo service tomcat7 restart

これで、設定したユーザ、パスワードを使って、 http://tomcat.example.org:8080/manager/ からTomcat管理画面にアクセスできます。あとは、先ほどダウンロードしたwarファイルを使ってデプロイしてやれば、 Jenkinsが起動します。

と思ったら大間違いで、デプロイできても起動できません。

原因は、tomcat7パッケージで作られるtomcat7ユーザのホームディレクトリの位置です。 tomcat7ユーザのホームディレクトリは、/usr/share/tomcat7になっているのですが、/usr以下のディレクトリはパッケージのインストール以外で置かれる静的ファイル以外は基本置かれません。しかし、Jenkinsは実行ユーザのホームディレクトリの直下に、.jenkinsディレクトリを作成し、そこに各種出力をします。/usr/share/tomcat7の所有権はrootユーザおよびrootグループであり、自由に書き込みはできません。

なので、次のようにしてやることで、この問題を回避できます。 [2]

$ sudo install -d -o tomcat7 -g tomcat7 -m 700 /var/lib/jenkins
$ sudo ln -s /var/lib/jenkins /usr/share/tomcat7/.jenkins

あとは、tomcatを再起動すれば、Jenkinsが起動します。

この問題、TomcatもUpstreamのwarファイルを使うか、あるいはJenkinsも公式のDebianパッケージ [3] を使えば発生しない現象ですね、おそらく。しかし、Wheezyでは残念ながら公式パッケージにJenkinsは含まれていないので、Debianパッケージを用意するならSidからのバックポートが必要になります。が、ビルドの依存関係多いので、jenkins以外にもバックポートが多数必要という罠。今回バックポートせずにJenkinsだけをwarファイル使ったのは、たんに私の甘え&ゆとりです。

Footnotes

[1]本来のきっかけとは別に、SidからWheezyやPrecise向けにDebianパッケージをバックポートしたり、自前のツールをDebianパッケージにする際のオートビルド環境として、jenkins-debian-glue が良いよ、と @lurdan に教えて頂いたので、それも動機となっています。
[2]/usr/share/tomcat7/.jenkinsディレクトリを作って、所有権をtomcat7:tomcat7にする、というのでも動きますが、お行儀悪いのでやめましょう。
[3]Upstreamが配布しているDebianパッケージもあります が、これはDebianの公式パッケージではないので、私は使いません。
]]>
Thu, 27 Mar 2014 00:00:00 +0900
http://d.palmtb.net/2014/03/26/how_to_encrypt_ansible_vault_in_the_tls_certificate.html http://d.palmtb.net/2014/03/26/how_to_encrypt_ansible_vault_in_the_tls_certificate.html <![CDATA[How to encrypt ansible-vault in the TLS certificate]]> How to encrypt ansible-vault in the TLS certificate

先週、Sidのansibleパッケージが1.4.5+dfsg-1から1.5.3+dfsg-1に上がったので、待望のansible-vaultを使ってみました。パスワードなどを暗号化するために使うのが主でしょうが、今回の私の目的は、TLS証明書を及びその秘密鍵の暗号化です。仕事で使っているplaybookに、PEM形式の証明書や秘密鍵を含めるのがいやだったのが動機です。

IMAPサーバ用のplaybookを例にします。

.
|-- development
|-- group_vars
|   |-- all
|   |-- development
|   `-- production
|-- imapd.yml
|-- production
|-- roles
(snip)
|   |-- dovecot
|   |   |-- handlers
|   |   |   `-- main.yml
|   |   |-- tasks
|   |   |   `-- main.yml
|   |   |-- templates
(snip)
|   |   |   |-- 10-ssl.conf.j2
    (snip)
|   |   |   |-- key.j2
|   |   |   `-- cert.j2
|   |   `-- vars
|   |       `-- main.yml
(snip)
`-- site.yml

ansible-vaultで暗号化する対象は、roles/dovecot/templatesディレクトリの下にある、key.j2とcert.j2の2つのテンプレートの中に出力する文字列です。 証明書とprivate keyを配布するだけなら、filesディレクトリの下に、証明書およびprivate keyファイル自体を配置し、copyモジュールでコピーすれば良いだけです。 しかし、 ドキュメントにもあるとおり ansible-vaultで対象に暗号化の対象にできるのは各種の変数だけなので、filesディレクトリ下の添付ファイルは復号できません。そこで、templateモジュールを使う必要があります。暗号化する文字列自体は、roles/dovecot/vars/main.ymlの中に記述します。

PEM形式の文字列は、

-----BEGIN CERTIFICATE-----
MIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UE
AwwNQUNFRElDT00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00x
CzAJBgNVBAYTAkVTMB4XDTA4MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEW
(snip)
-----END CERTIFICATE-----

のような形式になっているので、これをtemplateモジュールを使って、ファイルを配置するには、templates/cert.j2などのテンプレートに、

{{ cert_pem }}

とだけ記述し、vars/main.ymlには、

---
- cert_pem: "-----BEGIN CERTIFICATE-----\nMIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UE\nAwwNQUNFRElDT00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00x\nCzAJBgNVBAYTAkVTMB4XDTA4MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEW\n...(snip)...\n-----END CERTIFICATE-----"
- key_pem: "..."

のように、改行を”n”に変更して一行の文字列とし、それをダブルクォートかシングルクォートで括って指定します。 これで動作確認ができたら、vars/main.ymlを暗号化します。

$ ansible-vault encrypt roles/dovecot/vars/main.yml

暗号化されたファイルは下記のようになります。

$ANSIBLE_VAULT;1.1;AES256
39613864343833373066386636333338653831383630623938643138366230323336656234326234
3833663562396237393333363665643631653331386566660a653530326636666137633731373361
34653163626664376432393433303435333433303535626437623935313962626430643038623464
(snip)

暗号化された変数を使って、playbookを実行するには、 --ask-vault-pass オプションをつけてansible-playbookコマンドを実行すれば良いだけです。 このオプションをつけると、実行時にだけメモリ上に復号されます。

まとめ

今まで、パスワードなどはvars_promptで都度入力し、TLS証明書&秘密鍵などは別途配布する、という方法でやっていました。 これでplaybook自体にansible-vaultで暗号化して管理できるので、vautl passwordのみ、keepassなどで管理すれば良さそうです。

]]>
Wed, 26 Mar 2014 00:00:00 +0900
http://d.palmtb.net/2014/02/20/upgraded_squeeze_to_wheezy_lxc_host_and_containers.html http://d.palmtb.net/2014/02/20/upgraded_squeeze_to_wheezy_lxc_host_and_containers.html <![CDATA[Upgraded Squeeze to Wheezy LXC host and containers]]> Upgraded Squeeze to Wheezy LXC host and containers

長らくSqueezeで動かしていた、さくらのVPSのLXCのホスト&コンテナをWheezyにアップグレードしたので、その時のメモです。

うちのLXCは、Lennyの時のユーザランド管理ツールが 0.6.5 頃から使っている (lxcを導入してみた。) 秘伝のタレみたいなやつ [1] なので、安定稼働して当たり前で、最近の事情はあまり知らないのですが、最近、LXC流行っているみたいですね。 [2]

今回の味付け変更のトピック

で秘伝のタレはDebianのバージョンアップのタイミングで味付けが変わるのですが、LennyからSqueezeの時はそんなに大きな違いはなかったのですが、今回のSqueezeからWheezyに変わったタイミングで、地味ですが一つ嬉しい変更がありました。 [3] それは、コンテナのconfigに、”lxc.network.ipv4.gateway”を追加すると、default gatewayが自動設定されるということです。 [4] これ、使い始めた当時(2009年ごろ)欲しかった機能の一つでした。 [5] 便利になったものですね。

今回のアップグレードのまとめ

では、今回やったアップグレードのメモを残しておきます。 テスト自体は、さくらのVPSで稼働中のVMイメージを、さくらのクラウドにアーカイブし、そのアーカイブからさくらのクラウドで起動し、そのイメージでアップグレードテストを行いました。

共通

  • apt-get update && apt-get upgrade後、apt lineを変更してapt-get upgrade && apt-get dist-upgrade
  • sysstatのデータは互換性がないので削除し、debconfの設定はメンテナバージョンを使用
  • /etc/sudoersはメンテナバージョンを使用し、普段管理用に使用しているユーザをあとでsudoグループに追加
  • /etc/logrotate.d/rsyslog は現状のままにしておき、あとで下記を変更
-               invoke-rc.d rsyslog reload > /dev/null
+               invoke-rc.d rsyslog rotate > /dev/null
  • /etc/rsyslog.conf も現状のままにし、あとで下記を変更
-*.emerg
+*.emerg                                :omusrmsg:*

ホスト

  • lxc が 0.7.2-1 から 0.8.0~rc1-8+deb7u2 にアップグレード
  • Squeezeではカーネルオプションを変更してビルドした Linux Kernel 2.6.39.4を使っていたので、パッケージのアップデート完了後、再起動前に linux-image-3.2.0-4-amd64 をインストールし、それをGRUB_DEFAULTで指定、update-grubを実行
  • ネットワーク関連の設定は、post-upでシェルスクリプトでブリッジの設定をやっていたのですが、それをやめ、interfacesを下記のように変更。
auto lo
iface lo inet loopback

# The primary network interface
allow-hotplug br0
iface br0 inet static
    bridge_ports eth0
    bridge_fd 0
    address 192.0.2.100
    netmask 255.255.255.0
    gateway 192.0.2.1

nginx用のコンテナ

  • /etc/logrotate.d/nginx をメンテナバージョンを使用するようにし、後ほど、rotate回数を 52から 365に変更
  • 他は無し

CouchDB用のコンテナ

  • CouchDBはもともと1.2.0-1のバックポートを使用していたので、アップグレードのタイミングで、backports.debian.orgのAPT lineをコメントアウトしただけ。
  • /etc/login.defsをメンテナバージョンを使用するように変更

redmine用のコンテナ

  • mysql

    • /etc/mysql/my.cnfはメンテナバージョンを使用
    • debconfでrootのパスワードは変更しない
  • dist-upgradeでpostfixのアップグレードが失敗したので、再度upgrade実行することで正常にアップグレード

  • RubyGemでインストールしたredmine 1.2.1が稼働しており、DBにはMySQLを使用していましたが、Wheezyにするとこれは動かなくなる。

    • なので、これをDebianパッケージ( 1.4.4+dfsg1-2+deb7u1 ) に変更

    • redmine, redmine-mysqlパッケージをインストール

      • debconfの設定ではredmine/instances/defaultのDBをdbconfig-commonで設定
      • DBにはmysqlを選択
      • 既存のredmine用の管理権限ユーザのパスワードを設定
    • これだけでは実はだめなので、インストール完了後に、dpkg-reconfigure -plow redmineを実行

      • 管理者名をrootからredmineに変更
      • DB名をredmine_defaultからredmineに変更
      • /opt/redmineが/opt/redmine-1.2.1へのsymlinkになっているので、これをDebianパッケージの/usr/share/redmineへのsymlinkに変更
      • apache2を再起動すればアップグレード完了

Rails用のコンテナ

  • Apacheの設定が変更になり、/etc/apache/httpd.confが削除されたため、/etc/apache/apache2.confの207行目のInclude httpd.confを削除
  • アップグレード時に/var/wwwのowner, groupが変更されてしまうため、Passenger用のowner, groupに変更する

余談

コンテナを止めずにホストのアップグレードをしてしまったので、稼働中のカーネルではlxcのwheezyのバージョンに対応しておらず、ホストのカーネル再起動のときにコンテナも一緒に(自動的に)停止する、ということになってしまったですが、ホスト再起動後、前述のlxc.network.ipv4.gatewayを設定していなかったのにも関わらず、コンテナを起動してもなぜかdefault gatewayが設定される、という現象が発生しました。 [6] アップグレード前に正常停止させなかったから停止前の状態が残っていたのかもしれません。

ちなみに、このブログの冒頭の話をFaebookに書いたら、ITエンジニアではない方から「宇宙語?」と突っ込まれたのが本日のトピックです。w

追記

アップグレード後に新たにコンテナを追加したら、

lxc.cap.drop = sys_module mac_admin mac_override sys_time

が追加されていたので、既存のコンテナにも追加しました。日本語でのCapability関連は tenforward さんの メモ が詳しいです。

Footnotes

[1]ちなみに、Lennyの時は当然さくらのVPSではありませんでしたが、さくらのVPSに移行するときには、Lennyで使っていたLXC関連の設定とコンテナのrootfsはそのままそっくり移行しました。
[2]というかDockerですかね。
[3]まぁ、今までと挙動が変わったでハマった原因でもあります。
[4]裏を返せば、秘伝のタレの我が家のコンテナは、/etc/network/interfacesにgateway設定していたのだから(ry
[5]当時は、debootstrapでrootfsを作ったあと、コンテナ起動前に/path/to/container/rootfs/etc/network/interfaces を変更する、ということをやっていた訳です。
[6]なのでコンテナを一度停止してから再度稼働させるとデフォルトゲートウェイが設定されておらずハマった、という…。
]]>
Thu, 20 Feb 2014 00:00:00 +0900
http://d.palmtb.net/2014/02/19/replaced_wi_fi_router.html http://d.palmtb.net/2014/02/19/replaced_wi_fi_router.html <![CDATA[Replaced Wi-Fi router]]> Replaced Wi-Fi router

今まで使っていた無線LANルータが、最近頻繁に電源を入れなおさないと使えなくなることが増えたので、年明けに無線LANルータを買い替えました。買い替えたのは、NECの PA-WG1800HP/E です。以前は一台を家の中心にある和室に置いていたのですが、玄関側の部屋では電波が弱いこともあり、今回は2台購入し、両方共ブリッジモードで使うことにしました。

一台は玄関近くの洋室に縦置きに、もう一台はベランダ側のリビングに設置することにしたのですが、困ったのはリビング側。洋室の方はチャイルドゲートのおかげで娘が自由に行き来できないのですが、リビングだと確実にいたずらします。前の無線LANルータも娘のいたずらのせいでアンテナがもげてしまいました。なので購入時点で壁掛け設置にしようと決めていたのですが、購入して商品が届いてから気づいた失敗はこれ。

../../../_images/wifi0.png

自分でネジを用意しないとアカン、ということです。購入してからレビュー見てみたら、やはり同じように困っている人がいました。(持ち家ですが)壁に穴を開けるのは嫌なので、この説明書の写真を持って、ららぽーと横浜の東急ハンズで相談し、この ネジ

../../../_images/wifi1.png

と板を購入しました。推奨のネジとはちょっと形状が違いますが、これでも用は足りています。推奨ネジは大型店(新宿、渋谷など)しか置いていないようです。

次に悩んだのが設置場所。リビングには時計やカレンダーを掛けることのできるレールが元々設置されているので、それに掛けようかと思っていたら問題になったのは電源コードの長さ。天井近くから吊るすには電源コードは短すぎる上、このレールに引っ掛けたとしても電源コードと電源アダプター自体を娘が手の届かない家具の裏などに配置できない状態でした。

そこで、レールよりも少し下の位置にあり、ちょうど真下が家具になっている、和室用のエアコン用のダクトを利用することにしました。リビングのエアコンは大型のを設置していたこともあり、和室にはエアコンは必要なかったのでダクト自体は入居時のまま蓋をしていたのでした。

で、設置した結果がこんな感じです。

../../../_images/wifi2.png

正面

../../../_images/wifi3.png

ダクトにフックを通し、それを和室側に引っ掛け、

../../../_images/wifi6.png

Wi-Fiルータ自体はフックから針金で吊るし、針金はコードカバーをすることで目立たないようになりました。

../../../_images/wifi4.png

全体がこんな感じです。下に垂らしているのが電源コードですが、この下に家具があり、このコードと電源アダプターは娘の手には届かないという塩梅。ルータの右側にあるネズミのカレンダーが吊るしてあるのが前述のレールですね。

../../../_images/wifi5.png ]]>
Wed, 19 Feb 2014 00:00:00 +0900
http://d.palmtb.net/2014/01/30/how_to_create_a_debian_package_of_support_to_sysvinit__upstart__systemd.html http://d.palmtb.net/2014/01/30/how_to_create_a_debian_package_of_support_to_sysvinit__upstart__systemd.html <![CDATA[How to create a Debian package of support to sysvinit, upstart, systemd]]> How to create a Debian package of support to sysvinit, upstart, systemd

最近、サイボウズラボさんが開発した、yrmcdsというmemcached互換のKVSをDebianパッケージにして、main入りしました。 [1] いつもパッケージスポンサーをお願いしている 岩松さん 、upstreamの 山本さん のご協力のおかげです。 特に問題なければ、Ubuntuの次のLTSにも取り込まれるのではないかと思います。 お二人には、この場を借りてお礼申し上げます。

Python以外で、また、デーモンのパッケージ化は今回初めて行いました。 [2] sysvinitだけでなく、upstart, systemd対応も行ったので、デーモンのDebianパッケージを作成する場合のsysvinit, upstart, systemd対応の方法についてメモを残します。

sysvinit対応

sysvinitの対応は、dh_makeコマンドで生成されるテンプレートのdebian/init.dを使います。シングルバイナリパッケージの場合、ファイル名はdebian/init.dのままでも良いのですが、マルチバイナリパッケージの場合には、バイナリパッケージの名前をprefixにつけて、debian/<パッケージ名>.initのように変更します。yrmcdsのinit.dは sources.debian.net の次のURLで確認できます。 [3]

http://sources.debian.net/src/yrmcds/1.0.3-4/debian/yrmcds.init

check_for_upstart関数を定義し、/lib/lsb/init-functionsで定義されているinit_is_upstart関数を使って、upstartを使っている場合は、このスクリプト(つまり/etc/init.d/yrmcds)が実行されないようにしています。

upstart対応

upstartはテンプレートがありません。ファイル名は、debian/<パッケージ名>.upstartとして、upstart scriptを用意します。yrmcdsの場合、upstream側でetc/upstartが用意されています。upstreamのupstart scriptは、keepalivedの制御が入っていますが、Debianパッケージとしてはkeepalivedに依存するわけではないので、この部分はコメントアウトして、 debian/yrmcds.upstart としました。

systemd対応

systemdの場合は、debhelperのadd onとして、dh-systemdが用意されています。 ですので、まず、 debian/control のBuild-Dependsに、dh-systemdを追記します。

Build-Depends: debhelper (>= 8.0.0), (snip), dh-systemd (>= 1.5), (snip)

次に、 debian/rules の%ターゲットのdhコマンドのオプションとして、systemdを追記します。

%:
     dh $@ --with quilt,systemd

systemd用の設定ファイルは、upstartと同様テンプレートは用意されていません。debian/<パッケージ名>.serviceとして用意します。debian/yrmcds.service として作成します。

上記のみで、あとはdh-systemdが良きように設定してくれるのですが、これだけではpurge(apt-get purge)の時に残骸が残ります。 ですので、 postrm で下記のファイルを削除します。

  • /etc/systemd/system/yrmcds.service
  • /etc/systemd/system/multi-user.target.wants/yrmcds.service
  • /var/lib/systemd/deb-systemd-helper-enabled/yrmcds.service.dsh-also
  • /var/lib/systemd/deb-systemd-helper-enabled/multi-user.target.wants/yrmcds.service
  • /var/lib/systemd/deb-systemd-helper-masked/yrmcds.service

initの切替

debuildして作成したパッケージは、最小構成で作っておいたSidのVMを使ってテストを行います。パッケージ側ではsysvinit, upstart, systemdの切替の際に特に設定をすることはありません。 Debianはデフォルトではsysvinitになっているので、sysvinitからの切替が必要になります。upstartの場合は、upstartパッケージをインストールするだけで、sysvinitから自動的に切り替わります。 一方、systemdの場合は、systemdパッケージをインストールするだけでは、切り替わりません。今はブートローダーにGRUBを使っていることがほとんどだと思いますが、/etc/default/grubの GRUB_CMDLINE_LINUX_DEFAULTinit=/lib/systemd/systemd を追記し、 update-grub を実行する必要があります。 [4]

Footnotes

[1]2014/01/30現在のバージョンは 1.0.3-4 で、対応アーキテクチャは、linux-anyです。
[2]某所のローカルアーカイブ用には、FlaskやDjangoアプリ用にsysvinit対応のパッケージは作成していましたが、公式パッケージとしては初めてです。
[3]現状ではテンプレートの不要な処理をコメントアウトしただけの箇所が多いので、次のアップデートの時に削除する予定です。
[4]https://wiki.debian.org/systemd#Issue_.231:_sysvinit_vs._systemd-sysv
]]>
Thu, 30 Jan 2014 00:00:00 +0900
http://d.palmtb.net/2014/01/05/upgrade_os_x_10_7_lion_to_10_9_maveicks.html http://d.palmtb.net/2014/01/05/upgrade_os_x_10_7_lion_to_10_9_maveicks.html <![CDATA[Upgrade OS X 10.7 Lion to 10.9 Maveicks]]> Upgrade OS X 10.7 Lion to 10.9 Maveicks

The model of my MacBook Pro is 15-inch, Early 2011. I am usually using Debian GNU/Linux Sid on VirtualBox for OS X with full screen. The virtualBox-guest-{dkms,utils,x11} packages were upgraded 4.2.16 to 4.3.2 at last December. So I tried to OS X as host OS of VirtualBox.

  1. Upgraded VirtualBox for OS X 4.2.16 to 4.3.2.
  2. Upgraded virtualbox-guest-* packages of Sid, and rebuild virtualbox-guest-dkms.
  3. Exported virtual appliance of Sid to NAS [1].
  4. Upgraded OS X Lion to Maverikcs.

I was worried about the following link, but there has not yet been occured troubles my MacBook Pro now.

http://veadardiary.blog29.fc2.com/blog-entry-4884.html

Footnotes

[1]Firstly, I tried to backup with the Time Machine, but I gave up because this method was very very slow.
]]>
Sun, 05 Jan 2014 00:00:00 +0900
http://d.palmtb.net/2014/01/01/aspirations_of_2014_and_review_the_2013.html http://d.palmtb.net/2014/01/01/aspirations_of_2014_and_review_the_2013.html <![CDATA[Review the 2013 and aspiration of the 2014]]> Review the 2013 and aspiration of the 2014

娘の寝かしつけが終わり、あと30分で2013年も終わりのところで振り返りをしてみました。が、やはり書き終わらなかったので、今回も2013年の振り返りと2014年の抱負として書きました。

当初、「健康第一」を2013年の抱負としていました(A happy new year 2013) が、2013年を振り返ってみると、結局、私の体調が年中通して良くなかった一年でした。また3月に父が亡くなったのが、昨年一番大きな出来事でした。(My father was passed away)

昨年の主なトピック

時系列で追ってみてわかったのですが、家庭、仕事、Debian、どれかが原因、ではなく、いろいろな事象が自分の体調に影響していました。

  • 2月
    • 新データセンターをリリース
      • 2012年11月からこの頃まで大体終電続き
    • 父の見舞いに、金曜の晩に職場から、あるいは週末に実家に帰っていた
    • 右足に痛みが出始める
  • 3月
    • 父他界
      • 父の葬儀後、働いていた方が気が休まると思い、そのまま仕事再開
      • この時にリフレッシュ休暇を取っておけば違っていたのかもしれない
    • 8月ごろまで法事で父の実家の神戸に行ったり、最近も遺産相続手続きで実家にちょくちょく帰ったり
  • 4月
    • 接骨院に通い始める
      • 歩き方が原因だったらしく、その後、右足の痛みは治った
    • しかし、その後の体調不良が重なったり、娘を抱っこした際に腰痛になったりして10月まで通う
  • 5月
    • 上部消化管内視鏡検査で、逆流性食道炎が見つかる
      • 胸のあたりに違和感があったので検査をしてもらったところ逆流性食道炎になっていた
      • 投薬治療始める
    • 妻、別件で通院始める
  • 6月
    • 大統一Debian勉強会2013開催
      • 二回目の開催。スタッフとして再度参加
      • スポンサー募集も行ったので、お金の管理が必要ということで会計を担当
      • 運営内部では結構いろいろあった
  • 7月
    • 仕事でGrizzly版のKeyStoneの検証と、要件に合わせた修正(=魔改造)を始める
      • これも後述の体調不良のストレスの要因の一つだったのだろう
  • 8月
    • 黒色の便が出始める
      • 二回目の上部消化管内視鏡検査を行うも、異常見つからず
      • 逆流性食道炎は快癒
    • 娘と外で遊んでいるときに、肘内障にさせてしまう
    • Django関係など、仕事で使うソフトウェアのDebianパッケージのメンテナンス始める
      • それまでは仕事よりも、プライベートでの用途が主な動機
      • Django REST framework を仕事メインで使い始めたのがきっかけ
      • 自分で作ったツール (backup2swift, swiftsc)もDebianパッケージに。
  • 9月
    • 大腸内視鏡検査
      • この頃、下痢も伴ったので、実際には黒ではなく、黒緑色だったことが判明
      • 念の為の検査であったのでやはり異常見つからず
    • 仕事では、KeyStoneの修正(魔改造)プロジェクトを断念
  • 10月
    • 新チーム体制でプロジェクトをリセット
    • ピタッと便の異常止まる
      • その後、家庭の事情のストレスなどがあった時に再発したので、ストレスが原因であったことが判明
    • 娘が二回目の肘内障
  • 11月
    • 娘が熱痙攣を起こし、救急外来に
      • 初めての経験でかなり大変だった
    • 娘が三回目の肘内障
  • 12月
    • 諸事情により、自動車を買い換え
    • 妻が食事、トイレ、風呂以外安静にしなくてはいけなくなり、兼業主夫を再開&母親代わりの一人三役生活を始める
    • 娘が風邪を引き、それを自分も伝染ってしまったため、妻を自宅に置いて、娘と二人で実家に一週間疎開

総括

2013年は娘の生まれた2012年以上にいろいろありすぎたこと、また自分で思っているよりもしっかり休みを取らないと体調を崩すようになったのを実感した年でした。ストレス要因で体調悪化していただけでなく、年末に風邪をひいて体調崩したのも、結局は自分では大丈夫だ、と思って一人三役を頑張り過ぎた結果によるものでした。

新年を迎えて

今年の抱負は、昨年の達成できなかった「健康第一」としました。また昨年の反省から「休むときにしっかり休む」「人に頼る」「無理をしない」を念頭に置きたいと思います。

諸事情により妻の状態については触れませんが、現在の一人三役の生活はまだ2,3ヶ月ほど続きます。妻の両親、実家の家族の協力や、職場の上司や同僚の理解を得られてはじめて成り立っています。大変感謝しております。

動きたくても動いてはいけない妻には娘や私の様子に心配をさせてしまい、娘には母親に甘えたくても甘えさせられず、さらに急に保育園に通わせるようになったり、妻の実家に数日預けたりと、突然の環境の変化に一番辛い目に合わせてしまっていますが、2,3ヶ月後に今の状態を無事に終えるようにすることが、目下の目標であり、夫、父親、家計の主としての責務です。

勉強会関係は、娘が産まれてから基本Debian関係しか参加していませんが、Debian勉強会への参加もおそらく4月以降でないと難しい状況です。今の状況が落ち着いたら勉強会への参加を再開したいと思っています。また、Debianパッケージのメンテナンスももう一歩ステップアップしたいと考えています。

ブログは一昨年から勉強を兼ねて英語で書くようにしていますが、今年も継続しようと思っています。が、新年最初のエントリーは年末のDebian/Ubuntu Advent Calendar 2013の流れでそのまま日本語にしてしまいました。

プログラミングは専らPythonで時間取れたときにはそこそこやっていたのですが、最近はなかなか時間が作れなくなってしまい、めっきりです。

../../../_images/github-contributions-2013.png

昨年、 @miurahr さんから伺った朝の30分コードハックの習慣をつけようと思います。最近、ようやく起床から娘のトイレの世話、朝食の用意&片付け、洗濯、保育園への送りなどが、すこし要領よくできるようになってきたこともあるので。

各所、当面いろいろご迷惑をお掛けすると思いますが、どうぞよろしくお願いします。

]]>
Wed, 01 Jan 2014 00:00:00 +0900
http://d.palmtb.net/2013/12/23/extend_tacacs_plus_daemon.html http://d.palmtb.net/2013/12/23/extend_tacacs_plus_daemon.html <![CDATA[Extend TACACS+ daemon]]> Extend TACACS+ daemon

Debian/Ubuntu JP Advent Calendar 2013 の 23日目 [1] の記事です。 Advent Calendar、 今年こそは穴が出ないようにと思って、ホノルル時間を駆使して途中まで穴を埋めていましたが、(家事&仕事&育児)疲れ+娘からもらった風邪、で途中断念してしまいました。残念。

閑話休題。今回の内容は、「TACACS+でアクセス制御を行うユーザアカウントを、LDAPで一元管理できるようにTACACS+をカスタマイズしたよ」というお話です。

はじめに

ネットワーク機器へのアクセス制御用のプロトコルに TACACS+ というのがあります。またプロトコルと同じ名前の、Unix/Linux 上で動くデーモンもあります。元々CiscoがGPLv2で公開したものを機能拡張してメンテナンスされているのが リンク先 で公開されているもので、これは Debianパッケージ にもなっています。

背景

ネットワークエンジニア自体の数はたいてい少数で、共有アカウントでのネットワーク機器の運用を行っていることも多いかと思います。しかし、一方で、誰が何をやったのか、という作業ログは取りたい、という要望もあるでしょう。するとアカウンティングは最低限TACACS+でやろう、という話になるかと思います。そのついでに個人ユーザ化もできると良いよね、という展開になりますね。

さて、TACACS+では個人ユーザアカウントを作るには、設定ファイル(/etc/tacacs+/tac_plus.conf)で次のいずれかの設定を行います。

  • loginディレクティブなどで指定したpasswd(5)フォーマットのファイルでユーザ管理する
  • 必要なユーザ数分、userディレクティブで定義する

前者の場合、ユーザ名、および平文もしくはDES暗号化したパスワードを下記のように記述したファイルを作成します。

user1:password::::
user2:password::::

これを、 `login = file /path/to/passwd` として設定します。この方法のメリットは、このファイルを更新しても、tac_plusデーモンを再起動する必要がないことです。しかしこの方法の最大のデメリットは、この方法での一番のネックは「DESで暗号化したパスワードが必要」という点です。既にLDAPなどでユーザアカウントの管理を一元管理している場合、パスワードをユーザに入力させて、平文のパスワードをDESで暗号化し、その暗号化されたパスワードをこのファイルに登録ないし、更新を行わなければなりません。この方法を使うのであれば、LDAP用のパスワード変更用UIのバックエンドでこのファイルの更新処理も行うようにするという方法になるかと思いますが、処理が面倒な上、そのUIの管理が自分でない場合は、さらに(その管理者との)調整なども面倒です。また、ファイルの読み取りができればBrute force attackでパスワードの解読も可能な点も考えると、LDAPなどで一元管理していても別で漏れてしまう可能性がある方法を採用するのは避けたいところです。

一方、後者の必要なユーザ数分、userディレクティブで定義する場合、基本的には次のような設定を行います。 [2]

user = fred {
    login = des mEX027bHtzTlQ
    # (snip)
}

これではここにユーザ設定した上にDESで暗号化したパスワードも記述しないといけない分、先ほどのpasswdファイルでの管理よりも不便になってしまいます。そこで、PAMとの連携です。loginで指定している認証方法には PAM を使うこともできます。設定方法は下記の通りです。

user = fred {
    login = PAM
}

認証自体はPAMに任せてしまえば、あとはPAMで良きように計らってくれるのです。つまり、pam-ldapを使い、LDAPでユーザ認証を行っているのであれば、TACACS+で認証させたいユーザアカウントをtac_plus.confに定義だけ行っておけば、パスワード自体の管理は行う必要はありません。先ほどよりも結構便利です。

しかし、この方法もまだ不便な点があります。つまりtac_plus.confにユーザ定義を行わないと行けない、という点です。ユーザの追加・削除のたびにtac_plus.confを変更するという運用を行わなければいけません。

対応

とりうる対策としては2つです。

  1. LDAPからユーザアカウントが登録 or 削除されたら、tac_plus.confを書き換え、tac_plusにSIGHUPを発行する
  2. default authentication をPAM対応させる

前者で行うなら、LDAPのパスワード変更用UIのバックエンドで処理させたり、定期的にLDAPのデータをチェックして更新するようなジョブを組めば良いかもしれません。しかし、ansibleなどでpush型で反映するなり、TACACS+サーバ上で、ldapsearchの結果を元に変更するpull型でも即時反映されずタイムラグがある点を考慮すると微妙な感じです。

後者のdefault authenticationは、tac_plus.confで使えるデフォルトの認証方法の指定を行うためのディレクティブです。 が、現時点では前述の login ディレクティブなどで設定する、 file /path/to/passwd のような値しか取れません。なので、現時点ではgroup ディレクティブの中でloginの値として使う場合と同様、 TACACS+サーバにpasswd ファイルを配置し、その管理を行わなければなりません。 そこで、このdefault authenticationでPAMをサポートするようにしたのが今回の対応です。

default authentication = PAM

上記の設定を行うことで、個々のuserディレクティブの設定が不要になります。 [3]

この対応を、Sid版のtacacs+ 4.0.4.26と、Wheezy版の4.0.4.19にパッチを当てて、git-buildpackagesで管理したものをGitHubで公開しています。なので、git-buildpackageコマンドで自分でDebianパッケージを作成してお試しいただくこともできます。

また、Upstreamにパッチが取り込まれると、手離れできて嬉しいので、 MLに投稿してみました 。が、今のところ開発者からの反応はないので取り込まれるのは難しいのかなぁという感じです。クリスマスまでに反応があれば最高のクリスマスプレゼントなんですけどね。 :)

[1]またしてもホノルル時間です。
[2]この例はtac_plus.conf(5)に載っている例の一部引用です。
[3]ちなみにgroupディレクティブにlogin = PAMを設定すれば良いのではないか、と考えるかもしれませんが、その設定を行った場合でも、個々のuserディレクティブの設定が必要です。
]]>
Mon, 23 Dec 2013 00:00:00 +0900
http://d.palmtb.net/2013/12/12/debian_jr__project.html http://d.palmtb.net/2013/12/12/debian_jr__project.html <![CDATA[Debian Jr. Project]]> Debian Jr. Project

Debian/Ubuntu JP Advent Calendar 2013 の 12日目の記事です。

我が家の娘 [1] は今1歳9ヶ月になります。隙あらば、親のスマホやタブレットを奪い、大好きな丸いキャラクターの動画を見ようとしたり、幼児用のゲームで遊ぼうとします。2歳過ぎるまでは極力触らせないようにはしていますが、ロック解除の方法を盗み見して解除してしまったりと彼女の学習能力は親に比べ非常に高いので、羨ましいかぎり、もとい、この場合は悩ましい限りです。

とはいえ、そろそろ娘にもDebianユーザデビューを考えているところで、apt-cache search childの結果を眺めていて思い出したのが、主題の Debian Jr. Project です。これはDebian Pure Blend の一つであり、2011年の Debian/Ubuntu JP Advent Calendar 2011 の中尾さんによる記事、「 みんなのためのDebian Pure Blends 」でも紹介されていました。

このプロジェクトは、

「1歳から99歳までのこどもためのDebian」

であり、このプロジェクトの第一の目標は

Debian をこどもたちが 使いたくなるような OS にすること

となっています。

これは、「こどもが使いたくなるようなOS」が結果的にDebianだった、という状態にすることと同義ではないかと解釈しています。つまり、私と同様に「どうやってこどもにDebianを使わせようか」とお悩みの皆さんはもちろんのこと、「どうやってこどもにコンピュータを触れさせようか」とお悩みの皆さんにもうってつけではないでしょうか。

ということで、使わなくなった古いMacBookに、junior-* パッケージ群をインストールし、まず試してみてから娘にクリスマスに、は少し早いので2歳の誕生日にプレゼントしてみようかと思っています。

Footnotes

[1]ネットでの通称は「おまめ」です。
]]>
Thu, 12 Dec 2013 00:00:00 +0900
http://d.palmtb.net/2013/12/05/assigned_native_ipv6_automatically_from_ra.html http://d.palmtb.net/2013/12/05/assigned_native_ipv6_automatically_from_ra.html <![CDATA[Assigned native IPv6 automatically from RA]]> Assigned native IPv6 automatically from RA

Debian/Ubuntu JP Advent Calendar 2013 の五日目の記事です。nozzy nozzyさんが五日目の記事ではなく六日目の記事として 公開されていた ので、またしても例のトリック( How to change timezone in Debian )を使っています。(いつまでこの穴埋め続けるんや…。)

先日、某同僚から 今の環境ではデフォルトでRAでIPv6アドレスをアサインしている という資料が公開されていましたが、OSの初期インストール時は、DHCPでのIPv4アドレスを使用しており、ネットワーク設定ではIPv6がデフォルトにはなりません。そこで、Ubuntu 12.04 LTS(presice) とWheezyでは次のように preseed の late_commandを使って /etc/network/interfaces を書き換え、IPv6 もしくは IPv6/IPv4 デュアルスタックの設定を行っています。

IPv6 onlyの場合は、

iface eth0 inet6 auto

を使いますが、デュアルスタックの場合は、

iface eth0 inet dhcp

を追加しています。

presice の場合

cp -f /dev/null /etc/resolvconf/resolv.conf.d/original
sed -i 's/domain-name-servers, //' /etc/dhcp/dhclient.conf
cat << 'EOF' >  /etc/network/interfaces
> auto lo
> iface lo inet loopback
>
> auto eth0
> {% if host.ipv4 %}
> iface eth0 inet dhcp{% endif %}
> iface eth0 inet6 auto
>     dns-nameservers {{ dns_ipv6 }}
>     dns-search {{ subdomain }}.{{ dns_suffix }} {{ dns_suffix }}
> EOF

wheezy の場合

$ apt-get install -y resolvconf
$ cp -f /dev/null /etc/resolvconf/resolv.conf.d/original
$ sed -i 's/domain-name-servers, //' /etc/dhcp/dhclient.conf
$ cat << 'EOF' >  /root/interfaces
> auto lo
> iface lo inet loopback
>
> auto eth0
> {% if host.ipv4 %}
> iface eth0 inet dhcp{% endif %}
> iface eth0 inet6 auto
>     dns-nameservers {{ dns_ipv6 }}
>     dns-search {{ subdomain }}.{{ dns_suffix }} {{ dns_suffix }}
> EOF
$ sed -i 's/{{ host }}.bad/{{ host }}.{{ subdomain }}.{{ dns_suffix }}/g' /etc/hosts
$ echo '{{ host }}.{{ subdomain }}.{{ dns_suffix }}' > /etc/mailname
$ test -x /usr/sbin/postconf && /usr/sbin/postconf -e mydomain='{{ subdomain }}.{{ dns_suffix }}'

preciseとの違いとして、resolvconfをインストールとPostfixの設定を行っています。これらはUbuntu, DebianとでOSインストール後の設定や挙動を同じにするためです。preciseではresolvconfがデフォルトでインストールされますが、wheezyではインストールされません。また、後者はDebianではデフォルトMTAはEximなのでこれをPostfixに変更しているのですが [1] 、これらの設定を行わないと、localhost.localdomainのままになっているからです。

/etc/resolvconf/resolv.conf.d/originalを/dev/nullで上書きし、/etc/dhcp/dhclient.confでdomain-name-serversを削除していますが、これらは、前述のOSインストール時にはIPv4を使い、インストール後にはIPv6をデフォルト、必要に応じてデュアルスタックにする、というところに副作用があるためです。

このoriginalファイルはインストール時の情報を元に下記のように設定されます。wheezyの場合は、resolvconfパッケージをインストールした時点で、/etc/resolv.confの情報を元に設定されます。

search sub.example.org example.org
nameserver 192.0.2.1

しかしIPv6をデフォルトとしている環境なので、nameserverは、IPv6アドレスになっていることが本来の期待値です。

なので、これをこのままにしておくと、再起動やnetworkingの再起動時などの/etc/network/if-up.d/000resolvconfでresolvconf -aが実行されると、/etc/resolv.confの内容が書き換えられてしまう、という問題が発生します。なので、originalの中身を消しておけば、OS起動時などにRAで通知される値が正しく割り当てられます。

また、デュアルスタックを使用している場合には、DHCPのリース更新時や、dhclientの手動実行、あるいはservice networking restart実行時に、/etc/resolv.confのnameserverの値がIPv4に設定されてしまいます。これは、上述のdomain-name-serversを削除することによって、IPv6アドレスのままになります。なお、domain-nameを同様に削除すると、dhclient実行時に、下記のようなエラーが発生してしまうため、これは削除しません。

$ sudo dhclient eth0
RTNETLINK answers: File exists
chmod: cannot access `/etc/resolv.conf.dhclient-new.1276': No such file or directory
mv: cannot stat `/etc/resolv.conf.dhclient-new.1276': No such file or directory

今の職場環境の特殊事情ではありますが、もし同様なケースの場合には参考にしてみてはいかがでしょうか。

Footnotes

[1]ごめんなさい、小室さん
]]>
Thu, 05 Dec 2013 00:00:00 +0900
http://d.palmtb.net/2013/12/04/backup2swift_and_swiftsc.html http://d.palmtb.net/2013/12/04/backup2swift_and_swiftsc.html <![CDATA[backup2swift and swiftsc]]> backup2swift and swiftsc

Debian/Ubuntu JP Advent Calendar 2013 の四日目の記事です。早速前日のネタ( How to change timezone in Debian )を使うハメになるとは…。前日のネタを使っても、もはや1時間もありませんので、以前、作成&Debianパッケージ化したツールの紹介をしたいと思います。

ツールの名前は表題のとおりです。

前者はOpenStack Swiftにバックアップを取るためのコマンドラインツールです。後者はbackup2swiftが使用しているswift用のクライアントライブラリです。前者はswiftにバックアップを取りたいというよくありふれた欲求から開発しました。後者はpython-swiftclientパッケージを使えばそもそも必要ありませんが、それまで全くswiftを使ったことなかった上、Swift絡みで情報交換をしようという機会があり、そのコーディネートを私がやることになったこともあったので、じゃあクライアントライブラリも作ったるか、ということで、これらのツールを作りました。

Swiftの認証は、TempAuthとKeyStoneに対応してます。職場で使っている認証プラグインにも対応していますが、名称を忘れてしまったので思い出したらそのうち追記しておきます。

PKG-OpenStack team のThomas Goirand 氏にパッケージスポンサーをして頂き、python-backup2swift, python-swiftscとしてDebianパッケージになっています。また、Ubuntuにもuniverseとしてパッケージになっているようです。

ということで、Swiftを使っている方はぜひ使ってみて下さい。

なお、開発時には 石川さん に助言頂いておりました。石川さん、改めてお礼申し上げます。

]]>
Wed, 04 Dec 2013 00:00:00 +0900
http://d.palmtb.net/2013/12/03/how_to_change_timezone_in_debian.html http://d.palmtb.net/2013/12/03/how_to_change_timezone_in_debian.html <![CDATA[How to change timezone in Debian]]> How to change timezone in Debian

Debian/Ubuntu JP Advent Calendar 2013 の三日目の記事です。二日目じゃないよ、三日目だよ。

この時期になると各所で「もう少しだけ時間が伸びたらいいのにッ!」とお悩みの方が多いことでしょう。そんな貴方に朗報です。今からハワイにバカンスに行くのですッ!タイムゾーンは当然違う上、日付変更線越えるので一日巻き戻った感があってとってもお得ですね。

Debianでシステムグローバルにタイムゾーンを変更するには、 dpkg-reconfigure コマンドで行います。

$ sudo dpkg-reconfigure tzdata

あとは、「地理的情報」で「太平洋側」を選択し、「時間帯」で「ホノルル」を選択し、「了解」を押すだけですッ!良かった、これで貴方の Advent Calendarネタは間に合ったことでしょう。

もっと手軽にやりたい?

$ TZ='Pacific/Honolulu'; export TZ
$ date
2013年 12月  2日 月曜日 05:45:11 HST
$ tinker -p "How to change timezone in Debian"

New post created as '/home/mkouhei/docs/d.palmtb.net/2013/12/02/how_to_change_timezone_in_debian.rst'

はっ!?娘を寝かしつけて仕事やるかと目覚めたら、 二日目がなかった!とかそんな現実はなかった ので、このネタを使う必要はなかったようです。良かった良かった。

さー、仕事しよ、仕事。

]]>
Tue, 03 Dec 2013 00:00:00 +0900
http://d.palmtb.net/2013/10/10/my_debian_work_in_aug_sep_oct_2013.html http://d.palmtb.net/2013/10/10/my_debian_work_in_aug_sep_oct_2013.html <![CDATA[My debian work in Aug/Sep/Oct 2013]]> My debian work in Aug/Sep/Oct 2013

The software entered to the main Debian archive as following.

Thanks Iwamatsu-san, Thomas-san, Oinuma-san.

]]>
Thu, 10 Oct 2013 00:00:00 +0900
http://d.palmtb.net/2013/08/22/the_parameter_of_boot_option__auto__had_been_changed_for_auto_install_of_wheezy.html http://d.palmtb.net/2013/08/22/the_parameter_of_boot_option__auto__had_been_changed_for_auto_install_of_wheezy.html <![CDATA[The parameter of boot option "auto" had been changed for auto install of wheezy]]> The parameter of boot option “auto” had been changed for auto install of wheezy

Debian installer is enable to install automatically with preseed as you know. Auto installing needs boot parameter “auto” in the previous version. But the “auto” parameter had been changed in Wheezy.

previous version

auto url=autoserver

Wheezy

auto=true url=autoserver

Honjo-san, Thanks for providing preseed configuration file.

See also

The “auto” parameter is not yet modified in following document.

B.2.3. Auto mode

]]>
Thu, 22 Aug 2013 00:00:00 +0900
http://d.palmtb.net/2013/06/20/applying_openssh_lpk_to_wheezy.html http://d.palmtb.net/2013/06/20/applying_openssh_lpk_to_wheezy.html <![CDATA[Applying openssh-lpk to Wheezy]]> Applying openssh-lpk to Wheezy

This blog entry is rewritten version of Wheezy for an article I wrote earlier.

OpenSSH LDAP public key

Download this patch why OpenSSH version of Wheezy is 6.0p1. Then apply to source package.

$ wget http://distfiles.gentoo.org/distfiles/openssh-lpk-6.0p1-0.3.14.patch.gz
$ gzip -d  openssh-lpk-6.0p1-0.3.14.patch.gz
$ sudo apt-get build-dep openssh
$ sudo apt-get install libldap2-dev quilt fakeroot
$ apt-get source openssh
$ cd openssh-6.0p1
$ patch -p1 < ../openssh-lpk-6.0p1-0.3.14.patch

Modify failed to patch.

version.h

Index: openssh-6.0p1/version.h
===================================================================
--- openssh-6.0p1.orig/version.h        2013-06-20 06:11:07.000000000 +0000
+++ openssh-6.0p1/version.h     2013-06-20 06:23:27.808046150 +0000
@@ -3,7 +3,8 @@
 #define SSH_VERSION    "OpenSSH_6.0"

 #define SSH_PORTABLE   "p1"
-#define SSH_RELEASE_MINIMUM    SSH_VERSION SSH_PORTABLE
+#define SSH_LPK                "lpk"
+#define SSH_RELEASE_MINIMUM    SSH_VERSION SSH_PORTABLE SSH_LPK
 #ifdef SSH_EXTRAVERSION
 #define SSH_RELEASE    SSH_RELEASE_MINIMUM " " SSH_EXTRAVERSION
 #else

Makefile.in

Index: openssh-6.0p1/Makefile.in
===================================================================
--- openssh-6.0p1.orig/Makefile.in      2013-06-20 06:11:07.000000000 +0000
+++ openssh-6.0p1/Makefile.in   2013-06-20 06:25:46.242305737 +0000
@@ -94,7 +94,7 @@
        sftp-server.o sftp-common.o \
        roaming_common.o roaming_serv.o \
        sandbox.o sandbox-null.o sandbox-rlimit.o sandbox-systrace.o \
-       sandbox-darwin.o sandbox-seccomp-filter.o
+       sandbox-darwin.o sandbox-seccomp-filter.o ldapauth.o

 MANPAGES       = moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-keysign.8.out ssh-pkcs11-helper.8.out ssh-vulnkey.1.out sshd_config.5.out ssh_config.5.out
 MANPAGES_IN    = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-keysign.8 ssh-pkcs11-helper.8 ssh-vulnkey.1 sshd_config.5 ssh_config.5

Execute “dpkg-source –commit”.

In addition to the change at the time of the precise, “confflags + = - with-libs =-lldap” you must append.

confflags += --with-ldap
confflags += --with-libs=-lldap
# (snip)
cflags += -DWITH_LDAP_PUBKEY

Other procedures are the same as for the precise.

]]>
Thu, 20 Jun 2013 00:00:00 +0900
http://d.palmtb.net/2013/04/01/my_father_was_passed_away.html http://d.palmtb.net/2013/04/01/my_father_was_passed_away.html <![CDATA[My father was passed away]]> My father was passed away

My father was passed away on the 20th last March. He had difficulty disease. It was too late to cure the disease when his disease has found.

I went to visit my father in the hospital with his daughter about 2 weeks before my father died was the last face-to-face. My father at home until the last minute, do-it-yourself was doing as much as possible on his own. I regret and I should let them meet my daughter to him more. When I went to visit the week before he died, we exchanged words was his father’s last words.

I: “I also come with my wife and daughter in April.”

Father: “When you come next I hope to be able to chat with the grandchildren.”

I did not fulfill this promise that I have with my father.

Dad, may you rest in peace, we shall never forget you.

(This is not April fools’ joke.)

]]>
Mon, 01 Apr 2013 00:00:00 +0900
http://d.palmtb.net/2013/01/08/hardware_sensor_of_openblocks_a_series.html http://d.palmtb.net/2013/01/08/hardware_sensor_of_openblocks_a_series.html <![CDATA[Hardware sensor of OpenBlockS A series]]> Hardware sensor of OpenBlockS A series

I could get CPU temparature with lm-sensors, and storage temparature with hddtemp. I wrote blog post about hardware sensor at this entry.

CPU temparature

Firstly you should install “lm-sensors” package.

$ sudo apt-get install lm-sensors

lm-sensors has sensors command and sensors-detect command. The former prints sensors information, the latter is enable to detect hardware monitoring chips.

sensors command

This command is only enable to get CPU temparagure at OpenBlockS AX3. But it seems you can not get the correct values with the latest firmware (kernel-image 3.0.6-8)

kernel image 3.0.6-3

$ sensors
axp-hwmon-isa-0000
Adapter: ISA adapter
T-junction:  +54.5°C  (low  = +10.0°C, high = +105.0°C)  sensor = thermal dioed

kernel iamge 3.0.6-8

$ sensors
axp-hwmon-isa-0000
Adapter: ISA adapter
T-junction:   +0.1°C  (low  =  +0.0°C, high =  +0.1°C)  sensor = thermal diode

OpenBlockS A6 is disable to use sensors.

$ sensors
No sensors found!
Make sure you loaded all the kernel drivers you need.
Try sensors-detect to find out which these are.

sensors-detect command

This command is disable to detect any monitoring chips of OpenBlockS A6 and AX3 kernel provided by Plat’Home. On the contrary kernel internal error is occured if you enter YES unconditionally in OpenBlockS AX3.

$ sudo sensors-detect
(snip)
Some Super I/O chips contain embedded sensors. We have to write to
standard I/O ports to probe them. This is usually safe.
Do you want to scan for Super I/O sensors? (YES/no):
Probing for Super-I/O at 0x2e/0x2f

Message from syslogd@obsax3 at Jan  8 00:33:13 ...
kernel:Internal error: : 1028 [#2] SMP

Message from syslogd@obsax3 at Jan  8 00:33:13 ...
kernel:Process sensors-detect (pid: 1397, stack limit = 0xeb8882f0)
kohei@obsax3:~$
Message from syslogd@obsax3 at Jan  8 00:33:13 ...
kernel:Stack: (0xeb889f20 to 0xeb88a000)

Message from syslogd@obsax3 at Jan  8 00:33:13 ...
kernel:9f20: 00000001 eb8f6f00 00205998 eb889f70 eb889f6c eb889f40 c00fafa8 c0268880
(snip)

scanning occurs kernel internal error is following.

  • Super I/O sensors
  • IPMI interfaces
  • ISA I/O ports

OpenBlockS A6 does not occures kernel internal error, but scanning mv64xxx_i2c adopter is not reacted (to stop with SIGINT).

Storage temparature

You should install “hddtemp” package.

$ sudo apt-get install hddtemp

debconf setting is like as following.

  • SUID root: no
  • interval of check temparature: 0
  • daemon: yes
  • listen IP address: 127.0.0.1
  • port: 7634

hddtemp reads temparature with “S.M.A.R.T.”. It is supported by the following storage;

  • HalfSlim SSD 16GB MLC installed at OpenBlockS A6 product version and OpenBlockS AX3 rented
  • MLC SSD 128GB(PH-128G/SSDMA/AX3) installed OpenBlockS AX3 purchased

HalfSlim SSD

$ sudo hddtemp /dev/sda
/dev/sda: MRSAJ5A016GC118C00: 40 C

PH-128GB

$ sudo hddtemp /dev/sda
/dev/sda: ADATA SP900: 27 C

You can do health check storage if you install “smartmontools” package and use smartctl command.

I2C

You should install i2c-tools package.

$ sudo apt-get install i2c-tools

Execute “i2cdetect command” to detect I2C chips.

OpenBlockS AX3

$ sudo i2cdetect -l
i2c-0   i2c             mv64xxx_i2c adapter                     I2C adapter
i2c-1   i2c             mv64xxx_i2c adapter                     I2C adapter
$ sudo i2cdetect -y 0
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: 50 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
$ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: UU UU UU UU UU UU UU UU -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

Execute sensors-detect of lm-sensors.

$ sudo sensors-detect
(snip)
Lastly, we can probe the I2C/SMBus adapters for connected hardware
monitoring devices. This is the most risky part, and while it works
reasonably well on most systems, it has been reported to cause trouble
on some systems.
Do you want to probe the I2C/SMBus adapters now? (YES/no): yes
Sorry, no supported PCI bus adapters found.

Next adapter: mv64xxx_i2c adapter (i2c-0)
Do you want to scan it? (YES/no/selectively):
Client found at address 0x50
Probing for `Analog Devices ADM1033'...                     No
Probing for `Analog Devices ADM1034'...                     No
Probing for `SPD EEPROM'...                                 No
Probing for `EDID EEPROM'...                                No
(snip)

OpenBlockS A6

“sudo i2cdetect -y 0” is very very slowly at OpenBlockS A6.

$ sudo i2cdetect -l
i2c-0   i2c             mv64xxx_i2c adapter                     I2C adapter
$  sudo i2cdetect -y 0
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
]]>
Tue, 08 Jan 2013 00:00:00 +0900
http://d.palmtb.net/2013/01/07/uscan_for_github_as_of_january_2013.html http://d.palmtb.net/2013/01/07/uscan_for_github_as_of_january_2013.html <![CDATA[uscan for GitHub as of January 2013]]> uscan for GitHub as of January 2013

You should write “watch line” in debian/watch if upstream is hosted on GitHub as of January 2013.

version=3
https://github.com/<user>/<project>/tags .*/v(\d[\d\.]+)\.tar\.gz

It was missing “v” in Debian Wiki, so I have fixed up.

]]>
Mon, 07 Jan 2013 00:00:00 +0900
http://d.palmtb.net/2013/01/06/comparizon_of_openblocks_a6_and_openblocks_ax3.html http://d.palmtb.net/2013/01/06/comparizon_of_openblocks_a6_and_openblocks_ax3.html <![CDATA[Comparison OpenBlockS A6 and OpenBlockS AX3]]> Comparison OpenBlockS A6 and OpenBlockS AX3

I rented OpenBlockS A6 and OpenBlockS AX3 from Plat’Home Co., Ltd.(Thanks!) last early summer. I will write blog post about A6 and AX3 several times. I wrote blog post about comparison of A6 and AX3 at this entry.

../../../_images/obsa6_ax3_0.jpg

Opening ceremony of OpenBlockS A6 and AX3

ES version of A6

OpenBlockS A6 I rented the first was ES(engineering sample) version. It was exchanged to the product version on the way. The difference of both on the appearance was screws of body. The diameter of the screw hole of product version is smaller than ES version. The storage installed of ES version was ADATA’s 2.5 inch SSD 396 30GB, that of product version was HalfSlim SSD 16GB MLC.

../../../_images/obsa6_ax3_1.jpg

Left is OpenBlockS AX3, right is OpenBlockS A3 (ES version)

../../../_images/obsa6_ax3_2.jpg

Bottom view

../../../_images/obsa6_ax3_3.jpg

Another angle

Comaprison v.s. OpenBlockS 600

I compare their bodies against OpenBlockS 600. OpenBlockS A3 is slightly larger than OpenBlockS 600.

../../../_images/obsa6_ax3_4.jpg

Side view of OpenBlockS 600, OpenBlockS A3, OpenBlockS AX3

../../../_images/obsa6_ax3_5.jpg

Bird view of OpenBlockS 600, OpenBlockS A3, OpenBlockS AX3

Filesystem

I was formatted storage because The storage of ES version was not formatted. It is the same that case I bought OpenBlockS AX3 J. The storatge of product version was already mounted with UnionFS. It was the same that case I had rented OpenBlockS AX3.

$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/ram0 124M 92M 27M 78% /
udev 10M 88K 10M 1% /dev
tmpfs 64M 4.0K 64M 1% /dev/shm
/dev/sda1 14G 618M 13G 5% /.rw
unionfs 14G 618M 13G 5% /etc
unionfs 14G 618M 13G 5% /bin
unionfs 14G 618M 13G 5% /home
unionfs 14G 618M 13G 5% /lib
unionfs 14G 618M 13G 5% /sbin
unionfs 14G 618M 13G 5% /usr
unionfs 14G 618M 13G 5% /var
unionfs 14G 618M 13G 5% /root
unionfs 14G 618M 13G 5% /opt
unionfs 14G 618M 13G 5% /srv
unionfs 14G 618M 13G 5% /media

It is /etc/mtab as folloing.

$ cat /etc/mtab
/dev/ram0 / ext2 rw 0 0
proc /proc proc rw,noexec,nosuid,nodev 0 0
sysfs /sys sysfs rw,noexec,nosuid,nodev 0 0
udev /dev tmpfs rw,mode=0755 0 0
tmpfs /dev/shm tmpfs rw,nosuid,nodev,size=64m 0 0
devpts /dev/pts devpts rw,noexec,nosuid,gid=5,mode=620 0 0
/dev/sda1 /.rw ext4 rw,relatime,barrier=1,data=ordered 0 0
unionfs /etc unionfs rw,relatime,dirs=/.rw/etc=rw:/etc=ro 0 0
unionfs /bin unionfs rw,relatime,dirs=/.rw/bin=rw:/bin=ro 0 0
unionfs /home unionfs rw,relatime,dirs=/.rw/home=rw:/home=ro 0 0
unionfs /lib unionfs rw,relatime,dirs=/.rw/lib=rw:/lib=ro 0 0
unionfs /sbin unionfs rw,relatime,dirs=/.rw/sbin=rw:/sbin=ro 0 0
unionfs /usr unionfs rw,relatime,dirs=/.rw/usr=rw:/usr=ro 0 0
unionfs /var unionfs rw,relatime,dirs=/.rw/var=rw:/var=ro 0 0
unionfs /root unionfs rw,relatime,dirs=/.rw/root=rw:/root=ro 0 0
unionfs /opt unionfs rw,relatime,dirs=/.rw/opt=rw:/opt=ro 0 0
unionfs /srv unionfs rw,relatime,dirs=/.rw/srv=rw:/srv=ro 0 0
unionfs /media unionfs rw,relatime,dirs=/.rw/media=rw:/media=ro 0 0

This UnionFS is controlled by “/etc/init.d/openblocks-setup” and “/etc/default/openblocks”. This init script also controls hardware specific to OpenBlockS. Other are the same as a normal Debian system.

OpenBlockS 600

OpenBlockS 600 with CF boot is invisible the storage device.

$ df -h
Filesystem            Size  Used Avail Use% Mounted on
tmpfs                 507M     0  507M   0% /lib/init/rw
udev                   10M   48K   10M   1% /dev
tmpfs                 507M     0  507M   0% /dev/shm
rootfs                7.4G  869M  6.2G  13% /

“/etc/mtab” is as following.

$ cat /etc/mtab
tmpfs /lib/init/rw tmpfs rw,nosuid,mode=0755 0 0
proc /proc proc rw,noexec,nosuid,nodev 0 0
sysfs /sys sysfs rw,noexec,nosuid,nodev 0 0
udev /dev tmpfs rw,mode=0755 0 0
tmpfs /dev/shm tmpfs rw,nosuid,nodev 0 0
devpts /dev/pts devpts rw,noexec,nosuid,gid=5,mode=620 0 0
rootfs / rootfs rw 0 0

I think OpenBlockS A series are easier to manage than OpenBlockS 600, because storage device of A series is visible.

]]>
Sun, 06 Jan 2013 00:00:00 +0900
http://d.palmtb.net/2013/01/05/rewrite_history_with_git_filter_branch.html http://d.palmtb.net/2013/01/05/rewrite_history_with_git_filter_branch.html <![CDATA[Rewrite history with git-filter-branch]]> Rewrite history with git-filter-branch

I rewrote the history of Git repository that I developped a software when I would upload the software to GitHub. The history of repository has my some different COMMITER & AUTHOR NAME and EMAIL, and configurations for testing environments. So I wanted to change NAME and EMAIL to one is used for publish, and wanted to change to sample configurations.

My repository has two branches as master, devel, and has some tags. I took mainly three step .

  1. Change the NAME and MAIL
  2. Rewrite commit messeages and contents
  3. re-tags
$ git remote
origin
$ git remote rm origin

Change the NAME and MAIL

Filtering with “git filter-branch –commit-filter” and execute ‘git commit-tree “$@”’, a new commit tree is generated. Original tree is taken a backup to “original/refs/heads”.

$ git filter-branch --commit-filter  '
GIT_AUTHOR_NAME="Kouhei Maeda";
GIT_AUTHOR_EMAIL=mkouhei@palmtb.net;
GIT_COMMITTER_NAME="Kouhei Maeda";
GIT_COMMITTER_EMAIL=mkouhei@palmtb.net;
git commit-tree "$@"
' -- --all
Rewrite 97d9b7d1899f7e6b08d91f5e606c8521f907b01c (43/43)
Ref 'refs/heads/devel' was rewritten
Ref 'refs/heads/master' was rewritten
Ref 'refs/tags/v0.1' was rewritten
WARNING: You said to rewrite tagged commits, but not the corresponding tag.
WARNING: Perhaps use '--tag-name-filter cat' to rewrite the tag.
Ref 'refs/tags/v0.1.1' was rewritten
WARNING: You said to rewrite tagged commits, but not the corresponding tag.
WARNING: Perhaps use '--tag-name-filter cat' to rewrite the tag.
Ref 'refs/tags/v0.1.2' was rewritten
WARNING: You said to rewrite tagged commits, but not the corresponding tag.
WARNING: Perhaps use '--tag-name-filter cat' to rewrite the tag.

It is easy to understand with “gitk –all”.

Rewrite commit messages and contents

Rewrite commit messages

Use “–msg-filter” option to rewrite Sigined-off-by of commit message.

$ git filter-branch -f --msg-filter '
sed -e "s/\(Signed-off-by: \).*/\1Kouhei Maeda <mkouhei@palmtb.net>/g"
' -- --all
Rewrite 13cfa3ac719e507168822783822fa2480018a5ec (82/82)
Ref 'refs/heads/devel' was rewritten
Ref 'refs/heads/master' was rewritten
Ref 'refs/tags/v0.1' was rewritten
WARNING: You said to rewrite tagged commits, but not the corresponding tag.
WARNING: Perhaps use '--tag-name-filter cat' to rewrite the tag.
Ref 'refs/tags/v0.1.1' was rewritten
WARNING: You said to rewrite tagged commits, but not the corresponding tag.
WARNING: Perhaps use '--tag-name-filter cat' to rewrite the tag.
Ref 'refs/tags/v0.1.2' was rewritten
WARNING: You said to rewrite tagged commits, but not the corresponding tag.
WARNING: Perhaps use '--tag-name-filter cat' to rewrite the tag.

Rewrite contents with “–tree-filter”

If you specify target files with postfix as ‘find ./ -name “*.py”‘, you must specify files that are always present. Because you will fail if you specify a file that does not exist on any commit. You must specify multiple postfixt with “-o” options as following.

$ git filter-branch -f --tree-filter '
find ./ -name "*.py" -o -name "*.rst" -o -name "*.html" -o -name "*.1"| xargs sed -i "
s/mkouhei@workstation.example.com/mkouhei@palmtb.net/g
s/Kohei Maeda/Kouhei Maeda/g
s/http:\/\/scm.example.com/https:\/\/github.com\/mkouhei/g
s/Kohei Maeda <mkouhei@workstation>/Kouhei Maeda <mkouhei@palmtb.net>/g
s/mkouhei/testuser/g
s/test.example.com/ldap.example.org/g
s/dc=example,dc=com/dc=example,dc=org/g
"' -- --all
Rewrite 05db18486e3285bb6178d8da0c8952e63542ec80 (82/82)
Ref 'refs/heads/devel' was rewritten
Ref 'refs/heads/master' was rewritten
Ref 'refs/tags/v0.1' was rewritten
WARNING: You said to rewrite tagged commits, but not the corresponding tag.
WARNING: Perhaps use '--tag-name-filter cat' to rewrite the tag.
Ref 'refs/tags/v0.1.1' was rewritten
WARNING: You said to rewrite tagged commits, but not the corresponding tag.
WARNING: Perhaps use '--tag-name-filter cat' to rewrite the tag.
Ref 'refs/tags/v0.1.2' was rewritten
WARNING: You said to rewrite tagged commits, but not the corresponding tag.
WARNING: Perhaps use '--tag-name-filter cat' to rewrite the tag.

re-tags

I used a signed tag, so replace the same name tag with “-f” option. Firstly I confirmed date of original tag.

$ git show v0.1
tag v0.1
Tagger: Kouhei Maeda <mkouhei@palmtb.net>
Date:   Wed Dec 19 01:42:35 2012 +0900

release 0.1
(snip)

commit 795897ff28cea6512c457de02a1d6043236c685b
Merge: c4bc5bf a90fa12
Author: Kouhei Maeda <mkouhei@palmtb.net>
Date:   Wed Dec 19 01:39:02 2012 +0900

Merge branch 'devel'

Confirm commit hash of the same commit in a new tree.

$ git log --oneline :/Merge branch 'devel'
(snip)
1f1a023 Merge branch 'devel'
7e2682a closed #19 packaging Debian package
89a35fe Fix fail to execute console script

Replace tag.

$ GIT_COMMITER_DATE="2012-12-19 01:42:35+0900" git tag -f -s -m "release 0.1" -u 7E37CE41 v0.1 1f1a023

次のユーザーの秘密鍵のロックを解除するには
パスフレーズがいります:“Kouhei Maeda <mkouhei@palmtb.net>”
4096ビットRSA鍵, ID 7E37CE41作成日付は2009-06-19

Updated tag 'v0.1' (was 83cb501)

Repeat as many as numbers of tags. You should confirm commit messages and contents before you will push new remote repository.

]]>
Sat, 05 Jan 2013 00:00:00 +0900
http://d.palmtb.net/2013/01/04/open_multiple_channel_on_pidgin.html http://d.palmtb.net/2013/01/04/open_multiple_channel_on_pidgin.html <![CDATA[Open multiple channels on pidgin]]> Open multiple channels on pidgin

This is a short story.

pidgin is a chat GUI client. I usually use it for office only IRC, public IRC, and Skype. I open multiple channels with canma at the same server.

For example is following.

Input “#python,#haskell,#couchdb,#couchdeb-dev” for “irc.freenode.org”.

../../../_images/pidgin.png ]]>
Fri, 04 Jan 2013 00:00:00 +0900
http://d.palmtb.net/2013/01/03/tinkerer_1_0_2.html http://d.palmtb.net/2013/01/03/tinkerer_1_0_2.html <![CDATA[Debian package of Tinkerer 1.0.2]]> Debian package of Tinkerer 1.0.2

Tinkerer 1.0 was released last December 16. Tinkerer is supported both python2 and python3, so I have packaged Debian package of python2 and python3, and uploaded to mentors.debian.net.

It does not become the official package, why it is not yet able to resolve the issue of the license.

]]>
Thu, 03 Jan 2013 00:00:00 +0900
http://d.palmtb.net/2013/01/02/a_happy_new_year_2013.html http://d.palmtb.net/2013/01/02/a_happy_new_year_2013.html <![CDATA[A happy new year 2013]]> A happy new year 2013
A happy new year, everyone. I have witten this entry because I wrote the same title entry last year.
(2011年の振り返りと2012年の抱負。)

Review last year

Private

  • Our first baby was born at March first, and she has been ten months. She walks along the wall, and saids “Mamma”.
  • I stoped diet and temperance in the first half of last year, but I also resumed and ongoing.
  • I’m back to my parents’ house as soon as possible why health of my parent is not good.
  • My wife became ill after childbirth, she had surgrey in the hospital.
  • I and our daughter caught a cold from about Decenber, and we were in bed most of the time at the end of the holiday.

Work

  • I was scheduled to go home in mid-November. But I was nearly the last train back about one and a half months after the end of the work-at-home.
    • I made ​​a first-time telecommuting when my wife was infected with norovirus.
  • The articles that we was interviewed were published, and I had written the official blog.
  • Our mission was changed building a new data center, my main mission is testing and developping and building authentication and mail systems, packages and SCM repository.
  • I packaged unofficial Debian packages at using free software and I developped softwares.

Debian and others

  • Blockdiag series had been main.
    • Other softwares were almost uploads to mentors.debian.net, but were not yet main.
  • We had held “Grand union Debian meeting” (大統一Debian勉強会).
    • I have said “Opening speech”, and photo shoot of the day, only.
  • I had become a Debian JP leader of this term, but I do not play a role in private is too busy.
  • Currently, I have not been able to work my maintenance of the Debian packages.
  • Activity of the CouchDB JP was stopped.
  • Programming and python, python & Debian packaging only I was doing in both public and private.

In summary, child-rearing, nursing my wife, to go home to the parents’ frequent were more difficult than expected.

This year

I decided two simply.

First health

Health break, we would spend all one’s time to it. Our daughter, my wife, myself are to stay healthy firstly.

In moderation

What I want to do, that I do not have a lot to do everything this year. Last year only become hands full health aspects of my family, there was a lot of what was untouched. So, I think it is not aiming for 100%, 50%, 0%, and 80%, 80%, 80% would aim a little luck.

]]>
Wed, 02 Jan 2013 00:00:00 +0900
http://d.palmtb.net/2012/12/14/writing_preseed_for_gpt.html http://d.palmtb.net/2012/12/14/writing_preseed_for_gpt.html <![CDATA[GPT対応のpreseedの書き方]]> GPT対応のpreseedの書き方

この記事は Debian/Ubuntu JP Advent Calendar 2012 の 12/14(金) の記事です。昨日は岩松さん(@iwamatsu)による “namecheck / 同じ名前のパッケージ/プロジェクト名がないか確認する” でした。今日は、GPTを使う、要は2TBを超えるハードディスクに、preseedを使ってDebian/Ubuntuをインストールする方法について紹介します。

GPTとは

GUIDパーティションテーブル(GUID Partition Table)の略で、EFIの一部であることから、rEFItを使ってIntel Mac、特にMacBookなどにDebianをインストールしている面々には聞きなれた用語かと思います。EFIはx86アーキテクチャのBIOSに、GPTはMBRを置き換えるものとなっています。MBRの場合、2TBの壁がありますが、最近のディスクの大容量化により、2TBを超えるディスクを持っている方も増えているのではないかと思います。

ちなみに我が家では、OpenBlockS 266で使用している40GBとか80GBの5400rpmの2.5インチハードディスクが大半で、普段つかっているMacBook Pro 15インチは120GBのSSD、一番大きい容量でもMac miniの500GBなので、2TBを超えるなんてまだ当面先の話です。

閑話休題。2TBを超えるディスクといえば、1Uサーバでもお目にかかるようになりました。今回、職場で導入するサーバの一部で、2TBを超えるサーバにpreseedでUbuntu 12.04 LTSをインストールすることになったので、説明したいと思います。

Preseedについて

Preseedでの書き方について触れる前に、そもそもPreseedって何ぞや、という方のために少し説明。PreseedはDebianおよびDebianから派生したディストロで使用される、自動インストールのための仕組みです。みんな大好きRHEL系のディストロではKickStartに相当するものです。Debian系ではKickStartを使ってPXEブートで自動インストールすることもできますが、できることに一部制限があるので、Preseedを使うのがよいでしょう。

preseedでのパーティショニング

公式ドキュメントの B.4.7. パーティション分割 に例が記述されています。細かく指定するには、”partman-auto/expert_recipe”を使うのですが、残念ながらこの指定方法について細かく載っているマニュアルは、ネットで検索してもなかなか出てきません。上記リンク先で説明のあるとおり、debian-installerパッケージに含まれる、/usr/share/doc/debian-installer/devel/partman-auto-recipe.txt.gzを読むのが良いでしょう。公式ドキュメントのサンプルでは、

# If not, you can put an entire recipe into the preconfiguration file in one
# (logical) line. This example creates a small /boot partition, suitable
# swap, and uses the rest of the space for the root partition:
#d-i partman-auto/expert_recipe string                         \
#      boot-root ::                                            \
#              40 50 100 ext3                                  \
#                      $primary{ } $bootable{ }                \
#                      method{ format } format{ }              \
#                      use_filesystem{ } filesystem{ ext3 }    \
#                      mountpoint{ /boot }                     \
#              .                                               \
#              500 10000 1000000000 ext3                       \
#                      method{ format } format{ }              \
#                      use_filesystem{ } filesystem{ ext3 }    \
#                      mountpoint{ / }                         \
#              .                                               \
#              64 512 300% linux-swap                          \
#                      method{ swap } format{ }                \
#              .

と記載されていますが、各パラメータについての説明はありません。これは、partman-auto-recipe.txtによると、

<limits>::=<minimal size>_<priority>_<maximal size>_<parted fs>

となっています。サイズはmegabytesもしくはディスク容量の割合(%)で指定することができます。minimal sizeは最小サイズを指定します。priorityは小さい値の方が優先度が高くなります。maximalサイズは割り当ての上限サイズを指定し、-1を指定すると無制限となります。parted_fsは割り当てるパーティションの種類です。

つまり、上記では、

  • /boot
    • 最低40MB、最大100MBを割り当て
    • ext3ファイルフォーマット
    • 優先度はもっとも高い
  • /
    • 最低500MB、最大10^9MBを割り当て
    • ext3ファイルフォーマット
    • 優先度もっとも低い
  • swap
    • 最低64MB、最大メモリサイズの300%(3倍)のサイズを割り当て
    • swap領域
    • 優先度は2番めに高い

ということになります。

GPT対応した書き方

GPTの場合、1MBのbiosgrubという領域が必ず必要になります。これを忘れると、preseedでの自動インストールの途中、パーティショニングのところで失敗してしまいます。また、$gptonly{ }というパラメータも必要になります。

d-i partman-auto/expert_recipe string \
32 32 32 free \
$gptonly{ } \
$primary{ } \
$bios_boot{ } \
method{ biosgrub } \
. \
boot-root :: \
300 50 300 ext4 \
$gptonly{ } \
$primary{ } $bootable{ } \
method{ format } format{ } \
use_filesystem{ } filesystem{ ext4 } \
mountpoint{ /boot } \
. \
500 10000 -1 ext4 \
$gptonly{ } \
method{ format } format{ } \
use_filesystem{ } filesystem{ ext4 } \
mountpoint{ / } \
. \
8192 512 8192 linux-swap \
$gptonly{ } \
$primary{ } \
method{ swap } format{ } \
.

上記での場合、1MBのbiosgrub領域、300MBの/boot、8GBのswap領域、そして残りはすべて / ファイルシステムになる、ということです。この辺は、 Re: GPT preseed [ almost solved ] に掲載されています。なお、2TB未満のシステムであってもこれはそのまま使えます。(もしかしたら、そのまま使えるのはUEFI対応の機器だけかも知れませんが、その点は未検証です。)

さあ、これでもう迷わず preseed でパーティショニングの一番面倒な設定部分を書けるようになりましたね。おめでとうございます。

さーて、明日のAdvent Calendarは?

さあ、誰なんでしょうね。俺にも書かせろ、という方はぜひAdvent Calendarに参加してみてください。

]]>
Fri, 14 Dec 2012 00:00:00 +0900
http://d.palmtb.net/2012/12/11/rename_project_on_gitlab.html http://d.palmtb.net/2012/12/11/rename_project_on_gitlab.html <![CDATA[Rename project on GitLab]]> Rename project on GitLab

If you want rename project on GitLab, I think you will do it as following.

  1. move “Project home”
  2. “Edit”
  3. Change “Project name”
  4. “Save”

But you cannot change path of remote repository in this way. If you will change path, you take a next method.

  1. Create new project.
  2. Change local repository.
  3. git push

But you cannot port existed issues on GitLab 3.1. So you must change data with SQL directly.

$ mysql -u root -p gitlabhq_production
mysql> select id, name from projects;
+----+------------------------+
| id | name                   |
+----+------------------------+
(snip)
| 35 | test-project           |
(snip)
| 39 | prod-project           |
+----+------------------------+
29 rows in set (0.00 sec)

mysql> select project_id from issues where project_id = '35';
+------------+
| project_id |
+------------+
|         35 |
|         35 |
|         35 |
|         35 |
|         35 |
|         35 |
|         35 |
+------------+
7 rows in set (0.00 sec)

mysql> update issues set project_id = '39' where project_id = '35';
Query OK, 7 rows affected (0.03 sec)
Rows matched: 7  Changed: 7  Warnings: 0
]]>
Tue, 11 Dec 2012 00:00:00 +0900
http://d.palmtb.net/2012/11/27/python_ldap.html http://d.palmtb.net/2012/11/27/python_ldap.html <![CDATA[LDAP of the python, by the python, and for the python]]> LDAP of the python, by the python, and for the python

The title is a joke. :)

Usually, LDAP is controlled by LDIF and ldap-utils; ldapsearch, ldapadd, ldapmodify, etc. But I dislike to control many and variety data with LDIF and these tools because it is a very bother to generate LDIF. To control LDAP will be easier by programming with python-ldap. “python-ldap provides an object-oriented API to access LDAP directory servers from Python programs”. In this article I describe basic usage of python-ldap for search, add, modify, delete.

Intall python-ldap

python-ldap is provided as Debian package.

$ sudo apt-get install python-ldap

Connect to LDAP server

To connect to LDAP server in the following conditions, as described below.

>>> import ldap
>>> uri = "ldap://ldap.example.org"
>>> l = ldap.initialize(uri)
>>> rootdn = "cn=admin,dc=example,dc=org"
>>> password = "xxxxxxxx"
>>> method = ldap.AUTH_SIMPLE
>>> l.bind(rootdn, password, method)
1

Add

Firstly, you must use ldap.modlist.addModlist(). addModlist() convert dictionary into list of tuple.

>>> result = l.search_s(search_base, search_scope, search_filter)
>>> result[0][1]
{'cn': ['gonbeh'], 'objectClass': ['top', 'inetOrgPerson', 'posixAccount'], 'userPassword': ['{SSHA}M6H0rX2tGCwf6jBcgdP2hxSRisVoY55b=='], 'uidNumber': ['99999'], 'gidNumber': ['10000'], 'sn': ['nanashi'], 'homeDirectory': ['/home/nanashigonbeh'], 'mail': ['nanashigonbeh@net.example.org'], 'uid': ['nanashigonbeh']}
>>> import ldap.modlist
>>> data_l = ldap.modlist.addModlist(result[0][1])
>>> data_l
[('cn', ['gonbeh']), ('objectClass', ['top', 'inetOrgPerson', 'posixAccount']), ('userPassword', ['{SSHA}M6H0rX2tGCwf6jBcgdP2hxSRisVoY55b==']), ('uidNumber', ['99999']), ('gidNumber', ['10000']), ('sn', ['nanashi']), ('homeDirectory', ['/home/nanashigonbeh']), ('mail', ['nanashigonbeh@net.example.org']), ('uid', ['nanashigonbeh'])]

Override values of “uid”, “sn”, “cn”, “uidNumber”, “homeDirectory”, “mail” as like folloing.

>>> user = result[0][1].copy()
>>> user['uid'] = ['foobar']
>>> user['sn'] = ['foo']
>>> user['cn'] = ['bar']
>>> user['uidNumber'] = ['123456']
>>> user['homeDirectory'] = ['/home/foobar']
>>> user['mail'] = ['foobar@example.org']
>>> user
{'cn': ['bar'], 'objectClass': ['top', 'inetOrgPerson', 'posixAccount'], 'userPassword': ['{SSHA}M6H0rX2tGCwf6jBcgdP2hxSRisVoY55b=='], 'uidNumber': ['123456'], 'gidNumber': ['10000'], 'sn': ['foo'], 'homeDirectory': ['/home/foobar'], 'mail': ['foobar@example.org'], 'uid': ['foobar']}

Convert with addModlist().

>>> user_l = ldap.modlist.addModList(user)
>>> user_l
[('cn', ['bar']), ('objectClass', ['top', 'inetOrgPerson', 'posixAccount']), ('userPassword', ['{SSHA}M6H0rX2tGCwf6jBcgdP2hxSRisVoY55b==']), ('uidNumber', ['123456']), ('gidNumber', ['10000']), ('sn', ['foo']), ('homeDirectory', ['/home/foobar']), ('mail', ['foobar@example.org']), ('uid', ['foobar'])]

To add data is necessary to use add_s() with dn and list of data. When it is succeed to add, the response is “(105, [])”. “105” is tag of adding.

>>> dn = result[0][0]
>>> dn
'uid=nanashi_gonbeh,ou=People,dc=example,dc=org'
>>> dn = 'foobar,ou=People,dc=example,dc=org'
>>> l.add_s(dn, user_l,)
(105, [])

Compare and modify

To detect changed data, use compare_s(). To need to prepare below data. First argument is dn, second argument is attribute name, third argument is value (value is not list).

Compare

>>> user2 = result[0]
>>> user2[1]['userPassword']
['{SSHA}M6H0rX2tGCwf6jBcgdP2hxSRisVoY55b==']
>>> password = '{SSHA}Z7H50qdkcYdH+8ghga6MCevOSa8ax3xp'
>>> userdn2 = user2[0]
>>> l.compare_s(userdn2, 'userPassword', user2[1].get('userPassword')]
0
>>> l.compare_s(userdn2, 'userPassword', password)
1

0 is not changed, 1 is changed. When result of compare_s() is “1”, I’ll use data for modify.

Modify

We must use ldap.modlist.modifyModlist() to modify data. First argument is current data without dn, second argument is new data without dn.

>>> mod_info_l = ldap.modlist.modifyModlist(current_dict, new_dict)
>>> mod_info_l
[(1, 'userPassword', None), (0, 'userPassword', ['{SSHA}Z7H50qdkcYdH+8ghga6MCevOSa8ax3xp'])]

If multiple attributes are changed as like following,

>>> ldap.modlist.modifyModlist(current, new)
[(1, 'cn', None), (0, 'cn', ['bar']), (1, 'uidNumber', None), (0, 'uidNumber', ['123456']), (1, 'sn', None), (0, 'sn', ['foo']), (1, 'homeDirectory', None), (0, 'homeDirectory', ['/home/foobar']), (1, 'mail', None), (0, 'mail', ['foobar@example.org']), (1, 'uid', None), (0, 'uid', ['foobar'])]

modify with modify_s() using data that specified with dn and modlist data. When It is succeed to modify, the result is “(103, [])”. “103” is tag of modify.

>>> l.modify_s(dn, mod_info_l)
(103, [])

Delete

Delete is specified dn only.

>>> l.delete_s(dn)
(107, [], 12, [])

“107” is tag of delete. “12” is sequence number of registered ldap object.

See also

]]>
Tue, 27 Nov 2012 00:00:00 +0900
http://d.palmtb.net/2012/11/19/access_to_rsa_securid_token_with_cisco_asa_vpn_using_openconnect.html http://d.palmtb.net/2012/11/19/access_to_rsa_securid_token_with_cisco_asa_vpn_using_openconnect.html <![CDATA[Access to RSA SecurID token with Cisco ASA VPN using OpenConnect]]> Access to RSA SecurID token with Cisco ASA VPN using OpenConnect

What client do you use for access to Cisco ASA SSL VPN in your Debian system? It is usually to use Cisco AnyConnect, but we can use Debian package of OpenConnect. OpenConnect is a client for Cisco’s AnyConnect SSL VPN.

Install “openconnect” package.

$ sudo apt-get install openconnect

When use Cisco ASA without RSA SercurID token, follow next commands. It is using option “–no-cert-check” In this case, because we have not yet prepared signed by trusted Certificate Authority.

$ sudo openconnect --no-cert-check --user=user --passwd-on-stdin https://vpn.example.org/test_group

[sudo] password for user:

Attempting to connect to vpn.example.org:443
SSL negotiation with vpn.example.org
Server certificate verify failed: self signed certificate
Connected to HTTPS on vpn.example.org
GET https://vpn.example.org/test_group
Got HTTP response: HTTP/1.0 302 Temporary moved
SSL negotiation with vpn.example.org
Server certificate verify failed: self signed certificate
Connected to HTTPS on vpn.example.org
GET https://vpn.example.org/+webvpn+/index.html
POST https://vpn.example.org/+webvpn+/index.html
Please enter your username and password.
Password:
POST https://vpn.example.org/+webvpn+/index.html
Got CONNECT response: HTTP/1.1 200 OK
CSTP connected. DPD 30, Keepalive 20
Connected tun0 as 192.0.2.10 + 2001:0db8::10, using SSL
DTLS handshake failed: 2
DTLS handshake failed: 2
(snip)

When using Cisco ASA with two factor authentication as RSA SecurID token and LDAP authentication, openconnect command is following.

$ sudo openconnect --no-cert-check https://vpn.example.org/test_rsa
Attempting to connect to vpn.example.org:443
SSL negotiation with vpn.example.org
Server certificate verify failed: self signed certificate
Connected to HTTPS on vpn.example.org
GET https://vpn.example.org/test_rsa
Got HTTP response: HTTP/1.0 302 Temporary moved
SSL negotiation with vpn.example.org
Server certificate verify failed: self signed certificate
Connected to HTTPS on vpn.example.org
GET https://vpn.example.org/+webvpn+/index.html

Firstly, RSA SecurID token without PIN code. The former pair of username and passcode is SecureID token, the latter pair is LDAP authentication.

Enter blank to PIN. Display pass code without PIN.
Please enter your username and password.
Username:user
PASSCODE:
Username:user
PASSCODE:
POST https://vpn.example.org/+webvpn+/index.html

Set new PIN code. Don’t forgot it.

You must enter a new numeric PIN from 4to 8digits to continue.
New PIN:
Verify PIN:
POST https://vpn.example.org/+webvpn+/login/userpin.html

Enter PIN code in RSA token. Enter pass code as follows, so you can connected.

Enter PIN code. Display pass code with PIN.
Enter new PIN with the next card code to complete authentication.
PASSCODE:
POST https://vpn.example.org/+webvpn+/login/challenge.html
Got CONNECT response: HTTP/1.1 200 OK
CSTP connected. DPD 30, Keepalive 20
Connected tun1 as 192.0.2.10 + 2001:0db8::10, using SSL
DTLS handshake failed: 2
DTLS handshake failed: 2
(snip)

If you failed authentication after you have change PIN code

If you fail next prompt, then you will not be able to authenticate.

Enter new PIN with the next card code to complete authentication.
PASSCODE:

Please request to administrator to reset your PIN code.

]]>
Mon, 19 Nov 2012 00:00:00 +0900
http://d.palmtb.net/2012/11/09/create_multiple_database_to_openldap_with_apparmor.html http://d.palmtb.net/2012/11/09/create_multiple_database_to_openldap_with_apparmor.html <![CDATA[Create multiple database to OpenLDAP with AppArmor]]> Create multiple database to OpenLDAP with AppArmor

This entry is a supplement to “Create multiple databases to OpenLDAP”. AppArmor is disabled at Ubuntu 12.04 in the preious article. AppArmor is enable environment will fail just that steps. Because new directory “/var/lib/ldap2” is not allowed in AppArmor policy.

After making directory and changing permission, install dependency package and change setting of AppArmor.

$ sudo apt-get install apparmor-utils

Append path “/var/lib/ldap2” to config file “/etc/apparmor.d/usr.sbin.slapd”.

Default;

#include <tunables/global>

/usr/sbin/slapd {
  (snip)
  # the databases and logs
  /var/lib/ldap/ r,
  /var/lib/ldap/** rwk,

  # lock file
  /var/lib/ldap/alock kw,

  (snip)

Changed;

#include <tunables/global>

/usr/sbin/slapd {
  (snip)
  # the databases and logs
  /var/lib/ldap/ r,
  /var/lib/ldap/** rwk,
  /var/lib/ldap2/ r,
  /var/lib/ldap2/** rwk,

  /var/log/ldap/ r,
  /var/log/ldap/** rwk,

  # lock file
  /var/lib/ldap/alock kw,
  /var/lib/ldap2/alock kw,

  (snip)

After Change, reload policy.

$ sudo aa-enforce slapd
Setting /etc/apparmor.d/usr.sbin.slapd to enforce mode.

The rest of the steps are the same.

]]>
Fri, 09 Nov 2012 00:00:00 +0900
http://d.palmtb.net/2012/11/01/dovecot_with_ldap.html http://d.palmtb.net/2012/11/01/dovecot_with_ldap.html <![CDATA[Dovecot with LDAP]]> Dovecot with LDAP

Before Set up Dovecot with LDAP, you should prepare Postfix with LDAP. See also “Postfix with LDAP for Dovecot”.

Install packages

$ sudo apt-get install dovecot-pop3d dovecot-lmtpd dovecot-ldap dovecot-postfix

Configuration

/etc/dovecot/dovecot.conf

This file is basic configuration. It will be not changed.

!include_try /usr/share/dovecot/protocols.d/*.protocol
dict {
}
!include conf.d/*.conf
!include_try local.conf

/etc/dovecot/dovecot-ldap.conf.ext

You configure the connection to LDAP, and mapping of LDAP attributes in this file.

Default is enable “base = ” only. The value of “base” is null.

After change;

uris = ldap://ldap01.example.org/ ldap://ldap02.example.org/
tls = yes
tls_ca_cert_file = /etc/ssl/certs/ca-certificates.crt
tls_ca_cert_dir = /etc/ssl/certs
auth_bind = yes
auth_bind_userdn = uid=%n,ou=People,dc=example,dc=org
ldap_version = 3
base = ou=People,dc=example,dc=org
deref = never
scope = subtree
user_attrs = homeDirectory=home,uidNumber=uid,gidNumber=gid
user_filter = (&(objectClass=posixAccount)(uid=%n))
pass_attrs = uid=user,userPassword=password
pass_filter = (&(objectClass=posixAccount)(uid=%n))

“user_attrs” and “user_filter” are related user account.

  • “homeDirectory”, “uidNumber” and “gidNumber” are LDAP attributes
  • “home”, “uid” and “gid” are Dovecot attributes

“pass_attrs” and “pass_filter” are related password.

  • “uid” and “userPassword” are LDAP attributes
  • “user” and “password” are Dovecot attributes.

“%n” is user part in “user@domain” of mail address. I will user account mail address. See also Variables (of Dovecot).

/etc/dovecot/conf.d/10-auth.conf

Change authentication mechanism for using LDAP.

Default;

auth_mechanisms = plain
!include auth-system.conf.ext

After change;

auth_mechanisms = plain
!include auth-ldap.conf.ext

/etc/doveconf/conf.d/10-mail.conf

Set up location of mail delivery.

Default is null.

After change;

mail_location = maildir:/var/vmail/%d/%n/Maildir

Login account is email address. (user0@example.org) But this domain name is dummy. “auth_bind_userdn” specify “uid=%n”, “%n” is account name only. If support multiple domain, follow, and change LDAP setting of userdn to using “mailAddress”, and “olcAccess”.

Check configuration

Check configuration finally with “doveconf -n” command.

]]>
Thu, 01 Nov 2012 00:00:00 +0900
http://d.palmtb.net/2012/10/31/postfix_with_ldap_for_dovecot.html http://d.palmtb.net/2012/10/31/postfix_with_ldap_for_dovecot.html <![CDATA[Postfix with LDAP for Dovecot]]> Postfix with LDAP for Dovecot

When it is used for ldap server for authentication of IMAP4 or POP3 server are used with LDAP, firstly needs to set up MTA with LDAP for mail delivery to users. I have used Postfix as MTA in this case. OS is Ubuntu 12.04, and POP3 server is dovecot2, and MTA is Postfix.

Install packages

$ sudo apt-get install postfix-ldap mailutils

Install postfix-doc if you needs postfix-ldap documentation, then see /usr/share/doc/postfix/html/LDAP_README.html.

Configuration of debconf

  • General type of mail configuration
    • Internet Site
  • System mail name
    • mail.example.org

Configuration

The points are next parameters of postmap for ldap.

  • “query_filter” is “(mail=%s)”
  • “result_attribute” is some cases
  • “scope” is “one”

LDAP lookups

postmap file name is any. I have named “/etc/postfix/ldap-alias.cf” in this case.

$ sudo postconf alias_maps=hash:/etc/aliases,ldap:/etc/postfix/ldap-aliases.cf

/etc/postfix/ldap-aliases.cf is as follows.

server_host = ldap://ldap01.example.org ldap://ldap02.example.org
timeout = 10
search_base = ou=People,dc=example,dc=org
domain = example.org
query_filter = (mail=%s)
result_attribute = mail
scope = one
bind = no
dereference = 0
start_tls = yes
version = 3
tls_ca_cert_dir = /etc/ssl/certs
tls_ca_cert_file = /etc/ssl/certs/ca-certificates.crt

Confirm above settings.

$ sudo postmap -q user0@example.org ldap:/etc/postfix/ldap-aliaces.cf
user0@example.org

Create and/or update database.

$ sudo postmap /etc/postfix/ldap-aliases.cf

Setting alias maps.

$ postconf alias_maps
alias_maps = hash:/etc/aliases
$ sudo postconf alias_maps = hash:/etc/aliases,ldap:/etc/postfix/ldap-aliases.cf

see more ldap_table(5)

domain setting

$ postconf mydomain
mydomain = localdomain
$ sudo postconf mydomain=example.org

Virtual domains

Set up “virtual_mailbox_domains” if you use virtual domains.

$ postconf virtual_mailbox_domains
virtual_mailbox_domains = $virtual_mailbox_maps
$ sudo virtual_mailbox_domains=/etc/postfix/virtual_domains

/etc/postfix/virtual_domains

example.org
example.net
example.com

Virtual mailbox

/etc/postfix/virtual_mailbox is follows;

server_host = ldap://ldap01.example.org ldap://ldap02.example.org
timeout = 10
search_base = ou=People,dc=example,dc=org
domain = example.org
query_filter = (mail=%s)
result_attribute = mail
result_format = %d/%u/Maildir/
scope = one
bind = no
dereference = 0
start_tls = yes
version = 3
tls_ca_cert_dir = /etc/ssl/certs
tls_ca_cert_file = /etc/ssl/certs/ca-certificates.crt

Confirmation

$ postalias -q user0@example.org ldap:/etc/postfix/virtual_mailbox
example.org/user0/Maildir/

Create database

$ sudo postmap /etc/postfix/virtual_mailbox

Set up “virtual_mail_box_maps” and “virtual_mailbox_base”.

$ postconf virtual_mailbox_maps
virtual_mailbox_maps =
$ sudo postconf virtual_mailbox_maps=ldap:/etc/postfix/virtual_mailbox

$ postconf virtual_mailbox_base
virtual_mailbox_base =
$ sudo postconf virtual_mailbox_base=/var/vmail

Make directory, and change owner & group, permission.

$ sudo mkdir -p /var/vmail/example.org
$ sudo chown -R root:mail /var/vmail
$ sudo chmod 2775 /var/vmail

Mailbox owner

You set up mailbox owners are each uid, /etc/postfix/virtual_uids is follows;

server_host = ldap://ldap01.example.org ldap://ldap02.example.org
timeout = 10
search_base = ou=People,dc=example,dc=org
domain = example.org
query_filter = (mail=%s)
result_attribute = uidNumber
scope = one
bind = no
dereference = 0
version = 3
start_tls = yes
tls_ca_cert_dir = /etc/ssl/certs
tls_ca_cert_file = /etc/ssl/certs/ca-certificates.crt

Confirm

$ postalias -q user0@example.org ldap:/etc/postfix/virtual_uids
10001

Create database

$ postmap /etc/postfix/virtual_uids

Set up “virtual_uid_maps”.

$ postconf virtual_uid_maps
virtual_uid_maps =
$ sudo postconf virtual_uid_maps=ldap:/etc/postfix/virtual_uids

Mailbox group

Mailbox group is specified “mail” group.

$ postconf virtual_gid_maps
virtual_gid_maps =
$ id mail
uid=8(mail) gid=8(mail) groups=8(mail)
$ sudo postconf virtual_gid_maps=static:8

Confirmation

$ date | mail -s test user0@example.org
$ sudo tree /var/vmail
/var/vmail/example.org/
└── user0
    └── Maildir
        ├── cur
        ├── new
        │   ├── 1348801351.V805I2b4cM580106.mx2
        │   ├── 1348801351.V805I2c6dM544653.mx2
        │   ├── 1348801351.V805I2c6eM565186.mx2
        │   ├── 1348801351.V805I2c71M587794.mx2
        │   └── 1348801396.V805I232dM112750.mx2
        └── tmp

5 directories, 5 files
]]>
Wed, 31 Oct 2012 00:00:00 +0900
http://d.palmtb.net/2012/10/30/create_multiple_databases_to_openldap.html http://d.palmtb.net/2012/10/30/create_multiple_databases_to_openldap.html <![CDATA[Create multiple databases to OpenLDAP]]> Create multiple databases to OpenLDAP

Perform the following action at creating a new other database if a database is already existed.

Setting of OpenLDAP

$ sudo mkdir /var/lib/ldap2
$ sudo chown openldap:openldap /var/lib/ldap2
$ sudo ldapvi -Y EXTERNAL -h ldapi:/// -b cn=config

Append lines as follow to last lines with a blank line.

add olcDatabase=hdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcHdbConfig
olcDatabase: {1}hdb
olcDbDirectory: /var/lib/ldap2
olcSuffix: dc=example,dc=org
olcAccess: {0}to attrs=userPassword,shadowLastChange by self write by anonymous auth by dn="cn=admin,dc=example,dc=org" write by * none
olcAccess: {1}to dn.base="" by * read
olcAccess: {2}to * by self write by dn="cn=admin,dc=example,dc=org" write by * read
olcLastMod: TRUE
olcRootDN: cn=admin,dc=example,dc=org
olcRootPW: {SSHA}AWtw2vmrYibntFzTJrcxjW13A3xlI+ck
olcDbCheckpoint: 512 30
olcDbConfig: {0}set_cachesize 0 2097152 0
olcDbConfig: {1}set_lk_max_objects 1500
olcDbConfig: {2}set_lk_max_locks 1500
olcDbConfig: {3}set_lk_max_lockers 1500
olcDbIndex: objectClass eq

(save then,)
add: 1, rename: 0, modify: 0, delete: 0
Action? [yYqQvVebB*rsf+?] y
Done

Generate password for rootdn of a new database

$ slappasswd
New password:
Re-enter new password:
{SSHA}3n2Z4m3XfLFMV6wK+neR8bGlptUHJpJC

Add new entries to new database

You should use ‘-A’ option, this option start with an empty file without searcing.

$ sudo ldapvi -D cn=admin,dc=example,dc=org -A

--- Login
Type M-h for help on key bindings.

Filter or DN: cn=admin,dc=example,dc=org
Password: ********

Example entries is follow

add dc=example,dc=org
objectClass: top
objectClass: dcObject
objectClass: organization
o: example.org
dc: example

add cn=admin,dc=example,dc=org
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
userPassword: {SSHA}3n2Z4m3XfLFMV6wK+neR8bGlptUHJpJC

add ou=People,dc=example,dc=org
objectClass: organizationalUnit
ou: People

(save, then)
add: 3, rename: 0, modify: 0, delete: 0
Action? [yYqQvVebB*rsf+?] y
Done

At this point, you will be able to do the entry in the same way as the existing LDAP database.

]]>
Tue, 30 Oct 2012 00:00:00 +0900
http://d.palmtb.net/2012/10/29/openssh_with_public_key_managed_by_openldap.html http://d.palmtb.net/2012/10/29/openssh_with_public_key_managed_by_openldap.html <![CDATA[OpenSSH LDAP public key]]> OpenSSH LDAP public key

Ubuntu

Ubuntu (and Debian) don’t have official debian package of openssh-lpk package. So I applied openssh with openssh-lpk patch from Gentoo. I think it is enable to build with the same way in Debian. (But I have not tried)

Package build

Download patch and apply to source package.

$ wget http://distfiles.gentoo.org/distfiles/openssh-lpk-5.9p1-0.3.14.patch.gz
$ gzip -d openssh-lpk-5.9p1-0.3.14.patch.gz
$ sudo apt-get build-dep openssh
$ sudo apt-get install libldap2-dev quilt
$ apt-get source openssh
$ cd openssh-5.9p1
$ patch < ../openssh-lpk-5.9p1-0.3.14.patch
$ dpkg-source --commit

Remove line #234 because this patch has a bug.

$ vi ./auth-rsa.c (234 line delete)

Execute “quilt refresh”.

$ quilt refresh

Edit debian/rules

$ vi debian/rules
 --- a/rules 2012-04-02 10:38:04.000000000 +0000
 +++ b/rules 2012-06-12 21:46:43.000000000 +0000
 @@ -81,6 +81,7 @@

  # The deb build wants xauth; the udeb build doesn't.
  confflags += --with-xauth=/usr/bin/xauth
 +confflags += --with-ldap
  confflags_udeb += --without-xauth

  # Default paths. The udeb build has /usr/bin/X11 and /usr/games removed.
 @@ -93,6 +94,7 @@
  cflags := $(default_cflags)
  cflags += -DLOGIN_PROGRAM=\"/bin/login\" -DLOGIN_NO_ENDOPT
  cflags += -DSSH_EXTRAVERSION=\"$(SSH_EXTRAVERSION)\"
 +cflags += -DWITH_LDAP_PUBKEY
  cflags_udeb := -Os
  cflags_udeb += -DSSH_EXTRAVERSION=\"$(SSH_EXTRAVERSION)\"
  confflags += --with-cflags='$(cflags)'

Append libldap2-dev to Build-Depends of debian/control.

$ vi debian/control
(snip)
Build-Depends: ..., libldap2-dev
(snip)

Build package with “debuild” and “pbuilder” after update debian/changelog. You install openssh-client, openssh-server, these two package at lease.

$ sudo dpkg -i openssh-client_5.9p1-5ubuntu1+cust1_amd64.deb openssh-server_5.9p1-5ubuntu1+cust1_amd64.deb

Setting of OpenSSH

/etc/ssh/sshd_config

UseLPK yes
LpkServers ldap://127.0.0.1/
LpkUserDN ou=People,dc=example,dc=org
LpkGroupDN ou=Group,dc=example,dc=org
LpkForceTLS no

Restart sshd.

Postscript

I use patch in this time that does not support URL of IPv6 format at LpkServers. But, name base is no problem for IPv6. And you must use libnss-ldapd and libpam-ldapd.

CentOS 6

CentOS 6 supports openssh-lpk in default. So you will it, you only do install “openssh-ldap”, and set up.

$ sudo yum install openssh-ldap
$ sudo vi /etc/ssh/sshd_config

/etc/ssh/sshd_config

PubkeyAuthentication yes
AuthorizedKeysCommand /usr/libexec/openssh/ssh-ldap-wrapper
AuthorizedKeysCommandRunAs nobody

/etc/ssh/ldap.conf

Copy from “/usr/share/doc/openssh-ldap-5.3p1/ldap.conf” as template to “/etc/ssh/ldap.conf”. openssh-ldap package of CentOS6 supports IPv6.

uri ldap://ldap.example.org
port 389
base dc=example,dc=org
ldap_version 3
scope sub
timelimit 30
bind_timelimit 30
bind_policy hard
ssl no

Restart sshd.

]]>
Mon, 29 Oct 2012 00:00:00 +0900
http://d.palmtb.net/2012/10/26/change_master_specified_by_slave.html http://d.palmtb.net/2012/10/26/change_master_specified_by_slave.html <![CDATA[Change master specified by syncrepl of slave]]> Change master specified by syncrepl of slave

The story of this entry is a supplement of previous migration(Migration OpenLDAP 2.3 to 2.4). The third step and fourth step is the same with first step, so I omit it. Current slave servers are OpenLDAP 2.3 on CentOS 5.4. We build New slave servers with OpenLDAP 2.4 on Ubuntu 12.04, but we must also operate legacy servers, because we don’t stop these at the this time. Need to remove database, when It is changed master server on slave.

The procedure on CentOS5.4 as slave server is follow.

$ sudo /sbin/service ldap stop
$ cd /var/lib
$ sudo tar zcvf /path/to/ldap_backup.tgz ./ldap
$ sudo -s
# rm ldap/{*log*,*db*,alock}
# exit
$ sudo /sbin/service ldap start

A legacy slave server is enable to replicate from a new master server as OpenLDAP 2.4 on Ubuntu 12.04.

]]>
Fri, 26 Oct 2012 00:00:00 +0900
http://d.palmtb.net/2012/10/25/change_slave_to_master_of_openldap_2_4_configuration.html http://d.palmtb.net/2012/10/25/change_slave_to_master_of_openldap_2_4_configuration.html <![CDATA[Change slave to master of OpenLDAP 2.4 configuration]]> Change slave to master of OpenLDAP 2.4 configuration

The story of this entry is previous migration second step (Migration OpenLDAP 2.3 to 2.4). Firstly set up as slave, then change config. Namely see “Replication from OpenLDAP 2.3 to 2.4”.

Disable replication

Delete “olcSyncrepl”, “olcUpdateRef” lines from “olcDatabase={1}hdb”.

$ sudo ldapvi -Y EXTERNAL -h ldapi:// -b cn=config olcDatabase=hdb

Before

(snip)
olcAccess: {12}to * by * none
olcSyncrepl: {0}rid=xxx provider=ldaps://xxx.xxx.xxx.xxx bindmethod=simple binddn="cn=ldapadmin,dc=example,dc=org" credentials=xxxxxxxx searchbase="dc=example,dc=org" type=refreshAndPersist retry="5 10 60 +"
olcUpdateRef: ldaps://xxx.xxx.xxx.xxx

Changed

(snip)
olcAccess: {12}to * by * none

Load module

Load module syncprov for master.

$ sudo ldapvi -Y EXTERNAL -h ldapi:// -b cn=config cn=module{0}

Before

0 cn=module{0},cn=config
objectClass: olcModuleList
cn: module{0}
olcModulePath: /usr/lib/ldap
olcModuleLoad: {0}back_hdb

Changed

0 cn=module{0},cn=config
objectClass: olcModuleList
cn: module{0}
olcModulePath: /usr/lib/ldap
olcModuleLoad: {0}back_hdb

add cn=module,cn=config
objectClass: olcModuleList
cn: module
olcModulePath: /usr/lib/ldap
olcModuleLoad: syncprov.la

Index

Delete “description eq” line from “olcDbIndex,olcDatabase={1}hdb”.

$ sudo ldapvi -Y EXTERNAL -h ldapi:// -b cn=config olcDatabase=hdb olcDbIndex

Before

olcDbIndex: objectClass eq,pres
olcDbIndex: uid eq,pres,sub
olcDbIndex: uniqueMember,memberUid eq
olcDbIndex: uidNumber,gidNumber eq
olcDbIndex: cn eq
olcDbIndex: sudoUser eq,sub
olcDbIndex: description eq
olcDbIndex: entryCSN,entryUUID eq

Changed

olcDbIndex: objectClass eq,pres
olcDbIndex: uid eq,pres,sub
olcDbIndex: uniqueMember,memberUid eq
olcDbIndex: uidNumber,gidNumber eq
olcDbIndex: cn eq
olcDbIndex: sudoUser eq,sub
olcDbIndex: entryCSN,entryUUID eq

Access control

Insert a new writing “sshPublicKey” lines.

$ sudo ldapvi -Y EXTERNAL -h ldapi:// -b cn=config olcDatabase={1}hdb olcAccess

Before

0 olcDatabase={1}hdb,cn=config
olcAccess: {0}to * by dn="cn=ldapadmin,dc=example,dc=org" write by * none break
olcAccess: {1}to attrs=userPassword by self read by anonymous auth by * none
olcAccess: {2}to dn.subtree="ou=ACL,ou=policy,dc=example,dc=org" by * compare by * none
olcAccess: {3}to dn.subtree="ou=Password,ou=policy,dc=example,dc=org" by * none
olcAccess: {4}to dn.subtree="ou=SUDOers,ou=policy,dc=example,dc=org" by * read by * none
olcAccess: {5}to dn.subtree="ou=People,dc=example,dc=org" by self read by * read
olcAccess: {6}to dn.subtree="ou=Group,dc=example,dc=org" by * read
olcAccess: {7}to dn.subtree="dc=example,dc=org" by * search  by * none
olcAccess: {8}to * by * none

Changed

0 olcDatabase={1}hdb,cn=config
olcAccess: {0}to * by dn="cn=ladpadmin,dc=example,dc=org" write by * none break
olcAccess: {1}to attrs=sshPublicKey by self write by * none
olcAccess: {2}to attrs=userPassword by self read by anonymous auth by * none
olcAccess: {3}to dn.subtree="ou=ACL,ou=policy,dc=example,dc=org" by * compare by * none
olcAccess: {4}to dn.subtree="ou=Password,ou=policy,dc=example,dc=org" by * none
olcAccess: {5}to dn.subtree="ou=SUDOers,ou=policy,dc=example,dc=org" by * read by * none
olcAccess: {6}to dn.subtree="ou=People,dc=example,dc=org" by self read by * read
olcAccess: {7}to dn.subtree="ou=Group,dc=example,dc=org" by * read
olcAccess: {8}to dn.subtree="dc=example,dc=org" by * search  by * none
olcAccess: {9}to * by * none

sizelimit

Add olcSizeLimit to “cn=config”.

$ sudo ldapvi -Y EXTERNAL -h ldapi:/// -b cn=config cn=config

Before

0 cn=config
objectClass: olcGlobal
cn: config
olcArgsFile: /var/run/slapd/slapd.args
olcLogLevel: 128
olcPidFile: /var/run/slapd/slapd.pid
olcTLSCertificateFile: /etc/ssl/certs/hoge.pen
olcTLSCertificateKeyFile: /etc/ssl/private/hoge.key
olcToolThreads: 1

Changed

0 cn=config
objectClass: olcGlobal
cn: config
olcArgsFile: /var/run/slapd/slapd.args
olcLogLevel: 128
olcPidFile: /var/run/slapd/slapd.pid
olcTLSCertificateFile: /etc/ssl/certs/hoge.pen
olcTLSCertificateKeyFile: /etc/ssl/private/hoge.key
olcToolThreads: 1
olcSizeLimit: unlimited

syncprov overlay

Add a syncprov overlay DN.

$ sudo ldapvi -Y EXTERNAL -h ldapi:/// -b cn=config olcDatabase={1}hdb

Before

0 olcDatabase={1}hdb,cn=config
(snip)
olcDbIndex: uidNumber,gidNumber eq
olcDbIndex: uniqueMember,memberUid eq

Changed

0 olcDatabase={1}hdb,cn=config
(snip)
olcDbIndex: uidNumber,gidNumber eq
olcDbIndex: uniqueMember,memberUid eq

add olcOverlay=syncprov,olcDatabase={1}hdb,cn=config
objectClass: olcOverlayConfig
objectClass: olcSyncProvConfig
olcOverlay: syncprov

setting LDAP client of master-self

Needs these setting in a master server.

/etc/ldap/ldap.conf

URI ldap://127.0.0.1
BASE dc=example,dc=org
TLS_CACERTDIR /etc/ssl/certs
TLS_REQCERT never
ssl start_tls

Postscript

Iou must not set up “/etc/ldap.conf” when using libpam-ldapd, libnss-ldapd. Especially, you will use OpenSSH-lpk, you must use libpam-ldapd and libnss-ldapd.

Confirmation

At least, this server as LDAP master of OpenLDAP2.4 on Ubuntu 12.04 is now available. Confirmation is using “ldapsearch” command and “id” command. And you also look on a audit.log of the slave server.

]]>
Thu, 25 Oct 2012 00:00:00 +0900
http://d.palmtb.net/2012/10/24/openldap_replication_from_2_3_to_2_4.html http://d.palmtb.net/2012/10/24/openldap_replication_from_2_3_to_2_4.html <![CDATA[Replication from OpenLDAP 2.3 to 2.4]]> Replication from OpenLDAP 2.3 to 2.4

The story of this entry is previous migration first step (Migration OpenLDAP 2.3 to 2.4). Master and slave servers that are OpenLDAP 2.3 with slapd.conf on CentOS 5.4 are running currently. I have prepared OpenLDAP 2.4 with slapd-config on Ubuntu 12.04 as slave server.

Install packages

$ sudo apt-get install slapd ldap-utils

Debconf setting is follows;

slapd configuration

  • Administrator password
  • Confirm password

Setup OpenLDAP

I have set up with LDIF files of prepared schemas in previous story.

$ sudo vi /etc/default/slapd

default:

SLAPD_SERVICES="ldap:/// ldapi:///"

Changed:

SLAPD_SERVICES="ldap:/// ldaps:/// ldapi:///"

Restart slapd.

$ sudo service slapd restart

Change schemas

I have changed “core.schema” using ldapvi because the present core.schema had been customized.

$ sudo ldapvi -Y EXTERNAL -h ldapi:// -b cn=config cn={0}core
(snip)
olcAttributeTypes: {51}( 1.2.840.113549.1.9.1 NAME ( 'email' 'emailAddress' 'pkcs9email' ) DESC 'RFC3280: legacy attribute for email addresses in DNs' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} )
(snip)

The details of changes are omitted.

Import additional schema

I have added previous prepared schemas.

$ sudo ldapadd -Y EXTERNAL -H ldapi:// -f ~/local.ldif
$ sudo ldapadd -Y EXTERNAL -H ldapi:// -f ~/sudo.ldif
$ sudo ldapadd -Y EXTERNAL -H ldapi:// -f ~/openssh-lpk.ldif
$ sudo ldapadd -Y EXTERNAL -H ldapi:// -f /etc/ldap/schema/ppolicy.ldif

ppolicy is present by default, but not load.

Load module

$ sudo ldapvi -Y EXTERNAL -h ldapi:// -b cn=config cn=module{0}

Default is follow;

0 cn=module{0},cn=config
objectClass: olcModuleList
cn: module{0}
olcModulePath: /usr/lib/ldap
olcModuleLoad: {0}back_hdb

Change is follows;

0 cn=module{0},cn=config
objectClass: olcModuleList
cn: module{0}
olcModulePath: /usr/lib/ldap
olcModuleLoad: {0}back_hdb

add cn=module,cn=config
objectClass: olcModuleList
cn: module
olcModulePath: /usr/lib/ldap
olcModuleLoad: auditlog.la

add cn=module,cn=config
objectClass: olcModuleList
cn: module
olcModulePath: /usr/lib/ldap
olcModuleLoad: ppolicy.la

Use “add” command when using new dn.

Change suffix

Default suffix is “cn=admin,dc=nodomain”. I have replaced “admin” to “ldapadmin”, “dc=nodomain” to “dc=example,dc=org”. Changes lines are follow.

  • olcSuffix
  • olcAccess {0}, {2}
  • olcRootDN
$ sudo ldapvi -Y EXTERNAL -h ldapi:// -b cn=config olcDatabase=hdb

Default is follow;

0 olcDatabase={1}hdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcHdbConfig
olcDatabase: {1}hdb
olcDbDirectory: /var/lib/ldap
olcSuffix: dc=nodomain
olcAccess: {0}to attrs=userPassword,shadowLastChange by self write by anonymous auth by dn="cn=admin,dc=nodomain" write by * none
olcAccess: {1}to dn.base="" by * read
olcAccess: {2}to * by self write by dn="cn=admin,dc=nodomain" write by * read
olcLastMod: TRUE
olcRootPW: {SSHA}xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
olcDbCheckpoint: 512 30
olcDbConfig: {0}set_cachesize 0 2097152 0
olcDbConfig: {1}set_lk_max_objects 1500
olcDbConfig: {2}set_lk_max_locks 1500
olcDbConfig: {3}set_lk_max_lockers 1500
olcDbIndex: objectClass eq
olcRootDN: cn=admin,dc=nodomain

Change is follow;

0 olcDatabase={1}hdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcHdbConfig
olcDatabase: {1}hdb
olcDbDirectory: /var/lib/ldap
olcSuffix: dc=example,dc=org
olcAccess: {0}to attrs=userPassword,shadowLastChange by self write by anonymous auth by dn="cn=ldapadmin,dc=example,dc=org" write by * none
olcAccess: {1}to dn.base="" by * read
olcAccess: {2}to * by self write by dn="cn=ldapadmin,dc=example,dc=org" write by * read
olcLastMod: TRUE
olcRootPW: {SSHA}xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
olcDbCheckpoint: 512 30
olcDbConfig: {0}set_cachesize 0 2097152 0
olcDbConfig: {1}set_lk_max_objects 1500
olcDbConfig: {2}set_lk_max_locks 1500
olcDbConfig: {3}set_lk_max_lockers 1500
olcDbIndex: objectClass eq
olcRootDN: cn=ladpadimn,dc=example,dc=org

Index

objectClass and entryCSN,entryUUID is required for replication at least.

$ sudo ldapvi -Y EXTERNAL -h ldapi:// -b cn=config olcDatabase=hdb olcDbIndex

Default:

olcDbIndex: objectClass eq

Changed:

olcDbIndex: objectClass eq,pres
(snip)
olcDbIndex: entryCSN,entryUUID eq

Other changes are ommitted.

TLS Certifiation

$ sudo ldapvi -Y EXTERNAL -h ldapi:// -b cn=config cn=config

Add path of certification and key file to olcTLSCertificateFile, olcTLSCertificateKeyFile.

for example, using /etc/ssl/private/hoge.key and /etc/ssl/cert/hoge.pem,

Default

0 cn=config
objectClass: olcGlobal
cn: config
olcArgsFile: /var/run/slapd/slapd.args
olcLogLevel: none
olcPidFile: /var/run/slapd/slapd.pid
olcToolThreads: 1

Changed

0 cn=config
objectClass: olcGlobal
cn: config
olcArgsFile: /var/run/slapd/slapd.args
olcLogLevel: none
olcPidFile: /var/run/slapd/slapd.pid
olcToolThreads: 1
olcTLSCertificateFile: /etc/ssl/certs/hoge.pem
olcTLSCertificateKeyFile: /etc/ssl/private/hoge.key

LogLevel

$ sudo ldapvi -Y EXTERNAL -h ldapi:/// -b cn=config cn=config olcLogLevel

Default

0 cn=config
olcLogLevel: none

Changed

0 cn=config
olcLogLevel: 512

Change rsyslog setting when next error occurs.

rsyslogd-2177: imuxsock lost 228 messages from pid 2547 due to rate-limitin

Add follow parameter to /etc/rsyslog.conf

# Disable rate limiting
# (default is 200 messages in 5 seconds; below we make the 5 become 0)
$SystemLogRateLimitInterval 0

Restart rsyslog.

$ sudo service rsyslog restart

DB Cachesize

$ sudo ldapvi -Y EXTERNAL -h ldapi:/// -b cn=config olcDatabase=hdb olcDbCacheSize

Default:

0 olcDatabase={1}hdb,cn=config

Changed:

0 olcDatabase={1}hdb,cn=config
olcDbCacheSize: 2000

DB IDL Cache size

$ sudo ldapvi -Y EXTERNAL -h ldapi:/// -b cn=config olcDatabase=hdb olcDbIDLcacheSize

Changed:

0 olcDatabase={1}hdb,cn=config
olcDbIDLcacheSize: 2000

Access control

$ sudo ldapvi -Y EXTERNAL -h ldapi:// -b cn=config olcDatabase={1}hdb olcAccess

Default:

0 olcDatabase={1}hdb,cn=config
olcAccess: {0}to attrs=userPassword,shadowLastChange by self write by anonymous auth by dn="cn=ldapadmin,dc=example,dc=org" write by * none
olcAccess: {1}to dn.base="" by * read
olcAccess: {2}to * by self write by dn="cn=ldapadmin,dc=example,dc=org" write by * read

Changed:

0 olcDatabase={1}hdb,cn=config
olcAccess: {0}to * by dn="cn=ldapadmin,dc=example,dc=org" write by * none break
olcAccess: {1}to attrs=userPassword by self read by anonymous auth by * none
olcAccess: {2}to dn.subtree="ou=ACL,ou=policy,dc=example,dc=org" by * compare by * none
olcAccess: {3}to dn.subtree="ou=Password,ou=policy,dc=example,dc=org" by * none
olcAccess: {4}to dn.subtree="ou=SUDOers,ou=policy,dc=example,dc=org" by * read by * none
olcAccess: {5}to dn.subtree="ou=People,dc=example,dc=org" by self read by * read
olcAccess: {6}to dn.subtree="ou=Group,dc=example,dc=org" by * read
olcAccess: {7}to dn.subtree="dc=example,dc=org" by * search  by * none
olcAccess: {8}to * by * none

OpenLDAP 2.4 needs the rule of ‘to dn.subtree=”dc=example,dc=org” by * search by * none’, OpenLDAP 2.3 does not needs.

auditlog

$ sudo ldapvi -Y EXTERNAL -h ldapi:/// -b cn=config olcDatabase={1}hdb

Changed:

0 olcDatabase={1}hdb,cn=config
(snip)

add olcOverlay=auditlog,olcDatabase={1}hdb,cn=config
objectClass: olcOverlayConfig
objectClass: olcAuditLogConfig
olcOverlay: auditlog
olcAuditlogFile: /var/log/ldap/audit.log

make directory.

$ sudo mkdir /var/log/ldap
$ sudo chown -R openldap: /var/log/ldap

ppolicy

$ sudo ldapvi -Y EXTERNAL -h ldapi:/// -b cn=config olcDatabase={1}hdb

Changed:

0 olcDatabase={1}hdb,cn=config
(snip)

add olcOverlay=ppolicy,olcDatabase={1}hdb,cn=config
objectClass: olcOverlayConfig
objectClass: olcPPolicyConfig
olcOverlay: ppolicy
olcPPolicyDefault: cn=default,ou=Password,ou=policy,dc=example,dc=org
olcPPolicyUseLockout: TRUE

Replication

olcDbIndex entryUUID must be “eq”. Change rid, provider, and credentials of follow.

$ sudo ldapvi -Y EXTERNAL -h ldapi:/// -b cn=config olcDatabase=hdb

Default:

(snip)
olcDbIndex: uidNumber,gidNumber eq
olcDbIndex: uniqueMember,memberUid eq

Changed:

olcDbIndex: uidNumber,gidNumber eq
olcDbIndex: uniqueMember,memberUid eq
olcSyncrepl: rid=xxx provider=ldaps://xxx.xxx.xxx.xxx bindmethod=simple binddn="cn=ldapadmin,dc=example,dc=org" credentials=xxxxxxxx searchbase="dc=example,dc=org" type=refreshAndPersist retry="5 10 60 +"
olcUpdateRef: ldaps://xxx.xxx.xxx.xxx

If you change master server, choise one of two method.

  1. Remove current syncrepl setting and restart slapd, then add new syncrepl setting. (Don’t forget restart slapd.)
  2. Stop slapd, then remove /var/lib/ldap/*, start slapd, change syncrepl setting.

Change parameters are rid, master server uri, and credential. You must execute plan 2) when there is next message on Syslog. This time setting only user for replication and the access control has been omitted.

Sep 13 19:27:08 ldaptest01 slapd[3272]: do_syncrepl: rid=xxx rc -2 retrying
Sep 13 19:28:08 ldaptest01 slapd[3272]: do_syncrep2: rid=xxx LDAP_RES_SEARCH_RESULT (53) Server is unwilling to perform
Sep 13 19:28:08 ldaptest01 slapd[3272]: do_syncrep2: rid=xxx (53) Server is unwilling to perform

ldap client for self

Install libnss-ldapd, libpam-ldapd but not libnss-ldap, libpam-ldap.

$ sudo apt-get install libnss-ldapd libpam-ldapd nslcd

/etc/nsswtich.conf and /etc/pam.d/common-{account,auth,password,sesson,session-noninteractive} are changed by Debconf of postinst.

nslcd configuration

  • LDAP server URI:
  • LDAP server search base:
    • dc=example,dc=org
  • Check server’s SSL certificate:
    • never

nslcd

/etc/nslcd.conf

uid nslcd
gid nslcd
uri ldap://localhost
base dc=example,dc=org
ssl start_tls
tls_reqcert never

/etc/ldap/ldap.conf

URI ldap://localhost
BASE dc=example,dc=org
TLS_CACERTDIR /etc/ssl/certs
TLS_REQCERT never
ssl start_tls

/etc/nslcd.conf

uid nslcd
gid nslcd
uri ldap://127.0.0.1
base dc=example,dc=org
pam_authz_search (&(objectClass=posixAccount)(uid=$username)(description=admin)

Postscript

Iou must not set up “/etc/ldap.conf” when using libpam-ldapd, libnss-ldapd. Especially, you will use OpenSSH-lpk, you must use libpam-ldapd and libnss-ldapd.

Confirmation

At least, replication of from the master of OpenLDAP 2.3 on CentOS5.4 to the slave OpenLDAP2.4 on Ubuntu 12.04 is now available. Replication is going to be running at the stage has been set for replication. Whether replication is done, you can be found at audit.log. Other confirmation is using ldapsearch command and id command.

]]>
Wed, 24 Oct 2012 00:00:00 +0900
http://d.palmtb.net/2012/09/20/migrate_2_3_with_slapd_conf_to_2_4_with_slapd_config.html http://d.palmtb.net/2012/09/20/migrate_2_3_with_slapd_conf_to_2_4_with_slapd_config.html <![CDATA[Migration OpenLDAP 2.3 to 2.4]]> Migration OpenLDAP 2.3 to 2.4

Current LDAP servers are CentOS 5.4 and OpenLDAP 2.3 with slapd.conf. I will replace these as Ubuntu 12.04 and OpenLDAP 2.4 with slapd-config. I write notes so I tested the migration.

System envrironment

Current is like this.

New will be next.

Step of migration is next.

  1. Prepare a new master as slave of current
  1. Change a new master as slave to master
  1. Prepare a new slave
  1. Stop current LDAPs

sammary of setting up

I tried to convert with slaptest. slaptest is needed to convert custom schema to ldif. But this method has next failures.

  • Additional schemas are not included
  • Custom and additiona modules are not loaded
  • Database setting is not converted all
  • Access control is not converted
  • Global settings as LogLevel and TLS Certification etc are not converted
  • Overlay as like ppolicy and syncrepl etc are not converted

In other words, it means almost useless with slaptest, except of converting custom schema to LDIF. So I basically have set up using ldapvi.

Install packages

I had installed next packages.

  • slapd
  • ldap-utils
  • ldapvi
  • nslcd

Debconf asked these parameters when some packages installed. Second level items are set up values this time.

slapd

  • Administrator password
  • Confirm password

nslcd

  • LDAP server URI
  • LDAP server search base
    • dc=example,dc=org
  • Check server’s SSL vertificatte
    • never

Convert additional schema to LDIF

I converted additional schema to LDIF with slaptest after I installed slapd. I made temporary directory and copying files as slapd.conf, schema files as local.schema, sudo.schema, openssh-lpk.schema from current slave server of CentOS5.4.

$ sudo service slapd stop
$ cd /tmp
$ mkdir -p slapd.d/cn\=config/cn\=schema
$ cp -i slapd.conf .
$ cp -i local.schema sudo.schema openssh-lpk.schema slapd.d/cn\=config/cn\=schema/
$ sudo slaptest -f slapd.conf -F /tmp/slapd.d/
$ cd /tmp/slapd.d/cn\=config/cn\=schema
$ sudo mv -i cn\=\{4\}sudo.ldif sudo.ldif
$ sudo mv -i cn\=\{6\}local.ldif local.ldif
$ sudo mv -i cn\=\{7\}openssh-lpk.ldif openssh-lpk.ldif

Don’t forget to delete last 9 lines of each generated LDIF files.

I copied certification and private key files from current slave server. For example, it is as follows.

  • /etc/ca-certificates/myserver.key
  • /etc/ca-certificates/myserver.crt

Using ldapvi

ldapvi is “is an interactive LDAP client for Unix terminals. Using it, you can update LDAP entries with a text editor”. Debian package name is the same.

For example of changing it is as follows.

$ sudo ldapvi -Y EXTERNAL -h ldapi:// -b cn=config olcDatabase={1}hdb olcRootDN
----
0 olcDatabase={1}hdb,cn=config
olcRootDN: cn=admin,dc=nodomain       # <- before
olcRootDN: cn=admin,dc=example,dc=org # <- after
----
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
      1 entry read
add: 0, rename: 0, modify: 1, delete: 0
Action? [yYqQvVebB*rsf+?] y
Done.

Action of ldapvi are follows:

  • y commit changes
  • e open editor again
  • Y commit, ignoring errors
  • v view changes as LDIF change records
  • V view changes as ldapvi change records
  • + rewrite file to include schema comments
  • b show login dialog and rebind
  • B toggle SASL
  • * set SASL mechanism
  • s skip one entry
  • f forget all deletions
  • q save changes as LDIF and quit
  • Q discard changes and quit

see also ldapvi User Manual .

Detail of Setting up as slave using ldapvi will be posted next time.

]]>
Thu, 20 Sep 2012 00:00:00 +0900
http://d.palmtb.net/2012/09/17/failed_travis_ci_pep8.html http://d.palmtb.net/2012/09/17/failed_travis_ci_pep8.html <![CDATA[Fail testing pep8 with travis-ci]]> Fail testing pep8 with travis-ci

I use travis-ci for GitHub, but test_pep8 failed.

$ pip install -r requirements.txt --use-mirrors
Downloading/unpacking pep8 (from -r requirements.txt (line 1))
  Downloading pep8-1.3.3.tar.gz
  Running setup.py egg_info for package pep8
(snip)
Successfully installed pep8 minimock
Cleaning up...
$ nosetests
............E....
======================================================================
ERROR: tonicdnscli.tests.test_pep8.test_check_pep8
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/travis/virtualenv/python2.7/local/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/home/travis/builds/mkouhei/tonicdnscli/src/tonicdnscli/tests/test_pep8.py", line 25, in test_check_pep8
    runner = pep8.input_file
    AttributeError: 'module' object has no attribute 'input_file'

----------------------------------------------------------------------
Ran 17 tests in 0.070s

FAILED (errors=1)

Done. Build script exited with: 1

Cause is version of pep8 module. Travis-ci’s is 1.3.3, but Debian GNU/Linux Sid as my environment is 1.2. So I have appended version of pep8 to requirements.txt.

pep8==1.2
minimock
]]>
Mon, 17 Sep 2012 00:00:00 +0900
http://d.palmtb.net/2012/09/16/from_mt2rest_to_hatena2rest.html http://d.palmtb.net/2012/09/16/from_mt2rest_to_hatena2rest.html <![CDATA[Changed mt2rest to hatena2rest]]> Changed mt2rest to hatena2rest

I released mt2rest at 30 March that is tool to convert(GEEK DAY TOKYOに参加しました。). It is to convert Hatena Diary exported into reST format. I had migrated from Hatena Diary to Tinkerer. But it was incomplete conversion with this tool, because I made improvised for that time event.

I rewrote this tool with using Hatena diary XML format instead of MovableType format as input. The two reason is as follows. Firstly it is too hard to distinguish the notation of Hatena Diary written in the code block to separate the entries of daily correctly. Secondary it is also hard to parse distinguish the code of blog-parts when I use the MovableType format as input file. I renamed a project name “hatena2rest. It is now not use MovableType format why “mt” of mt2rest is Abbreviation of “MovableType”.

Use this tool if you will migrate tinkerer from Hatena Diary. Usage is written in README.

I make a note that I had a hard time.

Detection of half-width characters and full-with characters

String must has border line as “=” * character length at section, subsection and simple table of Sphinx. Single-byte character is simple, so character length of border equals character length of string. String encoded with unicode is also the same.

>>> len(r"single")
6
>>> len(u"single")
6

But double-byte character is complicated. Character length of string is different with encoded with unicode and raw.

>>> len(r"全角")
6
>>> len(u"全角")
2

“Hankaku kana” is below

>>> len(r"テスト")
9
>>> len(u"テスト")
3

“Zenkaku” must be two or more characters, “Hankaku” must be at least one character when Sphinx border character. It is hard to detect with len(). So I used unixcodedata.east_asian_width().

unicodedata module is embedded with Python. east_asian_width() has next 6 values.

  • F: Fullwidth
  • H: Halfwidth
  • W: Wide
  • Na: Narrow
  • A: Ambiguous
  • N: Neutral

According to “WikiPedia”, “A” is processed as 1 or 2 characters, but Sphinx processes as like below probably.

  • F: 2 character width
  • H: 1 character width
  • W: 2 character width
  • Na: 1 character width
  • A: 1 character witdh
  • N: 1 character width

Then next code is enable to get width of string.

def length_str(string)
    fwa = ['F', 'W', 'A']
    hnna = ['H', 'N', 'Na']

    if isinstance(string, unicode):
        zenkaku = len([unicodedata.east_asian_width(c)
                       for c in string
                       if unicodedata.east_asian_width(c) in fwa])
        hankaku = len([unicodedata.east_asian_width(c)
                       for c in string
                       if unicodedata.east_asian_width(c) in hnna])
        return (zenkaku * 2 + hankaku)
    elif isinstance(string, str):
        return len(string)

https://github.com/mkouhei/hatena2rest/blob/master/src/hatena2rest/utils.py#L61

Exception occurs when use “&” in raw directive of html

“&” is disable to use in raw directive of html. Blog parts is converted to html raw directive. Then exception occurs when running build(tinker -b command)..

# Sphinx version: 1.1.3
# Python version: 2.7.3
# Docutils version: 0.8.1 release
# Jinja2 version: 2.6
Traceback (most recent call last):
  File "/usr/lib/pymodules/python2.7/sphinx/cmdline.py", line 189, in main
    app.build(force_all, filenames)
  File "/usr/lib/pymodules/python2.7/sphinx/application.py", line 204, in build
    self.builder.build_update()
  File "/usr/lib/pymodules/python2.7/sphinx/builders/__init__.py", line 196, in build_update
    'out of date' % len(to_build))
  File "/usr/lib/pymodules/python2.7/sphinx/builders/__init__.py", line 255, in build
    self.finish()
  File "/usr/lib/pymodules/python2.7/sphinx/builders/html.py", line 433, in finish
    for pagename, context, template in pagelist:
  File "/usr/lib/python2.7/dist-packages/tinkerer/ext/blog.py", line 85, in html_collect_pages
    for name, context, template in rss.generate_feed(app):
  File "/usr/lib/python2.7/dist-packages/tinkerer/ext/rss.py", line 54, in generate_feed
    app.config.website + post[:11])),
  File "/usr/lib/python2.7/dist-packages/tinkerer/ext/patch.py", line 91, in patch_links
    doc = xml.dom.minidom.parseString(in_str)
  File "/usr/lib/python2.7/xml/dom/minidom.py", line 1930, in parseString
    return expatbuilder.parseString(string)
  File "/usr/lib/python2.7/xml/dom/expatbuilder.py", line 940, in parseString
    return builder.parseString(string)
  File "/usr/lib/python2.7/xml/dom/expatbuilder.py", line 223, in parseString
    parser.Parse(string, True)
ExpatError: not well-formed (invalid token): line 70, column 363

This problem is solved with escaping to character entity references, but there is no meaning as hyperlink. So I extracted URI as simple hyperlink.

Other

I spent a lot of regular expression.

]]>
Sun, 16 Sep 2012 00:00:00 +0900
http://d.palmtb.net/2012/09/15/disqus_cookie.html http://d.palmtb.net/2012/09/15/disqus_cookie.html <![CDATA[Disqus comment fail to appear]]> Disqus comment fail to appear

Tinkerer is enable to use disqus as comment plugin, but Chromiums blocks the reading third-party cookie. Disqus appear dialog that says you should allow third-party cookies, but at least I want to allow only necessary domain’s. So I have set up cookie of disqus “[*.]disqus.com” to exception of cookie and site data. You may set up with next list when you specify domains explicitly.

  • disqus.com
  • mediacdn.disqus.com
  • your-disqus-shortname.disqus.com (example mkouhei.disqus.com)
  • qq.disqus.com
  • securecdn.disqus.com
  • juggler.services.disqus.com
]]>
Sat, 15 Sep 2012 00:00:00 +0900
http://d.palmtb.net/2012/09/14/tinkerer0_4_updated.html http://d.palmtb.net/2012/09/14/tinkerer0_4_updated.html <![CDATA[Updated Tinkerer 0.4b]]> Updated Tinkerer 0.4b

I updated Tinkerer from 0.3b to 0.4b. This update has a problem. 0.4b recommended using html_theme is modern5. I changed from modern to modern5, tried to run tinker -b. But building failed that exception occured jinja2.TemplateNotFound when modern5.

$ tinker -b -q
(snip)
Exception occurred:
  File "/usr/lib/pymodules/python2.7/sphinx/builders/__init__.py", line 196, in build_update
    'out of date' % len(to_build))
  File "/usr/lib/pymodules/python2.7/sphinx/builders/__init__.py", line 255, in build
    self.finish()
  File "/usr/lib/pymodules/python2.7/sphinx/builders/html.py", line 438, in finish
    self.write_genindex()
  File "/usr/lib/pymodules/python2.7/sphinx/builders/html.py", line 495, in write_genindex
    self.handle_page('genindex', genindexcontext, 'genindex.html')
  File "/usr/lib/pymodules/python2.7/sphinx/builders/html.py", line 728, in handle_page
    output = self.templates.render(templatename, ctx)
  File "/usr/lib/pymodules/python2.7/sphinx/jinja2glue.py", line 128, in render
    return self.environment.get_template(template).render(context)
  File "/usr/lib/python2.7/dist-packages/jinja2/environment.py", line 719, in get_template
    return self._load_template(name, self.make_globals(globals))
  File "/usr/lib/python2.7/dist-packages/jinja2/environment.py", line 693, in _load_template
    template = self.loader.load(self, name, globals)
  File "/usr/lib/python2.7/dist-packages/jinja2/loaders.py", line 115, in load
    source, filename, uptodate = self.get_source(environment, name)
  File "/usr/lib/pymodules/python2.7/sphinx/jinja2glue.py", line 149, in get_source
    raise TemplateNotFound(template)
TemplateNotFound: genindex.html
The full traceback has been saved in /tmp/sphinx-err-hQwPgt.log, if you want to report the issue to the developers.
Please also report this if it was a user error, so that a better error message can be provided next time.
Either send bugs to the mailing list at <http://groups.google.com/group/sphinx-dev/>,
or report them in the tracker at <http://bitbucket.org/birkenfeld/sphinx/issues/>. Thanks!

This work around of problem is changed disable html_use_index.

diff --git a/conf.py b/conf.py
index c5ef69e..0950c51 100644
--- a/conf.py
+++ b/conf.py
@@ -81,6 +81,6 @@ master_doc = tinkerer.master_doc
 version = tinkerer.__version__
 release = tinkerer.__version__
 html_title = project
-html_use_index = True
+html_use_index = False
 html_show_sourcelink = True
 html_add_permalinks = True
]]>
Fri, 14 Sep 2012 00:00:00 +0900
http://d.palmtb.net/2012/08/12/poe_switch.html http://d.palmtb.net/2012/08/12/poe_switch.html <![CDATA[Replaced PoE switch]]> Replaced PoE switch

Recently, repeater hub that we were using to connect to the Internet at home was broken. The hub that had been prepared from the beginning at the time of purchase condominiums, had been placed under the floor of the closet. When I was calling the help desk of the provider, they said that the hub was not their asset, which is rather our asset. They said to me that the period a defect of the hub was finished, and I exchanged with myself. The hub had to ensure the power from the electrical outlet under the floor, but I want to operate switch without the AC adapter, so I bought a switch for PoE.

I purchased two kinds of intelligent switches. Those are GS108PEv2 and GS108Tv2 of NETGEAR. The former is for the power supply switch, switch for receiving the latter. In addition, I has used Plathome’s OpenMicroServeres are supporting for PoE, we decided to operate without AC adapter those as well.

After exchanging was to look like below.

GS108PEv2

GS108Pv2

OpenMicroServer

OpenMicroServer without AC adopter

closet

State opened the closet

GS108Tv2 under closet

GS108Tv2 setted under closet

]]>
Sun, 12 Aug 2012 00:00:00 +0900
http://d.palmtb.net/2012/07/30/gitlab_update.html http://d.palmtb.net/2012/07/30/gitlab_update.html <![CDATA[Updating from 2.4.2 to 2.7.0 of GitLab]]> Updating from 2.4.2 to 2.7.0 of GitLab

My colleague requested me to update GitLab from 2.4.2 to 2.7.0. Then I did it. The procedure is accoding to documents of GitLab, next links.

I upgraded from 2.4.2 to 2.7.0 without at once, it was upgraded in stages. I made the record to the following procedure.

from 2.4.2 to 2.5.0

$ sudo /etc/init.d/gitlab stop
$ sudo su - gitlab
$ cd gitlab
$ git remote update
$ git checkout v2.5.0
$ git checkout -b v2.5.0
$ bundle install --without development test
$ exit
$ sudo gem update --system
$ sudo su - gitlab
$ bundle exec rake db:migrate RAILS_ENV=production
$ exit
$ sudo /etc/init.d/gitlab start

from 2.5.0 to 2.6.0

$ sudo /etc/init.d/gitlab stop
$ sudo su - gitlab
$ git checkout v2.6.0
$ git checkout -b v2.6.0
$ bundle install --without development test
$ bundle exec rake db:migrate RAILS_ENV=production
$ exit
$ sudo /etc/init.d/gitlab start

from 2.6.0 to 2.7.0

$ sudo /etc/init.d/gitlab stop
$ sudo su - gitlab
$ git stash
$ git checkout v2.7.0
$ git checkout -b v2.7.0
$ cp -i config/gitlab.yml.example config/gitlab.yml
$ sed -i 's/localhost/gitlab.example.org/g' config/gitlab.yml
$ bundle install --without development test
$ bundle exec rake db:migrate RAILS_ENV=production
$ touch log/githost.log
$ exit
$ sudo /etc/init.d/gitlab start
  • If just copy config/gitlab.yml.example to config/gitlab.yml, it occurs problem in the WebUI that be ‘localhost’ instead of FQDN. This is as a previous article. See also “GitLabを導入してみた話。”.
  • If not touch log/githost.log, http 500 error occurs at Logs view of admin area.
]]>
Mon, 30 Jul 2012 00:00:00 +0900
http://d.palmtb.net/2012/07/28/git_pyfes201207.html http://d.palmtb.net/2012/07/28/git_pyfes201207.html <![CDATA[Python Developers Festa 2012.07 でGitの話をしてきました。]]> Python Developers Festa 2012.07 でGitの話をしてきました。

V さんからGitの深いを話をしる、と頼まれたので、GitPythonの話をしてきました。資料はこちら。

http://www.slideshare.net/mkouhei/git-pyfes201207presen

Git自体の深い話は岩松さんや小川さんのようにはできないので困ったなあと思っていたところ、先日の”第8回CloudFoundry輪読会でlxcの話をしてきました。“のLXCの話があったので、ちょうど話す内容の元ネタは兼ねることができたので助かりました。

あとCouchDBの話をするべし、と yssk22 さんから頼まれていたので、CouchbaseのTシャツがめっちゃ余っとるから、次回のCouchDB JPの勉強会に参加してよ、と宣伝しておきました。

]]>
Sat, 28 Jul 2012 00:00:00 +0900
http://d.palmtb.net/2012/07/26/lxc_cfcrjp8.html http://d.palmtb.net/2012/07/26/lxc_cfcrjp8.html <![CDATA[第8回CloudFoundry輪読会でlxcの話をしてきました。]]> 第8回CloudFoundry輪読会でlxcの話をしてきました。

yssk22 さんからlxcの話をしる、と頼まれたので、2009年12月に東京エリアDebian勉強会で行ったlxcの話を焼き直して発表してきました。資料はこちら。

http://www.slideshare.net/mkouhei/lxc-cf201207presen

40人中、lxcを聞いたことがある人は25-30人くらいいらっしゃいました。が、実際に使ってことのある人は2人、うち1人は私と同じ職場でかつ同じチームの人でした。orz

資料の最後で紹介している、lxcをpython-libvirt経由で操作するために、2週間ほど前から作り始めた Iori 「庵」 のコードの話をしたら、大幅に時間オーバーしてしまいました…。

https://github.com/mkouhei/iori

また、発表資料の中で紹介したlxc JPのメーリングリスト(Google group)はlxcのことを日本語で語らう場です。lxcについて話をしたい人はぜひ購読ください。

https://groups.google.com/forum/?hl=ja&fromgroups#!forum/lxc-jp

]]>
Thu, 26 Jul 2012 00:00:00 +0900
http://d.palmtb.net/2012/07/11/lxc_libvirt_sid.html http://d.palmtb.net/2012/07/11/lxc_libvirt_sid.html <![CDATA[LXCをlibvirtd経由で起動させる。]]> LXCをlibvirtd経由で起動させる。

Sidでlxcを使うには、lxcパッケージをインストールし、README.Debianにあるとおり/etc/fstabに

cgroup /sys/fs/cgroup cgroup defaults 0 0

と記述し、cgroupをマウントすれば使えます。一方、libvirtd経由で起動させる場合、

<domain type='lxc'>
  <name>vm1</name>
  <memory>100000</memory>
  <os>
    <type>exe</type>
    <init>/bin/sh</init>
  </os>
  <vcpu>1</vcpu>
  <clock offset='utc'/>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>destroy</on_crash>
  <devices>
    <emulator>/usr/lib/libvirt/libvirt_lxc</emulator>
    <interface type='network'>
      <source network='default'/>
    </interface>
    <console type='pty' />
  </devices>
</domain>

のようなlibvirtの定義ファイルを用意してやります。libvirtグループのアカウントで下記を実行します。

$ virsh --connect lxc:/// define vm1.xml
$ virsh --connect lxc:/// start vm1

これで起動できる!と思ったら大間違い。下記のようなエラーを吐いてこけます。

2012-07-10 15:44:06.531+0000: 24033: error : lxcVmStart:1783 : internal error Unable to find 'memory' cgroups controller mount

このワークアラウンドは Debian Wiki に記述されており、/etc/default/grubに下記の設定を行い、update-grub2を実行しkernelを再起動してやればOKです。

GRUB_CMDLINE_LINUX="cgroup_enable=memory"

kernel 2.6.39-1でFixされている ようなのですが、実際には kernel 3.0.0-1でも同じ問題に遭遇します。

とりあえず、これで無事起動できるようになった筈です。実際に実行してみます。

$ virsh --connect lxc:/// start vm1
Domain vm1 started

$ virsh --connect lxc:/// list --all
Id    Name                           State
----------------------------------------------------
5511  vm1                            running

$ sudo virsh --connect lxc:/// console vm1
Connected to domain vm1
Escape character is ^]
#

無事起動できましたね。今回はshを起動しているだけなのでネットワークの設定は行う意味がありませんが、debootstrapで作成したDebianイメージはあらかじめブリッジの設定をしておかないと、

error: Failed to start domain vm1
error: Unable to add bridge virbr0 port veth0: No such device

のようなエラーを吐いてコンテナ自体を起動できないので注意。debootstrapで作成したDebianイメージもlibvirtで問題なく起動できるか否かは未確認。

追記

3.2.0をインストールしてみましたが、GRUBでのcgroup_enable=memoryのオプションはやはり必要でした。

]]>
Wed, 11 Jul 2012 00:00:00 +0900
http://d.palmtb.net/2012/06/20/python_mysqldb.html http://d.palmtb.net/2012/06/20/python_mysqldb.html <![CDATA[PythonのMySQL用インタフェースを使ってみた。]]> PythonのMySQL用インタフェースを使ってみた。

TonicDNSのアカウントを発行するのに、いちいちSQLを実行していたのですが、SQL書き直して実行とか面倒なので主題のインタフェースを使ってみました。Debianパッケージではpython-mysqldbがそれです。

コードは Githubにあげているとおり ですが、実際には下記の部分だけ。

import MySQLdb as mdb
(snip)
con = mdb.connect('localhost', user, passwd, db)

with con:
    cur = con.cursor()
    cur.execute("SELECT * from users WHERE username = %s", username)
    if cur.rowcount:
        print('Already that useraccount exists')
    else:
        cur.execute(
            "INSERT INTO users VALUES (NULL, %s, %s, %s, %s, %s, 0, 0)",
                    (username, passmd5, fullname, email, comment))

使い方は リンク先 かパッケージに含まれている /usr/share/doc/python-mysqldb/MySQLdb.txt.gz を読めば分かります。(内容は同じです)

]]>
Wed, 20 Jun 2012 00:00:00 +0900
http://d.palmtb.net/2012/06/19/enable_recoursion_pdns-server.html http://d.palmtb.net/2012/06/19/enable_recoursion_pdns-server.html <![CDATA[PowerDNS Authoritative Serverで再帰問い合わせを有効にする。]]> PowerDNS Authoritative Serverで再帰問い合わせを有効にする。

ローカルDNSでコンテンツサーバとして使用しているPowerDNS Authoritative Serverで諸事情により再帰問い合わせを行わせることにしました。PowerDNSの公式ドキュメントは充実しているのですが、PowerDNS recursor(pdns-recursor)を導入せずに再帰問い合わせさせる方法については記載が無かったのでメモしておきました。 [1]

環境。

  • Ubuntu 10.04
  • pdns-server 2.9.22

設定。

/etc/powerdns/pdns.conf の下記を設定します。

  • allow-recursion
    • 再帰問い合わせを許可するホスト(クライアント)のIPアドレスを指定します。複数指定はカンマ区切りで、ネットワークアドレスをprefix lengthで指定することもできます。が、ハマったのが0.0.0.0は指定できないということ。これを指定すると再帰問い合わせ自体が有効になりませんでした
  • recursive-cache-ttl
    • 再帰問い合わせのキャッシュ時間。デフォルトは10秒
  • recursor
    • 再帰問い合わせ先のDNSのIPアドレスを指定します
  • lazy-recursion
    • 上記で設定した再帰問い合わせを許可するためのフラグ。許可する場合はyesを指定

実際に設定すると下記のような感じ。

diff --git a/powerdns/pdns.conf b/powerdns/pdns.conf
index eb5e473..80a49a2 100644
--- a/powerdns/pdns.conf
+++ b/powerdns/pdns.conf
@@ -8,7 +8,7 @@ allow-axfr-ips=127.0.0.1
 #################################
 # allow-recursion      List of netmasks that are allowed to recurse
 #
-allow-recursion=127.0.0.1
+allow-recursion=10.0.0.0/8

 #################################
 # allow-recursion-override   Local data even about hosts that don't exist will
@@ -84,7 +84,7 @@ launch=gmysql
 #################################
 # lazy-recursion       Only recurse if question cannot be answered locally
 #
-lazy-recursion=no
+lazy-recursion=yes
@@ -189,12 +189,12 @@ module-dir=/usr/lib/powerdns
 #################################
 # recursive-cache-ttl  Seconds to store packets in the PacketCache
 #
-# recursive-cache-ttl=10
+recursive-cache-ttl=10

 #################################
 # recursor     If recursion is desired, IP address of a recursing nameserver
 #
-#recursor=
+recursor=10.0.1.1

 #################################
 # setgid       If set, change group id to this gid for more security

追記。

「再帰」がことごとく「再起」になっていた罠。変換ミスに気づいていないとは…。orz

footnote

[1]設定する各パラメータについては説明がありますが、どれを設定するのか、という説明がないということです。
]]>
Tue, 19 Jun 2012 00:00:00 +0900
http://d.palmtb.net/2012/06/17/vyatta_nat_stateful_failover_limitation.html http://d.palmtb.net/2012/06/17/vyatta_nat_stateful_failover_limitation.html <![CDATA[VyattaでNAT stateful failoverを使う場合の制限。]]> VyattaでNAT stateful failoverを使う場合の制限。

VyattaでVRRPを使っている場合、VRRPのfailoverが発生してもBackupに引き継いでそのまま通信できるようにNAT stateful failverを使うと思います。が、NATテーブルのエントリ数がある一定を超えると、failoverが発生してからNATテーブルのエントリが引き継がれる途中でBackupがカーネルごと落ちてしまう、という事象に遭遇しました。もうそのまんまなので特にひねりもないのですが、一応検証を行った条件を掲載しておきます。

環境。

  • メモリ 2GB
  • Vyatta core 6.3 64bit

CPUとかディスクとかは実質ほとんど影響ないので省略。

条件。

VyattaでNATします。負荷検証には、専用のアプライアンスを使い、Webサーバに対してApacheのindex.htmlをGETするだけの負荷をかけました。fail overの基準とする数値はNATテーブルのエントリ数で、/proc/sys/net/netfilter/nf_conntrack_countの値を下記のような感じで監視しました。実際には下記のコマンドでこの数値を観察しながらfailoverさせました。

$ mkfifo nf_conntrack_count
$ while true; do date > nf_conntrack_count; cat /proc/sys/net/netfilter/nf_conntrack_count > nf_conntrack_count; sleep 1; done &
$ tail -f nf_conntrack_count

ネットワーク構成は下記。Vyatta0の10.0.10.10-10.0.10.250はNAT用のIPアドレス。

結果。

最初、200万程度NATテーブルにエントリがある状態で通信させている状態でfailoverさせてみたところ、Backup側に当初は切り替わりましたが、途中で通信できなくなりBackup側もカーネルごとrebootまたは落ちてしまいました。エントリ数を下げてやってみたところ、7万程度ならfailoverできることは確認しました。これがメモリを2GBから増やした場合変わるのかどうかも気にはなったものの、そもそもこんな低い値では使い物になりません。Masterが落ちた場合に全面ダウンしてしまいます。なので、NAT stateful failover自体を行わないことにしました。単体でNAT処理させる場合は、メモリ2GBのIAサーバでもNATテーブルのエントリが200万は処理できた(それ以上はアプライアンス側の制約で負荷を掛けられず)ので、fail over時の通信およびスイッチのMACアドレス学習までの数秒は諦める、ということにしました。

]]>
Sun, 17 Jun 2012 00:00:00 +0900
http://d.palmtb.net/2012/05/31/genpw_with_mkpasswd.html http://d.palmtb.net/2012/05/31/genpw_with_mkpasswd.html <![CDATA[mkpasswdコマンドを使ってshadowパスワードを生成する。]]> mkpasswdコマンドを使ってshadowパスワードを生成する。

passwdコマンドでの対話形式ではなく、任意のshadowパスワードを予め生成しておきたい場合、mkpasswdコマンドを使えますよ、という小ネタ。/etc/shadowの第2フィールドの文字列は、単純に任意の文字列をmd5sumコマンドを使ってもダメですが、mkpasswdコマンドを使うと簡単に生成できます。mkpasswdはwhoisパッケージにあるので、これをインストールしておきます。

$ sudo apt-get install whois

インストールした後、生成するには次のコマンドを実行します。

$ mkpasswd -S $(head -c 4 /dev/urandom | xxd -p) -m md5
Password:
$1$a243949c$w2efZ4cQRTDGxaZNuFDAG/

生成された文字列はvipw -sで任意のユーザアカウントの第2フィールドに記入すれば、入力したパスワードでログインなりsuなりできるようになります。ちなみに上記の文字列を生成するために入力した文字列(パスワード)は、11111111なのでそのまんま使わないようにね。(わら

]]>
Thu, 31 May 2012 00:00:00 +0900
http://d.palmtb.net/2012/05/24/do_you_know_mkfifo.html http://d.palmtb.net/2012/05/24/do_you_know_mkfifo.html <![CDATA[名前付きパイプを知らない?]]> 名前付きパイプを知らない?

名前付きパイプを知らないという人が意外といるみたいなので、小ネタとして紹介します。名前付きパイプとは、パイプ’|’の代わりに使える特殊ファイルです。mkfifoコマンドで作成します。

$ mkfifo hoge

このhogeというファイルをreadしておき、別のプロセスでこのファイルに何らかの出力を書き込んでやると、hogeをreadしている側でその書き込まれた出力が読めます。

たとえば、Netfilterのカウンター(/proc/sys/net/netfilter/nf_conntrack_count)を見たい場合、

$ watch cat /proc/sys/net/netfilter/nf_conntrack_count

とかでも良いですが、上記を名前付きパイプに常に書き込む用にしてやっても良いわけです。この値だけを書き込むだけならあまり意味がありませんが、ちょっと加工したい場合に便利です。

$ mkfifo hoge
$ while true
do
  date > hoge;
  cat /proc/sys/net/netfilter/nf_conntrack_count > hoge
  sleep 1
done &
$ tail -f hoge

こうしてやると、

Thu May 24 21:00:28 JST 2012
21130
Thu May 24 21:00:29 JST 2012
21173
Thu May 24 21:00:30 JST 2012
21201
Thu May 24 21:00:31 JST 2012
21216
(snip)

というように見ることができます。ssh経由で扱うこともできます。

$ ssh remotehost tail -f hoge
Thu May 24 21:07:08 JST 2012
20587
Thu May 24 21:07:09 JST 2012
20585
Thu May 24 21:07:10 JST 2012
20594

ログはローカルに吐きたくないけれど、ログ監視はしたい、でもsyslogで転送したくない、という場合は、これを使うとできますね。どんなケースだ、それ。

]]>
Thu, 24 May 2012 00:00:00 +0900
http://d.palmtb.net/2012/05/22/couchdb1_2_0_squeeze.html http://d.palmtb.net/2012/05/22/couchdb1_2_0_squeeze.html <![CDATA[CouchDB 1.2.0をようやく導入した話。]]> CouchDB 1.2.0をようやく導入した話。

CouchDB 1.2.0がリリースされて早一ヶ月。なかなか導入する暇が無かったので放置していました。が、さくらのVPSの移行のタイミングで1.1.0で動かしている こまちゃん監視カメラのビューワ を1.2.0にすることにしました。

こまちゃん監視カメラ の現在の仕様はWebカメラでひたすら動体検知や明度の変化を検知した瞬間の写真をJSONに変換してCouchDBに保存し、不連続での過去10時間分を閲覧できるものです。昨年の震災をきっかけにした不在中のこまちゃんの様子を確認するためのツールなので、古い画像は必要ありません。が、画像及び画像を内部ドキュメントとして格納したドキュメントは定期的に削除していません。1画像あたり8-10KB程度なのでスマホでも簡単に確認できるのでますが、塵も積もればなんとやらで、移行時点で既に4GBを超える量。さくらのVPS 512では20GBのディスクで、LXCでのDebianのコンテナが5,6個動かしていたので圧縮して移行する余裕はありません。なので、新しくSqueezeのコンテナを作り、そこでDebianパッケージを作ることにしました。

Debianパッケージの作成事前準備。

CouchDBのビルドに必要なパッケージを手っ取り早くインストールするために、SqueezeのCouchDB 0.11.0に依存するビルド環境を整えます。

$ sudo apt-get build-dep couchdb

次にCouchDBのソースパッケージをダウンロードします。

$ apt-get source couchdb

devscriptsのuscan && uupdateでCouchDBのソースパッケージをアップデートしてみましたが、残念ながらSidでの1.1.1までしかアップグレードされません。原因は1.2.0からパスが変更されたため、debian/watchのパスと異なるためです。下記のように書き換えます。

$ diff -u a/debian/watch b/debian/watch
--- a/debian/watch      2012-05-22 01:22:34.000000000 +0900
+++ b/debian/watch      2012-05-22 01:22:39.000000000 +0900
@@ -1,3 +1,3 @@
 version=3

-http://www.apache.org/dist/couchdb/([\d\.]+)/apache-couchdb-([\d\.]+)\.tar\.gz
+http://www.apache.org/dist/couchdb/releases/([\d\.]+)/apache-couchdb-([\d\.]+)\.tar\.gz

変更したら、ソースパッケージをアップグレードします。

$ uscan
couchdb: Newer version (1.2.0) available on remote site:
 http://www.apache.org/dist/couchdb/releases/1.2.0/apache-couchdb-1.2.0.tar.gz
 (local version is 1.1.1)
couchdb: Successfully downloaded updated package apache-couchdb-1.2.0.tar.gz
    and symlinked couchdb_1.2.0.orig.tar.gz to it
$ uupdate ../apache-couchdb-1.2.0.tar.gz 1.2.0
New Release will be 1.2.0-1.
-- Untarring the new sourcecode archive ../apache-couchdb-1.2.0.tar.gz
Unpacking the debian/ directory from version 1.1.1-2 worked fine.
Remember: Your current directory is the OLD sourcearchive!
Do a "cd ../couchdb-1.2.0" to see the new package

Backportのパッケージ入手。

CouchDB 1.2.0は、Erlang R15B以上でなければなりません。SqueezeはR14Aなのでbackports.debian.orgを使い、置き換えることにしました。/etc/apt/soruces.listに下記を追記します。

deb http://backports.debian.org/debian-backports squeeze-backports main
deb-src http://backports.debian.org/debian-backports squeeze-backports main

sudo apt-get updateを実行後、CouchDBのビルドに必要なパッケージを下記のようにsqueeze-backportsを指定してインストールします。

$ sudo apt-get -t squeeze-backports install erlang-base erlang-crypto erlang-dev \
            erlang-syntax-tools autoconf erlang-eunit erlang-inets erlang-os-mon \
            erlang-tools erlang-xmerl libjs-jquery

ソースコードを元に普通に./configure && make && sudo make installをできることを確認します。問題なくビルドできたら、いよいよDebianパッケージの作成です。

Debianパッケージのビルド。

実はCouchDB 1.2.0はJavaScriptエンジンとして、Spidermonkeyの1.8.5が必要 です。が、Squeezeにも、Backportsにもありません。Sidにはlibmozjs185-1.0, libmozjs185-devがパッケージになっているので、Sidの環境でソースパッケージを取得し、ビルドに必要なパッケージをインストール後、このソースパッケージを使ってSqueeze向けのlibmozjs185を作ります。

$ sudo apt-get install libffi-dev zip pkg-kde-tools
$ debuild
$ sudo dpkg -i ../libmozjs185-1.0_1.8.5-1.0.0+dfsg-3_amd64.deb \
             ../libmozjs185-dev_1.8.5-1.0.0+dfsg-3_amd64.deb

ビルドしてできたlibmozjs185パッケージをインストールしたら、CouchDBのビルドを行います。debian/ディレクトリ以下のファイルの設定が一部不足しているので、以下のようにしました。

debian/control

$ diff -u couchdb-1.1.1/debian/control  couchdb-1.2.0/debian/control
4,5c4,5
< Maintainer: Erlang Packaging Team <pkg-erlang-devel@lists.alioth.debian.org>
< Uploaders: Sergei Golovan <sgolovan@debian.org>, Sam Bisbee <sbisbee@computervip.com>, Elliot Murphy <elliot@ubuntu.com>
---
> Maintainer: Kouhei Maeda <mkouhei@palmtb.net>
> Build-Depends: debhelper (>= 7.0.50~), autotools-dev, erlang-eunit, erlang-base, erlang-crypto, erlang-dev, erlang-syntax-tools, autoconf, libmozjs185-dev, cdbs
7,9d6
< Build-Depends: cdbs (>= 0.4.42), debhelper (>= 7.2.11),
<  erlang-dev (>= 1:13.b.1-dfsg-3), help2man, libcurl4-openssl-dev,
<  libicu-dev, libmozjs-dev, libreadline-dev
11,12d7
< Vcs-Svn: svn+ssh://svn.debian.org/svn/pkg-erlang/couchdb
< Vcs-Browsern: http://svn.debian.org/viewsvn/pkg-erlang/couchdb
16,17c11,12
< Depends: ${misc:Depends}, ${shlibs:Depends}, ${erlang:Depends},
<  ${erlang-abi:Depends}, adduser, libjs-jquery, lsb-base, procps, mawk
---
> Depends: ${shlibs:Depends}, ${misc:Depends}, ${erlang:Depends},
>  ${erlang-abi:Depends}, adduser, libjs-jquery, lsb-base, procps, mawk, libmozjs185-1.0
29c24
<  languages and environments.
---
>  languages and environments.

debian/rules

DEB_CONFIGURE_USER_FLAGの指定が肝ですね。

$ diff ../couchdb-1.1.1/debian/rules  debian/rules
15a16,17
> DEB_CONFIGURE_USER_FLAGS += \
>        --with-js-lib-name=mozjs185
34a37
>       mkdir -p debian/couchdb/usr/share/lintian/overrides/
39,41c42,44
<       chmod 660 debian/couchdb/etc/couchdb/local.ini
<       chmod 750 debian/couchdb/var/lib/couchdb
<       chmod 750 debian/couchdb/var/log/couchdb
---
>       chmod 664 debian/couchdb/etc/couchdb/local.ini
>       chmod 755 debian/couchdb/var/lib/couchdb
>       chmod 755 debian/couchdb/var/log/couchdb

/etc/init/coudhb.tpl.inの修正

$ quilt diff | sed 's/^/    /g'
Index: couchdb-1.2.0/etc/init/couchdb.tpl.in
===================================================================
--- couchdb-1.2.0.orig/etc/init/couchdb.tpl.in      2012-05-20 01:02:37.495545236 +0900
+++ couchdb-1.2.0/etc/init/couchdb.tpl.in   2012-05-20 01:09:00.859545321 +0900
@@ -84,6 +84,7 @@
     # Start Apache CouchDB as a background process.

     mkdir -p "$RUN_DIR"
+    chown "$COUCHDB_USER":"$COUCHDB_USER" "$RUN_DIR"
     command="$COUCHDB -b"
     if test -n "$COUCHDB_STDOUT_FILE"; then
         command="$command -o $COUCHDB_STDOUT_FILE"

これでdebuildし、できたパッケージをインストールすれば、上記のリンク先の問題もクリアした上でSqueeze向けの 1.2.0を使えるようになります。

]]>
Tue, 22 May 2012 00:00:00 +0900
http://d.palmtb.net/2012/05/21/lxc_migration.html http://d.palmtb.net/2012/05/21/lxc_migration.html <![CDATA[LXCのマイグレーションを行った話。]]> LXCのマイグレーションを行った話。

さくらのVPS 512から1Gに契約を切り替えで、使用しているLXCの移行を先週行いました。が、ちょいとハマったのでメモ。同じ環境の人は多分いないと思うので、同じようにハマる人は少ないと思いますが。

既存環境。

もともとの512の方は、Debian GNU/Linux LennyをインストールしSqueezeにアップグレードした環境でした。SqueezeではLXCを使うには一部カーネルオプションが無効になっているのでカーネルビルドが必要です。Linux Kernel 2.6.39.1でリビルドし、Debianパッケージで提供されているlxc 0.7.2-1を使っていました。( lxcを久々に使うことに。on さくらのVPS 512

また、2009年に0.6.2だか0.6.3のころから、SidのDebianパッケージで使い始めていましたが、このころは自動起動の仕組みが無く、自分でスクリプト書いていたこともあり、0.7.2に存在する自動起動の仕組みは使わずに使っていました。コンテナのrootfsをインストールしていた先も、パッケージでの標準の/var/lib/lxcではなく、/lxcrootディレクトリを作りこの下にdebootstrapで作ったイメージを置いていました。

新環境。

1Gでは512を使い始めた時と違い、Squeeze用のインストール用ISOイメージが提供されています。今回はSqueezeをインストールした後、Linux Kernel 3.3.6とDebianパッケージのlxcおよび最新のlxc 0.8.0 rc1を試そうとしました。最終的には元々の環境と同じメインバージョンの、2.6.39.4、lxcはsqueezeの同じDebianパッケージを使いました。

ハマったことその1。

一つは、最初にインストールしたDebianのディストリビューションの違い。LennyのカーネルではCONFIG_VIRTIO_BLKが無効になっていますが、Squeezeではこれが有効になっているので、Lennyからアップグレードした512の環境ではディスクが/dev/sdaとして認識していました。しかし1Gの環境では/dev/vdaです。1Gの環境で2.6.39.4でビルドする際に512の/boot/config-2.6.39.1をベースにしてビルドしたのですが、このカーネルでもCONFIG_VIRTIO_BLKは無効にしたままだったため、リブート時にinitramfsがrootfsを見つけられなくてブート途中で止まってしまう、という初歩的なミスでハマりました…。

ハマったことその2。

二つ目は、Linux Kernelのバージョンの違いによるものです。当初、3.3.6でビルドしたカーネルを使おうとしたのですが、SqueezeのDebianパッケージとしてあるlxc 0.7.2-1でも、0.7.2-1のソースパッケージからuscan;uupdateで取得した0.8.0 rc1でも、プロセスすら起動できない、という状況。発生するエラーは、

$ sudo lxc-start -n anycontainer
lxc-start: No such file or directory - failed to rename cgroup /var/local/cgroup//lxc/11783->/var/local/cgroup//lxc/anycontainer

だったはず。2.6.39系だと、cgroup filesystemに作成されるコンテナのメタ情報は、/var/local/cgroup/anycontainerディレクトリの下ですが、3.3系だと、そのパスが変わってしまっている様子。5/19で期間延長が終了予定で、原因追求している時間もとれないので、3.3.6で使うのは今回は諦めました。敗北…。

ハマったことその3。

3.3系でダメだった際にlxc-0.8.0-rc1のDebianパッケージを作成したので、これも3.3系だけでなく、2.6.39.4で試して見ました。が、こっちもダメ。こちらのエラーも、

$ sudo lxc-start -n anycontainer
lxc-start: No such file or directory - failed to rename cgroup /var/local/cgroup//lxc/11783->/var/local/cgroup//lxc/anycontainer

なので、3.3系は0.8以降で使えるようになるはず?

環境できてれば後は楽。

コピー先のLXCの環境さえできてしまえば、512の方でlxc-freezeし、コンテナのrootfsとconfig含んだディレクトリをtarballにし、伸長します。コンテナの設定ファイル(anycontainer/config)のうち、

  • lxc.rootfs
  • lxc.mount.entry=proc
  • lxc.mount.entry=devpts
  • lxc.mount.entry=sysfs

の4ヶ所のパスを/lxcrootにしていたところを、Debianパッケージのデフォルトの/var/lib/lxcに変更し、次のコマンドを実行します。

$ sudo lxc-create -n anycontainer -f /tmp/anycontainer/config -t debian

を実行すると、/var/lib/lxcディレクトリ下にanycontainer/{config,rootfs}がコピーされます。ホストの起動時に自動起動させるには、/var/lib/lxc/anycontainer/configを、/etc/lxc/anycontainer.confにコピーし、/etc/default/lxcを下記のように変更すれば、OKです。

RUN=yes <- コメントを外す
CONF_DIR=/etc/lxc
CONTAINERS="anycontainer" <-/etc/lxc/ディレクトリ下に置いた*.confのうち、起動させたいコンテナを'.conf'を取り除いた形で列挙する。複数ある場合はスペース区切り
]]>
Mon, 21 May 2012 00:00:00 +0900
http://d.palmtb.net/2012/05/15/multi_nw_dnsmasq.html http://d.palmtb.net/2012/05/15/multi_nw_dnsmasq.html <![CDATA[dnsmasqで複数N/Wそれぞれにdefault gatewayを設定する。]]> dnsmasqで複数N/Wそれぞれにdefault gatewayを設定する。

もともとdnsmasqサーバにのみアクセスさせる用途で使っていたのですが、他のネットワークにもアクセスする必要がでたので調べてみました。

ます、複数のNICを持つサーバで、dnsmasqを使ってDHCPサーバを立てる場合、払い出すNICとDHCPの範囲を指定します。

interface=eth1
interface=eth2
interface=eth3
interface=eth4
interface=eth5
interface=eth6

dhcp-range=10.0.0.10,10.0.0.250,30m
dhcp-range=10.0.1.10,10.0.1.250,30m
dhcp-range=10.0.2.10,10.0.2.250,30m
dhcp-range=10.0.3.10,10.0.3.250,30m
dhcp-range=10.0.4.10,10.0.4.250,30m
dhcp-range=10.0.5.10,10.0.5.250,30m

しかし、これだとデフォルトゲートウェイが設定されません。上記のネットワークはそれぞれ24bitなので、デフォルトゲートウェイも別々に設定したいですね。dhcp-optionで、option:routerを使うと一つのネットワークに対してデフォルトゲートウェイを設定できますが、そのままでは複数のネットワークに対して設定できません。そこで、tagを使います。tagでつける名前は任意の半角英数の文字列です。

dhcp-range=tag:eth1,10.0.0.10,10.0.0.250,30m
dhcp-range=tag:eth2,10.0.1.10,10.0.1.250,30m
dhcp-range=tag:eth3,10.0.2.10,10.0.2.250,30m
dhcp-range=tag:eth4,10.0.3.10,10.0.3.250,30m
dhcp-range=tag:eth5,10.0.4.10,10.0.4.250,30m
dhcp-range=tag:eth6,10.0.5.10,10.0.5.250,30m

dhcp-option=tag:eth1,option:router,10.0.0.1
dhcp-option=tag:eth2,option:router,10.0.1.1
dhcp-option=tag:eth3,option:router,10.0.2.1
dhcp-option=tag:eth4,option:router,10.0.3.1
dhcp-option=tag:eth5,option:router,10.0.4.1
dhcp-option=tag:eth6,option:router,10.0.5.1

あとはdnsmasqを再起動すれば、セグメント毎にデフォルトゲートウェイを設定できます。 dnsmasqのマニュアル には他の設定もいろいろ記載されています。コマンドラインで使うオプションを、設定ファイル(/etc/dnsmasq.conf)でそのまま使えるのが良いですね。

]]>
Tue, 15 May 2012 00:00:00 +0900
http://d.palmtb.net/2012/05/11/gitlab.html http://d.palmtb.net/2012/05/11/gitlab.html <![CDATA[GitLabを導入してみた話。]]> GitLabを導入してみた話。

ちょいと昨日、GitLabをUbuntu12.04に導入してみました。基本的には、 Install for stable version (recommended) の通りです。GitLabの現時点のstableはRuby 1.9.2を必要としますが、Ubuntu 12.04では、1.9.1どまりなので、Rubyについては、上記の手順どおりソースコードからビルドし、Ruby関連パッケージは全てGem経由でインストールしました。

一部、手順の 4. Install gitlab and configuration. Check status configuration. において、Gemに紛れて、

sudo pip install pygments

と、pygmentsをpipでインストールする手順があります。が、これはDebianパッケージがあり、バージョンの指定もないので、python-pygmentsパッケージをインストールしました。

この手順どおりに行うと、インストール後に表示されるGitリポジトリのURIのホストがlocalhostになってしまいます。インストール後に、/home/gitlab/gitlab/config/gitlab.ymlのサーバ絡みの変更すると、gitlite関連の手順がGitlab経由で行えません。gitlite絡みというのは、つまりユーザ作成後のSSHキーの登録であったり、ベアリポジトリの作成です。原因は、gitlab.yamlのホスト関連の情報をlocalhostからホスト名やIPアドレスに変更すると、インストール手順の中で行っていたgit clone先のホスト名と変わってしまうためと思われます。ですので、上記手順の CHECK: Logout & login again to apply git group to your user のうち、

sudo -u gitlab -H git clone git@localhost:gitolite-admin.git /tmp/gitolite-admin

は、localhostではなく、サーバのホスト名もしくはIPアドレスを指定し、前述の4の手順で

sudo -u gitlab cp config/gitlab.yml.example config/gitlab.yml

を行った直後に、gitlab.yamlのlocalhostの部分を変更しておく必要があると思います。「思います」と書いているのは、未確認だからです。私が実際にやったのは後からgitlab.yamlを修正した場合の手順。つまり、

  • ホストキーの再生成
$ sudo -H -u gitlab ssh-keygen -q -N '' -t rsa -f /home/gitlab/.ssh/id_rsa
  • setupの再実行
$ sudo -u git sh -c 'echo -e "PATH=\$PATH:/home/git/bin\nexport PATH" > /home/git/.profile'
$ sudo -u git -i -H /home/git/gitolite/src/gl-system-install
$ sudo cp /home/gitlab/.ssh/id_rsa.pub /home/git/gitlab.pub
$ sudo chmod 777 /home/git/gitlab.pub
$ sudo -u git -H sed -i 's/0077/0007/g' /home/git/share/gitolite/conf/example.gitolite.rc
$ sudo -u git -H sh -c "PATH=/home/git/bin:$PATH; gl-setup -q /home/git/gitlab.pub"
  • 手順4の再実行
$ sudo -u gitlab -H git clone git@repos.example.org:gitolite-admin.git /tmp/gitolite-admin
$ sudo rm -rf /tmp/gitolite-admin

を行って解決しました。ただし、「setupの再実行」のうち、gl-system-installスクリプトの実行は、下記の用にwarningが出るのでいらないかも。(これもまた未確認)

$ sudo -u git -i -H /home/git/gitolite/src/gl-system-install
-sh: 1: -e: not found
using default values for EUID=109:
/home/git/bin /home/git/share/gitolite/conf /home/git/share/gitolite/hooks

                ***** WARNING *****
/usr/bin precedes /home/git/bin in your $PATH,
and it *also* contains gl-setup.  This is almost certainly going to confuse
you or me later.

Since gl-setup MUST be run from the PATH (and not as src/gl-setup or such),
you must fix this before running gl-setup.  The simplest way is to add

    PATH=/home/git/bin:$PATH

to the end of your bashrc or similar file.  You can even simply run that
command manually each time you log in and want to run a gitolite command.

Run /home/git/gitolite/src/gl-system-install -h for a detailed usage message.

ReadOnlyでグローバルアクセスさせたいのだけど。

コードだけでなく、各種サーバのある設定ファイルの置き場として、ログインせずにHTTPでReadOnlyアクセスもできるようにしたかったのですが、Public repositories、これは今後も予定されてないみたいです。理由は、 GitLabの開発を行っている企業が目指しているのはプライベートなGitHubで、githubの競合になることは避けるためだとか 。 rejectされたみたいですが、 コメント欄での反応が割と良かったこんな pull request もあります。残念ながら導入したのがstableだったのですぐに試せず。

今回みたいな場合は Gitrious の方があってそうですねえ。見た目はGitLabの方がgithubに近いのでいいんですけどね。残念。

]]>
Fri, 11 May 2012 00:00:00 +0900
http://d.palmtb.net/2012/04/22/120000.html http://d.palmtb.net/2012/04/22/120000.html <![CDATA[optparseからargparseに変更。 ]]> optparseからargparseに変更。 [1]

tonicdnscli のPython 3への対応をしようとした際、コマンドラインオプションに使用している optparseモジュールがPython 2.7 で廃止予定だということを知りました。そこで、optparseからargparseに変更することにしました。optparseでは、入力ファイルをJSON形式で表示させるためのオプションや、TonicDNSからレコードを取得して表示、レコードの登録、レコードの削除を行うのをオプションで行っていましたが、argparseに変更するタイミングで、これらをサブコマンドとして実装しなおしました。変更した結果が下記の表です。

機能 optparse argparse
変換・表示 -o/–stdout show
取得表示 -g/–retrieve get
レコード登録 -c/–create create
レコード削除 -d/–delete delete

基本的には 公式ドキュメント を読めばoptparseでやっていたことをargparseに置き換えるのは問題なくできます。ちょいとハマったのが、サブコマンドのオプションを相互排他にする方法。メインパーサと、ArgementParserのadd_subparsers()メソッドで作成するサブパーサと、どちらにadd_mutually_exclusive_group()メソッドを使うのかとか、相互排他でどちらかを必須にするにはrequired=Trueをadd_mutually_exclusive_group()メソッドと、add_argument()メソッドのどちらの引数として渡すのか、といったあたりです。

結果は下記のとおり。(createの例)

# Create records
parser_create = subparsers.add_parser(
    'create', help='create records of specific zone')
parser_create.add_argument('infile', action='store',
                             help='pre-converted text file')
parser_create.add_argument('-s', dest='server', required=True,
                           help='specify TonicDNS hostname or IP address')
parser_create.add_argument('-u', dest='user', required=True,
                           help='TonicDNS username')
group_create = parser_create.add_mutually_exclusive_group(required=True)
group_create.add_argument('-p', dest='password',
                           help='TonicDNS password')
group_create.add_argument('-P', action='store_true',
                           help='TonicDNS password prompt')
parser_create.set_defaults(func=create)

argparseを使った場合のヘルプは下記のようになります。

$ tonicdnscli -h
usage: tonicdnscli [-h] [-v] {show,get,create,delete} ...

usage

positional arguments:
  {show,get,create,delete}
                        commands
    show                show converted JSON
    get                 retrieve records of specific zone
    create              create records of specific zone
    delete              delete records of specific zone

optional arguments:
  -h, --help            show this help message and exit
  -v, --version         show program's version number and exit

サブコマンド毎のヘルプも表示できます。(createの場合)

$ tonicdnscli create -h
usage: command.py create [-h] -s SERVER -u USER (-p PASSWORD | -P) infile

positional arguments:
  infile       pre-converted text file

optional arguments:
  -h, --help   show this help message and exit
  -s SERVER    specify TonicDNS hostname or IP address
  -u USER      TonicDNS username
  -p PASSWORD  TonicDNS password
  -P           TonicDNS password prompt

“-p”と”-P”がサブコマンドで相互排他かつ入力必須というわけです。

入力が不完全な場合は、下記のように表示されます。まずはサブコマンドが無い場合。

$ tonicdnscli
usage: tonicdnscli [-h] [-v] {show,get,create,delete} ...
tonicdnscli: error: too few arguments

サブコマンドの引数が足りない場合。

$ tonicdnscli create
usage: tonicdnscli create [-h] -s SERVER -u USER (-p PASSWORD | -P) infile
tonicdnscli create: error: too few arguments

サブコマンドの引数が足りない場合。

$ tonicdnscli create examples/example.org.txt
usage: tonicdnscli create [-h] -s SERVER -u USER (-p PASSWORD | -P) infile
tonicdnscli create: error: argument -s is required

結構親切で便利です。optparseと違ってデフォルトでサブコマンドを作れることも考慮すると、もはやoptparseを使わず、argparseにした方が良いですね。

tonicdnscli/src/tonicdnscli/command.pyでの置き換えは Gistに上げておきました 。置き換え後が結構冗長ですね。

[1]タイトルが間違ってました。 Vさん、ご指摘ありがとうございました。
]]>
Sun, 22 Apr 2012 00:00:00 +0900
http://d.palmtb.net/2012/04/21/211900.html http://d.palmtb.net/2012/04/21/211900.html <![CDATA[第87回東京エリアDebian勉強会に参加してきた。]]> 第87回東京エリアDebian勉強会に参加してきた。

おまめちゃんの誕生があったので、1月以来で久々に参加してきました。今日のテーマはDebianでのnode.jsの話、AndroidデバイスでDebianを動かす話、月刊Debhelper。あと、今期のDebian JP Projectの会長に再選されたので、今期の所信表明をしてきました。node.jsの設計思想がいろいろアレゲで、Debianパッケージにするのは魔窟過ぎて泣けるなぁと思った次第です。(通常の)Debian勉強会への初参加の方も3人いらっしゃり、宴会も盛り上がって楽しかったです。

なお、来月のDebian勉強会は、おまめちゃんの世話で留守番のため不参加です。次の参加は 6/23の大統一Debian勉強会 ですね。

]]>
Sat, 21 Apr 2012 00:00:00 +0900
http://d.palmtb.net/2012/04/20/031000.html http://d.palmtb.net/2012/04/20/031000.html <![CDATA[TonicDNS Clientを作成しました。]]> TonicDNS Clientを作成しました。

俺得シリーズ。 “TonicDNSでレコードの一括登録・削除するためのJSONを生成する。“でTonicDNS用にJSONを生成するツールを作成しましたが、これにTonicDNS API用のクライアント機能を実装しました。 Github および PyPI で公開しています。使い方は src/README.rst に記述していますが、現時点でできることは以下の通りです。

  • 半角空白文字区切りフォーマットのテキストファイルからJSONへの変換
  • TonicDNS API経由でのPowerDNSの操作
    • 指定ドメインのレコード情報の一括表示
    • 指定ドメインへのレコード一括登録
    • 指定ドメインからのレコード一括削除

登録 or 削除対象が100件を超える場合

コミット 7571109876 で実装したのですが、登録もしくは削除対象が100件を超える場合は、100件毎に処理するようにしています。例えば345件の登録を行う場合は、100, 100, 100, 45と、計4回処理します。コミットメッセージにも書いたのですが、これはHTTP PUTメソッド、もしくはDELETEメソッドで、送信するbodyサイズ、つまりJSONファイルのサイズが27,915byte以上、27,938byteより下の間が処理可能なサイズの境になっているためです。この送信可能なデータサイズの上限がどこで決められているのかは、現状ではまだ分かっていません。POSTメソッドならTonicDNSが実装されているPHPの場合は、php.iniの post_max_size で変更でき、デフォルト値は8MBになっていますが、PUTやDELETEの場合はありません。また、使用している環境に合わせ、PHP 5.3.2, TonicDNS develブランチの d4906df6 , Apache 2.2.14のソースコードを調べてみましたが、現時点ではPUTメソッドやDELETEメソッドでの送信データの上限に関わる値を決めているロジックは見当たりませんでした。

初めてのPythonパッケージ

今回、はじめてPythonパッケージを作成してみました。 公式ドキュメント と、Debianパッケージのメンテナンスをしているblockdiagを参考にして行ったら結構分かりやすかったです。これは、PythonツールのDebianパッケージ作成を行うときに実行する、

dh $@ --with python2

で行う処理が、

python setup.py sdist bdist

を実行しているのだな、と理解できるようになったことなど、Pythonパッケージの作成の処理が理解できるようになったのは、PythonのDebianパッケージをメンテナンスする上でも重要なので良かったなと思います。

Upstream = Debian パッケージメンテナ = オレ、ってあり?

tonicdnscliは、自分で作ったツールですが普段使う際、

$ sudo python setup.py install

でインストールはするのは割けたいところです。これだと/usr/local下にインストールされてしまうからです。なので、まだITPはしていませんがDebianパッケージを作成してインストールしています。Githubではdebian/ディレクトリ以下のファイルもリポジトリに追加しています。ITPをしていないので、debain/copyrightのBTS番号のみがテンプレートのままですが、手元でdebuildしてもパッケージを作成することはできます。さて、自分がUpstreamのソフトウェアを自分でITPしてパッケージメンテナになるのはアリなんでしょうか?

PowerDNS + TonicDNSのススメ。

現時点では処理対象のレコードが既に登録されているものがないかをチェックする機能を実装していません。また、レコード単位でのアップデートも現時点ではできず、一度対象のレコードを削除した後、再度まとめて登録するしかありませんが、この辺も近々対応する予定です。これを実装すれば、まあかなりtonicdnscliも使える感じになるかなと思っています。

また、TonicDNSとtonicdnscliや、PowerDNS GUI、ton-katsuさんの作成した novadns [1] とPowerDNS + MySQLの環境を活用するツールがだいぶ揃ってきた感じです。特にシステムの自動化を行っていく上でPowerDNSとTonicDNSの組み合わせはかなり便利です。まだDNSの運用を行っていたり、OpenStackでホスト名の登録とIPアドレスの紐付けをどうしようか検討している人もいると思います。そういう人にはうってつけです。TonicDNSは機能的に足りない部分やバグもまだありますが、開発速度も割と速い上、パッチ投げると内容によってはマージしてもらえますので、是非使ってみてはいかがでしょうか。

[1]OpenStackのNovaではインスタンスを作成すると、ランダムにホスト名及びインスタンス名が作成されますが、novadnsは、このホスト名とインスタンス作成時に自動的に割り当てられるIPアドレスを使って、自動的にTonicDNS経由でPowerDNSにAレコードを登録するデーモンです。
]]>
Fri, 20 Apr 2012 00:00:00 +0900
http://d.palmtb.net/2012/04/16/011000.html http://d.palmtb.net/2012/04/16/011000.html <![CDATA[blockdiag 1.1.3以降ビルド時のエラーの原因。]]> blockdiag 1.1.3以降ビルド時のエラーの原因。

結構ハマったので、後々のためにメモっておきました。

フォントの検出部分でのエラー。

blockdiagシリーズがmain入りしました。” で書いたとおり、blockdiag 1.1.3以降、SidでのDebianパッケージ作成時に下記のエラーが出ていました。エラーが出るようになったのは、以前はdebuild時にnosetestsを実行していなかったのを、実行するように変更したのがきっかけですが、そのままにはできないので原因を調べてみました。

======================================================================
FAIL: test_auto_font_detection (blockdiag.tests.test_boot_params.TestBootParams)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/user/debpkg/blockdiag/blockdiag-1.1.4/src/blockdiag/tests/utils.py", line 14, in wrap
    func(*args, **kwargs)
  File "/home/user/debpkg/blockdiag/blockdiag-1.1.4/src/blockdiag/tests/test_boot_params.py", line 158, in test_auto_font_detection
    self.assertTrue(fontpath)
AssertionError: None is not True
    'None is not True' = self._formatMessage('None is not True', "%s is not True" % safe_repr(None))
>>  raise self.failureException('None is not True')


----------------------------------------------------------------------
Ran 295 tests in 3.400s

FAILED (failures=1)
make[1]: *** [override_dh_auto_test] エラー 1

この原因は、src/blockdiag/utils/bootstrap.pyの下記の部分でした。

def detectfont(options):
    fonts = ['c:/windows/fonts/VL-Gothic-Regular.ttf',  # for Windows
             'c:/windows/fonts/msgothic.ttf',  # for Windows
             'c:/windows/fonts/msgoth04.ttc',  # for Windows
             '/usr/share/fonts/truetype/ipafont/ipagp.ttf',  # for Debian
             '/usr/local/share/font-ipa/ipagp.otf',  # for FreeBSD
             '/Library/Fonts/Hiragino Sans GB W3.otf',  # for MacOS
             '/System/Library/Fonts/AppleGothic.ttf']  # for MacOS

テストでipafontのチェックが行われるようになったのですが、このパスのipagp.ttfはttf-ipafont-gothicパッケージに含まれています。Sidではfonts-ipafont-gothicに変わっており、パスも下記のように変わっています。

$ apt-file search ipagp.ttf
fonts-ipafont-gothic: /usr/share/fonts/opentype/ipafont-gothic/ipagp.ttf

おまけに、私の環境ではそもそもIPAフォントをインストールしていなかったので、エラーになっていたワケです。インストールするフォントは人によって異なるので、インストールしてある何らかのTrueTypeフォントが検出されればOKになるようにパッチを作成しました。

$ quilt diff
Index: blockdiag-1.1.4/src/blockdiag/utils/bootstrap.py
===================================================================
--- blockdiag-1.1.4.orig/src/blockdiag/utils/bootstrap.py       2012-02-13 18:59:29.0000000
+++ blockdiag-1.1.4/src/blockdiag/utils/bootstrap.py    2012-04-14 13:17:48.066795947 +0900
@@ -181,13 +181,21 @@


 def detectfont(options):
-    fonts = ['c:/windows/fonts/VL-Gothic-Regular.ttf',  # for Windows
-             'c:/windows/fonts/msgothic.ttf',  # for Windows
-             'c:/windows/fonts/msgoth04.ttc',  # for Windows
-             '/usr/share/fonts/truetype/ipafont/ipagp.ttf',  # for Debian
-             '/usr/local/share/font-ipa/ipagp.otf',  # for FreeBSD
-             '/Library/Fonts/Hiragino Sans GB W3.otf',  # for MacOS
-             '/System/Library/Fonts/AppleGothic.ttf']  # for MacOS
+    fonts = [
+             # for Windows
+             'c:/windows/fonts/VL-Gothic-Regular.ttf',
+             'c:/windows/fonts/msgothic.ttf',
+             'c:/windows/fonts/msgoth04.ttc',
+             # for FreeBSD
+             '/usr/local/share/font-ipa/ipagp.otf',
+             # for MacOS
+             '/Library/Fonts/Hiragino Sans GB W3.otf',
+             '/System/Library/Fonts/AppleGothic.ttf']
+
+    # fot Debian
+    import glob
+    for f in glob.glob('/usr/share/fonts/truetype/*/*.ttf'):
+        fonts.append(f)

     fontpath = None
     if options.font:

コメントの位置を変更したのは、pep8のポリシーでは元の位置のままだとエラーになるためです。ttf-ipafont-gothicパッケージをインストールして、リストのttf-ipafont-gothicのパスになるように変更した場合に発生しました。”for Debian”のコメント部分を含めると一行が長すぎるため、下記のようなエラーが発生します。

======================================================================
FAIL: blockdiag.tests.test_pep8.test_pep8
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/home/user/debpkg/blockdiag/blockdiag-1.1.4/src/blockdiag/tests/test_pep8.py", line 38, in test_pep8
    assert errors + warnings == 0, message
AssertionError: pep8: 1 errors / 0 warnings
    0 = <module 'pep8' from '/usr/lib/pymodules/python2.7/pep8.pyc'>.get_count('W')
    'pep8: 1 errors / 0 warnings' = 'pep8: %d errors / %d warnings' % (1, 0)
    print 'pep8: 1 errors / 0 warnings'
>>  assert 1 + 0 == 0, 'pep8: 1 errors / 0 warnings'

-------------------- >> begin captured stdout << ---------------------
/home/user/debpkg/blockdiag/blockdiag-1.1.4/src/blockdiag/utils/bootstrap.py:187:80: E501 line too long (80 characters)
             '/usr/share/fonts/opentype/ipafont-gothic/ipagp.ttf',  # for Debian
                                                                            ^
1       E501 line too long (80 characters)
pep8: 1 errors / 0 warnings

--------------------- >> end captured stdout << ----------------------

----------------------------------------------------------------------
Ran 295 tests in 3.676s

FAILED (failures=1)
make[1]: *** [override_dh_auto_test] エラー 1
make[1]: ディレクトリ `/home/user/debpkg/blockdiag/blockdiag-1.1.4' から出ます
make: *** [build] エラー 2
dpkg-buildpackage: error: debian/rules build gave error exit status 2
debuild: fatal error at line 1350:
dpkg-buildpackage -rfakeroot -D -us -uc failed

ちなみに、下記の位置にコメントを書くとE261エラーになります。

fonts = [# for Windows
         'c:/windows/fonts/VL-Gothic-Regular.ttf',

override_dh_auto_testでハマった箇所。

前述したとおり1.1.2-1まではoverride_dh_auto_testを行っていませんでした。1.1.2の時点で既にupstreamにはテストが含まれていましたが、debianパッケージ作成時にはnosetestsを実行できていませんでした。src/blockdiag/testsディレクトリ以下のテストを実行するには、blockdiagのモジュールをちゃんとimportしないとpbuilderなどのようなクリーン環境ではコケます。そこでdebian/rulesに下記のようの追記を行いビルド時にテストを行うようにしました。

override_dh_auto_test:
ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
        set -e; \
        PYTHONPATH=$(CURDIR)/src nosetests -d
endif

PYTHONPATHに$(CURDIR)/srcを指定するというのが分かるまで、_build/lib.linux-x86_64-2.7や、debian/python-blockdiag/usr/share/pysharedを指定してみて上手くいかず、プギャーと言ってました…。orz

なお、debian/controlのBuild-Dependsに何らかのフォントパッケージを指定しておかないと、pbuilder環境ではフォントが全くインストールされません。なので、前述のようにglobパターンでTrueTypeフォントを検出するようにしてもテストがこけてしまう問題が結局あります。IPAフォントよりも標準的にインストールされるVL Gothic(fonts-vlgothic)を指定したのですが、それなら前述のパッチもVL Gothicのパスをハードコーディングしておけば良いのではないかと、迷いますね…。

]]>
Mon, 16 Apr 2012 00:00:00 +0900
http://d.palmtb.net/2012/04/13/190000.html http://d.palmtb.net/2012/04/13/190000.html <![CDATA[λ式でdictionaryを返す。]]> λ式でdictionaryを返す。

Pythonのλ式って、こういう書き方もできるんですね。便利。

>>> hoge = lambda act: {"records": 1 } if act else {"name": "moge", "records": 2}
>>> hoge(1)
{'records': 1}
>>> hoge(0)
{'records': 2, 'name': 'moge'}
>>> hoge(True)
{'records': 1}
>>> hoge(False)
{'records': 2, 'name': 'moge'}
>>> import json
>>> json.JSONEncoder().encode(hoge(False))
'{"records": 2, "name": "moge"}'
]]>
Fri, 13 Apr 2012 00:00:00 +0900
http://d.palmtb.net/2012/04/12/183000.html http://d.palmtb.net/2012/04/12/183000.html <![CDATA[圧縮されたテキストファイルを編集する。]]> 圧縮されたテキストファイルを編集する。

先ほど気がついたのですが、vimやemacsだと圧縮されたテキストファイルを直接編集できるのですね。ちょっと調べてみました。

tool(ver) / compress gzip bzip2 xz
cat (8.13) NG NG NG
more (2.20.1) NG NG NG
less (444) NG NG NG
lv (4.51.a) OK OK NG
vim.tiny (7.3.429) NG NG NG
vim.basic (7.3.429) OK OK OK
emacs 23.3.1 OK OK OK

vimでもemacsでも行けるようです。lvはそのうちxzも対応するんでしょうか。ところで、catはさておき、lvがあるのにmoreやlessなんて、もはや普段は使いませんよねえ。

]]>
Thu, 12 Apr 2012 00:00:00 +0900
http://d.palmtb.net/2012/04/10/190000.html http://d.palmtb.net/2012/04/10/190000.html <![CDATA[tinkererの下書きをGitで管理する。]]> tinkererの下書きをGitで管理する。

まずは、tinkererで下書きを使う場合の手順のおさらいです。下書き用のreSTファイルを生成するには-dオプションを使います。

$ tinker -d hoge
New draft created as '/home/user/myblog/drafts/host.rst'

生成されたreSTファイルを編集します。完成したら日付のディレクトリを作り、そこに下書きのreSTファイルを移動させます。master.rstにエントリを登録してビルドしたら終わりです。

$ mkdir -p 2012/04/10
$ mv draft/host.rst 2012/04/10/
$ vi master.rst
$ tinker -b -q

簡単ですね。

reSTをGitで管理する。

tinkererをGitで管理する場合、pagesディレクトリ、ブログ用のYYYY/MM/DDディレクトリ以下の各reSTファイル、toctree用のmaster.rst、設定ファイルのconf.py、_staticディレクトリの下のファイルを対象にします [1] 。コミットしたらどこかのリモートリポジトリに置いておけば、どこからでもブログを書けるようになります。

ところで、作成途中の下書きは別で管理したいですよね。公開済みのブログの原稿のreSTファイルは、ブログで公開しているのですから、別に公開したところで何も変わりませんが、下書きは公開したくない情報を入れているかもしれません。文章も公開用に推敲されていないかもしれません。下書きだけに。

そこで、下書き用のdraftsブランチを作成します。対象はdraftsディレクトリ以下の下書き用のreSTファイルだけで大丈夫です [2] 。下書きが完成するまで、適当にコミットし、完成したら、先ほどの手順でYYYY/MM/DD形式の日付のディレクトリを作成し、reSTファイルを移動しコミットします。

$ git branch
* drafts
  master
$ git add drafts/hoge.rst
$ git commit -sm "Add draft of hoge"
$ git add drafts/hoge.rst
$ git commit -sm "Update draft of hoge"
$ git add drafts/hoge.rst
$ git commit -sm "Finish draft of hoge"
$ mkdir 2012/04/10
$ git mv drafts/hoge.rst 2012/04/10/hoge.rst
$ git commit -sm "Add entry hoge"

これをmasterブランチに取り込みたいのですが、masterブランチにmergeしてしまうと、他のdraftsディレクトリで管理されている下書きも追加されてしまいます。困りました。そこでcherry-pickですよ。cherry-pickを使えば、先ほどのコミットだけを取り込むことができます。

$ git checkout master
$ git log drafts
$ git cherry-pick 6890c74 270c118 4f2a0df 2acd8a3
[master 1c28f33] Add draft of hoge
 0 files changed
 create mode 100644 drafts/hoge.rst
[master 503e07a] Update draft of hoge
 1 file changed, 428 insertions(+)
[master 84be7d7] Finish draft of hoge
 1 file changed, 428 insertions(+)
[master 265ec60] Add entry hoge
 1 file changed, 0 insertions(+), 0 deletions(-)
rename drafts/hoge.rst => 2012/04/10/hoge.rst (100%)

コミットを取り込んだら、master.rstを編集し、先ほどのエントリを追加して、git commit –amendすれば、取り込んだ下書きと同じコミットとして管理することができます。あるいは、git cherry-pickで–no-commitオプションをつければ、indexに登録するだけなので、そっちの方が良いかもしれません。

[1]_staticディレクトリに何もファイルが無ければ、.gitkeepを作って管理しておくと、ビルド時に余計なエラーが発生しません。
[2]draftsディレクトリ以下のreSTファイルはビルドの対象にはならないので、下書き用のreSTファイルだけを管理すれば良いわけです。
]]>
Tue, 10 Apr 2012 00:00:00 +0900
http://d.palmtb.net/2012/04/08/235959.html http://d.palmtb.net/2012/04/08/235959.html <![CDATA[おまめちゃん、初物づくし。]]> おまめちゃん、初物づくし。

今日はおまめちゃんの初物づくしの一日でした。

まず、大國魂神社が自宅から程近いところにあり、産後1ヶ月も経過したこともあったので親子三人でお参りに行ってきました。桜がとても綺麗でした。ちゃんとベビードレス&着物来て、というのはお食い初めのころに実家の近くの神社で行う予定なので、お宮参りというよりは普通にお参りしてきただけの感じですね。

大國魂神社の桜。

ちなみにおまめちゃんは自宅ではよくグズりおしっこでもうんちでも、おっぱいでもなく、抱っこしても泣き止まないということもままあるのですが、外出すると大人しくしています。というか大抵寝ています。自宅でも寝ていてくれると助かるのですが、泣くことが彼女の仕事であり、コミュニケーションの手段なので、こればかりはワシたち夫婦が勉強するしかありませんね。

2つめはお宮参りの帰り道のお花見。ヨメさんが弁当を作ってくれていたので家の近所の公園に寄ってお花見、しようとしたのですが思いの外肌寒く、公園のベンチではおくるみを二重にしていたといえ、おまめちゃんが寒そうで可哀想なのと、お花見したいというのは親のエゴでしか無いよね、ということで車の中で弁当を食べることにしました。来年はおまめちゃん連れて家族皆でお花見したいですね。

そして3つめは、お風呂デビュー。昨日まではヨメさんが沐浴していたのですが、本日初めて一緒にお風呂に入りました。一度沐浴させていたので、お風呂入れるのはさほど苦労はしませんでしたが、シャワーヘッドからのお湯の出し方やシャワーや湯船のお湯の温度など、結構微妙な違いで嫌がったりするのは難しいですね。沐浴よりは上がった後に寒さで震えてはいなかったので、取り敢えず及第点でしょうか。

]]>
Sun, 08 Apr 2012 00:00:00 +0900
http://d.palmtb.net/2012/04/08/003000.html http://d.palmtb.net/2012/04/08/003000.html <![CDATA[iPXEでサーバの機器情報を取得する。]]> iPXEでサーバの機器情報を取得する。

新しい機器をラックマウントする際には、納品時にメーカー、型番、シリアル番号を控え、ラック位置、棚位置とひもづける必要があると思います。この手の管理作業は台数が増えるほど手間が増えるので手作業ではやりたくないことの一つです。どの型番のどのスペックの機器にどのOSをインストールするか、という観点ではシリアル番号での識別が必要です。実際にPXEブートでOSをインストールするには、シリアル番号に紐づいたMACアドレスを指定してやる必要があります。MACアドレスを指定するためにMACアドレスを控えるにはBIOSの設定画面などからMACアドレスを確認し控えるというアナログなことをやるかもしれませんが、これは怠惰な我々にとっては面倒過ぎて死ねますね。

PXEブートを使っている場合、iPXEを使うとこの面倒な作業をなくすことができます。PXEブートでインストールするには、通常はDHCPでIPアドレスを割り当て、TFTPサーバからブートイメージをダウンロードし、PreseedやKickstartなどでOSをインストールすると思います。DHCP/TFTPサーバとしてdnsmasqを使用していることを前提とすると、OSのインストール用のイメージをダウンロードさせるにはdnsmasqでMACアドレスが登録されていることを必要条件とします。一方、MACアドレスが未登録の場合にはiPXEを使うようにしてやれば、機器情報を取得することができます。

iPXEスクリプトで取得できる情報。

ハードウェアの構成情報として、資産管理の観点も含めて必要な情報としては、シリアル番号、MACアドレス、メーカー、機器タイプでしょう。最低限シリアル番号とMACアドレスがあれば問題ないかもしれませんが、シリアル番号をキーにして別でメーカー、機器タイプを記述した管理表を作るのも面倒です。これらの情報を取得するには、次のようなiPXEスクリプトを用意します。

#!ipxe

dhcp
chain http://${next-server}:9393/inventory/${serial:uristring}/${mac}/${manufacturer:uristring}/${product:uristring}

chainで渡されたURL の各パラメータは次の通りです。iPXEクライアントである各マシンの情報がこのパラメータに埋め込まれた形で、各マシンから${next-server}で指定されたWebサーバ(TFTPサーバ)にアクセスされます。

  • ${serial:urlstring}:シリアル番号(string), 21byte
  • ${mac}:MACアドレス(hex)
  • ${manufacturer:uristring}:メーカー(string), 33byte
  • ${product:uristring}:機器型番(string), 31byte

string型のパラメータはそれぞれ固定長なので例えば次のようなコードでログに出力すると

f.puts "#{Time.now} SN: #{params[:sn]} MAC: #{params[:mac]} Manu: #{params[:manufacturer]} prod: #{params[:product]}"

下記のように余計な空白が残ります。

Thu Apr 05 17:24:59 +0900 2012 SN: MA6S000000           MAC: 00:26:2d:01:01:01 Manu: FUJITSU-SV                       prod: PRIMERGY RX200 S6

不要な半角空白文字は次のようにトリミングしてやれば良いでしょう。

sn = params[:sn].gsub(/\s+$/, '')
mac = params[:mac].gsub(/\s+/, '')
manufacturer = params[:manufacturer].gsub(/\s+$/, '')
product = params[:product].gsub(/\s+$/, '')
Fri Apr 06 18:37:27 +0900 2012 SN: MA6S000000 MAC: 00:26:2d:01:01:01

なお、iPXEスクリプトのその他の設定項目については Upstreamのドキュメント を参照ください。

iPXEスクリプトに誘導する。

iPXEスクリプトをロードさせるには、DHCPでIPアドレスを割り当て、TFTPサーバからiPXE用のブートイメージをダウンロードできるようにします。dnsmasqを使う場合、下記のように設定します。

enable-tftp
tftp-root=/var/lib/pxelerator/tftpboot
dhcp-boot=net:#known,undionly.kpxe
dhcp-match=gpxe,175   # gPXE sends a 175 option.
dhcp-boot=net:gpxe,http://${next-server}:9393/SNreg.ipxe

各項目は次の通りです。

最新バージョンのdnsmasqでは下記のように設定するのが良いでしょう。 [2]

enable-tftp
tftp-root=/var/lib/pxelerator/tftpboot
dhcp-boot=tag:!known,undionly.kpxe
dhcp-match=set:gpxe,175   # gPXE sends a 175 option.
dhcp-boot=tag:gpxe,http://${next-server}:9393/SNreg.ipxe

iPXEスクリプトでchainで渡されたURLには、は何らかのWebアプリケーションサーバで処理すれば良いでしょう。自分たちの環境では t9mdさん が開発した pxelerator というリモートインストールツールの中でこれらの仕組みを使っており、パラメータの処理はRubyの軽量WebフレームワークSinatraで行っています。 [3]

最低限必要な作業。

シリアル番号、MACアドレス、メーカー、機器タイプは取得できるようになりました。ラック位置、棚位置は別の方法で取得する必要があります。これは、例えばラック位置や棚位置によって使用するスイッチ、スイッチポートをルールづけしておけば、スイッチで接続している対向機器のMACアドレスを収集すればMACアドレスをキーにして先ほどの情報と突合せできるでしょう。また、ラックマウントでの物理作業を除くと、最低限シリアル番号は控えておく必要があります。これらを取得できれば、rackdiagなどを使えばラック構成図の自動生成もできなくはないでしょう。

しかしこれでもまだ機器毎に任意のOSをインストールすることはできません。そこでpxeleratorのような自動インストール管理ツールの出番です。pxeleratorではMACアドレスが分かればインストールする機器毎にPXEブートでTFTPで渡すbootmenuとKickStartファイルを動的に渡すことができます。MACアドレス毎にインストールの許可不許可を与えるためにMACアドレスとホスト名の対を記述しファイルをdhcp-hostsfileで指定しています。このファイルへのMACアドレスの自動登録の話を次回行う予定です。

[1]現在はUbuntu 10.04 LTSを使用しており、このdnsmasqのバージョンは2.52なのでちょうど古い設定方法なのですね。
[2]下位互換の関係で古い形式でも大丈夫です。
[3]Githubで公開されているのはかなり初期のバージョンなので今とだいぶ違いますし、今回の話の機能はもちろんありません。
]]>
Sun, 08 Apr 2012 00:00:00 +0900
http://d.palmtb.net/2012/04/04/070000.html http://d.palmtb.net/2012/04/04/070000.html <![CDATA[一ヶ月検診、そして風邪をひいていた事実。]]> 一ヶ月検診、そして風邪をひいていた事実。

今日はおまめちゃんの一ヶ月検診でした。身長は56.4cm, 体重は4,640gでした。誕生時からそれぞれ+4.4cm, +926gの増加です。順調に育っているのですが、髪の毛の伸び具合は、同時期に生まれた子よりも遅いみたいです。女の子なのに…。ヨメさんが髪の毛伸びるのが遅いらしいので、そこは母親になのかもしれません。どっちに似ている、といえば低気圧で体調が悪くなるのはワシに似てしまったのか、昨日の春の嵐の前日の一昨日にめっちゃグズっていたらしく、低気圧になってしまった昨日は割とおとなしかったとのこと。似てほしくない変なところばかり、親に似てしまうとは…。

http://distilleryimage9.instagram.com/b3d78edc7e4811e18bb812313804a181_7.jpg

似てほしくないといえば、今日の一ヶ月検診でおまめちゃんは風邪をひいていると診断されてしまいました。そしてワシも今朝渋谷駅降りて改札駅を出たあたりからめまいがして、一日ダルい感じ。そんなところも似てしまったのか、と思ったのですが、おまめちゃんは先週の土曜あたりから泣き声がハスキーボイスになっているので、おまめちゃんが先に風邪ひいて、それをワシがもらったのかもしれません。が、ヨメさんには、ワシの場合は休んでないし疲れがたまっているだけでしょ、と言われました。

おまめちゃんと一緒に今日は早く寝ることにします…。

]]>
Wed, 04 Apr 2012 00:00:00 +0900
http://d.palmtb.net/2012/04/03/235959.html http://d.palmtb.net/2012/04/03/235959.html <![CDATA[tinkererでblockdiagを使う。]]> tinkererでblockdiagを使う。

tinkererはSphinxを使っているので、blockdiagを組み込むのも簡単です。 blockdiagの公式ドキュメント にあるとおり、conf.pyのextensionsに shinxcontrib.blockdiag を追記し、blockdiag_fontpathでフォントパスを指定します。

diff --git a/conf.py b/conf.py
index e1fab6c..9e5a79f 100644
--- a/conf.py
+++ b/conf.py
@@ -47,7 +47,7 @@ rss_service = None
 # **************************************************************

 # Add other Sphinx extensions here
-extensions = ['tinkerer.ext.blog', 'tinkerer.ext.disqus']
+extensions = ['tinkerer.ext.blog', 'tinkerer.ext.disqus', 'sphinxcontrib.blockdiag']

 # Add other template paths here
 templates_path = ['_templates']
@@ -66,6 +66,8 @@ html_sidebars = {
     "**": ["recent.html", "searchbox.html"]
 }

+blockdiag_fontpath = '/usr/share/fonts/truetype/vlgothic/VL-PGothic-Regular.ttf'
+
 # **************************************************************
 # Do not modify below lines as the values are required by
 # Tinkerer to play nice with Sphinx

あとは、tinkerコマンドでブログ用のreSTファイルを生成し、

$ tinker -p 235959
New post created as '/home/user/blog/2012/04/03/235959.rst'

blockdiagのコードを記述します。試しに公式ドキュメントにあるサンプルを記載してみました。

Name Description
A browsers in each client
B web server
C database server

最後にtinkerコマンドでビルドすれば完了です。

$ tinker -b -q
]]>
Tue, 03 Apr 2012 00:00:00 +0900
http://d.palmtb.net/2012/04/01/235959.html http://d.palmtb.net/2012/04/01/235959.html <![CDATA[1ヶ月経ちました。]]> 1ヶ月経ちました。

世の中はエイプリルフールネタで今年も盛り上がっていたみたいですが、我が家では今日でちょうどおまめちゃんが生まれて一ヶ月記念で盛り上がっていました。午前中はワシが家の掃除をしている間、ヨメさんと一緒にヨメさんの実家に行き、遊びに来ていたヨメさんの親戚に可愛がられていたようです。夕方にはワシの母が、妹のお宮参り&七五三のときに使った着物を持ってきてくれたので、記念写真を撮りました。今週末には親子3人で近所の氏神様にお参り行って、親を交えたお宮参りはもう少し暖かくなってから実家の近くの神社に行く予定です。

../../../_images/omame-20120401.jpg ../../../_images/omame-20120401-kimono.jpg ]]>
Sun, 01 Apr 2012 00:00:00 +0900
http://d.palmtb.net/2012/03/31/235959.html http://d.palmtb.net/2012/03/31/235959.html <![CDATA[GEEK DAY TOKYOに参加しました。]]> GEEK DAY TOKYOに参加しました。

前職で一緒に働いていた nittyan に何か発表してほしいと依頼されたので、 GEEK DAY TOKYO でネタを発表してきました。 ”こまちゃん監視システムをPicasaからCouchDBに切り替えた。” のような軽めの内容でということだったのですが、1週間くらい前まで何も考えていませんでした。おまめちゃんで手一杯だったのが正直なところです。で以前からブログの移行を考えていたことや、3月にはてブのトラッキング情報取得の騒動と、4/1の前日ということでちょうど良いタイミングだな、ということではてなダイアリーからの移行についてをネタにしました。発表の資料は slideshare に公開してあります。ヨメさんの用事や車の6ヶ月点検が終わってから夕方からの参加でした。いつも参加している勉強会とはちょっと趣きも、発表内容の対象も異なる勉強会で、印象的にはOSCの懇親会でのLTみたいな感じでした。ここ数年懇親会参加してませんけど。:p

移行の技術的な理由は資料に書いてありますので、ここではGithubで公開した 移行ツール についての補足をしておきます。使い方は README.md に記載してあるので、ここでは書いていないことをば。Movable Type形式のエクスポートデータを入力ファイルにしてmt2rest.pyを実行すると、カレントディレクトリ下にoutディレクトリを作成し、その下にtinkererで生成するYYYY/MM/DD形式でのディレクトリを作ります。そしてその下に、はてなダイアリーでのエントリ毎( ‘*’ 一つで始まるエントリ)にreSTファイルを生成します。tinkererではreSTファイルのファイル名は、 tinkerer -p POST のように -p オプションで指定したブログタイトルがファイル名 title.rst のようになりますが、そのままブログのタイトルを使ってしまうと、ファイル名が日本語名になってしまうので不都合です。なので、エントリの公開時間を使い、 HHMMDD.rst となるようにしています。このエントリの名前は、master.rst.tmpに、最新の日付が上になるようにソートして記述しています。master.rstの並び順は、ブログでの表示順に影響します。一度生成したoutディレクトリ以下のreSTファイルを使って、tinkerコマンドでHTMLを生成すると、最初の一回だけRSSが生成されますが、その後reSTファイルを編集してHTMLを再発行してもRSSには再発行されません。現状、mt2rest.pyでは部分的にできていないことがありますが、機能実装後やバグ修正後にmt2rest.pyでreSTファイルを再生成し、HTMLを再発行してもRSSは再発行されませんので、エクスポートデータだけ保存しておけば、機能未実装分で意図通りに表示されない項目があっても個別に手で編集しなおす必要はありません。

なお、GEEK DAY TOKYOで発表後に、画像が表示されない件については既に修正済みです。まだ未実装部分やバグがあるので、はてなダイアリーからの移行を考えている方は、バグ報告及びパッチプリーズ。

]]>
Sat, 31 Mar 2012 00:00:00 +0900
http://d.palmtb.net/2012/03/31/073524.html http://d.palmtb.net/2012/03/31/073524.html <![CDATA[ブログ移行しました。]]> ブログ移行しました。

色々思うところあって、ブログを移行することにしました。

こちらでの更新はこれが最後です。

移行先はこちらです。

http://d.palmtb.net/

コメントなど、まだ部分的に未設定のところもあったり、ちゃんと移行できていない箇所(画像も表示できてないな…。)も所々ありますがはてダの記事&コメントは基本的に全て移行済みです。

はてなさん、今までありがとうございました。

]]>
Sat, 31 Mar 2012 00:00:00 +0900
http://d.palmtb.net/2012/03/30/000426.html http://d.palmtb.net/2012/03/30/000426.html <![CDATA[グズりにやられる。]]> グズりにやられる。

この2週くらい、おまめちゃんのグズりが酷くなり何をしても泣き止まないので泣き止むまで=寝付くまで抱っこしていたりします。こっちが先に眠くなってしまうこと多々。帰宅してからヨメさんと話をすると、一日グズってばかりだった、という日がほぼ毎日。帰宅してから寝付くまでの数時間で音を上げているワシに比べ、ヨメさんすごいなぁと。感謝。

おまめちゃんの泣き声は耳塞いでも空気越しの骨伝導で聞こえる…。

]]>
Fri, 30 Mar 2012 00:00:00 +0900
http://d.palmtb.net/2012/03/29/023654.html http://d.palmtb.net/2012/03/29/023654.html <![CDATA[一回お休み。]]> 一回お休み。

ちょっと今日は余裕が無いのでネタなしです。

]]>
Thu, 29 Mar 2012 00:00:00 +0900
http://d.palmtb.net/2012/03/28/195317.html http://d.palmtb.net/2012/03/28/195317.html <![CDATA[pystacheで使ってはいけない文字列。]]> pystacheで使ってはいけない文字列。

pystacheは、ヒゲテンプレートエンジンMustacheのPython版なのですが、あるファイルをpystacheを使うとコケる、という問題に遭遇しました。

$ python mt2rest.py data/mkouhei.txt
Traceback (most recent call last):
  File "mt2rest.py", line 201, in <module>
    print(o.render().encode('utf-8'))
  File "/usr/lib/python2.7/dist-packages/pystache/view.py", line 110, in render
    return Template(template, self).render(encoding=encoding)
  File "/usr/lib/python2.7/dist-packages/pystache/template.py", line 42, in render
    template = self.render_sections(template, context)
  File "/usr/lib/python2.7/dist-packages/pystache/template.py", line 78, in render_sections
    insides.append(self.render(inner, item))
  File "/usr/lib/python2.7/dist-packages/pystache/template.py", line 42, in render
    template = self.render_sections(template, context)
  File "/usr/lib/python2.7/dist-packages/pystache/template.py", line 78, in render_sections
    insides.append(self.render(inner, item))
  File "/usr/lib/python2.7/dist-packages/pystache/template.py", line 43, in render
    result = self.render_tags(template, context)
  File "/usr/lib/python2.7/dist-packages/pystache/template.py", line 96, in render_tags
    func = modifiers[tag_type]
KeyError: u'#'

入力元のファイルは、はてなダイアリーのエクスポートデータだったのですが、コケていたのは この記事 。原因は”{{“と”}}”でした。納得。そりゃエスケープしないとアカンすな。

]]>
Wed, 28 Mar 2012 00:00:00 +0900
http://d.palmtb.net/2012/03/27/154557.html http://d.palmtb.net/2012/03/27/154557.html <![CDATA[TonicDNSでレコードの一括登録・削除するためのJSONを生成する。]]> TonicDNSでレコードの一括登録・削除するためのJSONを生成する。

TonicDNSを使う場合、APIに投げるためのJSONの生成が面倒なので、 半角スペースまたはタブ区切りのテキストファイルからJSONを生成するスクリプト を書きました。例えば、

# name type content ttl priority
test0.example.org A 10.10.10.10 86400
test1.example.org A 10.10.10.11 86400
test2.example.org A 10.10.10.12 86400
example.org MX mx.example.org 86400 0
example.org MX mx2.example.org 86400 10
mx.example.org A 10.10.11.10 3600
mx2.example.org A               10.10.11.10 3600

と記述したファイル(example.org.txt)を引数で指定すると、

$ python json-convert.py example.org.txt
{"records": [
{"content": "10.10.10.10", "priority": null, "type": "A", "name": "test0.example.org", "ttl": "86400"},
{"content": "10.10.10.11", "priority": null, "type": "A", "name": "test1.example.org", "ttl": "86400"},
{"content": "10.10.10.12", "priority": null, "type": "A", "name": "test2.example.org", "ttl": "86400"},
{"content": "mx.example.org", "priority": "0", "type": "MX", "name": "example.org", "ttl": "86400"},
{"content": "mx2.example.org", "priority": "10", "type": "MX", "name": "example.org", "ttl": "86400"},
{"content": "10.10.11.10", "priority": null, "type": "A", "name": "mx.example.org", "ttl": "3600"},
{"content": "10.10.11.10", "priority": null, "type": "A", "name": "mx2.example.org", "ttl": "3600"}],
"name": "example.org"}

のようにTonicDNSのレコード登録および削除用のフォーマットを生成します。

いつものように GitHubで公開 しています。

]]>
Tue, 27 Mar 2012 00:00:00 +0900
http://d.palmtb.net/2012/03/26/011215.html http://d.palmtb.net/2012/03/26/011215.html <![CDATA[iCloudは非同期処理で共有するのか。]]> iCloudは非同期処理で共有するのか。

昨日実家に帰った際、おまめちゃんの写真を共有するために父にあげたiPad2のiCloudに自分のアカウントの設定とフォトストリームの設定を行ったのですが、iPhoneで写真を撮っても父のiPad2のフォトストリームには反映されない、という問題に遭遇しました。昨日はそのまま帰ってきたのですが、自宅のiPadにはテスト用に撮った写真がちゃんと同期されていました。もしかして非同期なんじゃ?と思っていたら、やはり今日になって父からおまめちゃんの写真が見られたよ、というメールが。予想通り非同期処理だったのですねぇ。

]]>
Mon, 26 Mar 2012 00:00:00 +0900
http://d.palmtb.net/2012/03/25/005032.html http://d.palmtb.net/2012/03/25/005032.html <![CDATA[おまめの沐浴がなっとらん。]]> おまめの沐浴がなっとらん。

という言い方はされてないのですが、あれじゃおまめちゃんが可哀想だ、と言われました。誰にかというと両親です。おまめちゃん誕生後、実家に帰っていなかったので今日久々に帰ることになったため、おまめちゃんの沐浴撮影したデジカムやデジカメとかもろもろ持って帰って見せたらそんな感じで指摘されました。他にもいろいろ指摘されました。子育てはまだまだ手探り状態で毎日が勉強ですね。

]]>
Sun, 25 Mar 2012 00:00:00 +0900
http://d.palmtb.net/2012/03/24/004703.html http://d.palmtb.net/2012/03/24/004703.html <![CDATA[はてダのデータエクスポートの形式を調べてみた。]]> はてダのデータエクスポートの形式を調べてみた。

はてなダイアリーから移行しようと前々から思っていた [1] のですが、最近の騒動もありちょうど良い機会なので、reST形式で記述できるブログに移行することにしました。 先日tinkererをBTSした のもこれ絡みであったりします。今回のエントリはその下調べについてお話です。

エクスポートの方法。

はてなダイアリーのユーザならもちろん知っていると思うのですがおさらいです。画面上部のメニューにある[管理]リンクから、画面遷移後の左のメニュー[データ管理]をクリックすると、[ブログのエクスポート]というセクションに、”はてなの日記データ形式”、”Movable Type形式”、”CSV形式”が選べます。はてなの日記データ形式は、はてな記法で書いたブログエントリがXMLで

<?xml version="1.0" encoding="UTF-8"?>
<diary>
<day date="2006-12-23" title="">
<body>
*1169835868*[生活]せっかく天気の良い土曜なのに、起きたら14時半。
うちは東向きなので、もう洗濯物も布団も干す意味ない…。明日はちゃんと起きよう。

*1169835977*[駄文]Blogなぞ使ってみることにした。
Blogなんぞ使うつもりは今までまったく無かったのだが、以下のような理由で使ってみることにした。

+最近自宅サーバのサイト「 `ペンギンと愉快な機械たち <http://www.palmtb.net/>`_ 」のFrontPageに駄文を書き連ねることが多くなった。(でも、いつ書いたのか分からないんだよな)
+社内研究会でBlogを使うようになった。(インターネットでは無かった、ということ。社内ブログはMovableType Enterprise Edition)
+Google先生のBloggerが正式にリリースされた

とまぁ、こんな所かな。手順書とかトラブるなどの技術関連のまとめた文書は今までどおり本家に記載していくので、まぁ、棲み分けはできるかと。
</body>
</day>
(snip)

という形式になっています。一方、Movable Type形式では、

AUTHOR: mkouhei
TITLE: せっかく天気の良い土曜なのに、起きたら14時半。
STATUS: Publish
ALLOW COMMENTS: 1
CONVERT BREAKS: 1
ALLOW PINGS: 1
DATE: 12/23/2006 03:24:28 AM
CATEGORY: 生活
-----
BODY:

                <div class="section">
                        <p>うちは東向きなので、もう洗濯物も布団も干す意味ない…。明日はちゃんと起きよう。</p>
                </div>

-----
EXTENDED BODY:

-----
EXCERPT:

-----
KEYWORDS:
-----

--------

という感じになっています。はてなダイアリ独自のフォーマットを解析するよりも、Movable Type形式を解析する方が汎用性があるのでこちらを解析することにしました。ちなみにCSV形式の場合は、ブログエントリの本文がMovable Type形式と同じHTML形式になっています。

Movable Type形式での1エントリあたりのフォーマット

Movable Type形式でエクスポートすると、1エントリが次のようになっています。ここでのエントリとは、はてな記法の1個のアスタリスク”*”で始まるブログエントリです。

  • 同じ日に複数エントリがある場合は、別のエントリとして区切られます
  • メタ情報は1つのkeyが1行に記述されます。keyとvalueの区切りは”: “になっています
  • BODYの中はHTMLで記述されています
  • エントリの終わりは、8個のハイフン”——–”になっています

1エントリのフォーマットは次のようになります。

AUTHOR,TITLE,STATUS,ALLOW COMMENTS,CONVERT BREAKS,ALLOW PINGS,DATE,CATEGORY (←実際にはこれらが一行ずつ記載されます)
-----
BODY
(エントリ本文がHTMLで記述)
-----
EXTENDED BODY:
-----
EXCERPT:
-----
KEYWORDS: (以上、3つのキーは実際には使われません)
-----
(コメントがある場合のみ)
COMMENT,AUTHOR,EMAIL,IP,URL,DATE,コメント本文
-----
(複数コメントがある場合)
COMMENT,AUTHOR,EMAIL,IP,URL,DATE,コメント本文
-------- (←エントリの区切り)

メタ情報のkey

  • AUTHOR: はてなID
  • TITLE: はてな記法で1アスタリスク(*)で始まるタイトル
  • STATUS: Publish ←Publishしかないので、公開済みのエントリだけがエクスポートされる
  • ALLOW COMMENTS: 1
  • CONVERT BREAKS: 1
  • ALLOW PINGS: 1 ←以上3つのキーは全てのエントリで1。特に今回は使わないので無視
  • DATE: MM/DD/YYYY HH:dd:ss AM|PM 形式ののローカルタイム(JST)
  • CATEGORY: カテゴリで指定したカテゴリ。複数ある場合は複数行。

本文(BODY)のHTMLタグのフォーマット

エントリの本文の単位は

<div class="section">
</div>

になっています。一行エントリを書くと

<div class="section">
<p>本文ほげほげ</p>
</div>

となっているので、このsectionクラスのdiv要素内にエントリの本文が記述されるワケですね。

サブセクション(**)を使った場合のフォーマット

h4を使い、同じdiv要素の中に記述されます。

<div class="section">
<p></p>
<h4></h4>
<p></p>
</div>

コードブロックのフォーマット

pre要素を使っているだけです。

<pre class="syntax-highlight">
hoge
</pre>

コードブロックの中でのsyntax highlight

<span class="someclass">hoge</span>

という感じで、単語や記号ごとにspan要素で括られています。reSTのコードブロックに移行する上ではこのsyntax highlight用のspanは取り除く必要があります。なお、使われているclassは次の通りです。(以下はshの場合)

  • synComment
    • ナンバー(#)以降の文字列。
  • synStatement
    • ダブルクォーテーション(&#34;), start, stop, ||, exit,
  • synConstant
    • ダブルクォーテーションで括られた文字列, exit のあとのリターンコードの数字,
  • synSpecial
    • ハイフン(-)で始まる文字列(つまり、コマンドオプション), {, },

footnoteのフォーマット

注釈記号のフォーマットは下記のようになっています。

<span class="footnote"><a href="/hatenaID/#f1" name="fn1" title="footnoteの文章">*1</a>

また、footnote自体の記述位置とフォーマットは以下の通りです。

<div class="section">
</div>
<div class="footnote">
<p class="footnote"><a href="/hatenaID/#fn1" name="f1">*1</a>: footnoteの文章</p>
</div>

引用のフォーマット

<blockquote>
<p>文章</p>
</blockquote>

なのでHTMLでの標準的な記述方法ですね。

ブログパーツ

使用しているものによってまちまちですが、基本的にそのまま出力されています。例えば、 amazletでは

<div class="amazlet=box">hogehoge</div>

gistでは

<script src="https://gist.github.com/hoge.js?file=hoge.sh"></script>

という感じです。

次回に続く!

[1]一番の理由は広告です。基本毎日更新しないと最新のエントリのすぐ下に広告が表示されるようになったこと、スマホのブラウザでアクセスすると問答無用で広告が表示されることが移行することを決心した理由です。私のブログを購読して下さっている方がいらっしゃるのはもちろん嬉しいのですが、自分のブログは備忘録であったり日記であったりと書いている一番の理由は、自分のためであるというのがあるので、意図しない広告が表示されるのはとても鬱陶しいのですよね。
]]>
Sat, 24 Mar 2012 00:00:00 +0900
http://d.palmtb.net/2012/03/23/124932.html http://d.palmtb.net/2012/03/23/124932.html <![CDATA[upstartでプロセスを自動再起動させる。]]> upstartでプロセスを自動再起動させる。

おぷすたでインスタンスを作成した際に、自動でDNSにAレコードを登録するデーモンが(チーム内で作って)あるのですが、これが落ちていたためインスタンス起動時にレコードが登録されない、ということがありました。プロセスが死んだとしても勝手に再起動させればよいので、inittabかdaemontoolsかmonitあたりでやろうかなぁと考えていたら、

http://twitter.com/#!/matsuu/status/182835985619501057:

ああ、もうdaemontoolsいらないね。落ちた時の自動起動だけならupstartで実現できる。Debianは6以降、RHELも6以降は標準でインストールされてる。Amazon Linuxも標準装備。ただしGentooでは使えません。 12 hours ago

との matsuuさん のtweetでupstartでもできることを思い出し [1] 、Ubuntu上で稼働していたので、そうすることにしました。

設定ファイルの作成。

/etc/init/novadns.conf

# novadns
description     "novadns"

start on filesystem
stop on runlevel S

respawn
respawn limit 10 5
umask 022
oom never

pre-start script
    test -x /usr/sbin/novadns || { stop; exit 0; }
    test -e /etc/novadns/setting.ini || { stop; exit 0; }
    test -e /etc/novadns/logging.conf || { stop; exit 0; }
    test -c /dev/null || { stop; exit 0; }
end script
exec /usr/sbin/novadns

とこんな感じでファイルを作成します。

ジョブの制御。

ファイルを作成すると早速確認できます。

$ sudo initctl status novadns
novadns stop/waiting
$ ps -ef | grep novadns
20667    23885 23382  0 11:22 pts/1    00:00:00 grep --color=auto novadns

プロセス起動してみます。

$ sudo initctl start novadns
novadns start/running, process 23909
$ sudo initctl status novadns
novadns start/running, process 23909
$ ps -ef | grep novadns
root     23909     1  0 11:23 ?        00:00:00 python /usr/sbin/novadns
20667    23912 23382  0 11:23 pts/1    00:00:00 grep --color=auto novadns

プロセス停止してみます。

$ sudo initctl stop novadns
novadns stop/waiting
$ sudo initctl status novadns
novadns stop/waiting

プロセス殺しても自動で再起動するか確認してみます。

$ sudo initctl start novadns
novadns start/running, process 23924
$ sudo kill 23924
$ sudo initctl status novadns
novadns start/running, process 23927

ということでOK。

[1]一昨年2回も Debian勉強会でUpstartネタやっていたのに忘れてました…。
]]>
Fri, 23 Mar 2012 00:00:00 +0900
http://d.palmtb.net/2012/03/22/140147.html http://d.palmtb.net/2012/03/22/140147.html <![CDATA[VRRP構成のVyattaでMapping NATを行う。]]> VRRP構成のVyattaでMapping NATを行う。

VRRP構成のVyattaでNAT Statuful failoverで192.168.0.0/24→10.0.0.0/24とか192.168.1.0/24→10.0.1.0/24にMapping NATを行う場合、下記のようなNATの設定を行います。Vyattaの公式ドキュメントではMapping NATは双方向Source NATにする方法が掲載されているので、typeはdestinationではなくsourceになっています。

service {
    conntrack-sync {
        event-listen-queue-size 8
        failover-mechanism {
            vrrp {
                sync-group syncgroup0
            }
        }
        interface eth0.101
        mcast-group 225.0.0.50
        sync-queue-size 1
    }
    nat {
        rule 1 {
            outbound-interface eth1.1
            outside-address {
                address 10.0.0.0/24
            }
            source {
                address 192.168.0.0/24
            }
            type source
        }
        rule 2 {
            outbound-interface eth1.2
            outside-address {
                address 10.0.1.0/24
            }
            source {
                address 192.168.1.0/24
            }
            type source
        }
        rule 11 {
            destination {
                address 10.0.0.0/24
            }
            inbound-interface eth1.1
            inside-address {
                address 192.168.0.0/24
            }
            type destination
        }
        rule 12 {
            destination {
                address 10.0.1.0/24
            }
            inbound-interface eth1.2
            inside-address {
                address 192.168.1.0/24
            }
            type destination
        }
    }
(snip)
}

ところでNAT用のIPアドレスはどう設定するのかまでは書かれていません。1台でMapping NATを使う場合は、今回の用にVLANを使っているならvifの下に直接addressで設定すれば良いのですが、VRRP構成ではそれやると行きのパケットは到達しても戻りのパケットがスイッチのARPテーブルの状態によってはちゃんとmasterのVyattaを通過するものと、backupのVyattaのI/Fに到達してしまい、行きのパケットが無くてVyattaで破棄されてしまうものとが発生します。運が良ければ疎通があり、悪ければ疎通できない、という状態です。

VRRPを使う場合、virtual-addressを使い、仮想IPアドレスとして仮想ルータに設定すれば良いのですが、Vyatta Core 6.3時点の仕様では、vrrp-groupで設定するVRID毎に20 VIPしか使えません。

# set interfaces ethernet eth0 vrrp vrrp-group 1 virtual-address
Possible completions:
  <x.x.x.x>     Virtual IP address (up to 20 per group)
  <x.x.x.x/x>   Virtual IP address with prefix (up to 20 per group)

[edit]

さて困りました。VRRPでMapping NATを使いたい場合、20個までしか1対1でマッピングできないということでしょうか?いんや、そんなこたぁ無い。20個のVIP毎にVRIDを新しく設定すればこの問題を回避できます。ただ、この問題点、VRIDを枯渇する可能性があります。VRIDはRFC 3768で、1-255の整数しか使えません。

http://www.ietf.org/rfc/rfc3768.txt

5.3.3. Virtual Rtr ID (VRID)

The Virtual Router Identifier (VRID) field identifies the virtual

router this packet is reporting status for. Configurable item in the

range 1-255 (decimal). There is no default.

なので、サブネットマスクの値が小さいほど枯渇するという問題は回避できません。が、そもそもそんなにNATすることは無いでしょということで、24bitのサブネットマスクのネットワークを2つマッピングできることは確認済みなので、20VIP毎にVRIDを作るスクリプトをGistで公開しておきました。