その手の平は尻もつかめるさ

ギジュツ的な事をメーンで書く予定です

YAPC::Fukuoka 2017 HAKATAのトークプロポーザルを出した

yapcjapan.org

出しました.最近YAPCでしか喋ってない感じがしますね.果たしてそうなのです.

というわけでプロポーザル内容は以下のとおりです.

Web application good error messages and bad error messages

Webアプリケーションを作り,運用していると例外的な状況が発生するものです.
例外的な状況 (エラー) は起きない (起こさない) に越したことはありませんが,しかしながらそれらをゼロにするのには相当のコストを要しますし,そもそも「本当にエラーが起きる余地が無いのかどうか」を証明するのも困難です (こうした問題領域を解決する為の手法やツールもありますが,そうしたものについては本トークでは触れません).
従って現実問題として,そうした例外的な状況に対応していく必要があります.そのような時にプリミティヴな武器として有効なもののひとつに「エラーメッセージをログに書き込んでおく」というものが挙げられると思います.また,エラーメッセージはサーバ内にログとして留めておくだけではなく,クライアントに対して表現する必要がある場合もあります.つまり,サーバ・クライアントを問わず,エラーメッセージは問題の修正・解決にとって重要な役割を果たしていると言うことが出来るでしょう.これはユーザ体験にも直結する要因のひとつとも言えます.

本セッションでは

  • サーバ内部でのエラーメッセージ
  • 外部に提供するエラーメッセージ

という2つの文脈について

  • 問題の「修正」に役立つエラーメッセージとは
  • 問題の「解決」に役立つエラーメッセージとは
  • エラーメッセージの粒度
  • エラーメッセージのレベル
  • エラーメッセージの検索性
  • perlにおけるロギング

などといった話題について触れたいと考えています.




エラーメッセージやロギング等はアプリケーションの構築および運用において不可欠で重要な存在だと思っているのですが,あまりそこら辺にフォーカスを当てた発表や資料が無いな〜と思ったので *1 こうしたテーマを選択した次第です.

採択されたら喋れます.よろしくお願いします.

*1:しっかりあることにはある.例えば右は非常によい資料です: 良いデバッグログはプロジェクトの資産である // Speaker Deck

OpenWrtの環境に対してAnsibleでプロビジョニングをかける

メモ.
Ansibleを利用するという文脈におけるbareなOpenWrtの環境の特徴としては以下のようなものがある;

  • sftpが有効ではない
  • Pythonランタイムが入っていない

これらを解決すれば,あとはいつものように普通にAnsibleを使える (はず).
というわけでそれぞれに対する対応は以下の通り.

sftp-server が有効ではない

そうした場合にansibleを走らせると以下のようなエラーが出る.

failed to open a SFTP connection (Channel closed.)

対応としては ansible.cfg に以下のように設定を書き込むと良い.

[ssh_connection]
scp_if_ssh=True

