mixlib-cliのオプションで複数の値を渡す
mixlib-cli、便利ですよね。
この option
で同じオプションで複数の値を渡したい時はどうすればいいか
例えば --hosts
で複数のホストの情報を渡したいとか。
ぱっと調べた感じ&動作を見た感じでは、 cmd --hosts host1 --hosts host2
とかいう渡し方でうまく処理してくれるということはなさそう
:proc
オプションを使うとそれっぽくできる
:proc
オプションは、 Proc
を渡しておくと渡された値をその関数で前処理しておいてくれる。
options :hosts, :long => "--hosts", :proc => Proc.new { |a| a.split(",") }
↑のようにしておくと cmd --hosts host1,host2
で複数の値をカンマ区切りで渡せば、プログラム内で config[:hosts] = ["host1", "host2"]
として使える。
テーブルのカラムにないデータをEloquentのレスポンスに入れる
なんて言ったらいいかよくわからないけどタイトルみたいなことがしたいときどうするか
テーブルのデータそのものじゃなくてテーブルのデータから計算できるデータがあったとして、それをクライアントに計算させるんじゃなくてレスポンスに入れて返したいとかそんな時
普通にドキュメントに書いてあるけど、そういう時は Accessors と $appends
ってのを使うとできる
Accessors は↓これ。で、 appends については同じページの一番下に書いてある
Eloquent ORM - Laravel - The PHP Framework For Web Artisans
$appends
は Eloquent
を継承してるクラスのメンバ変数として定義しておく
class SomeModel extends Eloquent { protected $table = 'some_table'; protected $appends = array('some_append_data'); // ←これ // Accessors public getSomeAppendDataAttribute() { return "something"; } }
こうすると、 SomeModel::find($id)
とかで返ってくるデータに
"some_append_data" => "something"
も一緒に入ってくる。
Laravel4 で rename column しようとするとエラー
php artisan migrate PHP Fatal error: Class 'Doctrine\DBAL\Driver\PDOMySql\Driver' not found in .../vendor/laravel/framework/src/Illuminate/Database/MySqlConnection.php on line 59
みたいなエラーが出てなんぞ、と思っていたところ
Schema Builder - Laravel - The PHP Framework For Web Artisans
Before dropping a column, be sure to add the doctrine/dbal dependency to your composer.json file.
普通にドキュメントに書いてあった。
composer.json の "require"
に "doctorine/dbal" : "2.5.*"
を足して composer install
して解決
tmux で Not privileged to set domain environment
いつからかtmuxを起動すると
Not privileged to set domain environment. Not privileged to set domain environment.
とエラーが出るようになった。
なんだこれは。
調べるとどうも .zshrc で launchctl setenv
とかいじってるのが問題らしい。
何してたかというと、
launchctl setenv GOROOT=$GOROOT launchctl setenv GOPATH=$GOPATH
とかしていた。
IDEA とかに渡すには setenv
で GOPATH
とか設定しておかないといけないもんで、.zshrc に書きゃいいかとか安直に考えたわけだね、昔の俺。
違う違う。 launchctl
なんだから launchd
を使おう。
/etc/launchd.conf
に
setenv GOROOT=$GOROOT setenv GOPATH=$GOPATH
と書くようにすることで解決。
ちなみに $HOME/.launchd.conf
はダメ。
rustのffiでkqueue呼び出してみた
rustでentrクローンしてみようとした
rustがそろそろ1.0出るってことでしばらく前からいじり始めた。
entrをgoでcloneしたgotrを見てちょっといいお題かも?とか思って書いてみようと思った。
結果
今んとこできたこと
イベント検知して渡されたコマンドを実行できるようになった。-c で画面をクリアするところまで。
けど後で書くけど、エディタで編集するとダメという残念仕様になってる。
更には本家はplatform非依存(多分?)だけどこれはinotify使えないとダメなのでlinux(でかつinotify使えるバージョン)限定
これの開発中entrでcargo buildを回し続けてたけど、代わりに自分が書いたclone使えるかっていうと使えないというレベル。
entrの-dとか-rオプションがなんなのかよくわからんかったので実装してない。
あと排他処理とか実装してないのでひどい。
その他感想?
やはり本家はよくできてるなーと。
inotifyをわかってないので原因わかってないけど、エディタで編集すると単純にinotify使うだけだと監視し続けられないのかな??その後のイベント検出しなくなる(DELETE_SELFが飛ぶからかな?)
けどentrはうまくやってるっぽい。
inotify? fsnotify?
軽い気持ちで書き始めて後で気付いたけどinotifyとかさっぱりわかってなかった。
inotifyとfsnotifyの違いがわかってなくて、fsnotifyのつもりでinotify-rsを使っててmacで動かない理由がしばらくわからなかった
macではkqueueというのがあるのね。go-fsnotifyではmacではkqueueをラップしてた。
fsnotify-rsのmacとかlinuxの部分を作ってやろうと思ってffiと数日戦った。
けど、macのkqueueでkeventがeventを待ってくれずすぐ変な値を返してきてうまくいかず、cの知識もrustの知識もないのでどこがいけないのかよくわからず断念した
ownership難しいな
rustについてはやはりownershipが難しい。
ちょっとstructにしてみようとかthreadで使ってみようとか思うと途端に扱いが難しくなる(気がした)
'staticじゃないとダメだと言われたり、does not live long enoughが解決できなかったり
大体はとりあえず&を付けてみたりしてなんとかなるところあるけど、それ全くわかってないしちょっと複雑になると太刀打ちできなくなる
RcとかArcとかRwLockとかその辺ちゃんと使えるようになる必要があるかなー
Go便利
参考にGoのコードをたくさん読んで、Goいいなと思った
appcコンテナを作ってみる
前回 Docker のイメージから ACI を作り、 Rocket で動かすということをやってみた。
今回は仕様を見ながらイメージを作ってみる。
appc の仕様はここにまとまっている。(リンクはこれを書いてる時点で見てたバージョン。v0.4.1)
https://github.com/appc/spec/blob/bf255efb12f2455c0f6eb81932458abc0ad80413/SPEC.md
App Container Image の部分を中心に見る。
ACI のファイルフォーマットのことをイメージアーカイブと呼んでいるらしい。 その構造について決まっていることはいくつかあって、
- 拡張子は .aci じゃないといけない
- 中身に重複がない tar ファイルフォーマットのファイルじゃないといけない
- トップレベルに manifest というファイルと rootfs というディレクトリを持っていないといけない
- イメージに入れるファイルは元々の属性を全部維持していないといけない
- gzip, bzip2, xz のどれかで圧縮してもOK
- AES対称暗号(?)で暗号化してもいい
- PGPで署名されるべき
- 署名の拡張子は .aci.asc
という感じ
ここによれば、最も単純な ACI は、単なる tar ファイルで、最低限 manifest と rootfs があればいいことがわかる。
今回はその最も単純な方法で、 nc を使った簡易ウェブサーバが動くか試してみる。
こういうシェルスクリプトを動かしたい。
#!/bin/sh while true; do ( echo "HTTP/1.0 200 Ok"; echo; echo "Hello World" ) | nc -l 8080; [ $? != 0 ] && break; done
manifest ファイルはちょっとめんどいので、まずは入れ物のディレクトリを作る
mkdir rootfs
コンテナには必要なものを全部入れる必要がある。
ここでいうとこのスクリプトを動かす sh と、中で使っている nc が少なくとも必要になってくる。
というわけでまず rootfs に bin のディレクトリを作る。
で、そこに sh と nc を入れる
mkdir rootfs/bin cp -a /bin/sh rootfs/bin/sh cp -a /bin/dash rootfs/bin/dash cp -a /bin/sh rootfs/bin/sh cp -a /bin/nc.openbsd rootfs/bin/nc
最初ここでシンボリックリンクの /bin/sh と /bin/nc しかコピーしてなくて、リンク先がなくて動かないという凡ミスを犯したw
nc は今回試した環境では↓こうなってたので、リンク先を名前変えて突っ込む
vagrant@vagrant-ubuntu-trusty-64:~$ ls -la /bin/nc lrwxrwxrwx 1 root root 20 Jan 30 18:42 /bin/nc -> /etc/alternatives/nc vagrant@vagrant-ubuntu-trusty-64:~$ ls -la /etc/alternatives/nc lrwxrwxrwx 1 root root 15 Jan 30 18:42 /etc/alternatives/nc -> /bin/nc.openbsd
次に、実行するファイルが使うライブラリもないといけない。
vagrant@vagrant-ubuntu-trusty-64:~/test-container$ ldd rootfs/bin/sh linux-vdso.so.1 => (0x00007fff059e6000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb2255f9000) /lib64/ld-linux-x86-64.so.2 (0x00007fb225be8000) vagrant@vagrant-ubuntu-trusty-64:~/test-container$ ldd rootfs/bin/nc linux-vdso.so.1 => (0x00007fffd20f4000) libbsd.so.0 => /lib/x86_64-linux-gnu/libbsd.so.0 (0x00007fec3a421000) libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007fec3a206000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fec39e3f000) /lib64/ld-linux-x86-64.so.2 (0x00007fec3a639000)
これらが全部必要なので、rootfs 以下の対応する場所にこれらをコピーしておく。
で、最後に動かしたいシェルファイルを適当な場所に置く。
今回は /usr/bin に置く。
やってみて、ディレクトリは以下のようになった
vagrant@vagrant-ubuntu-trusty-64:~/test-container$ tree . . ├── manifest └── rootfs ├── bin │ ├── dash │ ├── nc │ └── sh -> dash ├── lib │ └── x86_64-linux-gnu │ ├── ld-2.19.so │ ├── libbsd.so.0 -> libbsd.so.0.6.0 │ ├── libbsd.so.0.6.0 │ ├── libc-2.19.so │ ├── libc.so.6 -> libc-2.19.so │ ├── libresolv-2.19.so │ └── libresolv.so.2 -> libresolv-2.19.so ├── lib64 │ └── ld-linux-x86-64.so.2 -> /lib/x86_64-linux-gnu/ld-2.19.so └── usr └── bin └── tinyweb 7 directories, 13 files
次に manifest を作っていく
manifest のスキーマは以下にまとまっている。 https://github.com/appc/spec/blob/bf255efb12f2455c0f6eb81932458abc0ad80413/SPEC.md#manifest-schemas
具体的には Go のコード読んだほうがいいかも https://github.com/appc/spec/blob/bf255efb12f2455c0f6eb81932458abc0ad80413/schema/image.go
SPEC.md にある例をコピーして、必要ないところは消しつつ作ってみる
type ImageManifest struct { ACKind types.ACKind `json:"acKind"` ACVersion types.SemVer `json:"acVersion"` Name types.ACName `json:"name"` Labels types.Labels `json:"labels,omitempty"` App *types.App `json:"app,omitempty"` Annotations types.Annotations `json:"annotations,omitempty"` Dependencies types.Dependencies `json:"dependencies,omitempty"` PathWhitelist []string `json:"pathWhitelist,omitempty"` }
ここで omitempty になるものはなくてもいいはず。
なので acKing, acVersion, name は書く。
labels はそのまま残しておこう。
app はなくてもいいが、ないと思ったとおりに実行できないので書く。
exec にさきほど用意した /usr/bin/tinyweb を指定する。
その他は特に今回は不要なので空にしておく
docker と違ってデフォルトではホストのネットワークを使うので、特にポートをバインドとかは必要ない。
で、結果として以下のような感じになった
vagrant@vagrant-ubuntu-trusty-64:~/test-container$ cat manifest { "acKind": "ImageManifest", "acVersion": "0.4.1", "name": "test-container", "labels": [ { "name": "version", "value": "1.0.0" }, { "name": "arch", "value": "amd64" }, { "name": "os", "value": "linux" } ], "app": { "exec": [ "/usr/bin/tinyweb" ], "user": "0", "group": "0", "eventHandlers": [], "workingDirectory": "", "environment": [ ], "isolators": [ ], "mountPoints": [ ], "ports": [ ] }, "dependencies": [ ], "annotations": [ { "name": "authors", "value": "totem3 <totem3@github>" }, { "name": "documentation", "value": "https://github.com/totem3/containers" }, { "name": "homepage", "value": "https://github.com/totem3/containers" } ] }
これで作ってみよう。
vagrant@vagrant-ubuntu-trusty-64:~/test-container$ tar cvf test-container.aci manifest rootfs manifest rootfs/ rootfs/lib/ rootfs/lib/x86_64-linux-gnu/ rootfs/lib/x86_64-linux-gnu/libresolv-2.19.so rootfs/lib/x86_64-linux-gnu/libresolv.so.2 rootfs/lib/x86_64-linux-gnu/libc.so.6 rootfs/lib/x86_64-linux-gnu/libbsd.so.0.6.0 rootfs/lib/x86_64-linux-gnu/libc-2.19.so rootfs/lib/x86_64-linux-gnu/libbsd.so.0 rootfs/lib/x86_64-linux-gnu/ld-2.19.so rootfs/lib64/ rootfs/lib64/ld-linux-x86-64.so.2 rootfs/usr/ rootfs/usr/bin/ rootfs/usr/bin/tinyweb rootfs/bin/ rootfs/bin/sh rootfs/bin/nc rootfs/bin/dash
done
動かしてみよう。
rkt で動かす
vagrant@vagrant-ubuntu-trusty-64:~/test-container$ sudo rkt run test-container.aci /etc/localtime is not a symlink, not updating container timezone.
動いた。 /etc/localtime がないと言われているが、これはとりあえず置いておこう
別のターミナルから8080番ポートを叩いてみる
vagrant@vagrant-ubuntu-trusty-64:~$ curl localhost:8080 Hello World
返ってきた。コンテナ側にもリクエストを受け付けた形跡がある
vagrant@vagrant-ubuntu-trusty-64:~/test-container$ sudo rkt run test-container.aci /etc/localtime is not a symlink, not updating container timezone. GET / HTTP/1.1 User-Agent: curl/7.35.0 Host: localhost:8080 Accept: */*
うん、動いていそう。
プロセスツリーはこうなってる。(このうえはsshとかshell)
root 9906 0.0 0.4 65736 2128 pts/0 S+ 21:13 0:00 |\_ sudo rkt run test-container.aci root 9907 28.0 0.2 27808 1216 pts/0 S+ 21:13 0:01 | \_ stage1/rootfs/usr/lib/ld-linux-x86-64.so.2 stage1/rootfs/usr/bin/systemd-nspawn --boot --register false --quiet --uuid=9a78fc07-b3cd-4fd3-8f84-749167e27f8e --directory=stage1/rootfs -- -- root 9912 0.0 0.4 22568 2224 ? Ss 21:13 0:00 | \_ /usr/lib/systemd/systemd --default-standard-output=tty --log-target=null --show-status=0 root 9913 0.0 0.0 4108 384 ? Ss 21:13 0:00 | \_ /usr/bin/sleep 9999999999d root 9915 0.0 0.1 4444 660 ? Ss 21:13 0:00 | \_ /bin/sh /usr/bin/tinyweb root 9917 0.0 0.0 9128 432 ? S 21:13 0:00 | \_ nc -l 8080
ランタイムの話はまた今度やろう
ちなみにコンテナの終了は ^] (ctrl+]) を3回