libspecinfra 開発者向けチュートリアル

ATL 宮下 です。

先日 libspecinfra プロジェクトの概要と今後について というエントリにて、 libspecinfra プロジェクト の概略について説明しました。今回は libspecinfra プロジェクトが実際にどんなものか、触って試すための手順を解説します。

このチュートリアルでは、Rustmruby で書かれたコードに触れるため、Rust と mruby の簡易的なチュートリアルにもなっています(mruby-libspecinfra は、mruby といいつつもほとんどがCのコードですが)。

また、既存環境に影響を与えないよう、Docker コンテナの利用を前提とした手順で解説しますが、コンテナ環境ではなくても、macOS や Ubuntu であればほぼ同じ手順で動くはずですので、適宜ご自身の環境に合わせて修正してください(筆者は macOS 上で直接開発を行っています)。

ただ動かすだけであれば、全部入りのDockerイメージを用意するだけで済みますが、それだと面白みがないので、ソースコードを見たり修正したりしながら動かせる、すなわち、開発しようと思えばできる環境をつくる、ということを目標にします。


libspecinfra では現状何ができるのか

チュートリアルに入る前に、現在の libspecinfra プロジェクトの状況について説明します。

Ruby 版 specinfra対応しているリソースやプラットフォームがたくさんある ため、完成にはまだほど遠い状態ですが、現在以下のようなステータスになっています。

  • Direct バックエンドと SSH バックエンドは対応済み。
    • Direct バックエンドは Ruby 版 specinfra の Exec バックエンドにあたるもので、直接対象ホスト上で処理を行うためのバックエンドです。
    • SSH バックエンドは手抜き実装なのでポート番号固定だったり、SSHエージェントでの認証にしか対応していません(プルリクエスト大歓迎です)。
  • OSは macOS と Ubuntu のみ対応で、他はまだ未対応。
    • 他の OS だと、OS を識別する処理でコケます。
  • リソースは File のみ実装済み。
    • pocket7878 さんが 実装して プルリク を送ってくれました。ありがとうございます。
    • ただし、Direct バックエンドはフル機能が使えるが、SSH バックエンドは一部機能しか使えない。

この辺りの対応状況の詳細については、GitHub 上の README に対応マトリクスを載せている ので、ご参照ください。

また、各種言語バインディングや周辺ツールの対応状況は以下の通りです。

このチュートリアルでは、最終的には mruby-serverspec-libspecinfra を動かしてローカルファイルのテストを行うまでの手順を解説します。


Dockerコンテナの起動と必要なパッケージのインストール

最初に、チュートリアルで使うためのコンテナを起動します(Docker のインストール手順や使い方等は割愛)。

以降はコンテナ内での操作です。必要なパッケージをインストールしておきます。


Rust 環境のセットアップ

Rust オフィシャルサイト にある手順の通り、curl コマンドを実行して Rust 環境のセットアップを行います。

インストール完了後、$HOME/.cargo/bin へパスを通すため以下のコマンドを実行します。


libspecinfra コアの準備

libspecinfra のコアである Rust 版 specinfra を GitHub からチェックアウトします。

チェックアウトしたらビルドします。ビルドするだけなら cargo build でいいのですが、せっかくなのでテストも一緒に実行してみましょう。

初回は依存する crate (Ruby でいう gem)のダウンロードとビルドも一緒に走るので、少し時間がかかります。

ビルドしてできた libspecifnfra.so (macOS の場合は libspecinfra.dylib)は mruby-libspecinfra から参照できるところに配置する必要があるので、/usr/local/lib 配下からシンボリックリンクを張ります。

ビルドしたファイルができる target/debug ディレクトリを環境変数 LD_LIBRARY_PATH に追加する、というやり方などでも構いません。


libspecinfra コアのソースコードに触れてみる

libspecinfra コアのソースコードに興味ある人は、とっかかりとしてテストコードから覗いてみることをお勧めします。現在テストコードが書かれているファイルは test/file.rs だけですが、実際にどういうコードを書いて libspecinfra を動かすのか、端的に知ることができます。

テストコードや本体のコードを適当に書き換え、cargo test を実行して、テスト結果がどのように変わるか見てみると良いでしょう。

cargo test 実行時は、テストコード中で println!() を実行しても、標準出力には表示されません。表示したい場合には、--nocapture オプションをつける必要があります。

現在のテストコードは Direct バックエンドしか使用していません。SSH バックエンドを利用したコード例は GitHub 上の libspecinfra/examples リポジトリ にあるので、興味ある方はこちらも覗いてみてください。


mruby-libspecinfra を動かしてみる

次に、libspeinfra コアの機能を mruby から呼び出すための、mruby-libspecinfra を動かしてみます。

まずはソースコードを GitHub からチェックアウトします。

