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

Thanks Driven Life

日々是感謝

Ruby 2.x 環境で magic comment 無しファイルを開くと flycheck で "invalid multibyte char (us-ascii)" と言われる場合

結論から言うと

(setenv "LC_ALL" "ja_JP.UTF-8")

;; or

(setenv "LANG" "ja_JP.UTF-8")

を試しましょう

経緯

こんなファイルのことです。

p 'あいうえお'

f:id:gongoZ:20160210091618p:plain

メッセージ自体はお馴染のものなので

といった情報がググるとすぐ出てきます。確かに ↑ のファイルに # coding: utf-8 を追加したらメッセージは出なくなりました。

ですが私が使っているマシンにはもはや Ruby 1.9 は入っていないので、このメッセージが出るのがおかしい。ってことで謎は深まっておりました。

原因

そんなときに @ さんより

といったアドバイスを頂いたので

(setenv "LC_ALL" "ja_JP.UTF-8")

を実行してみると

f:id:gongoZ:20160210092451g:plain

消えました。やったぜ。@ さんありがとうございました!

まとめ

以前から https://github.com/purcell/exec-path-from-shell は使っていて GOPATH とか RBENV_ROOT は取り込むようにしていましたが、 LC_ALL とかのことは忘れていました。要注意。

「Serverspec で期待値を直書きしてる部分、Puppet の hiera から持ってこれるけどどうする?」

Puppet や Serverspec に限らず、Chef でも Itamae でも awspec でも自前スクリプトでも何でもいい話なんですが。 つまり テストコードに書く期待値を、構成管理ツールで使っているパラメータファイルから取ってきたほうがいいのか という話題。

結論から言うと「何をテストしたいのか」によって Yes/No が変わるんじゃないかな、と思います。

前置き: 例えばこんなこと

hiera でこう書いてたとして

---

packages:
  - emacs
  - vim

manifest でこう書いてたとすると

$packages = hiera('packages')
package { $packages:
  ensure => latest
}

Serverspec ではこう書くと思います

describe package('vim') do
  it { should be_installed }
end

describe package('emacs') do
  it { should be_installed }
end

ある日、こんな要望がありました

  1. PHP 追加したいから hiera に書いといて
  2. emacs 必要無くなったから hiera から消しといて
 packages:
-  - emacs
   - vim
+  - php-common

このとき、テストコードでは describe package('xxx') の部分を一つずつ直していくことになるでしょう。 数はまだ少ないですが、もしパッケージ数が5個とか10個とかになるとどうでしょうか。 また、パッケージだけならともかく、service だったり iptables だったり、その他細々としたものを書き換える度に

「よっしゃ、manifest 書いてデプロイ完了したぜっってテスト落ちてる…あーはいはい、テストコードの部分を更新し忘れてましたね…」

となることはないでしょうか*1。 その時にアナタはこう思うでしょうか。


「テストコードも hiera を参照してくれれば変更点1箇所で済むのに」


すると、アナタはこんな感じでがんばるかもしれません

hiera = Hiera.new(config: '/path/to/hiera.yaml')
hiera.config[:yaml][:datadir] = '/path/to/hiera/hiera_data'
packages = hiera.lookup('packages', nil, {}) # ['vim', 'php5-common']

packages.each do |pkg|
  describe package(pkg) do
    it { should be_installed }
  end
end

こうすることで

  1. パラメータの変更を hiera に反映する
  2. puppet apply
  3. rspec

という形で サーバの仕様変更におけるパラメータ編集箇所 が1箇所に集約できるメリットが生まれました

本題: これでいいのかどうか

これまでの流れからすると、おそらく Puppet でサーバを構築しつつ Serverspec でテストしているこの人は

さきほど修正した hiera が、ちゃんとサーバに apply されているかどうか

というのを一番チェックしたいと考えていると思います。

f:id:gongoZ:20160115162912p:plain

これ自体は特に問題ないと思っていて、ちゃんとテスト流してて素晴しいですよねみたいな未来です。


ですがこれはあくまで視点の一つで、おそらくもう一つ、下図のような見方をすることもあると考えています。

f:id:gongoZ:20160115162916p:plain

つまり直前にテストしたかどうか、とかは関係なく、純粋に 現時点でのサーバが期待した状態(つまり仕様)を保っているか を中心とするテストです。

この場合、逆に hiera の値をテストコードに使うのはよくなくて

  1. hiera で php を追加するつもりが ruby を追加してしまった
  2. 気づかずに apply
  3. rspec
  4. 本当は php がインストールされていてほしいが、hiera 上は ruby が正義なので PASS

ここもレビューをしっかりしていれば防げるかもしれません。しかし、往々にして人は見逃してしまうものなので、ありえない未来じゃないなと思っています。

