読者です 読者をやめる 読者になる 読者になる

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

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

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したら知見がモリモリ集まってきた.ありがとうございます.

めっちゃ便利!!!!!

YAPC::Kansai 2017 OSAKAで喋ってきました

タイトルは「Webアプリケーションのキャッシュ戦略とそのパターン 」です.

speakerdeck.com

告知で書いたように,ここ1・2年は規模感のあるWebアプリケーションを開発していて,なおかつキャッシュ周りの設計・開発・運用をモリモリやっていたので,その関連で学んだこと,感じたことをまとめて発表したという感じです.聞きに来てくださった皆さんありがとうございます.内容についてはスライドをご覧いただければご理解頂けるかと存じます.

ところでトーク中に言い忘れたこととして,「ランキングの構造を返すJSON」みたいなものはえてして大きくなりがち,かつランキングをバッチで構築している場合は或る単位時間内に変化することが少ない (あるいは無い) ので Cache-Control を付けてJSONを返してしまうと負荷が大きく下がって便利,みたいな話題もありました.しっかりした原稿を作っていないとこういううっかりがあるものですね.反省します.

Varnishについて

トーク中に「Varnishを使ってないんですすみません」という話をしましたところ,懇親会等でVarnish周りで色々なフィードバックを頂戴することが出来てたいへん有益でした.
ざっくりとまとめると;

  • 古来,Varnishの利用に際して孕んでいた問題としてHTMLをゴリッとキャッシュして配信していると「他のユーザのログイン済み画面を誤って表示してしまう」と言うものがあり,このリスクが大きかった
  • 近年ではユーザがログイン済みかどうかはJSでハンドリングすることが出来る (そしてそういう手法を採ることが多い)
    • そして「ログイン済みの時に表示するコンテンツ」はJSがAPIを叩いて取得してくることが出来る (そしてそういう手法を採ることが多い)

という感じで,つまり

  • 大枠のコンテンツ (つまりあらゆるユーザに返しても問題のないコンテンツ) を持っているHTMLについてはVarnishで返してしまう
  • ログイン済みかどうか,あるいはどのユーザか,といったクライアント側に紐づくコンテンツに関しては別口でAPI越しに返してやる

といった手法が現代では可能なので,割と安全にVarnishを活用できるのだなあという認識に落ち着いてきました.あとはVCLが便利とか.Varnish自体に関しては利用できる箇所であれば利用したいところなので,今後適所に取り入れていきたいと思います.

トークをするとこういった情報が集まってきて嬉しいですね.ありがとうございます.