iCloudは非同期処理で共有するのか。

昨日実家に帰った際、おまめちゃんの写真を共有するために父にあげたiPad2のiCloudに自分のアカウントの設定とフォトストリームの設定を行ったのですが、iPhoneで写真を撮っても父のiPad2のフォトストリームには反映されない、という問題に遭遇しました。昨日はそのまま帰ってきたのですが、自宅のiPadにはテスト用に撮った写真がちゃんと同期されていました。もしかして非同期なんじゃ?と思っていたら、やはり今日になって父からおまめちゃんの写真が見られたよ、というメールが。予想通り非同期処理だったのですねぇ。

おまめの沐浴がなっとらん。

という言い方はされてないのですが、あれじゃおまめちゃんが可哀想だ、と言われました。誰にかというと両親です。おまめちゃん誕生後、実家に帰っていなかったので今日久々に帰ることになったため、おまめちゃんの沐浴撮影したデジカムやデジカメとかもろもろ持って帰って見せたらそんな感じで指摘されました。他にもいろいろ指摘されました。子育てはまだまだ手探り状態で毎日が勉強ですね。

はてダのデータエクスポートの形式を調べてみた。

はてなダイアリーから移行しようと前々から思っていた 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

    • ダブルクォーテーション("), 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

一番の理由は広告です。基本毎日更新しないと最新のエントリのすぐ下に広告が表示されるようになったこと、スマホのブラウザでアクセスすると問答無用で広告が表示されることが移行することを決心した理由です。私のブログを購読して下さっている方がいらっしゃるのはもちろん嬉しいのですが、自分のブログは備忘録であったり日記であったりと書いている一番の理由は、自分のためであるというのがあるので、意図しない広告が表示されるのはとても鬱陶しいのですよね。

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ネタやっていたのに忘れてました…。

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で公開しておきました。