まとめ

私が業務で触っている部分では

  • Puppet
  • Terraform

に対して

  • Serverspec
  • infrataster
  • awspec

のテストを用意していて、それぞれのディレクトリも似たような構成にしています。 そのため、hiera ファイルをそのまま使えちゃうので、どうしても「テストコードにも書くのめんどいわー」みたいなことが、無くも無いです。

最終的にはどちらが良い悪い、ということではなくて「何をテストしたいか」っていう当たり前のことを忘れないでいてくれれば10年後の8月また元気で出会えるんじゃないかなと思います。

*1:マニフェストとテストコードをしっかり同時にレビューしてると、こういうのは無さそうですが…

Turnip 2.0.2, turnip_formatter 0.4.0, gnawrnip 0.4.0 リリースしました

新機能追加したわけじゃないです

Turnip 2.0.2

これまで gherkin3 という名前で開発が進んでいた gherkin の version3 が gherkin に rename されました。

https://github.com/cucumber/gherkin/commit/d47add1a5e1a835af8c5dd9f55f7fe7a4916c7dd

これにより、例えば Turnip 2.0.1 の gemspec のように

s.add_runtime_dependency "gherkin", ">= 2.5"

こう書いていると gherkin2 と互換性のない gherkin3 がインストールされるようになった というわけです。 issue で教えてもらいました。感謝 https://github.com/jnicklas/turnip/issues/169

turnip_formatter, gnawrnip 0.4.0

turnip_formatter は Turnip 2.0.2 に、gnawrnipturnip_formatter 0.4.0 に それぞれ追従する形で gemspec 直したりテスト対象の RSpec のバージョン直したりしてました。 たぶん動くと思います。

Gherkin3 について

将来的には Gherkin3 への対応をしようかなと考えてたりします。

Use Gherkin3 · Issue #171 · jnicklas/turnip

いつになるかはわかりませんが。

2015年を振り返って

f:id:gongoZ:20151231190704p:plain

gongo.hatenablog.com

ふりかえり〜

OSS活動

2014年に Turnip のオーナー権を貰って から、ちょくちょく活動しています。 今年の作業としては、RSpec のバージョンを結構新しめ限定にするという Turnip 2.0.0 をリリースできたのが良かったです。

[Proposal] RSpec support policy · Issue #158 · jnicklas/turnip

社外でこのような提案する機会は今までなかったので、良い経験でした。

発表

今年は珍しく発表する機会がありました。

最初で最後だった YAPC Asia はやはり印象深いです。よく、あの規模の会場の壇上にあがって Perl にまったくカスらない内容を発表できたなーと。 発表のネタに繋がる作業は割とマジメに取り組んでいたんですが、結果的に笑い取れたので今年勝利したことにしておきます。

その他

久々に Advent Calendar に参加したり、ちょくちょく Vue.js 触ったり、ぐらいでしょうか。 2014年のふりかえり と見比べると、だいたい同じことしてるなという感想です。

まとめ

2016年もよろしくお願い致します。

Turnip 2.0.1 リリースしました

Release Version 2.0.1 · jnicklas/turnip

修正内容

たとえばこういう feature があったとして

Feature: Feature with background
  Background:
    Given there is a monster
  Scenario: simple scenario
    When I attack it
    Then it should die

RSpec の documentation format でテスト結果を表示した場合、Turnip 2.0.0 までは

Feature with background
  simple scenario
    When I attack it -> Then it should die

こういう形で Background のステップ名が表示されていなかった のですが、2.0.1 より

Feature with background
  simple scenario
    Given there is a monster -> When I attack it -> Then it should die

こんな感じで Background のステップ名も表示されるようになりました。

まとめ

メリークリスマス!!

Turnip 2.0.0 リリースされました

Release Version 2.0.0 · jnicklas/turnip

メジャーバージョンアップとなる 2.0.0 ですが、機能追加されたとか機能削除されたとかではなく

RSpec のサポートバージョンポリシー策定

の一環です。

経緯

github.com

以前は RSpec 2.14.x 系から RSpec 3.x の最新まで全てをサポートする体制でした。 定義されていなかった というのが正確なところですが。

ともかく近年の RSpec の躍進ぶりを追い続けるため、全てのバージョンをサポートしていくのは現状メンテナ一人の状態では無理と判断し、上記のような提案をさせていただきました。

提案の結果

反応としては「まあいいんじゃないのー」といった肯定的なものだったので、安心してばっさりいきました。つまり

  • 最新のバージョン、およびその一つ前のバージョンだけをサポートする
  • それ以前のバージョンはサポート対象外(動くかもしれない)

という形にしました。

