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

エンジニアですよ!

頑張れ俺くん、巨匠と呼ばれるその日まで

mixlib-cliのオプションで複数の値を渡す

github.com

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のレスポンスに入れる

laravel

なんて言ったらいいかよくわからないけどタイトルみたいなことがしたいときどうするか

テーブルのデータそのものじゃなくてテーブルのデータから計算できるデータがあったとして、それをクライアントに計算させるんじゃなくてレスポンスに入れて返したいとかそんな時

普通にドキュメントに書いてあるけど、そういう時は Accessors と $appends ってのを使うとできる

Accessors は↓これ。で、 appends については同じページの一番下に書いてある

Eloquent ORM - Laravel - The PHP Framework For Web Artisans

$appendsEloquent を継承してるクラスのメンバ変数として定義しておく

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 とかに渡すには setenvGOPATH とか設定しておかないといけないもんで、.zshrc に書きゃいいかとか安直に考えたわけだね、昔の俺。

違う違う。 launchctl なんだから launchd を使おう。

/etc/launchd.conf

setenv GOROOT=$GOROOT
setenv GOPATH=$GOPATH

と書くようにすることで解決。

ちなみに $HOME/.launchd.conf はダメ。

rustのffiでkqueue呼び出してみた

前回うまくできなかったけどやってみたらうまくいったという、それだけ。

前回試した時はopenの戻り値の型が c_int だから kevent struct の ident の型も無理矢理 c_int にしてたから、 Invalid Argumentのエラーが出てたんだけど、last_os_error()とか見てなかったから気付かなかったという話だった

正しくuintptr_tで定義して、渡すときは as uintptr_t でキャストしたらいけた。

gistでいいくらいの内容だけど

github.com

rustでentrクローンしてみようとした

rustがそろそろ1.0出るってことでしばらく前からいじり始めた。

entrをgoでcloneしたgotrを見てちょっといいお題かも?とか思って書いてみようと思った。

totem3/rustr · GitHub

結果

今んとこできたこと

イベント検知して渡されたコマンドを実行できるようになった。-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-rsmacとか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回