JINS Moisture®を2ヶ月使ってみた。

JINS PCはニュース記事にもなったので有名ですが、JINS Moisture®については知っている人は割と少ないと思います。そこで2ヶ月ほど使用してみたので、使用感についてレビューしてみました。

https://lh5.googleusercontent.com/-vYxvDBHTaN4/TwJtRzb3xoI/AAAAAAADZgk/c4-D7Q9sey8/s559-c-k/02%2B-%2B1

きっかけはqpstudy

松鵜さん がqpstudyでやった JINS PCを使ってみたネタLTのスライド を見て 1 、値段も安いのでJINS PCを試してみようと思いました。

元・大痔主であるだけでなく、ドライアイ持ちでもあるのです。

7、8年前からドライアイになり、市川に住んでいたときは、行徳駅にある セントラル眼科 に症状緩和を目的に眼科通いしていました 2 。当然平日は通えず、土曜も毎週行けるわけではなかったので、2、3ヶ月分の目薬を処方してもらっていました。この病院はとてもよかったのですが、現在の多摩方面に引っ越してからは、近所および通勤経路で良い眼科が無かったこともあり、市販薬でl-メントールの入っていない目薬でごまかすようになりました 3 。ドライアイの原因は、モニタを見るときにまばたきが減っていることが大きいので、JINS PCが気休めでもいいので使ってみよう、と思ったわけです。

JINS PCではなくJINS Moistureにした理由。

新宿ミロードのJINSでJINS PCを試したところ、ほとんど効果が分からず、ほんとに気休めになりそうだったので微妙すぎるなぁと思ったのですが、同じ棚に JINS Moisture がありました。JINS PCで謳っている機能より、目を保湿する、という謳い文句は私の悩みにはうってつけでした。フレームの側面に、水を入れるウォーター・ポケットがあり、フレーム自体が目を覆うのでこれは効果が期待できそうだと。というわけで、JINS PCより若干高かったものの、何色か出ているのに無色のモデル一つしか無かったこともあり即買いしました。ちなみに、JINS PCと違い、度付きレンズに変更できますが、モニタを見るときには不要なので度付きにはしていません。

で、使ってみた感想。