最近の RSpec 3.x のリリースは 2,3 ヶ月に1回となっており、まあ約半年ぐらいあれば Turnip ユーザも手元の RSpec のバージョン上げられるだろ、ぐらいの気持ちで進めています。

そんなわけで

Turnip をこれからもよろしくお願い致します。

heroku-docker を使って Emacs & Cask がインストールされた Heroku 環境 (Slug) を作成する Docker イメージ作った

成果物

経緯

Emacs を使っている人は、日頃から

「あー Emacs でも HTTP サーバ立てられるんだし Heroku で起動してーなー」

と考えていると思います。

しかし Emacs ぐらいになると Heroku が標準サポートしている環境には含まれておらず、
いわゆるサードパーティ製 buildpack の導入が必要となります。

Emacs の buildpack もあった*1 のですが

  1. 試しに使ってみたら、なんかエラー出た*2
  2. まあ直せばいいかーと思う
  3. buildpack の修正検証ってものすごいめんどくさいイメージ(ちゃんと調べてない)
  4. モチベーション消えた

みたいな人生を送っていました。

Heroku + Docker

そんなある日、もう一つの可能性である Docker を思い出しました。

Build and Deploy with Docker | Heroku Dev Center

リリースされた当時は

「好きな Docker イメージを Heroku で動かせるのかよすごい!!」

みたいな反応が多数(私も)だったのですが、実際には

  1. 「Heroku と同等の環境を Docker イメージとして配布する」
  2. 「その中で動作確認しろよ」
  3. 「(制限はあるが)そのままデプロイできるフローも作ったぜ」

的なものでした。

デプロイ方法もあるし、ドカドカデバックできるので、これで行こうと決めました。

そんなわけで作りました。

https://github.com/gongo/emacs-heroku-docker

概要は README を読んでもらうとして、つまり必要なことは

  1. 普段通り Emacs Lisp で Web アプリケーションを書く
  2. Cask ファイルを作成し、依存パッケージを書く
  3. Heroku ではお馴染の Procfile に、起動コマンドを書く
  4. コンテナビルドしたり Heroku へリリースするためのファイルを作成
    • docker build したあとのファイルを転送するため、リリースにも使われる
  5. heroku docker:release

みたいな感じです。

試しに作ったのがこちら

https://emacs-heroku-docker-sample.herokuapp.com/

いつか消します

補足

heroku-docker でデプロイする時に注意するところ、備忘録も兼ねて

1. /app 以下のファイルしか転送されない

heroku docker:release で Heroku にデプロイされるファイルは、awesome氏のポストにもある通り

/app以下をtgzで固めてcpコマンドでそれを取り出している.なのでDockerfileに独自の変更を加えるときは注意が必要で/app以下に依存をちゃんと含めるように書く必要がある.

Herokuの'docker:release'の動き | SOTA

という制限(仕様)となっています。

つまり、Dockerfile で素直に apt-get install emacs とかやっても、Heroku 側には Emacs が入っていない slug が転送されてしまう、ということです。 なので今回はソースコードからコンパイルし、 /app/emacs 以下にインストールすることで依存を /app 以下に閉じ込めました。Cask についても同様。

2. 環境変数 export は /app/.profile.d/* 以下に書いておこう

上記のとおり heroku docker:release で転送されるのは、コンテナ内の /app 以下だけ。つまり

ENV PATH /app/emacs/bin:$PATH

みたいなのを書いていても、docker run した環境では使えますが Heroku 上には反映されません

ではどうするか。/app/.profile.d/ 以下に、環境変数設定するファイルを書いておきます。

.profile.d Scripts | Heroku Dev Center

$HOME/.profile.d/ 以下に置いたやつは Dyno 起動時に読まれるので、必要な処理はここに書いておきましょう。

ちなみに heroku-ruby では Dockerfile の ENTRYPOINT として init.sh というものを仕込んでいます。

#!/bin/bash

for SCRIPT in /app/.profile.d/*;
  do source $SCRIPT;
done

exec "$@"

こうすることで

Procfile:

web: cask exec emacs -Q --batch -l app.el

docker run 時:

$ docker run `コンテナ名` cask exec emacs -Q --batch -l app.el

つまり

  • Procfile に書くコマンドと docker run のコマンドを揃えることができる
  • どちらもコンテナ起動時に /app/.profile.d/* 以下を読んでくれる

という感じで、より Heroku の環境に近づけることができる、というわけです。

まとめ

heroku-docker を使うことで、buildpack よりも破壊再構築のサイクルを早く回せると思います。 どんどん作って最高のオレオレ cedar:14 にしよう!!

参考

*1:https://github.com/technomancy/heroku-buildpack-emacs

*2:libgpmが無いとかなんとか