Brainfuckインタープリタを実装してみました
久々に月間200時間ペースで働いていたら、結構大変です。よく以前平均これより働いてたな・・・。
さて、このインタープリタですが、ずっとやってみたかったやつですが、予定より早めに会社で使う資料ができて、時間ができたので作ってみました。
ものすごい素朴な実装ですので、最適化とか関数型言語っぽくないとか色々あると思いますが、正味2時間くらいで実装できました。
やっぱりOCamlとかだと、こういうものは書き易いと思います。素朴に書いても普通に読める長さです。Brainfuck自体の実装がシンプルだと言われればそうなのですが・・・。
https://github.com/derui/brainfuck
とりあえずgithubに上げました。最近なるべくgitで管理するようにしています。
気付いたら今年も残り四分の一になろうとしています。やろうとしていることを選別しないとなー・・・、と思いつつ、やりたいことは増えていくのです。
S2JUnit4をJUnit4.8でも使いたい
このブログでJavaについて書くのは初めてな気がしますが、仕事では基本的にJava使いです。
Seasar2を使い始めたのは、今の会社に入ってからなのですが、S2JUnit4が中々使いやすいので、今のプロジェクトでも導入してみてました。
しかし、S2JUnit4は、JUnit4.4でしか(完全には)動作せず、4.5や自分のプロジェクトで使っている4.8とかでは、一部メソッドだけの実行が上手くいかなかったり、Enclosedの内部クラスで上手く動作しなかったりと、なにかと不便です。
特に、メソッド単位で実行できないのは、Quick JUnitの恩恵があまり受けられないため、わりとストレスに感じていました。ですが、今のプロジェクトでは、テストに限定して導入しているため、全体はDIをするような作りになっていませんし、テストだけだからまぁいっか・・・という感じでした。
それでも、ひたすらコーディングしていると、それらのわずらわしさがやたらと気になりはじめたので、ちょっと調査してやってみました。
S2JUnit4でメソッド単位実行できるように
まず、上手くいかない原因は、Sorterに渡しているS2TestClassRunnerのインターフェースがRunnerで作成しているのですが、Sorterに渡すのはSortableインターフェースでなければならないため、ここに齟齬が発生していたようでした。S2TestClassRunner自体はSortableインターフェースをimplementsしていたので、これをそのまま渡せばいいんじゃまいか、ということで、以下のように派生クラスを作成してやってみました。
まずはSeasar2クラスの派生クラス。
package hoge; import org.junit.runner.Description; import org.junit.runner.manipulation.Filter; import org.junit.runner.manipulation.NoTestsRemainException; import org.junit.runner.manipulation.Sorter; import org.junit.runner.notification.RunNotifier; import org.seasar.framework.unit.S2TestClassRunner; import org.seasar.framework.unit.Seasar2; public class Seasar2Extension extends Seasar2 { private final S2TestClassRunner extendedDelegate; /** * @param clazz * @throws Exception */ public Seasar2Extension(final Class<?> clazz) throws Exception { super(clazz); setProvider(new S2DefaultProviderExtension()); this.extendedDelegate = (S2TestClassRunner) createTestClassRunner(clazz); } @Override public Description getDescription() { return extendedDelegate.getDescription(); } @Override public void run(final RunNotifier notifier) { extendedDelegate.run(notifier); } @Override public void filter(final Filter filter) throws NoTestsRemainException { filter.apply(extendedDelegate); } @Override public void sort(final Sorter sorter) { sorter.apply(extendedDelegate); } }
S2TestClassRunnerを生成するためのProviderについても、派生クラスを定義しておきます。
package hoge; import org.junit.runner.Runner; import org.seasar.framework.unit.S2Parameterized; import org.seasar.framework.unit.S2TestClassMethodsRunner; import org.seasar.framework.unit.Seasar2.DefaultProvider; public class S2DefaultProviderExtension extends DefaultProvider { @Override public Runner createTestClassRunner(final Class<?> clazz) throws Exception { if (hasParameterAnnotation(clazz)) { return new S2Parameterized(clazz); } return new S2TestClassRunnerExtension(clazz, new S2TestClassMethodsRunner(clazz)); } }
S2TestClassRunnerExtensionは、Seaser2Extensionと同様に、filterとsortでsorterなどに渡しているdelegateを、Runnerインターフェースではなく、S2TestClassMethodRunnerにして渡しているだけです。
実際に調べながらやったので、2時間くらいはかかりましたが、これでQuick JUnitも使えるようになり、同時にEnclosedしたクラスの内部クラスで@RunWithを使っても、問題なく動作するようになりました。
後はjmockitと同時に動かせればいいのですが・・・、まぁその辺はできなくてもなんとかなるので大丈夫です。
もし同じように悩んでいる方の参考になれば。
NodeのREPLとEmacsとで話をする
随分久しぶりになってしまいました。最近は土日しか時間が取れないうえ、土日もどっちかというとゲームに忙殺?される毎日です。
以前ac-typescriptというものを作りましたが、実際パフォーマンスについてはまだ満足いっていない状態でした。
パフォーマンスが上がらなかったのは、原因としてはもうWebsocketだから、という他無さそうです(TypeScriptコンパイラ自体の遅さは置いておいて)。
しかし、WebSocket以上の速度を出そうとすると、取れる手段は後一つ・・・パイプ(ソケット)通信しかなさそうです。
EmacsからFirefoxのReplを動作させる、とかそういうこともできているようなので、できないことはなさそうです。
NodeのREPL
ローカルでJavaScriptを動作させるため、とりあえずNodeを使っています。
Nodeには、そのものずばりの名前を持つreplモジュールというのが標準で添付されています。
var repl = require('repl'); repl.start(" >");
みたいな感じで使えます。第二引数はstreamであればなんでもよいらしいので、ここにソケットとかを設定して、HTTP経由でREPLを弄ったり、というのもできるようです。
とりあえずこれを使ってみます。
Emacs側
Emacsは非同期プロセスを扱う柔軟な方法がいくつかあります。
- start-process
- start-process-shell-command
非同期で実行する場合、大体この二つのどちらかが利用されるようです。shellとかが無い環境でも動作するのはstart-processの方なんでしょうか?調べてませんが・・・。
これらは、いずれも起動させたプロセスに対して、バッファを一つ割り当てることができます。後述のfilterを設定していない場合、プロセスの出力が全部これに出力されます。
プロセスからのログとかを出力するだけならこれでもいいんですが、出力に対して動作をさせたいとかがある場合、
(set-process-filter プロセス 関数)
として、filterを登録する必要があります。このfilterには、プロセスとプロセスからの出力が渡されます。基本的には標準出力に出力された文字列が出力されてきます。
・・・が、今回はここで引っ掛かりました。
Nodeのreplに対して、process-send-stringでを文字列を送信しているのですが、この出力した文字列がprocess-filterに引っ掛かり、対してNodeの方でconsole.logをしている文字列が欠片も渡ってきません・・・。
というか、process-filterに入力した文字列が渡ってくること自体が想定外でした。よく考えればそりゃそうか、とも思えなくも無いのですが、どこでconsole.logしても文字列が返ってこないため、なんともはや、という状態です。
現状、これをどうにかしたいのですが、中々どうにかなってくれないため、色々試しています。これが上手くいけば大分速くなりそうなんですがねー。
Camlp4の文法拡張について
梅雨にかかわらず、記録的な少雨になりそうとか不吉なことが囁かれていて、今から夏が不安です。というか今から暑いのは勘弁してくださいほんと。
そんな中、ふとやってみたくなったことがありました。前に、Kaputtを紹介しましたが、BDD的なツールとして、RSpecをインスパイアしたOSpecというものも存在します。使ってはいないんですが、サンプルによるとこんなコードでテストができるようです。
https://github.com/andrenth/ospec/blob/master/examples/features.ml
describe "The number one" do it "should equal 2 when added to itself" do (1 + 1) should = 2 done; it "should be positive" do let positive x = x > 0 in 1 should be positive; 1 should be (fun x -> x > 0); 1 should be (fun x y -> x > y) 0 done; it "should be negative when multiplied by -1" do let x = 1 * (-1) in x should be < 0; x should not be >= 0 done; it "should raise when divided by 0" do let f = (fun () -> 1 / 0) in f should raise_an_exception; f should raise_exception Division_by_zero; f should not raise_exception Exit done; it "should match ^[0-9]+$ when converted to a string" do (string_of_int 1) should match_regexp "^[0-9]+$" done; it "should be cool" done
さて、これを見ると、通常のOCamlソースではないことは一目瞭然だと思います。
- do〜doneがfor/whileじゃないのに使えてる
- shouldとかbeとかが中置演算子みたいに使えてる
- 関数適用とかの順序がなんか違う
- =や>=が()でくくらなくても使えてる
こんなことは、Camlp4を使わないと不可能です。type_convのwithとかも多分Camlp4で文法拡張していると思います。
こういうのを見るとやってみたくなるのが、メインストリームじゃないもの(OCamlがメインストリームじゃないとは思いませんが)に興味を持つ人間の性ではありますが、Camlp4の情報がいかんせん少ないです。特に日本語情報が少なすぎて涙が出そうなので、とりあえず調べた結果を書き連ねていこうかと思います。
最終的には、簡単なSpecを書けるように(なれればいいなぁ)。
なお、以下ではCamlp4のquotationとかについては割愛します。確か前にこのブログで書いた気が・・・。
Camlp4の文法拡張について
Camlp4では、文法(Grammar)についても拡張することができます。
拡張は、以下のような形式で定義することができます。
EXTEND Gram ... END
重要なのは当然ながら...の部分なので、以下でそれを(私が調べた範囲で)詳しく書いていってみたいと思います。
文法の拡張方法
EXTEND Gram
...
END
の...にあたる部分(以降では文法定義とします)についてですが、これは基本的に以下のような構成となっています。
文法要素名 : {LEVEL "ラベル"} [{"ラベル"} [ 要素のBNF的な定義 -> 文法要素の結果の型となる値 | 要素のBNF的な定義 -> 文法要素の結果の型となる値 ... ] | {"ラベル"} [...] ]
つまり、その終端記号と認識するためのBNF的な定義にマッチした場合に、結果となる型を提供する、という
形になります。
二重になっている[]ですが、これがいまいち私も理解していないのですが、最外部のの内部は、定義されたの単位で、先に定義された方が低いレベルとして、パーサーの中で優先順位が下がる、という形になっているようです。
その前に付与されるラベルは、他の文法定義の中で利用するためのラベルとして利用されます。付与しなくてもOKです。
[]の前に付いているLEVEL "ラベル"ですが、これは基本的には無くても問題無いのですが、既存の文法を拡張するときとかは、これによって拡張先の文法を指定する、という感じ・・・だと思います(汗
BNF的な定義は、以下のような要素(termとでも呼ぶんでしょうか)を;で区切った形式で構成されます。ほかにもあるんでしょうが、あまり必要な気がしません。
- 文字列
- ソース上の文字列とそのまま対応する
- 束縛変数名 = 型
- その位置にある値が、指定した型である場合に、その型の値を変数に束縛する
`束縛変数名 = 型`の型の部分には、以下のようなtermを入れることができます。
- LIST0 term
- 指定した終端記号が0個以上。LIST0 〜 SEP ","のようにして、区切りを指定することもできる。また、termの部分は、[]で囲むことで、他の終端記号の組み合わせで構築することもできる
- STRING
- 文字列
- INT
- 整数
- FLOAT
- 浮動小数点数
- 文法要素名
- 指定した文法要素
Gramの直後の終端記号は、quotationとして指定することで、その内部が上記で指定したGrammarであるとしてパースしてくれます。
なお、BNF的な定義中で""で囲んだ部分については、実際のソース上では""が付かない形のものとして認識されます。
新規文法の作成
標準文法の作成だけではなく、新しいquotationsを一から作成することもできます、が、ここでは省略します。JSONを自動的にvalidなOCamlに変換する、とかもできるようですが、ここでは割愛します。またやってみたくなったら書くと思います。
文法拡張を含む場合のコンパイル
ocamlfindを利用する前提として、通常のcamlp4のコンパイルのフラグに加えて、以下のフラグを指定する必要があります。
- -package camlp4.extend
例として、myparser.mlというファイルに拡張文法を記載した場合のコンパイルは以下のようになります。
内部でquotationsを利用する場合は、packageに更にcamlp4.quotations.oとかを加える必要がありますが。
$ ocamlfind ocamlc -package camlp4.extend,camlp4.lib -syntax camlp4o myparser.ml
文法拡張が動作しているかのチェック方法
camlp4ofを使い、以下のような形で実施します。
$ camlp4of -parser <作成したcmo> <対象のml/mli>
結果は標準出力に出力されるので、それを確認しましょう。上手くいかなくても泣かない。
最小のサンプル
ここでは、OCamlの基本文法を拡張することを念頭に置いて、最も簡単な拡張のサンプルを記述してみます。
open Camlp4.PreCast open Syntax EXTEND Gram expr: LEVEL "simple" [ ["foo" -> <:expr<"foo+bar">>] ]; END
これは、fooというidentityがあった場合、それをfoo+barという「文字列」に展開するような文法を新規に定義しています。文字列の部分をexpr quotatonで囲んでいるのは、exprという文法要素が、ASTを返すことを要求しているため、これをやっておかないとそもそもコンパイルエラーになります。
これのコンパイルは、extendとquotatonを含んでいるため、以下のような形になります。(これをmyparser.mlというファイルに記述した場合)
$ ocamlfind ocamlc -package camlp4.quotations.o,camlp4.extend,camlp4.lib -syntax camlp4o myparser.ml
で、できたこれを
let a = foo ^ "bar"
というソースをsample.mlというファイルに保存した場合、以下のようにして結果を確認できます。
camlp4of -parser myparser.cmo sample.ml
出力結果は以下のようになります。
let a = "foo+bar" ^ "bar"
これくらいわかれば、後はquotationとantiquotationを駆使することでできるようです・・・。うん、そう簡単にいきませんよね。でもこれが大体わかったら、なんとなくですがソースは読めるようになりました。
とりあえず終わり
この記事の目的は、Camlp4の文法拡張方法についてまとめることでしたので、とりあえずこんな感じ、ということを書き連ねました。Camlp4については、実際に利用されているソースを見るのが一番の勉強になると思います、ほんと。
でも、最初のとっかかりがあれば、その調べる時間でいろいろ試すこととかもできるはずなので、なんかやってみたい人の最初の一歩になれればいいなー、と思います。というか自分がまず一歩を踏み出さんと。
xUnitもQuickCheckも使えるテストツールKaputt
現場が社内から、常駐先になったことで、なんか前職とあまり変わらない感覚になってしまい、どうにも色々とやる気がでませんでした。通勤時間が倍になったから、というのもあります。
まぁやる気が無いこと自体はいつものことではあるので、それはどうかとも思いますが、とりあえずやる気を捻りだしてみます。
OUnitで十分じゃ?
今まで、(あまり書いていませんが)OCamlでテストを書くときは、OUnitを利用していました。OUnitはシンプルかつ、test suiteとしてまとめやすい、JUnitとかとほとんど同じような使い勝手なので、あまり悩まずに利用できる、ということ感じでした。
もちろん現在でも更新は続けられていますし、余程複雑なものにでもならない限りは、これで必要十分じゃないかとも思います。
ただ、シンプルな分、他にやりたいことがあれば、自分で実装する必要があります。また、基本的にはReporterとかは用意されていないため、何かレポートが必要な場合などは、自分でなんやかや作る必要があります。(多分)
また、QuickCheck的な機構は当然ながら無いので、それらのテストを行いたい場合は、そのツールを別途導入する必要があります
Kaputtとは
Kaputtは、公式ページによると以下のようなテストを行うことができます。
- assertionベースのテスト(xUnit)
- specificationベースのテスト(QuickCheck)
- enumrationベースのテスト(SmallCheck)
- shellベースのテスト
SmallCheckってなんぞや?と思ってググってみましたが、Haskellで作成されたテスティングフレームワークのようです。ある値の全領域についてのテストを、自動的にテストケースを生成して実行する、というもののようです(合ってんのかな?)
これらがall in oneになっていることが、Kaputtの一番の特徴ではないかと思います。また、上記以外にも、
などが標準で用意されており、かなり強力です。
ただし、個人的には、OUnitにあった、コンビネータベースでtest suiteを作成できる機能が無いのがちょっと残念です。また、OUnitと流儀が違い、
- OUnit : 小さいテストを組み合わせて、suiteを実行する
- Kaputt : それぞれのテストケースを実行する(suiteとかの概念は基本無い)
という感じです。Kaputtでは、それぞれのテストケース自体に名前を付けることができるので、それでカバーできるとは思います。
使ってみる
とりあえず簡単にインストールして使ってみます・・・と言っても、opamからインストールできてしまうので、この辺の手間が省けてすばらしいです。
$ opam install kaputt
open Kaputt.Abbreviations let t = make_simple_test ~title:"first test" (fun () -> Assert.equal_string "hoge" "hoge"; Assert.not_equal_string "hoge" "foobar"; ) let () = Test.run_test t
とりあえずはこんな感じになります。Assertモジュールに各種assertionが定義されていますが、assertion builderというものもあり、それを利用すると、独自定義したような型に対するassertionも比較的簡単に作成することができます。
まぁもっと有用な実例は、Kaputtのリファレンスに詳しく載っていますので、そちらを見てもらった方が早いと思います。
OUnitでも十分ですが
Kaputtを使う理由としては、all in oneであることと、標準で様々な形式のreporterが提供されている、ということになるでしょうか。シンプルさでいえば、OUnitは非常にシンプルながら、こなれたインターフェースを利用できますので、色々な機能を自分で実装したいような方はOUnitでも十分だと思います。
ただ、色々なツールがあるのならば、それらを比較することも大切じゃまいか、ということで記事にしました。Kaputtの日本語記事はさっとググっても見付からなかったので、これが誰かの一助になればと思います。
GenericsでBackbone.jsのModelっぽいものを作ってみる
TypeScriptが、0.9.0.alphaとして、preview releaseが行われています。http://typescript.codeplex.com/releases/view/105503
0.9.0の目玉機能は、何といってもGenericsとOverload on constantsです。これが加わることで、大体Java5くらいの表現力があるんじゃないかと思います。
Genricsが使えるということは、型による制御が色んなところでできるんじゃね?という思いと共に、最近トレンドになってきたクライアントサイドMVCとかにもこれが生かせるんじゃないかとも思います。
ということで、これが使えて(多分)一番嬉しいと思われる、ModelをGenericsでなんとか表現できないか、色々試してみました。
この記事は、TypeScriptのrelease-0.9.0.alphaブランチを利用しています。バグが残っているかもしれませんし、そもそも細かい仕様とかが変わるかもしれませんので、その辺は最新の情報を参照してください
TypeScriptのGenerics
その前に、TypeScriptでのGenericsはどんな感じのものなのか見てみます。TypeScriptの仕様書に十分なサンプルが載っていますので、そこから引用すると
interface A { a: string; } interface B extends A { b: string; } interface C extends B { c: string; } interface G<T, U extends B> { x: T; y: U; } var v1: G<A, C>; // Ok var v2: G<{ a: string }, C>; // Ok, equivalent to G<A, C> var v3: G<A, A>; // Error, A not valid argument for U var v4: G<G<A, B>, C>; // Ok var v5: G<any, any>; // Ok var v6: G<any>; // Error, wrong number of arguments var v7: G; // Ok, equivalent to G<any, any>
Java5とかを御存じの方なら、これで大体把握されると思います。ちなみに、TypeScriptにおけるinterface/classは、基本的に全てJavaScriptのObjectリテラルで書くことができるので、上のGクラスでは、
{x:0, y:""}
とかを渡してもちゃんと動作します。
Genericsの制限
TypeScriptでは、型(特にinterface)は、JavaScriptの出力時に基本的に削除されます。型情報は、TypeScriptのコンパイル時における型チェックに利用されるためのもの(らしい)です。
そういうことなので、型アノテーションの部分の名前空間と、式の部分の名前空間は分断されている状態になっています。Javaとかでも出来なかったと思いますが、
class Hoge<T> extends T {}
みたいなことはできません。型パラメータの部分は特定のclassではありませんが、extends Tの部分は、特定のclassでなければならないからです。
同様に、上の例で言うところのTについて、型アノテーションの部分では利用できますが、式(普通のプログラム)では利用できません。書いてみても、「んな型知らん」と怒られます。怒られてもJavaScriptが出力されることはされますが。
この制限は、TypeScriptではJavaのようなことはできない、ということがわかります。JavaはClassクラスがあれば色々とわかりますが、TypeScriptではそもそもそんなものはないので、型アノテーション以外で型の情報を利用することができません(多分)。
Backbone.jsみたいなModelを作ってみる
さて、ここまでを踏まえたところで、Backbone.jsみたいなModelを作ってみます。書いてる本人はBackbone.jsをよく知らないので、情報が古いと思いますが、こちらを参考にして作ってみました。
無論、検証版なので、機能はがっつりと削っていますし、バグについては何をいわんや、という状態です。こんなこともできるんだ、という参考程度でお願いします。
interface ModelOption<A> { initialize?() :void; defaults() : A; } class Model<A> { private _option :ModelOption<A>; constructor(option:ModelOption<A>) { if (option) { this._option = option; } } _(a?:A) : A { var _a = {}; if (a) { Object.getOwnPropertyNames(a).forEach((v) => { Object.defineProperty( _a, v, {get: () => {return a[v];}, set: (val) => {a[v] = val;} }); }); } else { var d = this._option.defaults(); Object.getOwnPropertyNames(d).forEach((v) => { Object.defineProperty( _a, v, {get: () => {return d[v];}, set: (val) => {d[v] = val;} }); }); } return _a; } } class A { constructor(public hoge:number) {} } var m = new Model<A>({defaults : () => {return {hoge:1};}}); var h = m._(); console.log(h.hoge); // Ok console.log(h.huga); // Compile Error!!
さて、一応こんな感じで作成できます作成したmodelで、ベースとなる型に存在しないプロパティを指定すると、ちゃんとコンパイルエラーになってくれるので、本家のようにget/setで扱う必要がありません。もっとBackbone.jsのModelに似せることもできますが、それだとJavaScriptをそのまま書くのと変わりませんので。
もちろん欠点もあって、このやりかたは、参考にしたBackbone.jsよりも直感的ではありませんし、記述が多少面倒ではあります。しかし、汎用のgetter/setterを利用する必要が基本的に無いということで、Modelの実体を扱う、という側では、こっちの方がわかりやすいような気がします。
Genericsを使ってみて
TypeScriptの0.9では、ArrayもGenericsが使えるようになっており、それだけでもかなり有用だとは思いますが、型の情報を利用できない、というのが結構ネックになってしまいました。JavaScriptなので、Objectの情報を知らべればいいじゃん、ということなんでしょうが、undefinedだったりnullだったりというのからできれば開放されたくてGenericsを利用する、という部分もあると思うので、なんとか型の情報を利用できるようにしてもらえんかなー、とも思います。
しかし、Genericsが導入されたことで、TypeScriptはよりよくなると思います。JavaScriptのフリーダムっぷりに嫌気が差したけれども、CoffeeScriptとかを学ぶほどでもないなー、という方は、基本的にJavaScriptコンパチなTypeScriptを利用してはいかがでしょうか。
CloudFoundfy with Bosh on Openstackをインストールする KVM編
気付いたら一ヶ月経過していました。最近の時の流れが速すぎて困る。
さて、前回の話の続きですが、VirtualBoxだとにっちもさっちもいかなくなってきたので、KVMにOpenStackをインストールしてみることにします。興味もあったことだし。
私の環境はGentooですので、
http://en.gentoo-wiki.com/wiki/KVM
に従って、KVMを利用できるようにしておきます。
しかし、現時点ではqemu-kvm周りが大分変更になっているようで、実際には
qemu libvirt virt-manater bridge-util
を自前でemergeしました。また、libvirtについては、USEフラグにqemuとvirt-networkを忘れずに追加しておきます。
一番困るのがネットワークなのですが、これもvirt-managerでさっくりと作成できます。いずれvirt-managerを使わないで、こういう設定を作成する手法をやってみたいですが、今はとりあえず動かすのが先決なので、いいことにします。
さて、ここまでが違うだけで、後は基本的にVirtualBoxでのインストールと一緒です。忘れずにkvm_intelのnestedを有効にしておきましょう。novaの設定で、qemuとしていた部分が、kvmのままで通るようになり、パフォーマンスが目に見えて違います。
Micro BOSHのインストールまでは、VirtualBoxの時と一緒です。
CloudFoundryのインストール
Micro Boshがインストールできたら、やっとこさCloudFoundryのインストールを試せます。この部分のドキュメントが無い(2013/4/19日現在)ため、はっきり言って手探り状態です。vSphereとかについてはすでに記述されているため、そっちを参考にします。
CloudFoundryのリリース元として、今回はcf-releaseを利用します。
$ git clone git://github.com/cloudfoundry/cf-release.git $ cd cf-release $ bosh upload release releases/appcloud-131.yml
kvmだと、ディスクの状態にもよりますが、結構時間がかかります。
完了したら、cloudfoundryのmanifestを書きます・・・が、これがまたサンプルが無い状態です。幸い、gistで https://gist.github.com/BrianMMcClain/3148465 公開されている方がいましたので、これを盛大に流用させてもらいます。
また、vSphereでのsampleもあります。
https://github.com/cloudfoundry/cf-docs/blob/master/source/docs/running/deploying-cf/vsphere/cloud-foundry-example-manifest.md
・・・が、これを見てほとんどの方は「は?」って感じになると思います。長すぎですな・・・。でもこれを書かないといけないので、なんとか流用しながらやってみます。
さて、ここで注意することですが、このサンプル、いずれもかなり巨大な(個人としては)仮想環境を想定しています。少なくとも100GBのメモリとか、普通は積んでいませんし、72VCPUとか何を言わんや、という感じです。なので、今回は確認するための環境作りなので、必要最小限で作成します。実際には、こいつらはあくまで仮想的に用意される分であって、実際に利用されるわけではありません。あればあるだけいいのは確かですけども。
ここまでできたら、後は
$ bosh deployment ~/cloud-foundry.yml $ bosh deploy
とすることで、結構時間はかかりますが、デプロイが行われます。後はCFをインストールして色々できると思います。
まとめ
OpenStack + CloudFoundryは、公式ドキュメントでも、インストール部分だけ記述が無いため、他のvSphereとかを参考にしてやってみました。なんというか、CloudFoundryに詳しくなるというか、OpenStackに詳しくなってしまったような感があります。
悪いことではないんですが、vcap_devをやる方法に比較すると、簡単に試す、ということができなくなってしまっているなぁ、と感じます。もうちょっと手軽にやる手段が公式に提供されているといじりやすいんですがねー。
とりあえずこの記事が、同じようなことで悩んでいる人の一助になれば幸いです。