感触的には「微妙」です(わら。明らかに目の乾燥が減ったなぁ、という実感は感じにくいですね。ただ、目の乾燥が辛すぎて目薬を指さないとやってられん、という頻度が減った気がします。そういう意味では元々気休め程度の効果を求めてJINS PCを買いにいったことを考えれば、実感しづらいものの効果があるのかもしれません。あとはこれを通してモニタを見ると、若干赤みを帯びたように見えます。そのせいか普通にモニタを見るよりも若干目が疲れにくい、というか見るのが楽な感じがします。

使用上の不満やデメリットは二点あります。まず不満としては、左側のポケットの蒸発が早すぎること。右側は説明書にあった4時間程度は持つのですが、左側は2時間程度で完全に乾燥しきってしまいます。これは買った当初からだったのですが、寸法がおかしくて水漏れしているのではないかな、と思っています。騙し騙し使っていましたが、予備のポケットは、左右一つずつあるので、年明けから予備のものに交換して様子を見てみようと思います。

もう一つデメリットとしては、視野角が狭すぎるので、うっかり装着したまま移動したりすると、視界が狭くてとても不便です。 人間の視界は左右で200度程度ある と言われていますが、JINS Moistureは目の乾燥を防ぐために、花粉対策用眼鏡のように、目を覆うようになっています。つまり、テレビゲームの一人称視点に似たような視界ですね 4 。なので左右がまったく見えないのです。このままトイレに行って小便器や洗面台に立つと、隣に誰かが立っても誰かがいるのは分かるのですが顔がまったく見えません(わら。ああ、洗面台は鏡を見れば分かりますね、そうですね。用を足しているときに隣に誰かが立っても誰が立っているのかさっぱり分かりません。あー、なんか嫌な空気www。もっとも、これはPCを見る時だけに掛けるべきなので、まぁ席を立つときに眼鏡を外す習慣をつければ良いだけですね。普通にモニタを見ている時には視野が狭すぎる、ということはありません。

ちなみに、matsuuさんのJINS PCの所感にあった「肩凝り」については、私がもともと高校生の頃からひどい肩凝り持ちなので、そんな影響があるのかはっきり言って分かりません。

まとめ。

  • JINS PCについては matsuuさんの資料 を見てください。

  • ドライアイで悩んでいる人なら、気休めを試してみるには3,990円程度がリーズナブルだと思えるなら、騙されたと思って試してみると良いのではないでしょうか。

  • でも根本的にはドライアイが治るのが良いのですよね。涙点プラグ以外の治療法が発明されるといいなぁ。

1

最近qpstudyには参加してないのでslideshareの資料を見ただけです。

2

涙点プラグをする治療法もありますが、完治はしないことや人によっては副作用があることや、定期的な受診が結局必要であるということもあり、手術はしてません。

3

ドライアイには、l-メントール入りの目薬は逆効果だそうです。

4

ここ数年ゲームなんか全然やりませんが。

2011年の振り返りと2012年の抱負。

あけましておめでとうございます。

一年の計ということで、昨年の振り返りと今年のトピックや抱負について記録しておきます。

昨年の振り返り。

昨年の元日のブログにはこんなこと書いていました。

http://d.hatena.ne.jp/mkouhei/20110101

(略)その反省も踏まえて今年はいろんな意味で「動」の年にしたいなと思います。

で実際のところ、次のようなトピックがありました。

仕事もDebianでもプライベートでも激動の一年だったと思います。結婚した3年前よりも激しすぎますね。

今年のトピックや抱負。

  • プライベート

    • やはり2月中旬予定の第一子です。逆子もなおったので、このまま順調に母子ともに無事に産まれてほしいですね

    • ダイエット&酒絶ち継続

    • 親の健康が気になるようになってきたので、実家にこまめに帰るようにする

  • 仕事

    • 残業を極力しないでヨメさんの家事の負担を減らせるようにする生活に変える(忘れていたので追記)

    • 今月、来月の刊行の某誌に年末に所属チームで取材を受けたインタビュー記事が掲載、会社のブログへの寄稿 1

    • 今のチームのミッションの実現、運用自動化の推進

    • Debianパッケージメンテナンスも仕事に結びつけられるようにしていきたい

  • Debianなどの活動

といった感じです。やりたいことはいろいろあります。ただ、今年は子供のことだけでなく、他にもプライベートが一番優先度が高くなってきそうです。ちゃんと妻をフォローすることを大前提に、プライベートも仕事もDebianやCouchDBなどのFOSSの活動もできるように、貪欲にやっていきたいと思います。

ということで、どうぞ今年もよろしくお願いします。

1

つまり、転職先が公開される、というわけですね。

年賀状の宛名&挨拶状印刷用のPDF生成ツールを作りました。

新年あけたらしいですね、おめでとうございます。新年の挨拶、抱負 1 はまた別途ブログを書こうと思います。新年最初のブログは、今更ながら年賀状の宛名と挨拶状の印刷用のPDFを生成するツールを作った、というお話です。

何故作ることにしたのか。

昨年の年賀状までは、OOoのCalcで送り先のアドレス帳を管理し、Writerに差し込み印刷をしていました。今回もほとんど年賀状作成をする時間がなかったので、仕事納めの後から手をつけ始めたこともあり、OOo、というかLibreOfficeで同じように印刷するつもりでした。昨年同様、こまめの写真をGimpで加工し挨拶状の面をGimpで加工しようとしたところ、縦書きの文字列の再編集のやり方が分からない、という問題に遭遇しました。そしてもう一つ、もっと致命的な問題に遭遇しました。それは、LibreOfficeで差し込み印刷しようとしたところ、Calcのデータをデータストアとして指定できないことでした。

Gimpで挨拶状の面を作成するのは普段使わない分あまり慣れてないので結構大変なのですが、Writerでの宛名差し込み印刷はそれ以上に大変というかマンドイので、GUIを使うのはこまめの写真をGimpで加工するところだけでええわ、ということで、LaTeXで両面とも作成し、PDFを生成し、それを縁なし印刷することにしました。

挨拶状の面の生成。

これは、以前名刺をLaTeXで作成するようにしたこともあったので、Gimpで加工したこまめの写真をLaTeXで組版するだけの簡単なお仕事でした。

\documentclass[12pt]{jarticle}

\usepackage[dvipdfmx]{graphicx}
\usepackage{verbatim}
\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}

\begin{picture}(148,100)(0,0)
  \put(5,75){\fontsize{60pt}{0pt}{\mcfamily {謹賀新年}}}
  \put(10,60){\fontsize{12pt}{0pt}{\mcfamily 昨年中はお世話になり大変ありがとうございました。}}
  \put(6,55){\fontsize{12pt}{0pt}{\mcfamily 本年もどうぞよろしくお願いいたします。}}
  \put(6,50){\fontsize{12pt}{0pt}{\mcfamily 皆様のご健康とご多幸をお祈り申し上げます。}}
  \put(65,42){\fontsize{12pt}{0pt}{\ttfamily 平成二十四年 元日}}
  \put(10,21){\fontsize{12pt}{0pt}{\ttfamily かわいい にゃんこ}}
  \put(10,16){\fontsize{10pt}{0pt}{\ttfamily 〒000-0000}}
  \put(7,12){\fontsize{10pt}{0pt}{\ttfamily 都道府県市町村大字1丁目1番地}}
  \put(11,9){\fontsize{8pt}{0pt}{\ttfamily tel:}}
  \put(22,9){\fontsize{8pt}{0pt}{\ttfamily 00-0000-0000}}
  \put(7.5,6){\fontsize{8pt}{0pt}{\ttfamily email:}}
  \put(22,6){\fontsize{8pt}{0pt}{\ttfamily kitten@example.org}}
  \put(105,5){\includegraphics[width=35mm]{cat.jpg}}
  %% cat.jpg from http://animalphotos.info/a/2007/12/15/black-and-white-photo-of-a-forlorn-looking-kitten/
\end{picture}
\end{document}

“謹賀新年”の文字列を赤字にしようと、colorパッケージを使おうとするとこまちゃんの画像が表示されない、という問題に遭遇したため、そこだけ諦めて妥協したのは、ここだけの秘密です。

宛名の差し込み印刷をpystacheで実装。

アドレス帳の管理は、来年以降はヨメさんでもできるようにするために、とりあえずCSVで保存することにしました。CSCから宛名差し込み印刷するには、何らかのデータの埋め込みを行うテンプレートエンジンを使うのが楽なので、CouchDBのアプリを作るときによく使うヒゲテンプレートの mustache が、データを埋め込む文書を生成するのに向いています。なので、今回はそのPythonの実装であるpystacheをDebianパッケージにして、それでLaTeXを生成することにしました。pystacheはついでに ITP して、 mentorsにアップロード しておきました。

pystacheでは、CSVを読み込んだデータをLaTeX形式で標準出力するようにしました。それをEUC-JPに変換し、PDFにする、という形式です。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import pystache

texfile_name = 'atena.tex'
address_list = 'address.csv'

class Address(pystache.View):

    template_path = '.'
    template_name = 'address'
    template_encoding = 'utf-8'

    def datas(self):
        i=0
        datas = []
        for line in open(address_list, 'r'):
            # 0:flag, 1:name1, 2:name2, 3:address,
            # 4:no1, 5:no2, 6:no3, 7:no4, 8:no5, 9:no6, 10:no7
            list = line[:-1].split(',')
            if list[0] == "1":

                datas.append({
                    "name1":unicode(list[1], 'utf-8'),
                    "name2":unicode(list[2], 'utf-8'),
                    "address":unicode(list[3], 'utf-8'),
                    "no1":unicode(list[4], 'utf-8'),
                    "no2":unicode(list[5], 'utf-8'),
                    "no3":unicode(list[6], 'utf-8'),
                    "no4":unicode(list[7], 'utf-8'),
                    "no5":unicode(list[8], 'utf-8'),
                    "no6":unicode(list[9], 'utf-8'),
                    "no7":unicode(list[10], 'utf-8')
                    })
        return datas


str = Address().render()
print(str.encode('utf-8'))

テンプレートは下記のようなものを用意しました。

\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}

