Web系のAPIをたたいていると、たまにエラーが発生することがあります。要因はサーバー側がたまたまおかしかったり、proxyだったりと様々です。 エラー時にはリトライしつつAPIをたたく方法はいろいろ考えられますが、C#でのスマートな実例がStackOverflowで紹介されていました。リトライ専用のクラスとstaticメソッドを実装して、呼出にはデリゲート、ラムダ式を用いるという手法です。 Rubyでも同様の処理を行うコードを考えてみました。
Category: 開発
CVE-2008-0166の爪痕
偶然にも500万個のSSH公開鍵を手に入れた俺たちはという資料が公開されました。GitHubから公開鍵を大量に集めて調査してみたという内容なのですが、なかなか衝撃的だったので英語blogで内容をかいつまんで紹介してみました。 500万個のssh公開鍵のうち、Debian/Ubuntuで作成されたブラックリスト入りの鍵が208件あったそうです。割合として考えてみればそれほど多くはないのですが、まだ爪痕が残っていることを実感します。
ELECOM UCAM-C0220Fを使う
ふと思うところがあって、安価なUSBカメラを購入しました。エレコムの200万画素で安価(1000円程度)なモデルです。 最終的な目的の用途とは異なるのですが、とりあえず自宅の様子をストリーミングさせてみました。かつてはgstreamerを使っていろいろと余計な苦労をする羽目になったのですが(Google Slideの資料9ページ目参照)、いまどきはffmpeg/libavを使ってVorbis/TheoraやWebMにエンコードし、icecastに配送させるのが簡単だと思います。 このデバイスは映像入力をUVCクラス、音声(マイク)入力をAudioクラスとした複合デバイスに見えます。 ffmpegでalsaデバイスとしてこのオーディオデバイスを使うと、定期的に”[alsa @ 0x15fcc00] ALSA buffer xrun.”というエラーが出ます。どうもUSB audioとしての動作が何かおかしいようです。この状態でoggfwdを続けていると、icecast側から接続を切られてしまいます。まあ自分の主目的は映像をとることなのでその用途には十分使えそうです。
Webアプリを立てて外部から作業しやすくする
WX310K、いわゆる京ポン2を持って以降、出先でのWeb閲覧がお手軽にできるようになってからNexus5を持つ現在へと至っていますが、スマホ・タブレット時代になって相当リッチなWebアプリも動かせるようになりました。昔から現在に至るまで利用しているWebアプリケーションについて書いてみようと思います。 ソースコード閲覧 GNU Global このソフトはctagsの強化版といった感じのソフトウェアですが、ハイパーリンクでのクロスリファレンスを実現した静的HTMLも出力することができます。JavaScriptなどを使わないシンプルな出力なので、非力なWX310Kでもそれなりに利用できていました。今でも使っています。 gonzui 主にRubyで書かれたソースコード特化型検索エンジンです。残念ながら2005年を最後に更新がありません。かつては利用していました。 milkode 同じくRubyで書かれたソースコード検索エンジンです。開発は活発で、対応している言語もgonzuiより多いので、現在はこちらを使っています。gonzuiが独自データベースであったのに対し、milkodeはバックエンドにGroongaを使っています。 Pootle(翻訳) Pythonで書かれたWebアプリとして動作する翻訳ツールです。かなりモダンな造りでJavaScriptをガッツリ使っています。スタンダードなpo形式も扱えるので、役に立っています。 ownCloud(オンラインストレージ) PHPで書かれたオンラインストレージです。Linux, Windows, Android, iOS等のクライアントが用意されていますが、WebDAVとしても動作します。Webアプリとしても動きます。 サーバーサイドでAESを使った暗号化ができたり、サードパーティWebアプリがいろいろとあったりします。RSSリーダーもあるので、もしFeedlyがなくなってしまったらそれを使ってみようと考えています。 その他 gitlabやredmineも用意したのですが、これらはいまいち活用できていません。以前はWebでIMAPを扱えるIrohaMailも入れていたのですが、使い勝手がいまいちで消してしまいました。今時であればスマートフォンのIMAPクライアントで十分でしょう。
Google::API::OAuth2::Clientのトークン情報をシリアライズする
先日書いた「Google::API::Clientを使う(perl)」の続きです。前回示したコードでは毎回認証してアクセスコードを入力しなければいけないので、それを回避するためにjsonで保存するためのコード例を示してみます。 トークンの保存 トークンの読み込み Data::SerializerでGoogle::API::OAuth2::Clientを丸ごとシリアライズしてみる、ということもやってみたのですが、不完全のようでシリアライズ時に警告が出たり、デシリアライズしたオブジェクトを使った際、最後にsegfaultを起こしたりします。 あとは、new_from_client_secretsというメソッドでjsonファイル上に記録されたauth_uri, token_uri, client_id, client_secretを読み込んで新しいオブジェクトを作成するものも用意されていますが、token_objについては考慮されていません。ファイル外部にclient_id等を記録しておける点が良い、ぐらいのものです。 もうちょっと永続化に関する手続きも簡略化されているとうれしいところです。
Google::API::Clientを使う(perl)
ここのところいろいろな言語でGoogle APIをたたいてみています。PerlのGoogle::API::Clientを使ってみたのですが、ドキュメントがいまいち整備されていなかったので、実際にGmail APIをたたくサンプルを書いてみました。大まかな作りはruby, pythonのライブラリとあまり変わりありません。 OAuth2認証部分 $auth->authrorize_uriはresponce_type=codeなURLを生成します。上記コードで画面上に表示されたURLに接続・承認を行い、ブラウザ上に表示されたアクセスコードをexchangeメソッドの引数に渡します。これで認証は完了します。 client_secrets.jsonファイルからオブジェクトを生成するnew_from_client_secretsメソッドもありますが、jsonファイルにシリアライズするメソッドは用意されていないようです。 サービスの構築とメソッドの実行 ポイントは以下です。 client->buildでAPIとバージョンを指定 どんなメソッドがあるかはAPIs Explorerで確認 bodyは連想配列で記述(jsonにマッピングされる) 認証情報はexecuteの引数auth_driverに指定する リフレッシュはGoogle::API::Methods側でよしなにしてくれる 得られる結果もjsonを連想配列化したものになる ブラウザでAPIs Explorerを試しながらあれこれ試してみればすぐに理解できると思います。
cgroupsのnamespace手動削除
自宅のPCルーターは10年以上前に構築したDebian環境をもとに、HDDだけ移しながらupgradeを長年重ねて積み上げたもので、.emacsが結構な腐臭を放っているとか自作init scriptをmake styleにいい加減に修正したものがあったりとか、いろいろガタはあるものの今でも元気に動いています。 時代が時代なので当然アーキテクチャはi386なのですが、いまどきはDebian側でi386向けのamd64 kernelパッケージを提供しているので、現在はそれを使っています。メインメモリも8GB積んでいます。 kernelがamd64なので、debootstrapでamd64のuserlandを構築することも可能です(–arch amd64)。最近、これをベースにLXCコンテナ化しました。やることは単純で/var/lib/lxc/$name/rootfsにシンボリックリンクを張って、設定ファイルを適当にコピペででっちあげるだけです。 ただ、この作業の過程の中で、lxc-startを-KILLシグナルで殺してしまい、cgroupsのnamespaceが残ってしまうという問題が発生しました。これをどうやったら削除できるか調べてみた結果、rmdir /sys/fs/cgroups/lxc/$name で削除できることを覚えました(kernel documentのcgroups.txt)。最初 rm -rfで消そうとして消せない、と苦労していたのですが、ディレクトリだけを削除すれば良いようです。逆にmkdirするとblkioとかcpusetとか必要なものがごそっと生えてきます。 というわけで、何かしらの不手際でcgroupsのnamespaceが残ってしまった場合には、ディレクトリだけをrmdirしましょう。 ついでにわかったこととして、LXC 1.0.6ではこういった「同じ名前のnamespaceが既にある」状況では$name-1といった名前で重複しないように作るような動きをするようです。
DebianパッケージでBuild.PLをポリシーに合うように扱う
ちょっと手間取ったので記録に残しておきます。 かつてのPerlはExtUtils::MakeMakerという標準モジュールを使い、Makefile.PLを用意しておくというのが一般的でしたが、最近はそれ以外にもModule::Build, Module::Build::Tinyというパッケージを使い、Build.PLというファイルを用意して処理することもあるようです。dh-make-perlはModule::Buildにも対応しているような感じでしたが、Module::Build::Tinyには対応していないようです(dh-make-perl 0.84-1で確認)。 dhのoverrideを使って、以下のようなコードをdebian/rulesに追加することで望みどおりの動作をするようになりました。 追記 同じ内容の記事を英語blogの方にも書いたところ、debhelperの問題という指摘を受けました。この問題が発生するのはwheezyのdebhelperに限定されます。sidではこのような対応は不要です。
CAT68701にNetBSDを移植したときの思い出
これはNetBSD Advent Calendar 2014の12日目の記事です。 かつてCAT68710というsh3ベースのワンボードコンピュータがシリコンリナックスから販売されていました。標準OSはLinuxだったのですが、それをNetBSDに移植したときの思い出を記憶から掘り起こしてみます。もう10年以上前のことになりますが… まずCQREEKSH3をベースとすることを考えました。これは多分CQ RISC評価キット/SH3のコードです。組み込みsh3ボードは他にも複数あったのですが、なぜこれを選択したのかはよく覚えていません。confの差分を見ると相当いろんなものを削っていたのでどれをベースにしても大差なかったかもしれません。 CAT68710にはシリアルポートがあり、ブートローダーが最初から入っていて制御可能だったので、最初はとにかくシリアルからなにかしらの出力をさせるために、locore.Sをいじってシリアルに文字を出してみるところから始めました。シリアルコントローラはsh3内蔵のものをそのまま使っていたので、ブートローダーが既に初期化をしてる状態からシリアル出力をさせるのは簡単でした。 各種I/OデバイスのアドレスをCAT68710に合わせて起動させると、動いているっぽい感じはあったのですが出力がなにもなかったので困りました。先の「既に初期化されているシリアルポート」であることを利用してputcharに手をいれて、とにかくコンソール出力をさせてみたらpanicに至るメッセージが出力できて、ようやく手がかりをつかんだことが当時の日記に記録されています。 シリアルコントローラは初期化パラメータが間違っていたようで、それを修正して小細工なしにシリアルコンソールが出るようになりました(当時の記録)。さらにpcmciaのコードをmmeyeから持ってきて、CFスロットが認識できるようになりました。 ネットワークはCS8900を使っていて、幸いなことにNetBSD側にMIなドライバーがあったのでそれを組み込みました(記録)。割り込みベクタ番号を適切な値にすることで最終的にちゃんと動くようになりました。適切な値、というのはLinuxの方で設定しているirq番号を参考に適当に何かを足し引きしてたまたま動くやつがわかった、というような経緯だった記憶があります。この時にsh3 Linuxのデバイスドライバは基本x86のISAバスのセマンティックに無理やり合わせて動かしている、ということを学びました。今時のデバイスでは変わっているだろうと思います。 最終的にnfs rootでmulti user modeで動くところまでは持ってゆけました。作業はここで力尽きて止まったようです。 思い返してみると、NetBSDのMIドライバはよくできていたなと思います。既に複数の組み込みボードの移植コードが存在していたことも、自分がポーティングできた成功要因の一つだと思います。多分自分で書いたコード量は3ケタ行ぐらいだったと思います。しかし当時gitがなかったのが残念です。手元に残っていたコードは2つのtarballだけでした。
GData ClientのSpreadsheet ListFeed
個人的にはまったので記録に残しておこうと思います。 GoogleのAPIには2つの種類があります。一つはGoogle APIと呼ばれるもので、APIs Explorerにて確認できるものです。もう一つ、微妙に違うGoogle Data APIsというものがあります。GoogleはこれらのAPIを操作するためのライブラリを各種言語向け(Java, .NET, Python, ruby, PHP等)に用意しています。前者はgoogle-api-clientというような名前、後者はgdataというような名前を付けています。 この2つは微妙にセマンティックが違うのですが、OAuth2で認証できる点は同じで、認証ポイントも同一です。しかしそれぞれ個別にOAuth2認証クラスを持っていたりして、両方をまたいで(たとえばgmailとcalenderの組み合わせ等)使おうとするときは結構面倒です。両方をカバーするscopeでどちらかのライブラリで認証し、もう片方のOAuth2認証クラスに各種情報をコピーする必要があります。 それはともかく、今回はまったのは以前くらった「GData.SpreadsheetsライブラリのListFeedに潜む罠」の続きです。一行目に書かれた文字列がフィールドのキーとなるわけですが、さらにこの値は「API上は小文字しか受け付けない」という罠です。 たとえばA1に「Firstname」という値があったとして、ListEntry.CustomのLocalNameプロパティに”Firstname”としているとAPIレベルでエラーが帰ってきます。ここは”firstname”としなければなりません。 StackOverflowの“Cannot add a row to Google Spreadsheet”という記事でこのことが説明されていました。Google Sheets API version 3.0にはそのことは触れられていません… 毎度StackOverflowにはお世話になりっぱなしです。