website: plugin development basics

This commit is contained in:
Mitchell Hashimoto 2013-06-10 21:47:16 -07:00
parent 97ec004724
commit ba3e58f962
3 changed files with 154 additions and 5 deletions

View File

@ -0,0 +1,148 @@
---
layout: "docs"
---
# Developing Plugins
This page will document how you can develop your own Packer plugins.
Prior to reading this, it is assumed that you're comfortable with Packer
and also know the [basics of how Plugins work](/docs/extend/plugins.html),
from a user standpoint.
Packer plugins must be written in [Go](http://golang.org/), so it is also
assumed that you're familiar with the language. This page will not be a
Go language tutorial. Thankfully, if you are familiar with Go, the Go toolchain
makes it extremely easy to develop Packer plugins.
<div class="alert alert-block">
<strong>Warning!</strong> This is an advanced topic. If you're new to Packer,
we recommend getting a bit more comfortable before you dive into writing
plugins.
</div>
## Plugin System Architecture
Packer has a fairly unique plugin architecture. Instead of loading plugins
directly into a running application, Packer runs each plugin as a
_separate application_. Inter-process communication and RPC is then used
to communicate between the many running Packer processes. Packer core
itself is responsible for orchestrating the processes and handles cleanup.
The beauty of this is that your plugin can have any dependencies it wants.
Dependencies don't need to line up with what Packer core or any other plugin
uses, because they're completely isolated into the process space of the
plugin itself.
And, thanks to Go's [interfaces](http://golang.org/doc/effective_go.html#interfaces_and_types),
it doesn't even look like inter-process communication is occuring. You just
use the interfaces like normal, but in fact they're being executed in
a remote process. Pretty cool.
## Plugin Development Basics
Developing a plugin is quite simple. All the various kinds of plugins
have a corresponding interface. The plugin simply needs to implement
this interface and expose it using the Packer plugin package (covered here shortly),
and that's it!
There are two packages that really matter that every plugin must use.
Other than the following two packages, you're encouraged to use whatever
packages you want. Because plugins are their own processes, there is
no danger of colliding dependencies.
* `github.com/mitchellh/packer` - Contains all the interfaces that you
have to implement for any given plugin.
* `github.com/mitchellh/packer/plugin` - Contains the code to serve the
plugin. This handles all the inter-process communication stuff.
There are two steps involved in creating a plugin:
1. Implement the desired interface. For example, if you're building a
builder plugin, implement the `packer.Builder` interface.
2. Serve the interface by calling the appropriate plugin serving method
in your main method. In the case of a builder, this is `plugin.ServeBuilder`.
A basic example is shown below. In this example, assume the `Builder` struct
implements the `packer.Builder` interface:
<pre class="prettyprint">
import (
"github.com/mitchellh/packer/plugin"
)
// Assume this implements packer.Builder
type Builder struct{}
func main() {
plugin.ServeBuilder(new(Builder))
}
</pre>
**That's it!** `plugin.ServeBuilder` handles all the nitty gritty of
communicating with Packer core and serving your builder over RPC. It
can't get much easier than that.
Next, just build your plugin like a normal Go application, using `go build`
or however you please. The resulting binary is the plugin that can be
installed using standard installation procedures.
The specifics of how to implement each type of interface are covered
in the relevant subsections available in the navigation to the left.
## Logging and Debugging
Plugins can use the standard Go `log` package to log. Anything logged
using this will be available in the Packer log files automatically.
The Packer log is visible on stderr when the `PACKER_LOG` environmental
is set.
Packer will prefix any logs from plugins with the path to that plugin
to make it identifiable where the logs come from. Some example logs are
shown below:
```
2013/06/10 21:44:43 ui: Available commands are:
2013/06/10 21:44:43 Loading command: build
2013/06/10 21:44:43 packer-command-build: 2013/06/10 21:44:43 Plugin minimum port: 10000
2013/06/10 21:44:43 packer-command-build: 2013/06/10 21:44:43 Plugin maximum port: 25000
2013/06/10 21:44:43 packer-command-build: 2013/06/10 21:44:43 Plugin address: :10000
```
As you can see, the log messages from the "build" command plugin are
prefixed with "packer-command-build". Log output is _extremely_ helpful
in debugging issues and you're encouraged to be as verbose as you need to
be in order for the logs to be helpful.
## Plugin Development Tips
Here are some tips for developing plugins, often answering common questions
or concerns.
First, it is standard practice to name the resulting plugin application
in the format of `packer-TYPE-NAME`. For example, if you're building a
new builder for CustomCloud, it would be standard practice to name the
resulting plugin `packer-builder-custom-cloud`. This naming convention
helps users identify the purpose of a plugin.
Next, while developing plugins, you can configure your Packer configuration
to point directly to the compiled plugin in order to test it. For example,
building the CustomCloud plugin, I may configure packer like so:
<pre class="prettyprint">
{
"builders": {
"custom-cloud": "/an/absolute/path/to/packer-builder-custom-cloud"
}
}
</pre>
This would configure Packer to have the "custom-cloud" plugin, and execute
the binary that I am building during development. This is extremely useful
during development.
Additionally, it is recommended you use a tool like [goxc](https://github.com/laher/goxc)
in order to cross-compile your plugin for every platform that Packer supports,
since Go applications are platform-specific. goxc will allow you to build
for every platform from your own computer.

View File

@ -4,7 +4,7 @@ layout: "docs"
# Packer Plugins
Plugins allow Packer new functionality to be added to Packer without
Plugins allow new functionality to be added to Packer without
modifying the core source code. Packer plugins are able to add new
commands, builders, provisioners, hooks, and more. In fact, much of Packer
itself is implemented by writing plugins that are simply distributed with
@ -14,7 +14,7 @@ to load with Packer.
This page will cover how to install and use plugins. If you're interested
in developing plugins, the documentation for that is available the
[developing plugins](#) page.
[developing plugins](/docs/extend/developing-plugins.html) page.
Because Packer is so young, there is no official listing of available
Packer plugins. Plugins are best found via Google. Typically, searching
@ -65,13 +65,13 @@ from the core Packer configuration.
In addition to builders, other types of plugins can be installed. The full
list is below:
* "builders" - A key/value pair of builder type to the builder plugin
* `builders` - A key/value pair of builder type to the builder plugin
application.
* "commands" - A key/value pair of the command name to the command plugin
* `commands` - A key/value pair of the command name to the command plugin
application. The command name is what is executed on the command line, like
`packer COMMAND`.
* "provisioners" - A key/value pair of the provisioner type to the
* `provisioners` - A key/value pair of the provisioner type to the
provisioner plugin application. The provisioner type is the value of the
"type" configuration used within templates.

View File

@ -52,6 +52,7 @@
<li class="nav-header">Extend Packer</li>
<li><a href="/docs/extend/plugins.html">Packer Plugins</a></li>
<li><a href="/docs/extend/developing-plugins.html">Developing Plugins</a></li>
<li><a href="/docs/extend/builder.html">Custom Builder</a></li>
<li><a href="#">Custom Command</a></li>
<li><a href="#">Custom Provisioner</a></li>