【Vagrantドキュメント意訳】14.プラグイン

# はじめに

本文章は、Vagrant公式サイト内のドキュメント内の[PLUGINS](https://www.vagrantup.com/docs/plugins/)に記載されている内容を意訳に近い形で日本語化したものである。
誤訳が含まれている可能性が十分にあることを踏まえて、参考いただきたい。

# プラグイン

Vagrantには、その環境を起動して運用させるにあたり、多くの素晴らしいBox外の機能がある。しかしながら時折、Vagrantが何かを行うための方法を変更したり、Vagrantを拡張する機能を追加したいと思うだろう。これはVagrant*プラグイン*によって実現される。

プラグインは強力で、文書で十分裏付けられ、メジャー・バージョン・アップグレードに耐えることのできる安定したAPIを使用するので、Vagrantを拡張する第一級市民である。

事実、Vagrantのコアな部分の多くは [プラグインを使用して実装されている](https://github.com/mitchellh/vagrant/tree/master/plugins)。Vagrantは自分自身のプラグインAPIを[ドッグフーディング](https://en.wikipedia.org/wiki/Eating_your_own_dog_food)しているので、インタフェースが安定しており十分にサポートされていることを確認できる。

プラグインの使い方やビルドの仕方について学びたいのであれば、左側にあるナビゲーションを使って"プラグイン”セクションを参照のこと。

# プラグインの使い方

Vagrantのプラグインのインストール方法は簡単で数秒もかからない。

使い方に関する詳細な情報は、使用する予定のプラグインのドキュメントを参照すること。しかし、プラグインのインストールや有効化に関する共通的な一つの方法がある。

> **警告！**サード・パーティのプラグインは、非中心的なユーザーによって書かれており、その性質のためVagrantに不安定さを導入してしまうことがある。

## インストール

プラグインは`vagrant plugin install`を使用してインストールされる。

```bash
# Installing a plugin from a known gem source
$ vagrant plugin install my-plugin

# Installing a plugin from a local file source
$ vagrant plugin install /path/to/my-plugin.gem
```

一度プラグインがインストールされると、それは自動的にVagrantによってロードされる。ロードすることができなかったプラグインがVagrantをクラッシュさせることはない。その代わり、Vagrantはプラグインのロードに失敗したエラーメッセージを表示する。

## 使い方

一度プラグインをインストールしたら、その使い方を正確に理解するためにプラグインのドキュメントを参照するべきである。コマンドを追加するプラグインは`vagrant`によってすぐに使用可能となる。プロビジョナは`config.vm.provision`によって使用することができる。

**注意：**将来的に、`vagrant plugin`コマンドはそれぞれのプラグインのインストールのコンポーネントのドキュメントのためのサブ・コマンドを含むようになるだろう。

## アップデート

プラグインは`vagrant plugin update`を実行することでアップデートできる。これはインストールされているすべてのプラグインを最新のバージョンにアップデートする。`vagrant plugin update NAME`を呼び出すことで特定のプラグインをアップデートすることができる。Vagrantはどのプラグインがどのバージョンにアップデートされたかを出力する。

プラグインの特定のバージョンへの変更を決める際には、(たいていGitHubページもしくはそれに似た）プラグインのホームページを参照すること。彼または彼女が選んだプラグインに対してチェンジログを提供するのは、プラグイン作者の責任である。

## アンインストール

アンインストールもインストールと同様に簡単である。`vagrant plugin uninstall`コマンドを使用するだけでプラグインは削除される。例を示す。

```bash
$ vagrant plugin uninstall my-plugin
```

## プラグイン一覧

Vagrant環境に何のプラグインがインストールされているかを見るには`vagrant plugin list`コマンドを使用する。これは、バージョンとともにインストールされているプラグインを一覧表示する。

# プラグイン開発の基礎

プラグインは、Vagrantの振る舞いや機能性を拡張または変更するための、素晴らしい方法である。プラグインはユーザーにとって、更なる外部への依存性を導入することになるので、Vagrantで何かをしようとする際の最後の手段として使うべきであろう。

しかし、機能のアップグレードや安定したAPIの使用に対しては安全であるため、Vagrantにカスタマイズした動作を導入する必要があれば、プラグインは最も適切な方法である。

> **警告：上級者向け！**プラグインの開発は、Rubyに対して適度に不安がない、経験豊かなVagrantユーザーだけが近づくべき、上級者向けの記載である。

プラグインはRubyを使って書かれ、RubyGemsを使用してパッケージ化される。Rubyに精通していることが必須であるが、パッケージ化とディストリビューションのセクションは、プラグインをRubyGemにパッケージ化するためのガイドの助けとなるだろう。

## セットアップとワークフロー

プラグインはRubyGemsとしてパッケージ化されているので、Vagrantプラグインは、通常のRubyGemsと同じように開発されるべきである。これを行うための最も簡単な方法は`bundle gem`コマンドを使用することである。

一度、RubyGem用のディレクトリ構造をセットアップすれば、次はGemfileを編集したいと思うだろう。ここにVagrantのプラグイン開発用のGemfileの基本的な構造を示す。

```bash
source "https://rubygems.org"

group :development do
  gem "vagrant", git: "https://github.com/mitchellh/vagrant.git"
end

group :plugins do
  gem "my-vagrant-plugin", path: "."
end
```

このGemfileは開発用の"vagrant"を取得する。これは`bundle exec vagrant`によってすでにロードされたプラグインとともにVagrantと実行することができる。そして、その方法で手動でテストすることができる。

奇妙に見えるこのGemfileの唯一の点は、"plugins"グループとそのグループにpluginを入れているところだろう。`vagrant plugin`コマンドはdevelopment内では動作しないので、これはVagrantにプラグインを"インストール"する方法である。Vagrantは"plugins"グループにあるすべてのgemsを自動的にロードする。もし、プラグインがほかのプラグインとともに動作するのであれば、これは開発用のVagrantに複数のプラグインを追加することもできる。

適切なこの構造において、ワークフローはそのほかのRubyのようになるだろう。プラグインの手動テストを行いたい場合、(Gemfileの中で指定された)ロードしたプラグインとともにVagrantを動かす為に、`bundle exec vagrant`を使用する。

## プラグインの定義

すべてのプラグインは定義される必要がある。定義はその名前や、どのようなコンポーネントが含まれているかなどのプラグインの詳細を含む。

最低限の定義は以下のようになる。

```bash
class MyPlugin < Vagrant.plugin("2")
  name "My Plugin"
end
```

定義は`Vagrant.plugin("2")`から継承したクラスである。"2"はプラグインが有効となるバージョンである。APIの安定性はVagrantのそれぞれのメジャー・バージョンに対してのみ保証され、これは重要である。(1.x系は、APIバージョンが"2"であるので2.0に対して動作する)

**プラグイン定義で最も重要な機能**は、たとえどのようなバージョンのVagrantが稼働していても、*常に*ロードされることである。理論的には、Vagrantのバージョン87(これは実際には存在しない)は、バージョン2のプラグイン定義をロードすることができる。これは、プラグインの個別のコンポーネントの賢い遅延読み込みによって達成され、そして瞬時に行われる。

## プラグインのコンポーネント

定義の中で、プラグインは何のコンポーネントがVagrantに追加されるかを示す。以下に示す例では、コマンドとプロビジョナが追加されることを示す。

```bash
class MyPlugin < Vagrant.plugin("2")
  name "My Plugin"

  command "run-my-plugin" do
    require_relative "command"
    Command
  end

  provisioner "my-provisioner" do
    require_relative "provisioner"
    Provisioner
  end
end
```

ここで何が行われているかという大きな点を見てみよう。一般的なRuby言語の考え方から、上記には親近感があるだろう。文法に恐れることはないだろう。もしそうであれば、プラグインを書こうとする前に、Rubyに対してもっと詳しくなっておくこと。

初めに注意すべきことは、それぞれのコンポーネントは、`command`や`provisioner`のようなコンポーネントの名前とともにメソッド・コールされることで、定義される点である。これらは、いくつかのパラメータを持っている。上記の例の場合、コマンドの名前とプロビジョナの名前だけである。すべてのコンポーネントの定義は、実際のコンポーネント実装クラスを返すための、ブロック引数（コールバック）をとる。

ブロック引数は、(上記の例では)"clever lazy loading"が効果を示し始める部分である。コンポーネント・ブロックは、コンポーネントの実装を含む実際のファイルを遅延読み込みし、その後コンポーネントに戻ってくる。

これは、定義されたコンポーネントがメジャーなVagrantバージョンに対して安定的でない時に使用された場合に、実際に依存しているものやAPIが使用されるために行われる。Vagrant 2.0用のコマンドの実装はVagrant 3.0以降と互換性がない。しかし、定義は、将来のVagrantバージョンにとって、常に前方互換性のある、ただの素のRubyである。

繰り返しとなるが、Vagrantのプラグインの作業の方法として**プラグイン・コンポーネントの遅延読み込みは重要である**。すべてのコンポーネントは遅延読み込みと定義ブロック内から戻ることが必要である。

さて、それぞれのコンポーネントは異なるAPIを持っている。コンポーネントのそれぞれの種類を開発する為に、詳細を学びたいのであれば、左側にあるナビゲーションを使用して"プラグイン"にある関連するセクションを参照すること。

## エラー制御

Vagrantの最大の強みの一つは、潔いエラー制御と人間が読み取ることのできる方法によるその報告である。Vagrantは、ユーザーがスタック・トレースを見たとき、バグであると常に強く信じるさせることができる。プラグインは同じ方法をとるように期待され、そのためにVagrantは強力なエラー制御機構を提供する。

Vagrantにおけるエラー制御は、Rubyの例外の発生によって完全に行われる。しかし、Vagrantはそのほかのエラーとこれらのエラーを異なるものとして扱う。`Vagrant::Errors::VagrantError`から継承されたエラーが発生した場合、`vagrant`コマンドはコンソールへ素敵な赤色のテキストでエラーのメッセージを出力し、終了ステータス1で終了する。

そうでなければ、Vagrantはバグとして報告されるべき"unexpected error"を報告し、すべてのスタック・トレースやそのほかの見苦しいものを表示する。いずれのスタック・トレースもバグとして考えられるべきである。

従って、Vagrantのエラー制御機構に合わせるために、`VagrantError`のサブクラスと例外に対する適切なメッセージを設定する。この例を見るには、Vagrantの`組み込みエラー`を参照すること。

## コンソール入力と出力

多くのプラグインはおそらく何らかの入力/出力を行うであろう。プラグインはRubyの組み込みの`puts`や`gets`形式のメソッドを使用することはない。その代わりに、すべての入力/出力はある種のVagrant UIオブジェクトを通過する必要がある。そのVagnrat UIオブジェクトは、TTYがない、出力用パイプが閉じている、入力用パイプがないなどの状況を適切に制御する。

UIオブジェクトは`ui`プロパティを介したすべての`Vagrant::Environment`上で使用できる。そして、`:ui`キーによってすべてのミドルウェア環境上に公開される。UIオブジェクトは、そのソースの中のコメントに`適切なドキュメント`を持っている。

# アクション・フック

アクション・フックは、Vagrantのライフサイクルのさまざまなフェーズにおいて、ミドルウェアに注入することによって、非常に低いレベルで対話するための方法を提供する。これはプラグイン開発にとっても上級者向けである。

> **警告：上級者向け！**プラグインの開発は、Rubyに対して適度に不安がない、経験豊かなVagrantユーザーだけが近づくべき、上級者向けの記載である。

## パブリック・アクション・フック

次に示すアクション・フックはVagrantの中心で使用することができる。このリストはすべてを網羅していないこと、追加的なフックがプラグインによって追加できることについて注意すること。

* [`environment_plugins_loaded`](https://www.vagrantup.com/docs/plugins/action-hooks.html#environment_plugins_loaded) - プラグインが読み込まれた後に呼び出されるが、設定、プロビジョナ、プロビジョナなどが読み込まれる前である。
* [`environment_load`](https://www.vagrantup.com/docs/plugins/action-hooks.html#environment_load) - 環境やすべての設定が完全に読み込まれた後に呼び出される。
* [`environment_unload`](https://www.vagrantup.com/docs/plugins/action-hooks.html#environment_unload) - 環境が使用され始めた後に呼び出される。環境はこのフックで使用されてはならない。
* [`machine_action_boot`](https://www.vagrantup.com/docs/plugins/action-hooks.html#machine_action_boot) - ハイパー・バイザがマシンが起動したと報告した後に呼び出される。
* [`machine_action_config_validate`](https://www.vagrantup.com/docs/plugins/action-hooks.html#machine_action_config_validate) - すべての`Vagrantfiles`が読み込まれ、マージされ、有効化された後に呼び出される。
* [`machine_action_destroy`](https://www.vagrantup.com/docs/plugins/action-hooks.html#machine_action_destroy) - ハイパー・バイザが、仮想マシンが停止したと報告した後に呼び出される。
* [`machine_action_halt`](https://www.vagrantup.com/docs/plugins/action-hooks.html#machine_action_halt) - ハイパー・バイザがマシンをホルト状態（たいてい"stopped"であり”terminated"でない）に移動した後に呼び出される。
* [`machine_action_package`](https://www.vagrantup.com/docs/plugins/action-hooks.html#machine_action_package) - Vagrantが新しいBoxのパッケージ化に成功した後に呼び出される。
* [`machine_action_provision`](https://www.vagrantup.com/docs/plugins/action-hooks.html#machine_action_provision) - すべてのプロビジョナが実行された後に呼び出される。
* [`machine_action_read_state`](https://www.vagrantup.com/docs/plugins/action-hooks.html#machine_action_read_state) - Vagrantがディスクとハイパー・バイザから状態を読み込んだ後に呼び出される。
* [`machine_action_reload`](https://www.vagrantup.com/docs/plugins/action-hooks.html#machine_action_reload) - 仮想マシンが再読み込み（ハイパー・バイザによる変更）を行った後に呼び出される。
* [`machine_action_resume`](https://www.vagrantup.com/docs/plugins/action-hooks.html#machine_action_resume) - 仮想マシンが停止状態から起動状態に変化した後に呼び出される。
* [`machine_action_run_command`](https://www.vagrantup.com/docs/plugins/action-hooks.html#machine_action_run_command) - コマンドがマシン上で実行された後に呼び出される。
* [`machine_action_ssh`](https://www.vagrantup.com/docs/plugins/action-hooks.html#machine_action_ssh) - SSH接続が確立された後に呼び出される。
* [`machine_action_ssh_run`](https://www.vagrantup.com/docs/plugins/action-hooks.html#machine_action_ssh_run) - SSHコマンドが実行された後に呼び出される。
* [`machine_action_start`](https://www.vagrantup.com/docs/plugins/action-hooks.html#machine_action_start) - マシンが開始された後に呼び出される。
* [`machine_action_suspend`](https://www.vagrantup.com/docs/plugins/action-hooks.html#machine_action_suspend) - マシンがサスペンドした後に呼び出される。
* [`machine_action_sync_folders`](https://www.vagrantup.com/docs/plugins/action-hooks.html#machine_action_sync_folders) - 同期フォルダが設定完了した後に呼び出される。
* [`machine_action_up`](https://www.vagrantup.com/docs/plugins/action-hooks.html#machine_action_up) - マシンが起動状態になった後に呼び出される。

## プライベートAPI

Vagrantのソースコードを見れば、更なるアクション・フックを見つけることができるが、
ここにあるアクション・フックのリストにあるものは、Vagrantのリリースの間で維持されることを保証されている。予告なく変更されることがあるような内部APIに依存しないようにすること。

# プラグインの開発：コマンド

このページでは、Vagrantへ`あなたのVagrantコマンド`として呼び出し可能な、新しいコマンドを追加する方法を示す。これを読む前に[プラグイン開発の基礎](https://www.vagrantup.com/docs/plugins/development-basics.html)をよく読んでおくこと。

> **警告：上級者向け！**プラグインの開発は、Rubyに対して適度に不安がない、経験豊かなVagrantユーザーだけが近づくべき、上級者向けの記載である。

## コンポーネントの定義

プラグイン定義において、新しいコマンドは以下のように定義される。

```bash
command "foo" do
  require_relative "command"
  Command
end
```

コマンドは、ここでは"foo"のようにコマンドの名前を引数としてとる`command`メソッドで定義される。これは、`vagrant foo`によって呼び出し可能となるコマンドであることを意味する。続くブロック引数は`Vagrant.plugin(2, "command")`インタフェースを実装したクラスを返す。

基本的なコマンド以外も定義することもできる。これらのコマンドは`vagrant -h`の出力上では表示されない。これらはユーザーが明示的に、使用可能なコマンドの全リストを表示する`vagrant list-commands`を実行するときだけ表示される。これは、Vagrantの初心者が容易に使用できないように、高度に特定されたコマンドやプラグインに対して有用である。Vagrant自身は基本的なコマンド以外を、何らかの内部機能を公開する為に使用することができる。

基本的なコマンド以外を定義する例を以下に示す。

```bash
command("foo", primary: false) do
  require_relative "command"
  Command
end
```

## 実装

コマンドの実装は、バージョン2コマンドに対して適切なスーパークラスを返すVagrantのメソッドである`Vagrant.plugin(2, :command)`のサブクラスである。実装そのものは、`execute`メソッドのみが必須の実装であるクラスなため、とても単純である。例を示す。

```bash
class Command < Vagrant.plugin(2, :command)
  def execute
    puts "Hello!"
    0
  end
end
```

`execute`メソッドは、コマンドが呼び出されたときに呼ばれる。そして、終了ステータス(0が成功、それ以外はエラー)を返す。

これは最も単純な形のコマンドである。もちろん、コマンドのスーパークラスはVagrant環境へのアクセスする方法や、コマンドラインの解析などの共通のタスクを行うためのヘルパのようなものも提供する。

## コマンドライン解析オプション

`parse_options`メソッドは、コマンドラインの解析を使用することができる。これは引数として[オプション・パーサ](http://ruby-doc.org/stdlib-1.9.3/libdoc/optparse/rdoc/OptionParser.html)をとり、もし要求された場合に自動的にヘルプを表示するための`--help`フラグなどのような共通の要素のようなものを追加する。

これはコマンドライン・フラグの解析/操作に対して推奨される。以下は組み込みのVatrantの`destroy`コマンドから直接引っ張ってきたコマンドライン・フラグの解析の例である。

```bash
options = {}
options[:force] = false

opts = OptionParser.new do |o|
  o.banner = "Usage: vagrant destroy [vm-name]"
  o.separator ""

  o.on("-f", "--force", "Destroy without confirmation.") do |f|
    options[:force] = f
  end
end

# Parse the options
argv = parse_options(opts)
```

## Vagrantマシンを使う

`with_target_vms`メソッドは、Vagrantが標準的なVagrantの方法で管理しているマシンと双方向に対話することを助けるようなヘルパである。このメソッドは、コマンドライン(`vagrant foo my-vm`)で対象のマシンを制御して、マルチ・マシン環境である場合でも自動的にきちんと動作する。もし、SSHアクセスを含むVagrantマシンの何らかの操作が必要であれば、このヘルパを使用するべきである。

ヘルパの使用方法の例について、再び組み込みの`destroy`コマンドを引っ張ってきた。

```bash
with_target_vms(argv, reverse: true) do |machine|
  machine.action(:destroy)
end
```

この場合、逆順でマシンを確認し、それぞれに対してdestroyの実行を呼び出す。もし、ユーザーが`vagrant destroy foo`を呼び出した場合、ヘルパは自動的に`foo`マシンに対してのみ効果を及ぼす。もし、パラメータが与えられず、マルチ・マシン環境であれば、環境にあるすべてのマシンに効果を次々に及ぼす。それは単純に適切なことを行うのだ。

## 素のVagrant環境を使う

素の読み込んだ`Vagrant::Evvironment`オブジェクトは、'@env'インスタンス変数によって使用することができる。

# プラグインの開発：設定

このページでは、VagrantにVagrantfile内で`config.キー`で設定することが可能な、新しい設定オプションを追加する方法を示す。これを読む前に[プラグイン開発の基礎](https://www.vagrantup.com/docs/plugins/development-basics.html)をよく読んでおくこと。

> **警告：上級者向け！**プラグインの開発は、Rubyに対して適度に不安がない、経験豊かなVagrantユーザーだけが近づくべき、上級者向けの記載である。

## コンポーネントの定義

プラグイン定義において、新しい設定キーは以下のように定義される。

```bash
config "foo" do
  require_relative "config"
  Config
end
```

設定キーは、引数としての設定変数の名前を引数に盗る`config`メソッドで定義される。これは、Vagrantfile内で`config.foo`を介してアクセス可能な設定オブジェクトであることを意味する。その後に、`Vagrant.plugin(2, :config)`インタフェースを実装したクラスを返す、ブロック引数が続く。

## 実装

設定キーの実装は、バージョン2設定セクションに対して適切なスーパークラスを返すVagrantのメソッドである`Vagrant.plugin(2, :config)`のサブクラスである。実装はとても単純で、そのままのRubyオブジェクトとしておおむね動作する。ここに例を示す。

```bash
class Config < Vagrant.plugin(2, :config)
  attr_accessor :widgets

  def initialize
    @widgets = UNSET_VALUE
  end

  def finalize!
    @widgets = 0 if @widgets == UNSET_VALUE
  end
end
```

この設定クラスを使用する場合、以下のようになるだろう。

```bash
Vagrant.configure("2") do |config|
  # ...

  config.foo.widgets = 12
end
```

簡単であろう。ただ唯一の奇妙な点は、`UNSET_VALUE`である。これは実は、Vagrantが適切にかつ自動的に複数の設定をマージすることができるということである。マージは次のセクションの範囲に含まれており、`UNSET_VALUE`はそこで説明する。

## マージ

Vagrantは、[複数のVagrantfileとそれらのマージされたもの](https://www.vagrantup.com/docs/vagrantfile/#load-order)を読み込むことで動作する。このマージ・ロジックは設定クラスに対して組み込まれている。2つの設定オブジェクトをマージする際、それらを"旧"と"新"と呼ぶとして、"新"で定義された`UNSET_VALUE`でないすべてのインスタンス変数をデフォルトでとる。そして、マージの結果となる。

`UNSET_VALUE`はRubyの`nil`の代わりに使用される。それは、デフォルトを何らかの値にしたい場合やユーザーが実際に`nil`に値を設定したい場合にそれを可能とするため、また、ユーザーにインスタンス変数を設定するかどうかを自動的に決定させることやnilとしてデフォルトとすることをVagrantに対して不可能とするためである。

これは、ほとんど毎回望まれるマージのロジックである。ゆえに、上記の例において`@widgets`は`UNSET_VALUE`が設定される。もし、2つのVagrant設定オブジェクトが同じファイル内にあるならば、Vagrantは次のように適切なマージを行うだろう。以下の例はそれを示す。

```bash
Vagrant.configure("2") do |config|
  config.widgets = 1
end

Vagrant.configure("2") do |config|
  # ... other stuff
end

Vagrant.configure("2") do |config|
  config.widgets = 2
end
```

これがVagrantfile内にあれば、マージしたのち、widgetsの値は"2"となる。

`finalize!`メソッドは、デフォルトに設定する為に、最後の設定オブジェクト上で一度だけ呼ばれる。もし`finalize!`が呼び出されれば、設定は2度とマージされない、まさに最後である。これは、上記で示したように、どんな`UNSET_VALUE`をも検出させ、適切なデフォルト値を設定させる。

もちろん、時折、独自のマージ・ロジックがほしいと思うだろう。追加的なwidgetsがほしいとしてみよう。その場合、このようにして`merge`メソッドを上書きすることができる。:

```bash
class Config < Vagrant.config("2", :config)
  attr_accessor :widgets

  def initialize
    @widgets = 0
  end

  def merge(other)
    super.tap do |result|
      result.widgets = @widgets + other.widgets
    end
  end
end
```

この場合、その振る舞いを必要としないため、widgetsに対して`UNSET_VALUE`は使用されない。0をデフォルトとし、2つのwidgetsの統合によるマージが常に行われる。さて、3つの設定ブロックを持つ上記の例を実行した場合、widgetsの最終的な値は"3"となる。



## 検証

設定クラスは、その値の検証の責任も持っている。Vagrantはこのために`validate`メソッドを呼び出す。検証メソッドの例を以下に示す。

```bash
class Config < Vagrant.plugin("2", :config)
  # ...

  def validate(machine)
    errors = _detected_errors
    if @widgets <= 5
      errors << "widgets must be greater than 5"
    end

    { "foo" => errors }
  end
end
```

検証メソッドは、Vagrantが管理しているそれぞれのマシンに対して検証を行うため、`machine`オブジェクトを与えられる。これによりマシンやそれに準ずるものに基づいた何らかのキーを、条件に従いって検証することができる。

`_detected_errors`メソッドはVagrantによってすでに検出された、未知の設定キーのようなエラーを返す。 これはエラーメッセージの配列を返し、必ず後で返すための適切なハッシュ・オブジェクトに変換すること。

戻り値は、キーがセクション名で、値がエラー・メッセージのリストとなるRubyのハッシュオブジェクトである。これらはVagrantによって表示される。エラーがない場合、ハッシュには何の値も含まない。

## アクセス

すべての設定オプションがマージされ、ファイナライズされた後、おそらくプラグインのファイナライズされた値へアクセスしたいと思うだろう。イニシャライズ関数はプラグインの種類ごとに異なるが、多くのプラグインはイニシャライズを以下のように公開している。

```bash
def initialize(machine, config)
  @machine = machine
  @config  = config
end
```

プラグインを開発するとき、これらのインスタンス変数を設定する為にイニシャライズ関数で単純に`super`を呼ぶ。

```bash
def initialize(*)
  super

  @config.is_now_available
  # ...existing code
end

def my_helper
  @config.is_here_too
end
```

例えば、GitHub上にあるVagrantのソースにある`plugins`フォルダのVagrant自身の内部プラグインを見ている。

# プラグインの開発：ゲスト

このページでは、Vagratへ新しいゲストOSの検出を追加する方法を示す。これを読む前に[プラグイン開発の基礎](https://www.vagrantup.com/docs/plugins/development-basics.html)をよく読んでおくこと。

> **警告：上級者向け！**プラグインの開発は、Rubyに対して適度に不安がない、経験豊かなVagrantユーザーだけが近づくべき、上級者向けの記載である。

Vagrantは、フォルダのマウントやネットワークの設定など、ゲストOS特有の動作を必須とする多くの機能を持っている。これらのタスクはオペレーティング・システムごとにさまざまである。もし、あなたのオペレーティング・システムでこれらのうちの一つが動作しなかった場合、ゲストの実装が不十分か不適切なのかもしれない。

## コンポーネントの定義

プラグイン定義において、新しいゲストは以下のように定義される。

```bash
guest "ubuntu" do
  require_relative "guest"
  Guest
end
```

ゲストは`guest`メソッドで定義される。一つ目の引数はゲストの名前である。この名前はどこかで実際に使用されていないが、将来的に何らかの役に立つようなものを選ぶ。続くブロック引数は`Vagrant.plugin(2, :guest)`インタフェースを実装したクラスを返す。

## 実装

ゲストの実装は`Vagrant.plugin("2", "guest")`のサブクラスである。この実装において、唯一`detect?`メソッドのみ実装が必須である。

`detect?`メソッドは、何のオペレーティング・システムがゲストで稼働しているかを決定する為に、マシンが起動した後のある時点でVagrantによって呼び出される。そのオペレーティング・システムを検出した場合、`detect?`から`true`が返される。そうでなければ、`false`が返される。

マシンとの通信チャネルはこの時点で稼働することが保証され、オペレーティング・システムを検出するための最も共通的な方法は、いくつかの基本的なテストを行うことである。

```bash
class MyGuest < Vagrant.plugin("2", "guest")
  def detect?(machine)
    machine.communicate.test("cat /etc/myos-release")
  end
end
```

OSを検出した後、そのOSは、要求される様々な[ゲストの能力](https://www.vagrantup.com/docs/plugins/guest-capabilities.html)に対して使用される。

## ゲストの継承

ときどき、共通の祖先から枝分かれしたオペレーティング・システムもあるので、Vagrantはゲストに対する継承の形をサポートしている。この良い例は、LinuxはDebianの祖先であり、さらに多くにおいてUbuntuの祖先である。継承は、ディストリビューション特有の上書きを許すことで、ゲストが多くの共通の振る舞いを共有できるようにする。

Vagrantはカスタム化した[能力ベース](https://www.vagrantup.com/docs/plugins/guest-capabilities.html)システムを使用するため、継承は標準的なRubyのクラス継承によって行われない。Vagrantは継承の振り分けを制御する。

異なるゲストのサブクラスに対して、ゲスト定義における2つ目のパラメータとしてゲストの名前を指定する。

```bash
guest "ubuntu", "debian" do
  require_relative "guest"
  Guest
end
```

上記のコンポーネントで、"ubuntu"ゲストは"debian"から継承される。"ubuntu"に対する能力をみてみると、"debian"からのすべての能力も使用することができ、いくつかの"ubuntu"の能力は親の能力を上書きする。

`detect?`によってオペレーティング・システムを検出したとき、Vagranは常に、それらの親を確認する前に、子のオペレーティングシステムを検索することで深さ優先サーチを行う。そのため、上記の例では"ubuntu"上の`detect?`メソッドは"debian"の前に呼び出される。

# プラグインの開発：ゲストの能力

このページでは、[ゲスト](https://www.vagrantup.com/docs/plugins/guests.html)に対して、新しい動作が指定したゲスト・オペレーティング・システム上で行えるうように、新しい機能を追加する方法を示す。これを読む前に[プラグイン開発の基礎](https://www.vagrantup.com/docs/plugins/development-basics.html)をよく読んでおくこと。

> **警告：上級者向け！**プラグインの開発は、Rubyに対して適度に不安がない、経験豊かなVagrantユーザーだけが近づくべき、上級者向けの記載である。

ゲストの能力は、ゲストのオペレーティング・システムで動作するような、特定の"能力”をゲストに付与することによって、[ゲスト](https://www.vagrantup.com/docs/plugins/guests.html) を拡張する。

能力は、プラグインがVagrantのコアな部分を変更することなしに、既存のゲスト・オペレーティング・システムに新しい機能を追加することができる。Vagrantの早期のバージョンでは、ゲストのロジックのすべては、Vagrantのコアな部分に含まれており、簡単に増大することができなかった。

## コンポーネントの定義

プラグインの定義において、ゲストの能力は次のように定義される。

```bash
guest_capability "ubuntu", "my_custom_capability" do
  require_relative "cap/my_custom_capability"
  Cap::MyCustomCapability
end
```

ゲストの能力は、能力を追加したいゲストと能力そのものの名前の2つのパラメータをとる`guest_capability`メソッドを呼ぶことで定義される。そして、ブロック引数は、能力と同じ名前のメソッドを実装するクラスを返す。これは次のセクションで詳しく述べる。

## 実装

実装は、能力と同じ名前であるメソッドを持つ、クラスまたはモジュールとなる。`guest_capability`コンポーネントから返されたクラスにおいて、メソッドは即座にアクセス可能となるべきである。それは、インスタンスメソッドであれば、インスタンスが返されることを意味する。

通常、クラス・メソッドは能力に対して使用される。例えば、ここに上記の能力に対する実装を示す。

```bash
module Cap
  class MyCustomCapability
     def self.my_custom_capability(machine)
      # implementation
    end
  end
end
```

すべての能力は、一つ目の引数としてVagrantのマシン・オブジェクトをとる。追加の引数は、指定した能力によって決定される。より詳細な情報のために、実装しようとする能力の使い方や文書を見ること。

いくつかの能力は、呼び元へ値を返す必要もあるので、能力を実装する際には注意すること。

能力は常にマシン上でSSHなどの通信チャネルへのアクセス方法を持ち、マシンは一般的にブートされているとみなすことができる。

## 能力の呼び出し

すべての能力でマシンにアクセスすることができるので、能力はほかの能力を呼び出すこともできる。これはより詳しい情報をヘルパーに尋ねる可能性のために、能力の継承機構を使用することに対して有用である。例えば、"redhat"ゲストは、ネットワーク・スクリプトの場所を返す単純な能力を持っている。

CentOSやFedoraのようなRedHatの子ゲストはネットワーク・スクリプトの場所を決定する為に子の能力を使用する。また、時々それらを上書きしている。

能力はこのように呼び出される。

```bash
machine.guest.capability(:capability_name)
```

メソッドに与えられるいかなる追加の引数も能力に受け渡され、そして能力は実際に能力が返す値を返す。

# プラグインの開発：ホスト

このページでは、Vagrantが新しいオペレーティング・システム上でホスト特有の操作を適切に実行させるために、Vagratへ新しいホストOSの検出を追加する方法を示す。これを読む前に[プラグイン開発の基礎](https://www.vagrantup.com/docs/plugins/development-basics.html)をよく読んでおくこと。

> **警告：上級者向け！**プラグインの開発は、Rubyに対して適度に不安がない、経験豊かなVagrantユーザーだけが近づくべき、上級者向けの記載である。

Vagrantは、NFSフォルダのエクスポートのような、ホスト特有の機能を要求するいくつかの機能を持っている。これらのタスクはオペレーティング・システムごとにさまざまである。Vagrantは、これらのホストOS特有の操作を行うために[ホストの能力](https://www.vagrantup.com/docs/plugins/host-capabilities.html)だけでなくホストの検出も使用する。

## コンポーネントの定義

プラグインの定義において、新しいホストは以下のように定義することができる。

```bash
host "ubuntu" do
  require_relative "host"
  Host
end
```

ホストは`host`メソッドで定義される。一つ目の引数はホストの名前である。この名前はどこかで実際に使用されていないが、将来的に何らかの役に立つようなものを選ぶ。そして、ブロック引数は`Vagrant.plugin(2, ;host)'インタフェースを実装したクラスを返す。

## 実装

ホストの実装は`Vagrant.plugin("2", "host")`である。この実装において、`detect?`メソッドが唯一実装が必須なものである。

`detect?`メソッドは、Vagrantが稼働しているOSがこのホストであるかを決定する為に、その初期化の過程の早い段階でVagrantによって呼び出される。そのオペレーティング・システムであると検出した場合、`detect?`から`true`を返す。そうでなければ`false`を返す。

```bash
class MyHost < Vagrant.plugin("2", "host")
  def detect?(environment)
    File.file?("/etc/arch-release")
  end
end
```

OSを検出したのち、そのOSは、要求される様々な[ホストの能力][host capabilities](https://www.vagrantup.com/docs/plugins/host-capabilities.html)を使用する。

## ホストの継承

ときどき、共通の祖先から枝分かれしたオペレーティング・システムもあるので、Vagrantはホストに対する継承の形をサポートしている。この良い例は、LinuxはDebianの祖先であり、さらに多くにおいてUbuntuの祖先である。継承は、ディストリビューション特有の上書きを許すことで、ホストが多くの共通の振る舞いを共有できるようにする。

Vagrantはカスタム化した[能力ベース](https://www.vagrantup.com/docs/plugins/host-capabilities.html)システムを使用するため、継承は標準的なRubyのクラス継承によって行われない。Vagrantは継承の振り分けを制御する。

異なるホストのサブクラスに対して、ホスト定義における2つ目のパラメータとしてホストの名前を指定する。

```bash
host "ubuntu", "debian" do
  require_relative "host"
  Host
end
```

上記のコンポーネントで、"ubuntu"ホストは"debian"から継承される。"ubuntu"に対する能力を見てみると、"debian"からのすべての能力も使用することができ、いくつかの"ubuntu"の能力は親の能力を上書きする。

`detect?`によってオペレーティング・システムを検出したとき、Vagranは常に、それらの親を確認する前に、子のオペレーティングシステムを検索することで深さ優先サーチを行う。そのため、上記の例では"ubuntu"上の`detect?`メソッドは"debian"の前に呼び出される。

# プラグインの開発：ホストの能力

このページでは、[ホスト](https://www.vagrantup.com/docs/plugins/hosts.html)に対して、新しい動作が指定したホスト・オペレーティング・システム上で行えるうように、新しい機能を追加する方法を示す。これを読む前に[プラグイン開発の基礎](https://www.vagrantup.com/docs/plugins/development-basics.html)をよく読んでおくこと。

> **警告：上級者向け！**プラグインの開発は、Rubyに対して適度に不安がない、経験豊かなVagrantユーザーだけが近づくべき、上級者向けの記載である。

ホストの能力は、ホストのオペレーティング・システムで動作するような、特定の"能力”をホストに付与することによって、[ホスト](https://www.vagrantup.com/docs/plugins/hosts.html) を拡張する。

能力は、プラグインがVagrantのコアな部分を変更することなしに、既存のホスト・オペレーティング・システムに新しい機能を追加することができる。Vagrantの早期のバージョンでは、ホストのロジックのすべては、Vagrantのコアな部分に含まれており、簡単に拡張することができなかった。

## 定義と実装

ホストの能力の芸地と実装は[ゲストの能力](https://www.vagrantup.com/docs/plugins/guest-capabilities.html)と同じである。

しかしながら、ゲストの能力との主な違いは、一つ目の引数としてマシンをとる代わりに、すべてのホストの能力は一つ目の引数として`Vagrant::Environment`をとる。

環境へのアクセスは、ホストの能力がグローバルな状態へのアクセスすることを可能とする。そして、ほかのホストの能力を呼び出すこともできる。

## 能力の呼び出し

すべての能力において環境へアクセスできるので、能力は他の能力を呼び出すこともできる。これはより詳しい情報をヘルパーに尋ねる可能性のために、能力の継承機構を使用することに対して有用である。例えば、"linux"ゲストは、NFSが稼働しているかを確認する為に使用するコマンドを返す"nfs_check_command"能力を持っている。

ここに示す細かな点を除いて、RedHatやArchなどのようなLinuxの子ゲストの能力は、この能力を、たいていLinuxの振る舞いを継承したものとして使用する。

能力はこのように呼び出すことができる。

```bash
environment.host.capability(:capability_name)
```

メソッドに与えられるいかなる追加の引数も能力に受け渡され、そして能力は実際に能力が返す値を返す。

# プラグインの開発：プロバイダ

このページでは、VagrantがVirtualBox以外のシステムによって動かされているマシンの実行や管理ができるように、Vagrantに新しいプロバイダに対するサポートを追加する方法を示す。これを読む前に[プラグイン開発の基礎](https://www.vagrantup.com/docs/plugins/development-basics.html)をよく読んでおくこと。

プロバイダを開発する前に、ユーザー視点からみてどのように[プロバイダが動くか](https://www.vagrantup.com/docs/providers/)についても熟知しておくべきである。

> **警告：上級者向け！**プラグインの開発は、Rubyに対して適度に不安がない、経験豊かなVagrantユーザーだけが近づくべき、上級者向けの記載である。

## プロバイダの例：AWS

プロバイダをどのように書くかを学ぶための最も良い方法は、練習としてあるものがどのように書かれているかをみることであろう。この文書を拡張する為に、AWSプロバイダの実装である[vagrant-aws](https://github.com/mitchellh/vagrant-aws)プラグインについて十分学習しておこう。このプラグインは、あなたのプラグインの構造やテストや実装をどのように行うかの良い例である。

## コンポーネントの定義

プラグインの定義において、新しいプロバイダはこのように定義される。

```bash
provider "my_cloud" do
  require_relative "provider"
  Provider
end
```

プロバイダは、プロバイダの名前を指定する一つの引数をとる`provider`メソッドで定義される。これは、プロバイダを指定する為に`vagrant up`と共に使用される名前である。上記の例では、プロバイダは`vagrant up --provider=my_cloud`で呼ぶことで使用することができる。

ブロック引数は、次で説明する`Vagrant.plugin(2, :provider)`を実装したクラス、を遅延読み込みして返す。

## プロバイダ・クラス

プロバイダ・クラスは、Vagrantが適切な親クラスを返させるための安全なアップグレードの方法である`Vagrant.plugin(2, :provider)`のサブクラスであり実装であるべきである。

実装されるべきこのクラスとメソッドについては[とても良い文書](https://github.com/mitchellh/vagrant/blob/master/lib/vagrant/plugin/v2/provider.rb)がある。コメント内にあるクラスの文書は何をすべきかを理解するのに十分である。

[プラグインの全体的な構造](https://github.com/mitchellh/vagrant-aws)と同様に[AWSプロバイダ・クラス](https://github.com/mitchellh/vagrant-aws/blob/master/lib/vagrant-aws/provider.rb)を見ることは、初めの一歩として強く勧められることである。

実装される必要のあるメソッドのそれぞれについて深く見ていく代わりに、その文書は、高度であるが、プロバイダを作る手助けとなる重要なポイントを網羅している。

## Boxのフォーマット

それぞれのプロバイダは、自分自身のBoxのフォーマットをもつ責任がある。これは実際には、一般的なBoxはどうするかという、きわめて単純な手順である。それを説明する前に、一般的な[Boxのフォーマット](https://www.vagrantup.com/docs/boxes/format.html)に詳しくなるべきである。

Boxのフォーマットに対する唯一の要求は、`metadata.json`ファイルが、上記の例で選んだプロバイダの名前と一致する`provider`キーを持つことである。

これに加えて、metadataに何らかのデータを置くのと同様に、archiveに何らかのファイルも置くだろう。Vagrantのコア自身には配慮されていないので、Boxのデータを制御するのはそのプロバイダ次第である。Vagrantのコアはただ、展開とそのBoxが適切なプロバイダようであるか検証を制御するのみである。

実際に使用されている、一組のBoxフォーマット例としては、

* `virtualbox`のBoxフォーマットはちょうど、`VBoxManage export`コマンドの内容であるフラットなディレクトリである。
* `vmware_fusion`のBoxフォーマットはちょうど、`vmwarevm`フォルダの内容であるフラットなディレクトリである。ただしVMWareが機能する為の素の必須ファイルをふくむだけのものである。
* `aws`のBoxフォーマットはちょうど、Vagrantfileがデフォルトとしているいくつかの設定内容である。[awsのBoxを展開したものをここで](https://github.com/mitchellh/vagrant-aws/tree/master/example_box)見ることができる。

プロバイダに関する何かをまさに書こうとする前に、`vagrant box add`とともに実行することによってBoxのフォーマットが動作するかを検証することができる。`vagrant box list`を実行した場合、どのプロバイダがインストールされるかを見ることができる。

そのプロバイダに対するBoxを追加する為に、プロバイダのプラグインはインストールされる*必要は*ない。

## アクション

プロバイダを構築する際、理解する為に最も重要な概念は、おそらく、プロバイダの"action"インタフェースである。それは、プロバイダが魔法のような動作をするための秘密のソースである。

アクションは、[ミドルウェア](https://github.com/mitchellh/middleware)の概念の最上位に構築され、それはプロバイダが複数の異なる段階を実行したり、エラー回復機構をもったり、前後のふるまいや、そのほか多くのものを持つことを許す。

Vagrantコアは、プロバイダクラス上の`action`メソッドを通してプロバイダから特定のアクションを要求する。要求されるアクションの完全なリストは、そのスーパークラス上のメソッドのコメント上にリスト化されている。もし、プロバイダが適切なアクションを実装していない場合、Vagrantコアは親切なエラーを表示するだろう。どんなミスをしても心配しなくてもよい。それらは壮大なる爆発や破壊をすることはない。

VirtualBoxのプロバイダがどのように[複雑な何段階ものステップのプロセスを作り上げるためにアクションを使用するか](https://github.com/mitchellh/vagrant/blob/master/plugins/providers/virtualbox/action.rb#L287)を見ておこう。AWSプロバイダは[似たようなプロセスを使用している](https://github.com/mitchellh/vagrant-aws/blob/master/lib/vagrant-aws/action.rb)。

## 組み込みミドルウェア

共通のタスクを補助する為に、Vagrantは[組み込みミドルウェア](https://github.com/mitchellh/vagrant/tree/master/lib/vagrant/action/builtin)のセットを搭載している。いずれのミドルウェアも、その振る舞いやオプションのそれぞれに対する十分なコメントがある。そして、これらの組み込みミドルウェアの使い方は、適切なふるまいをするプロバイダを構築する為の肝である。

これらの組み込みミドルウェアはプロバイダのアクションのための標準ライブラリのように考えることができる。VirtualBoxプロバイダのコアはこれらの組み込みミドルウェアを頻繁に使用する。

## 状態維持

マシンの生成と管理のプロセスにおいて、プロバイダは通常、状態がどこにあるかなどを格納する必要がある。Vagrantはそれぞれのマシンに、この状態を格納するためのディレクトリを提供する。

これに関するユースケースの例としては、VirtualBoxプロバイダは、VirtualBox仮想マシンが生成したUUIDを格納する。これはプロバイダに、マシンが生成状態か、稼働状態か、サスペンド状態かどうかを追跡できるようにする。

実際にVMWareプロバイダはこの状態ディレクトリに、全仮想ディスク・ドライブとあらゆるもの、仮想マシンのすべてを格納する。

そのディレクトリは、プロバイダの初期化をするために与えられる`Machine`インスタンスの`data_dir`属性から取得することができる。ミドルウェアのアクションとともに、マシンは常にその環境の`:machine`キーを介して取得することができる。`data_dir`属性はRubyの[Pathname](http://www.ruby-doc.org/stdlib-1.9.3/libdoc/pathname/rdoc/Pathname.html)オブジェクトである。

プロバイダにとって、このディレクトリのすべての内容を慎重に管理することが非常に重要である。Vagrantコア自身は、このディレクトリを少し掃除する。しかしながら、マシンが削除された、このディレクトリからすべての状態を消去することを確認すること。

## 設定

Vagrantは、ユーザーがVagrantfileから特定のプロバイダを適切に調整したり制御したりするために[プロバイダ特有の設定](https://www.vagrantup.com/docs/providers/configuration.html)をサポートする。カスタムプロバイダがカスタム設定を公開できるようにするのも同じように簡単である。

プロバイダ特有の設定は、標準的な[プラグインの設定](https://www.vagrantup.com/docs/plugins/configuration.html)の特殊なケースである。設定コンポーネントの定義をするとき、設定の名前のつけ方はプロバイダと同様であり、2つ目のパラメータと同じように、`:provier`を指定する。

```bash
config("my_cloud", :provider) do
  require_relative "config"
  Config
end
```

プロバイダに名前が一致し、2つ目に`:provider`パラメータが与えられた場合、Vagrantは自動的に、これをそのプロバイダ用のプロバイダ特有の設定として公開する。ユーザーはVagrantfile内で以下のようにできる。

```bash
config.vm.provider :my_cloud do |config|
  # Your specific configuration!
end
```

プラグインの中の`config`コンポーネントから返される設定クラスは、そのほかの[プラグインの設定](https://www.vagrantup.com/docs/plugins/configuration.html)と同様であり、詳細な情報はそのページに読むこと。Vagrantは自動的にその設定をそのほかの設定項目のように制御する。

プロバイダ特有の設定は、`provider_config`属性を介して、マシン上で使用することができる。アクションやプロバイダクラスのように、`machine.provier_config`を介してアクセスすることができる。

> **ベスト・プラクティス**そのプロバイダが機能に対してプロバイダ特有の設定を必要としないならば、それは可能である。Vagrantは強く、[設定より規約](https://en.wikipedia.org/wiki/Convention_over_configuration) の哲学の実践している。ユーザーがそのプロバイダをインストールする際に、`vagrant up --provider=your_provider`をするだけで、それが動くことを理想としている。

## 並列化

Vagrantは、プロバイダがそれを明確にサポートしている場合、`vagrant up`などのようないくつかのアクションの並列化をサポートしている。デフォルトでは、Vagrantはプロバイダの並列化をしない。

並列化が有効になった場合、複数の[アクション](https://www.vagrantup.com/docs/plugins/providers.html#actions)が並列に実行されるだろう。そのため、プロバイダはそれらのアクションのスタックがスレッド・セーフであることを保証すべきである。Vagrantのコア自身は(Boxコレクション、SSHなど)はスレッド・セーフである。

プロバイダコンポーネント上に`paralled`オプションを設定することで、プロバイダは明確に並列化をすることができる。

```bash
provider("my_cloud", parallel: true) do
  require_relative "provider"
  Provider
end
```

並列化を有効化するのに必要な変更はこれだけである。

# プラグインの開発：プロビジョナ

このページでは、Vagrantがカスタム・プロビジョナを使用して、自動的にソフトウェアのインストールやソフトウェアの設定をできるための新しい[プロビジョナ](https://www.vagrantup.com/docs/provisioning/)をVagrantへ追加する方法を示す。これを読む前に[プラグイン開発の基礎](https://www.vagrantup.com/docs/plugins/development-basics.html)をよく読んでおくこと。

> **警告：上級者向け！**プラグインの開発は、Rubyに対して適度に不安がない、経験豊かなVagrantユーザーだけが近づくべき、上級者向けの記載である。

## コンポーネントの定義

プラグイン定義において、新しいプロビジョナは以下のように定義される。

```bash
provisioner "custom" do
  require_relative "provisioner"
  Provisioner
end
```

プロビジョナは、プロビジョナの名前を指定する一つの引数をとる`provisioner`メソッドとして定義される。これはプロビジョナを設定したり、有効化したりするときに`config.vm.provision`と共に使用される名前である。上記の例では、プロビジョナは`config.vm.provision :custiom`を使用して有効化されている。

ブロック引数は遅延読み込みをし、次に示す`Vagrant.plugin(2, :provisioner)`インタフェースを実装したクラスを返す。

## プロビジョナ・クラス

プロビジョナ・クラスは、Vagrantが適切な親クラスを返させるための安全なアップグレードの方法である`Vagrant.plugin(2, :provisioner)`のサブクラスであり実装であるべきである。

実装されるべきこのクラスとメソッドについては[とても良い文書](https://github.com/mitchellh/vagrant/blob/master/lib/vagrant/plugin/v2/provider.rb)がある。コメント内にあるクラスの文書は何をすべきかを理解するのに十分である。

実装すべき2つの主要なメソッドがある。`configure`メソッドと`provision`メソッドである。

`configure`メソッドは、マシンのブート・プロセスの早い段階において、プロビジョナがマシン上の共有フォルダやネットワークの定義など、新しい設定を定義できるように、呼び出される。一つの例として、[Chef solo プロビジョナ](https://github.com/mitchellh/vagrant/blob/master/plugins/provisioners/chef/provisioner/chef_solo.rb#L24)はこれを共有フォルダの定義に使用している。

`provision`メソッドは、マシンがブートし、SSH接続の準備ができた時点で呼び出される。このメソッドにおいて、プロビジョナは、実行する必要のある何らかのコマンドを実行すべきである。

# プラグインの開発：パッケージ化と配布

このページでは	
This page documents how to organize the file structure of your plugin and distribute it so that it is installable using [標準的なインストール方法](https://www.vagrantup.com/docs/plugins/usage.html)を使用してインストールできるように、プラグインのファイル構造の構築の仕方や、配布の仕方を示す。これを読む前に[プラグイン開発の基礎](https://www.vagrantup.com/docs/plugins/development-basics.html)をよく読んでおくこと。

> **警告：上級者向け！**プラグインの開発は、Rubyに対して適度に不安がない、経験豊かなVagrantユーザーだけが近づくべき、上級者向けの記載である。

## プラグインの例

パッケージ化や配布の記述するための最も良い近道は、ほかのプラグインのやり方を見ることである。これに関する最も適切な例のプラグインは[vagrant-aws](https://github.com/mitchellh/vagrant-aws)である。

[Bundler](http://bundler.io/)やRakeを使用して、新しいvagrant-awsパッケージを生成することは簡単である。単純に`rake package`を呼び出すことで、一つの`gem`ファイルがディレクトリに配置される。`rake release`を呼び出すことでgemが生成され、
それが、`vagrant plugin install`を使用することでインストール可能となる[RubyGems](https://rubygems.org/) 中央リポジトリにアップロードされる。

Bundlerを使用することで基本的に無用で手に入れられるので、プラグインは簡単にできるし、そうあるべきでもある。

## プロジェクトの設定

プロジェクトを設定するには、`bunndle gem vagrant-my-plugin`を実行する。これは、RubyGem用の初期レイアウトを持つ`vagrant-my-plugin`ディレクトリを生成する。

依存性の追加やメタデータの変更をするために`vagrant-my-plugin.gemspec`ファイルを修正するべきである。良い例として[vagrant-aws.gemspec](https://github.com/mitchellh/vagrant-aws/blob/master/vagrant-aws.gemspec)を参照すること。

> そのgemのために**Vagrantに依存しないこと**。Vagrantはもはやgemとして配布されていないし、そのプラグインがインストールされていればいつでも入手可能であると考えることが出来るだろう。

一度、RubyGem用のディレクトリ構造が構築されれば、そのGemfileを修正したくなるだろう。ここにVagrantプラグインの開発のための基本的なGemfileの構造を示す。

```bash
source "https://rubygems.org"

group :development do
  gem "vagrant", git: "https://github.com/mitchellh/vagrant.git"
end

group :plugins do
  gem "my-vagrant-plugin", path: "."
end
```

このGemfileは開発用の"vagrant"を取得する。これによって、すでにロードされているプラグインとともにVagranを稼働するために`bundle exec vagrant`を行うことができるようになる。そして、手動でテストすることが出来る。

奇妙に見えるこのGemfileの唯一の点は、"plugins"グループとそのグループにpluginを入れているところだろう。`vagrant plugin`コマンドはdevelopment内では動作しないので、これはVagrantにプラグインを"インストール"する方法である。Vagrantは"plugins"グループにあるすべてのgemsを自動的にロードする。もし、プラグインがほかのプラグインとともに動作するのであれば、これは開発用のVagrantに複数のプラグインを追加することもできる。

次に、いかに中身をしめすような最小限の`Rakefile`を生成する。

```bash
require "rubygems"
require "bundler/setup"
Bundler::GemHelper.install_tasks
```

もし`rake -T`を今実行した場合、使用できるrakeのタスクが一覧表示され、`package`や`release`のタスクを持っていることを見られるだろう。ついに、あなたはプラグインを開発することができ、それを作り出すことができたのだ。

テストを含むわかりやすい例については、[vagrant-aws Rakefile](https://github.com/mitchellh/vagrant-aws/blob/master/Rakefile)を見ればよいだろう。

## プラグインのテスト

開発期間においてプラグインのテストを手動で行うためには、そのプラグインをロードしてVagrantを起動する為に`bundle exec vagrant`を使用する(先に行ったGemfileの設定を思い出そう)。

自動テストに対しては、[vagrant-spec](https://github.com/mitchellh/vagrant-spec)プロジェクトが、 プラグインのユニットテストや受け入れテストの双方に対する補助を提供してくれる。そのプロジェクトに対してvagrant-specをどのように統合させていくかに関する詳細な説明については、巨大なREADMEを参照すること。Vagrant自身(さらにそのコアなプラグイン）は自動テストに対してvagrant-specを使用している。and all of its core plugins)。

# 関連記事

* 前の記事：[【Vagrantドキュメント意訳】13.プロバイダ](http://qiita.com/ringo0321/items/0861cd7e4f630e73164a)
* 次の記事：[【Vagrantドキュメント意訳】15.プッシュ](http://qiita.com/ringo0321/items/ab162e6786a0e30685d4)