公式ドキュメントによると,scp_if_ssh をTrueに設定すると,sftpの代わりにscpを利用してファイルの転送を行なうようになるとのこと *1
なお,環境変数で指定する場合には ANSIBLE_SCP_IF_SSH=true という風に指定すると良い様子.(参照: https://github.com/ansible/ansible/blob/feafae70b579a3890951fd5c7c7b6645c340ff00/lib/ansible/constants.py#L221)

参照: linux - Is the SSH SFTP subsystem required on the managed nodes for Ansible to work? - Server Fault

Pythonランタイムが入っていない

Pythonを入れれば良い……のだが,恐らくOpenWrtが動作するような環境では少しでもストレージの使用量を節約したいというのが人情でしょう.ここではPythonランタイムをインストールせずに済ませる方法を記す.

プロビジョニング対象の環境内にPythonが無い場合,playbook内に gather_facts: no と記述した上で,rawでタスクをモリモリ書いていけば良い.以下例.

- hosts: openwrt
  remote_user: root
  gather_facts: no
  tasks:
  - name: update opkg
    raw: opkg update
  - name: install openssl-util
    raw: opkg install openssl-util

なおplaybookではなくコマンドラインで何らか実行する際にrawを指定するには -m raw というオプションを付けてやると良い.
こうするとPython無しでも動く……のだがAnsibleの旨味がごっそり抜けてしまう (せっかくのOpenWrtサポートを利用できない) ので,もう諦めてPythonを入れてしまったほうが楽かもしれない.

参照: Python が入っていない NW 機器も Ansible で (一応) 制御できる - Qiita

考察

Ansibleを使わないで,普通に環境構築済みのイメージを用意してROM焼いてしまえば良いのでは無いか? (とは言え設定ファイルみたいなやつはAnsibleで撒きたい,みたいなのはあります)

*1:>Occasionally users may be managing a remote system that doesn’t have SFTP enabled. If set to True, we can cause scp to be used to transfer remote files instead:

OpenWrtの設定を強制的に初期状態に戻す (failsafe modeに入る)

OpenWrtでうっかりLANのInterfaceの設定をしくじってしまったりすると,Web UIに入れなくなってしまい (もちろんsshもできない) その後の設定が一切不能になって詰む事があります.そういう時に工場出荷時 (という表現が正しいのかどうかはわかりませんが) の状態に初期化する際の手順について記します.

ずばりこのStackOverflowなわけですが;

stackoverflow.com

しかし下記のバグトラッカーに記されているように,Chaos Calmer 15.05だと firstboot コマンドが上手く動かない様子.

#20168 (CC - firstboot is broken) – OpenWrt

というわけでChaos Calmer 15.05の場合は以下のような手順を踏むと良い.

  1. ルータの電源を切る
  2. WANポートにつながっているケーブルを外す
  3. マシンのNICIPアドレス192.168.1.2/24 に設定し,デフォルトゲートウェイ192.168.1.1 に設定する
  4. マシンとルータを有線で繋ぐ
  5. ルータに電源を入れる
  6. 赤いLEDが点滅しはじめたらルータのリセットボタンを押す (長押し?)
  7. 赤いLEDの点滅が高速になったらfailsafe modeに入っているということなので telnet 192.168.1.1 でルータに入って以下のコマンドを流し込む
mount_root ## ファイルを読み書き出来るようにマウントしなおす
mtd -r erase rootfs_data  ## firstbootとreboot -fの代替.しばらく待つと自動で再起動される

最初,WZR-HP-AG300Hのリセットボタンの位置が分からなくて困ったので取扱説明書は重要であるということがわかりました (ボタンは底面にあった).

なんらかの設定ミスでにっちもさっちも行かなくなっている場合は,初期化までしなくてもfailsafe modeのtelnetの中で設定ファイルを直せば済むという感じもあります.


failsafe modeの公式ドキュメント: OpenWrt Failsafe [OpenWrt Wiki]

WZR-HP-AG300HにOpenWrtを焼く

BUFFALOの無線LANルータであるところのWZR-HP-AG300HにOpenWrtを焼いて利用する際のメモです.なおマシンのOSはmacOSです.Windows等だとちょっと違うかもしれないが概ね問題ないはず.

buffalo.jp

AG300HとマシンをLANケーブルで繋ぐ

  • 適切なケーブルで繋ぐ
  • マシンのNICIPアドレス192.168.11.2/24 に固定する
  • 192.168.11.1 にアクセスするとBUFFALOの設定Web UIにアクセスできる

参照: インターネット接続のためブラウザーを開き、ユーザー名に「root」と入力すると認証エラーになります(WHR-G300N、WZR-HP-G300NH、WZR-AGL300NH、WZR2-G300N) - アンサー詳細 | BUFFALO バッファロー

AG300HのBUFFALO純正ファームを更新する

必要なさそうだが,念のためにやっておく.
Web UIのオンラインバージョンアップ機能を利用して1.75 (2017/05/07時点の最新バージョン) にファームのバージョンを上げる.別途ファームのバイナリをあらかじめダウンロードしておき,そのファイルを利用するのでも問題ない.

OpenWrtを焼く

https://downloads.openwrt.org/chaos_calmer/15.05.1/ar71xx/generic/openwrt-15.05.1-ar71xx-generic-wzr-hp-ag300h-squashfs-factory.bin

2017/05/07時点での最新バージョンであるところの,Chaos Calmer (15.05.1) を利用する.

純正ファームのAG300Hの為のOpenWrtバイナリがあるのでそれをダウンロードしてきて,Web UIのファーム更新ページ経由でそのバイナリを指定してOpenWrtを焼く.なお factory.bin というファイル名は「純正ファームからOpenWrtを焼く時に使用する」という意味らしい.

なおこの時点ではWi-Fiは無効になっているので,Wi-Fiを有効にする場合は引き続き有線で設定する必要がある.

OpenWrtのWeb UIであるところのluciに繋ぐ

BUFFALOのファームのときは 192.168.11.1 でWeb UIに繋いでいたが,OpenWrtでは192.168.1.1 がWeb UIのIP Addrとなるのでそちらに繋ぐ.適宜マシンのNICIPアドレスを固定する必要がある (場合がある).
Web UIは初期状態だとユーザ名root,パスワード空でログインができる.
ログインしたら適当にOpenWrtのパスワードなり,SSHの設定なり,Wi-Fiの有効化なりをやる必要がある.

メモ

FLETSのONUの出力をAG300HのWANに繋いでいると,192.168.1.1/24 を食い合うっぽいので,適宜LANの静的IPアドレスの設定で 192.168.11.1/24 なりに変更しておく必要がありそう.
というか面倒なのでAG300Hの設定を行っている時は,色々めんどいのでWANに繋がない方が楽な感じがした.

雑感

インターネットを眺めているとWZR-HP-AG300Hは純正ファームだと不安定だけど,OpenWrtにすると安定運用できる様子が伺える.
AG300HでOpenWrtを利用する際の情報もやけに充実していて便利 (Buffalo WZR-HP-AG300H [OpenWrt Wiki]).OpenWrtの為に登場した無線LANルータであるようにすら思える.
今回AG300Hをメルカリで買ったんだけど,中古だとだいたい2000円くらいで買えてお手軽.安い時だと1000円代で購入できることもあるのでどんどん買っていきたい.

MyBatis + GroovyでMapperを作っている時に良い感じでWHERE IN使いたいんですけど〜って時

MyBatisのMapperをGroovyのannotationを使って書くと何かと便利 (主に「XMLを書かなくても良い」という点で便利) なわけですが,そんな中で「WHERE IN」を利用したSELECTを @Select annotationベースでどうやって書くのかという件です.要は SELECT * FROM users WHERE id IN (?, ... , ?) のようにプレースホルダを利用した感じのクエリを書きたい.SQLインジェクションを防ぎたいので,その辺はORMの機構に任せてしまいたいのです.

結論から書くと,MyBatis XMLマクロの foreachを使うのがシンプルな様子.

@Select("""
<script>
  SELECT *
  FROM users
  WHERE user_id IN
  <foreach item='userId' collection='userIds' open='(' separator=',' close=')'>
    #{userId}
  </foreach>
</script>
""")
List<User> findUsersByIds(@Param('userIds') List<Long> userIds)

結局のところXMLを書く必要があるのだ!!!! (XMLを使うことでシンプルに済ませることが出来るのであればXMLを使ったら良いという事がわかりました).

Official doc:
http://www.mybatis.org/mybatis-3/dynamic-sql.html

MacでErlang/OTPをソースコードからビルドする時にNo usable OpenSSL foundって言われるんですけどって時

前提

OpenSSLがbrewで入っている.

結論

こうすれば良い (brew環境下あるある);

$ ./configure --with-ssl=$(brew --prefix openssl)

Ref. Erlang -- Building and Installing Erlang/OTP

所感

わざわざソースコードからビルドしなくても,brew使ってるんだったらbrewerlang入れたら良い.

サービスを提供するにあたって取得されたくないアカウント名が集まっているライブラリが欲しいんですけど〜みたいな時

例えば `logout` みたいなユーザ名を取得されてしまうと,ユーザ側からすると不気味に見えるし,URL設計が終了している時などに脆弱性になり得る (とは言うものの,そもそもそういった脆弱性は根本的に防ぐべきだし,URL設計を終了させてはならない).
ので,タイトルのようなことをpostしたら知見がモリモリ集まってきた.ありがとうございます.

めっちゃ便利!!!!!