{{#datas}}

\begin{picture}(100,148)(0,0)
    \put(41,127){\fontsize{24pt}{0pt}{\mcfamily { {{no1}} } } }
    \put(47.5,127){\fontsize{24pt}{0pt}{\mcfamily { {{no2}} } } }
    \put(54,127){\fontsize{24pt}{0pt}{\mcfamily { {{no3}} } } }
    \put(62,127){\fontsize{24pt}{0pt}{\mcfamily { {{no4}} } } }
    \put(68.5,127){\fontsize{24pt}{0pt}{\mcfamily { {{no5}} } } }
    \put(75,127){\fontsize{24pt}{0pt}{\mcfamily { {{no6}} } } }
    \put(81.5,127){\fontsize{24pt}{0pt}{\mcfamily { {{no7}} } } }
    \put(70,25){\vbox{\hsize=9.5cm\tate\fontsize{18pt}{0pt}{\mcfamily { {{address}} } } } }
    \put(45,25){\vbox{\tate\fontsize{36pt}{0pt}{\mcfamily {{name1}}} } }
    {{#name2}}
    \put(30,-11){\vbox{\tate\fontsize{36pt}{0pt}{\mcfamily {{name2}}} } }
    {{/name2}}
\end{picture}

{{/datas}}

\end{document}

送り先が一人の時はname2を使いませんが、ご夫婦宛に送ったりする場合は、name2に名前だけ挿入する、という感じですね。

これで来年からめっちゃ楽になるで…。

これで来年からはGUIの操作は写真の加工だけになるので楽になりますね。来年の話をしたら鬼が笑うとか言いますが、今年の年賀状の作成を始めたのが結局30日からだったので投函できるのが明日起きてから(つまり元日投函)だと言うのは内緒です…。

なお、ソースコードは、下記で公開しています。

https://github.com/mkouhei/GenNenga

1

というか今回も昨年の振り返りやらなかったな…。

第83回東京エリアDebian勉強会参加。

今回 はスクウェア・エニックスさんのセミナールームをお借りしての開催でした。セミナールームの入り口手前には先日話題になった肉まんのでかいヌイグルミがありました。セミナールーム内以外は写真撮影禁止だったので、帰宅後にヨメに何で写真ないの?と言われてしまいましたが、しゃあないですね。

事前課題紹介では私のメンテナンスしているパッケージでの課題についての話ができたので、個人的には今回はそれが一番の成果でした。毎年恒例の一年の振り返りも行いました。昨年の予想が結構当たっていることを確認でき、来年、再来年の予想をみんなで出し合いました。今度の予想はどのくらいあっているのでしょうね。

メインセッションとしては、杉本さんによるquiltを使ったDebian GNU/kFreeBSDへのportingの話、今回の幹事も行ってくれた野島さんによる月刊Debhelperの話でした。quiltは最近ようやく使い方が分かってきたばかりなので、ちょうどホットな話題でした。今月のDebhelperは、一番根本となるdhコマンドについて、とても分かりやすい資料&説明でした。パッケージメンテナンスをしていてDebian Develperを目指していて、本日参加しなかった人は人生損してますね。

宴会は、 ステーキハウス TEXUS で、2100円飲み放題のコースでした。めっちゃ安い&旨かった!宴会でも良いディスカッションができ、充実した忘年会でした。

Vyatta専用コマンドを深堀りしてみた。

前回のエントリ で書いた通り、configureコマンドやsetコマンドはシェルスクリプトでは使えませんでした。単にVyattaを運用するだけなら、そのまま ${vyatta_sbindir}/my_* コマンドを使えば良いのでしょう。でも何故使えなかったのでしょうか。なんでそのままにしておくのは気持ち悪くて、夜もぐっすり眠れません。精神衛生上よろしくありませんね。

ですので、このモヤモヤを解消するため、オペレーションモード、設定モードについてそれぞれ調べてみました。

オペレーションモードの専用コマンドを探る。

まず、aliasコマンドを実行してみると分かります。

$ alias
alias add='_vyatta_op_run add'
alias clear='_vyatta_op_run clear'
alias clone='_vyatta_op_run clone'
alias configure='_vyatta_op_run configure'
alias connect='_vyatta_op_run connect'
alias copy='_vyatta_op_run copy'
alias debug='_vyatta_op_run debug'
alias delete='_vyatta_op_run delete'
alias disconnect='_vyatta_op_run disconnect'
alias format='_vyatta_op_run format'
alias generate='_vyatta_op_run generate'
alias init-floppy='_vyatta_op_run init-floppy'
alias install-image='_vyatta_op_run install-image'
alias install-system='_vyatta_op_run install-system'
alias ls='ls --color=auto'
alias no='_vyatta_op_run no'
alias ping='_vyatta_op_run ping'
alias ping6='_vyatta_op_run ping6'
alias reboot='_vyatta_op_run reboot'
alias release='_vyatta_op_run release'
alias remove='_vyatta_op_run remove'
alias rename='_vyatta_op_run rename'
alias renew='_vyatta_op_run renew'
alias reset='_vyatta_op_run reset'
alias restart='_vyatta_op_run restart'
alias set='_vyatta_op_run set'
alias show='_vyatta_op_run show'
alias shutdown='_vyatta_op_run shutdown'
alias telnet='_vyatta_op_run telnet'
alias terminal='_vyatta_op_run terminal'
alias traceroute='_vyatta_op_run traceroute'
alias traceroute6='_vyatta_op_run traceroute6'
alias undebug='_vyatta_op_run undebug'
alias update='_vyatta_op_run update'

“_vyatta_op_run hoge”の形でaliasが設定されているのは全てVyatta専用のコマンドです。_vyatta_op_runは、/etc/bash_completion.d/vyatta-op-runで定義されている関数です。

_vyatta_op_run ()
{
    local -i estat
    local tpath=$vyatta_op_templates
    local restore_shopts=$( shopt -p extglob nullglob | tr \\n \; )
    shopt -s extglob nullglob

    _vyatta_op_last_comp=${_vyatta_op_last_comp_init}
    false; estat=$?

    i=1
    for arg in "$@"
        do
        if [ -f "$tpath/$arg/node.def" ] ; then
            tpath+=/$arg
        elif [ -f $tpath/node.tag/node.def ] ; then
            tpath+=/node.tag
        else
            echo "Invalid command" >&2
            eval $restore_shopts
            return 1
        fi
        let "i+=1"
    done

    local run_cmd=$(_vyatta_op_get_node_def_field $tpath/node.def run)
    local ret=0
    if [ -n "$run_cmd" ]; then
        if [[ -t 1 &&  "$1" == "show" && \
            ! $run_cmd =~ ^\(LESSOPEN=\|less\|pager\|tail\|/opt/vyatta/bin/vyatta-tshark-interface-port.pl\).* ]] ; then
            eval "($run_cmd) | ${VYATTA_PAGER:-cat}"
        else
            eval "$run_cmd"
        fi
    else
        echo "Incomplete command" >&2
        ret=1
    fi
    eval $restore_shopts
    return $ret
}

この中の”$run_cmd”が実際に実行するvyatta用のコマンドが設定されます。$run_cmdが、”show”だった場合、showコマンドで設定やステータスの情報を表示し、それ以外の場合は、$tpath/$arg/node.defで定義されているコマンドを実行します。このコマンドの引数などが不完全な場合は、”Incomplete command”と実行される、というわけです。$tpathは、$vyatta_op_templatesが代入されていますがこの変数は入れ子になっており、実際に実行するコマンドは/opt/vyatta/share/vyatta-op/templates/ ${arg}として、実行されるコマンドの処理内容は/opt/vyatta/share/vyatta-op/templates/${arg}/node .defに定義されています。例えば、 show interfaces とするとインタフェースの設定状況を確認できますが、これは、templates/show/interfaces/node.defで定義されており、その内容は

help: Show network interface information
run: ${vyatta_bindir}/vyatta-show-interfaces.pl --action=show-brief

となっています。この場合は

  • help: show interfacesコマンドのヘルプメッセージ

  • run: show interfacesコマンドが実行する内容( ${vyatta_bindir}/vyatta -show-interfaces.pl –action=show-brief)

というワケです。

なので、オペレーションモードのコマンドをシェルスクリプトにする場合は、シェルスクリプト内でaliasを使えるように、”expand_aliases”を有効にしてやり/etc/bash_completion.d/vyatta-opを読み込みんでやると、オペレーションモードと同じコマンドが使えるようになります。

#!/bin/vbash
shopt -s expand_aliases
. /etc/bash_completion.d/vyatta-op
show interfaces

または、下記のようにalias展開前のコマンドを記述して

#!/bin/vbash
. /etc/bash_completion.d/vyatta-op-run
_vyatta_op_run show interfaces

とするか、node.defのrunで設定されている実行コマンドを記述して

#!/bin/sh
${vyatta_bindir}/vyatta-show-interfaces.pl --action=show-brief

とすればシェルスクリプトでもオペレーションモードのコマンドを使えるようになります。ただし、設定モードに変更するために、

_vyatta_op_run configure

と記述してスクリプトを実行すると、対話形式で設定モードに切り替わってしまうので、その後ろに書いている設定モードのコマンドは実行されません。

オペレーションモードのtabキーの動きを探る。

vbashでは、tab補完が効きますが、何も入力していない状態でtabキーを一回押すと、

add             debug           install-image   release         set             traceroute6
clear           delete          install-system  remove          show            undebug
clone           disconnect      no              rename          shutdown        update
configure       format          ping            renew           telnet
connect         generate        ping6           reset           terminal
copy            init-floppy     reboot          restart         traceroute

のように実行可能なVyatta専用のコマンドが表示されます。これは、/opt/vyatta/share/vyatta-op/templates/以下をlsで見た場合と同じです。

$ ls /opt/vyatta/share/vyatta-op/templates/
add        connect  disconnect   install-image   ping6    rename   set       terminal     update
clear      copy     format       install-system  reboot   renew    show      traceroute
clone      debug    generate     no              release  reset    shutdown  traceroute6
configure  delete   init-floppy  ping            remove   restart  telnet    undebug

再度tabキーを押すと、各コマンドの概要が表示されます。

Possible completions:
  add           Add an object to a service
  clear         Clear system information
  clone         Clone an object
  configure     Enter configure mode
  connect       Establish a connection
  copy          Copy data
  debug         Enable debugging of specified routing protocol
  delete        Delete a file
  disconnect    Take down a connection
  format        Format a device
  generate      Generate an object
  init-floppy   Format and prepare a floppy to save the config.boot file
  install-image Install new system image to hard drive
  install-system
                Install system to hard drive
  no            Disable or reset operational variable
  ping          Send Internet Control Message Protocol (ICMP) echo request
  ping6         Send IPv6 Internet Control Message Protocol (ICMP) echo request
  reboot        Reboot the system
  release       Release specified variable
  remove        Remove an object from service
  rename        Re-name something.
  renew         Renew specified variable
  reset         Reset a service
  restart       Restart a service
  set           Set system or shell options
  show          Show system information
  shutdown      Shutdown the system
  telnet        Telnet to <hostname|IPv4 address>
  terminal      Control terminal behaviors
  traceroute    Track network path to <hostname|IPv4 address>
  traceroute6   Track network path to <hostname|IPv6 address>
  undebug       Disable specified debugging
  update        Run an update command

これは、node.defの、”help:”で設定されている内容が表示されます。

設定モードの専用コマンドを探る。

一方、設定モードで使用するcommitやsave, loadコマンドなどは、/etc/bash_completion.d/vyatta-cfgで定義されています。

$ grep '()' /etc/bash_completion.d/vyatta-cfg | egrep -v '^\s|declare|vyatta|get|print|generate|reset|really' | more
show ()
commit ()
commit-confirm ()
confirm ()
compare ()
save ()
reboot ()
rollback ()
shutdown ()
load ()
merge ()
top ()
edit ()
up ()
exit ()
run ()
loadkey()

オペレーションモードと同様にtabキーを押すと、コマンドが表示されます。

comment         commit-confirm  confirm         delete          edit            load            merge           rollback        save            show
commit          compare         copy            discard         exit            loadkey         rename          run             set

tabキーもう一回押して表示されるhelpは、オペレーションモードとは異なり、/etc/bash_completion.d/vyatta-cfgの中で変数_get_help_text_helpsに設定されています。

_get_help_text_helps=( \
  "Confirm prior commit-confirm" \
  "Add comment to this configuration element" \
  "Commit the current set of changes" \
  "Commit the current set of changes with 'confirm' required" \
  "Compare configuration revisions" \
  "Copy a configuration element" \
  "Delete a configuration element" \
  "Discard uncommitted changes" \
  "Edit a sub-element" \
  "Exit from this configuration level" \
  "Load configuration from a file and replace running configuration" \
  "Load user SSH key from a file" \
  "Load configuration from a file and merge running configuration" \
  "Rename a configuration element" \
  "Rollback to a prior config revision (requires reboot)" \
  "Run an operational-mode command" \
  "Save configuration to a file" \
  "Set the value of a parameter or create a new element" \
  "Show the configuration (default values may be suppressed)" \
)

設定モードで使えるコマンドは、この/etc/bash_completion.d/vyatta-cfgで定義されているコマンド以外に、aliasで設定されているものもあります。

$ configure
# alias
alias comment='/opt/vyatta/sbin/my_comment'
alias copy='/opt/vyatta/sbin/my_copy'
alias delete='/opt/vyatta/sbin/my_delete'
alias discard='/opt/vyatta/sbin/my_discard'
alias ls='ls --color=auto'
alias rename='/opt/vyatta/sbin/my_rename'
alias set='/opt/vyatta/sbin/my_set'
[edit]

先ほどのmy_setコマンドが設定されていることが分かります。ここで、オペレーションモードの時と同じように、

#!/bin/vbash
shopt -s expand_aliases
. /etc/bash_completion.d/vyatta-cfg
set interfaces ethernet eth0 description hoge

としても、残念ながら/etc/bash_completion.d/vyatta-cfgの読み込み時に、

# ./test.sh
/etc/bash_completion.d/vyatta-cfg: line 888: bind: warning: line editing not enabled
/etc/bash_completion.d/vyatta-cfg: line 889: bind: warning: line editing not enabled
/etc/bash_completion.d/vyatta-cfg: line 890: bind: warning: line editing not enabled
/etc/bash_completion.d/vyatta-cfg: line 892: bind: warning: line editing not enabled
/etc/bash_completion.d/vyatta-cfg: line 893: bind: warning: line editing not enabled
[edit]

のようにコケてしまいます 1 。オペレーションモードでこのスクリプトを実行するとwarningは出ませんがやはり設定はできていません。 前回のエントリ のように素直に ${vyatta_sbindir}/my_* コマンドを使うのがよいでしょう。

各レベルのパラメータの定義を探る。

オペレーションモードのコマンドを定義していたのが/opt/vyatta/share/vyatta-op/templates/以下でしたが、設定モードで使う各レベルのパラメータは/opt/vyatta/share/vyatta-cfg/templates/の下で定義されています。

VyattaはDebianベースのディストロです。Vyattaの最新版の6.3はDebian GNU/Linux Squeezeのi386, amd64がベースになっており、Vyatta独自のソフトウェアもDebianパッケージとして提供されています。前者はvyatta-opパッケージで、後者はvyatta-cfgパッケージで基本的に提供されています。vyatta-cfgパッケージで提供されているテンプレートはinterfacesだけでsystem,serviceなどのテンプレートは他のパッケージ(systemならvyatta-cfg-system, NATならvyatta-natなど)で提供されています。例えば、ホスト名の設定は、

# set system host-name hoge

と設定しますが、これはvyatta-cfg-systemパッケージのtemplates/system/host-name/node.defで定義されています。これの中を見てみると、

type: txt
help: Set system host name (default: vyatta)
default: "vyatta"
syntax:expression: pattern $VAR(@) "^[[:alpha:]][-.[:alnum:]]*[[:alnum:]]$"
                   ; "invalid host name $VAR(@)"
update: sudo sh -c " \
  hostname '$VAR(@)'
  echo '$VAR(@)' > /etc/hostname
  touch /etc/hosts
  sed -i '/^127.0.1.1/d' /etc/hosts
  echo -e \"127.0.1.1\t $VAR(@)\t #vyatta entry\" >> /etc/hosts
  if [ x$VAR(../domain-name/@) != x ]; then
    echo -e \"127.0.1.1\t $VAR(@).$VAR(../domain-name/@)\t #vyatta entry\" \
      >> /etc/hosts
    echo \"$VAR(@).$VAR(../domain-name/@)\" > /etc/mailname
  else
    echo \"$VAR(@)\" > /etc/mailname
  fi"
delete: sudo sh -c " \
  echo 'vyatta' > /etc/hostname
  hostname 'vyatta'
  touch /etc/hosts
  sed -i '/^127.0.1.1/d' /etc/hosts
  echo -e \"127.0.1.1\t vyatta\t #vyatta entry\" >> /etc/hosts
  if [ x$VAR(../domain-name/@) != x ]; then
    echo -e \"127.0.1.1\t vyatta.$VAR(../domain-name/@)\t #vyatta entry\" \
      >> /etc/hosts
    echo \"vyatta.$VAR(../domain-name/@)\" > /etc/mailname
  else
    echo \"vyatta\" > /etc/mailname
  fi"

となっています。この内容は、

  • type: とりうるパラメータの種類(ここではtxt)

  • help: コマンドのヘルプ

  • default: デフォルト値(デフォルトではホスト名はvyatta)

  • sytax:expression: 書式のパターン(ホスト名の先頭一文字目は半角英字、2文字目以降は半角英数もしくはハイフン、またはピリオド、最後の文字は半角英数を許可)

  • update: ホスト名更新時に実行される処理(/etc/hostname, /etc/hosts, /etc/mailnameを指定したホスト名およびドメイン名があればそれで更新)

  • delete: ホスト名削除時に実行される処理(update時に更新されるファイルをホスト名を”vyatta”として更新)

ですので、オペレーションモードでのコマンドの定義と基本的には同じだということが分かります。

${vyatta_sbindir}/my_* コマンドを探る。

それでは、先ほどの my_* コマンドについてもう少し突っ込んで見てみます。これらのコマンドの実体は ${vyatta_sbindir}/my_cli_bin へのシンボリックリンクになっています。

  $ ls -l ${vyatta_sbindir}/my*
  -rwxr-xr-x 1 root root 19512 Jul 21 09:31 /opt/vyatta/sbin/my_cli_bin
  -rwxr-xr-x 1 root root 32416 Jul 21 09:31 /opt/vyatta/sbin/my_cli_shell_api
  lrwxrwxrwx 1 root root    10 Jul 21 16:37 /opt/vyatta/sbin/my_comment -> my_cli_bin
  lrwxrwxrwx 1 root root    10 Jul 21 16:37 /opt/vyatta/sbin/my_commit -> my_cli_bin
  lrwxrwxrwx 1 root root    10 Jul 21 16:37 /opt/vyatta/sbin/my_copy -> my_cli_bin
  lrwxrwxrwx 1 root root    10 Jul 21 16:37 /opt/vyatta/sbin/my_delete -> my_cli_bin
  lrwxrwxrwx 1 root root    10 Jul 21 16:37 /opt/vyatta/sbin/my_discard -> my_cli_bin
  lrwxrwxrwx 1 root root    10 Jul 21 16:37 /opt/vyatta/sbin/my_move -> my_cli_bin
  lrwxrwxrwx 1 root root    10 Jul 21 16:37 /opt/vyatta/sbin/my_rename -> my_cli_bin
  lrwxrwxrwx 1 root root    10 Jul 21 16:37 /opt/vyatta/sbin/my_set -> my_cli_bin

:command:`${vyatta_sbindir}/my_cli_bin` コマンド自体は、ELF形式の実行ファイルで、my_setコマンドやmy_commitコマンドなどのシンボリックリンクも含め、これはvyatta-cfgパッケージによって提供されています。
$ dpkg -S ${vyatta_sbindir}/my_cli_bin
vyatta-cfg: /opt/vyatta/sbin/my_cli_bin

このバイナリパッケージに含まれているドキュメントは、/usr/share/doc/vyatta-cfg/READMEくらいですが、このファイルには

This package has the Vyatta configuration system, including the configuration back-end, the base configuration templates, and the config-mode CLI completion mechanism.

と書かれています。では、vyatta-cfgパッケージのソースコードを見てみます。

apt-get source vyatta-cfg、じゃあないの?!

前述のとおりVyattaはDebianベースなので、

$ apt-get source vyatta-cfg

でソースパッケージを取得しよう!と思うかもしれません。が、デフォルトではdeb-srcのAPT Lineが無いのでできません。そこで、デフォルトで設定されている

deb http://packages.vyatta.com/vyatta stable main # community #

をコピーして、

deb-src http://packages.vyatta.com/vyatta stable main

を設定しても、残念ながらリポジトリにはソースパッケージは置いてないのでapt-get updateがコケます。困ってしまいましたね。

Vyattaのソースコードの入手方法。

これもちゃんと ドキュメントに記述があります 。ソースコードを入手するにはbuild-src.gitリポジトリをgit cloneを行います。そして、今回必要なvyatta-cfgパッケージのソースコードはsubmoduleとして入手します。

$ git clone http://git.vyatta.com/build-iso.git
$ cd build-iso
$ git submodule init
(snip)
Submodule 'pkgs/vyatta-cfg' (http://git.vyatta.com/vyatta-cfg.git) registered for path 'pkgs/vyatta-cfg'
(snip)

submoduleの初期化後、submodule updateでpkg/vyatta-cfgリポジトリのコピーを行います。

$ git submodule update pkgs/vyatta-cfg
Cloning into 'pkgs/vyatta-cfg'...
Submodule path 'pkgs/vyatta-cfg': checked out '55dc3e317c138286de6353c21ab47c91fca9a2f4'

git submodule updateが完了すると、HEADがcheckoutされます。

$ cd pkgs/vyatta-cfg
$ git log
commit 55dc3e317c138286de6353c21ab47c91fca9a2f4
Merge: 02a2145 0b582e0
Author: rbalocca <rbalocca@vyatta.com>
Date:   Fri Dec 26 09:35:12 2008 -0800

    Merge branch 'islavista'
(snip)
$ ls
AUTHORS  COPYING  ChangeLog  Makefile.am  NEWS  README  configure.ac  debian  etc  scripts  src  templates

なお、単にソースコードを見るだけなら、gitweb経由で VyattaのGitリポジトリ は公開されています。 vyatta-cfgもその中で公開 されています。

my_cli_binのソースコードを見てみる。

最新のVyattaのリリースのバージョンはset versionコマンドで確認すると、VC6.3-2011.07.21だと分かります。

$ show version
Version:      VC6.3-2011.07.21
(snip)

vyatta-cfgのリポジトリのtagを確認するとVC6.3-2011.07.21にはamd64とi386とがあります。

$ git tag
(snip)
vyatta/VC6.3-2011.07.21/amd64
vyatta/VC6.3-2011.07.21/i386
vyatta/VC6.3-2011.10.04/amd64
vyatta/VC6.3-2011.10.04/i386

タグvyatta/VC6.3-2011.07.21/amd64をまずチェックアウトします。

$ git checkout vyatta/VC6.3-2011.07.21/amd64
Note: checking out 'vyatta/VC6.3-2011.07.21/amd64'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b new_branch_name

HEAD is now at 64d54e8... 0.99.8+napa6

my_cli_binをgrepすると、src/cli_bin.cppがソースコードだと分かります。

$ git grep my_cli_bin
Makefile.am:sbin_PROGRAMS += src/my_cli_bin
Makefile.am:src_my_cli_bin_SOURCES = src/cli_bin.cpp
Makefile.am:      $(LN_S) my_cli_bin my_set; \
Makefile.am:      $(LN_S) my_cli_bin my_delete; \
Makefile.am:      $(LN_S) my_cli_bin my_rename; \
Makefile.am:      $(LN_S) my_cli_bin my_copy; \
Makefile.am:      $(LN_S) my_cli_bin my_comment; \
Makefile.am:      $(LN_S) my_cli_bin my_discard; \
Makefile.am:      $(LN_S) my_cli_bin my_move; \
Makefile.am:      $(LN_S) my_cli_bin my_commit
debian/vyatta-cfg.postinst.in:for bin in my_cli_bin my_cli_shell_api; do

これを見ると実行するコマンドのパスのbasenameが、*op_bin_name配列の要素にマッチすれば、その機能が実行される、ということが分かります。

static int op_idx = -1;
static const char *op_bin_name[] = {
  "my_set",
  "my_delete",
  "my_activate",
  "my_deactivate",
  "my_rename",
  "my_copy",
  "my_comment",
  "my_discard",
  "my_move",
  "my_commit",
  NULL
};
static const char *op_Str[] = {
  "Set",
  "Delete",
  "Activate",
  "Deactivate",
  "Rename",
  "Copy",
  "Comment",
  "Discard",
  "Move",
  "Commit",
  NULL
};
static const char *op_str[] = {
  "set",
  "delete",
  "activate",
  "deactivate",
  "rename",
  "copy",
  "comment",
  "discard",
  "move",
  "commit",
  NULL
};
(snip)
#define OP_Str op_Str[op_idx]
#define OP_str op_str[op_idx]
#define OP_need_cfg_node_args op_need_cfg_node_args[op_idx]
#define OP_use_edit_level op_use_edit_level[op_idx]
(snip)
static void
doSet(Cstore& cstore, const Cpath& path_comps)
{
  if (!cstore.validateSetPath(path_comps)) {
    bye("invalid set path\n");
  }
  if (!cstore.setCfgPath(path_comps)) {
    bye("set cfg path failed\n");
  }
}
(snip)
typedef void (*OpFuncT)(Cstore& cstore,
                        const Cpath& path_comps);
OpFuncT OpFunc[] = {
  &doSet,
  &doDelete,
  &doActivate,
  &doDeactivate,
  &doRename,
  &doCopy,
  &doComment,
  &doDiscard,
  &doMove,
  &doCommit,
  NULL
};

int
main(int argc, char **argv)
{
  int i = 0;
  while (op_bin_name[i]) {
    if (strcmp(basename(argv[0]), op_bin_name[i]) == 0) {
      op_idx = i;
      break;
    }
    ++i;
  }
(snip)
  Cstore *cstore = Cstore::createCstore(OP_use_edit_level);
  Cpath path_comps(const_cast<const char **>(argv + 1), argc - 1);

  // call the op function
  OpFunc[op_idx](*cstore, path_comps);
  delete cstore;
  exit(0);
}

masterブランチは古いので要注意。

ちなみに、vyatta-cfgのリポジトリはmasterブランチが結構古いままです。前述のとおり、2008年12月26日のものがHEADになっています。なので git submodule update直後にそのままソースコードを見ても見つかりません。git logで確認すると2010年7月28日にsrc/cli_bin.cppが初めてコミットされているのが分かりますね。気をつけましょう。

$ git log --reverse src/cli_bin.cpp
commit 639c835bc2730a4fbffd915f5b2028a68375ee7a
Author: An-Cheng Huang <ancheng@vyatta.com>
Date:   Wed Jul 28 14:30:32 2010 -0700

    add new cstore library

まとめ

以上をまとめると、オペレーションモードでは次の方法でシェルスクリプトにすることができます。

  • expand_aliasesを有効にし、/etc/bash_completion.d/vyatta-opを読み込むことで、Vyattaのコマンドをそのまま使う

  • もしくは/etc/bash_completion.d/vyatta-op-runを読み込み、_vyatta_op_runの引数としてVyattaのコマンドを使う

設定モードでは、

  • /etc/bash_completion.d/vyatta-cfgを読み込むだけではダメ

  • ${vyatta_sbindir}/my_cli_bin へのsymlinkになっている、 ${vyatta_sbindir}/my_cli_bin コマンドを使う

ということで、これでシェルスクリプトで、快適なVyattaを自動化した生活を送れるようになれますね。

1

warningですが、実際に設定されていません。