チェックアウトしたら、テストを実行してみます。

実際に何をやってるかは Rakefile の中身を見てもらうとわかるのですが、mruby 本体のソースコードをチェックアウトし、そのディレクトリに cd して以下のコマンドを実行しています。

このコマンドでは、mruby-libspecinfra リポジトリに同梱してある build_config.rb を元に mruby をビルドし、mruby 本体のテストと mruby-libspecinfra のテストを実行しています。

mruby には mrbgems という、Ruby の RubyGems にあたる機能拡張の仕組みがありますが、mruby には動的にロードする仕組みがないため、build_config.rb で組み込む gem を指定して mruby をコンパイルする必要があります。

mruby-libspecinfra に同梱されている build_config.rb は以下のようになっていて、conf.gem File.expand_path(File.dirname(__FILE__)) の部分で、チェックアウト済みの mruby-libspecinfra ディレクトリを指定し、gem として組み込むよう指定しています。また、linker.libraries = %w(specinfra m) の部分では libspecinfra.so をリンクするように指示しています。


mruby-libspecinfra のソースコードに触れてみる

こちらも libspecinfra コア同様、テストコード から覗いてみるのがとっかかりとして良いでしょう。どのように mruby から libspecinfra を呼び出すのかが具体的なコードで示されています。

テストコードや 本体のコード (すべてCで書かれています)を修正して rake test を実行し、テスト結果がどのように変わるか見ることで、mruby-libspecinfra への理解が深まると思います。

こちらのテストコードも Direct バックエンドしか利用していませんが、SSH バックエンドを利用した mruby のサンプルコードも libspecinfra/examples リポジトリ にあります。


mruby-serverspec-libspecinfra を動かしてみる

次に、libspecinfra を利用したツールのサンプルとして開発している、mruby-serverspec-libspecinfra を動かしてみます。

まずはソースコードを GitHub からチェックアウトします。

チェックアウトしたら、テストを実行してみます。

mruby-libspecinfra と同様、何をしているかの詳細は Rakefile を見ればわかりますが、基本的にやってることは mruby-libspecinfra と同様、mruby のソースコードをチェックアウト、build_config.rb で mruby に mruby-serverspec-libspecinfra を組み込んでコンパイルし、mruby 本体のテストと mruby-serverspec-libspecinfra のテストを実行しています。テストコードは spec ディレクトリ以下に置いてあり、以下のようなコードになっています。Serverspec を使っている方にはお馴染みのコードですね。

rake test の代わりに以下のようすることで、mruby-serverspec-libspecinfra のテストのみを実行することもできます。


mruby-serverspec-libspecinfra のソースコードに触れてみる

mruby-serverspec-libspecinfra のソースコードについては、mrblib/serverspec/config.rbmrblib/serverspec/type/file.rb を見てもらうと、どのように mruby-libspecinfra を呼び出しているのか、雰囲気が掴めるかと思います。

現在は Direct バックエンドのみしか対応していないので、本家 Serverspec のように、 SSH 越しにテストを実行する、といったことはできません(が、libspecinfra コアと mruby-libspecinfra は SSH バックエンドに対応してるので、対応はそれほど難しくありません)。また、libspecinfra コアが File リソースしか実装していないので、ファイルに関するテストしかできません。

手元にチェックアウトした mruby-libspecinfra を 修正し、mruby-serverspec-libspecinfra から呼び出して動作を確認したい場合、以下のように build_config.rb を修正する必要があります。

mrbgem.rake には mrbgems の依存関係が記述されているのですが、そのままですと GitHub 上の mruby-libspecinfra を利用します。上記のように build_config.rb に mruby-libspecinfra のローカルディレクトリを指定すると、こちらの方が優先して利用されるようになります。

チュートリアルは以上です。


その他

mruby 版の Serverspec には既に syucream/mruby-serverspec という実装があるため、mruby-serverspec-libspecinfra はあくまでも libspecinfra を利用したツールのサンプルという位置づけです。

libspecinfra 開発にあたって、私が主に参考にしたリンクをあげておきます。

Rust は公式ドキュメントが非常に充実しているので、 ここ から辿れるリンクだけで十分に学習できます。

日本語の記事ですと、 最速で知る! プログラミング言語Rustの基本機能とメモリ管理【第二言語としてのRust】 – エンジニアHub|若手Webエンジニアのキャリアを考える! がわかりやすかったです。

mruby については私は以下の電子書籍を参考にしながら開発を進めました。

mruby や Ruby バインディングの開発には Objects – The Rust FFI Omnibus が参考になりました。Python、Haskell、Node.js、C# などのコード例も載っています。

libspecinfra についてご質問等ありましたら、@gosukenator 等まで、お気軽にご連絡ください。