2013-06-11 00:47:16 -04:00
|
|
|
---
|
2015-07-22 22:31:00 -04:00
|
|
|
description: |
|
|
|
|
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, from a user standpoint.
|
|
|
|
layout: docs
|
|
|
|
page_title: Developing Plugins
|
|
|
|
...
|
2013-06-11 00:47:16 -04:00
|
|
|
|
|
|
|
# Developing Plugins
|
|
|
|
|
2015-07-22 22:31:00 -04:00
|
|
|
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.
|
2013-06-11 00:47:16 -04:00
|
|
|
|
2016-01-14 15:31:19 -05:00
|
|
|
Packer plugins must be written in [Go](https://golang.org/), so it is also
|
2015-07-22 22:31:00 -04:00
|
|
|
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
|
2013-06-11 00:47:16 -04:00
|
|
|
makes it extremely easy to develop Packer plugins.
|
|
|
|
|
2015-07-22 22:31:00 -04:00
|
|
|
\~> **Warning!** This is an advanced topic. If you're new to Packer, we
|
2014-10-20 13:55:16 -04:00
|
|
|
recommend getting a bit more comfortable before you dive into writing plugins.
|
2013-06-11 00:47:16 -04:00
|
|
|
|
|
|
|
## Plugin System Architecture
|
|
|
|
|
|
|
|
Packer has a fairly unique plugin architecture. Instead of loading plugins
|
2015-07-22 22:31:00 -04:00
|
|
|
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.
|
2013-06-11 00:47:16 -04:00
|
|
|
|
|
|
|
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
|
2015-07-22 22:31:00 -04:00
|
|
|
uses, because they're completely isolated into the process space of the plugin
|
|
|
|
itself.
|
2013-06-11 00:47:16 -04:00
|
|
|
|
2015-07-22 22:31:00 -04:00
|
|
|
And, thanks to Go's
|
2016-01-14 15:31:19 -05:00
|
|
|
[interfaces](https://golang.org/doc/effective_go.html#interfaces_and_types), it
|
2015-07-22 22:31:00 -04:00
|
|
|
doesn't even look like inter-process communication is occurring. You just use
|
|
|
|
the interfaces like normal, but in fact they're being executed in a remote
|
|
|
|
process. Pretty cool.
|
2013-06-11 00:47:16 -04:00
|
|
|
|
|
|
|
## Plugin Development Basics
|
|
|
|
|
2015-07-22 22:31:00 -04:00
|
|
|
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!
|
2013-06-11 00:47:16 -04:00
|
|
|
|
2015-07-22 22:31:00 -04:00
|
|
|
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.
|
2013-06-11 00:47:16 -04:00
|
|
|
|
2015-07-22 23:25:58 -04:00
|
|
|
- `github.com/mitchellh/packer` - Contains all the interfaces that you have to
|
|
|
|
implement for any given plugin.
|
2013-06-11 00:47:16 -04:00
|
|
|
|
2017-01-03 18:05:29 -05:00
|
|
|
- `github.com/mitchellh/packer/packer/plugin` - Contains the code to serve
|
2015-07-22 23:25:58 -04:00
|
|
|
the plugin. This handles all the inter-process communication stuff.
|
2013-06-11 00:47:16 -04:00
|
|
|
|
|
|
|
There are two steps involved in creating a plugin:
|
|
|
|
|
2015-07-22 23:25:58 -04:00
|
|
|
1. Implement the desired interface. For example, if you're building a builder
|
|
|
|
plugin, implement the `packer.Builder` interface.
|
2013-06-11 00:47:16 -04:00
|
|
|
|
2015-07-22 23:25:58 -04:00
|
|
|
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`.
|
2013-06-11 00:47:16 -04:00
|
|
|
|
|
|
|
A basic example is shown below. In this example, assume the `Builder` struct
|
|
|
|
implements the `packer.Builder` interface:
|
|
|
|
|
2015-07-22 22:31:00 -04:00
|
|
|
``` {.go}
|
2013-06-11 00:47:16 -04:00
|
|
|
import (
|
2017-01-03 18:05:29 -05:00
|
|
|
"github.com/mitchellh/packer/packer/plugin"
|
2013-06-11 00:47:16 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
// Assume this implements packer.Builder
|
|
|
|
type Builder struct{}
|
|
|
|
|
|
|
|
func main() {
|
2015-07-22 22:31:00 -04:00
|
|
|
plugin.ServeBuilder(new(Builder))
|
2013-06-11 00:47:16 -04:00
|
|
|
}
|
2014-10-20 13:55:16 -04:00
|
|
|
```
|
2013-06-11 00:47:16 -04:00
|
|
|
|
|
|
|
**That's it!** `plugin.ServeBuilder` handles all the nitty gritty of
|
2015-07-22 22:31:00 -04:00
|
|
|
communicating with Packer core and serving your builder over RPC. It can't get
|
|
|
|
much easier than that.
|
2013-06-11 00:47:16 -04:00
|
|
|
|
2015-07-22 22:31:00 -04:00
|
|
|
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.
|
2013-06-11 00:47:16 -04:00
|
|
|
|
2015-07-22 22:31:00 -04:00
|
|
|
The specifics of how to implement each type of interface are covered in the
|
|
|
|
relevant subsections available in the navigation to the left.
|
2013-06-11 00:47:16 -04:00
|
|
|
|
2015-07-22 22:31:00 -04:00
|
|
|
\~> **Lock your dependencies!** Unfortunately, Go's dependency management
|
|
|
|
story is fairly sad. There are various unofficial methods out there for locking
|
|
|
|
dependencies, and using one of them is highly recommended since the Packer
|
|
|
|
codebase will continue to improve, potentially breaking APIs along the way until
|
|
|
|
there is a stable release. By locking your dependencies, your plugins will
|
|
|
|
continue to work with the version of Packer you lock to.
|
2013-06-27 13:43:19 -04:00
|
|
|
|
2013-06-11 00:47:16 -04:00
|
|
|
## Logging and Debugging
|
|
|
|
|
2015-07-22 22:31:00 -04:00
|
|
|
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.
|
2013-06-11 00:47:16 -04:00
|
|
|
|
2015-07-22 22:31:00 -04:00
|
|
|
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-11 00:47:16 -04:00
|
|
|
|
2015-07-22 22:31:00 -04:00
|
|
|
``` {.text}
|
2013-06-11 00:47:16 -04:00
|
|
|
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
|
|
|
|
```
|
|
|
|
|
2015-07-22 22:31:00 -04:00
|
|
|
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.
|
2013-06-11 00:47:16 -04:00
|
|
|
|
|
|
|
## Plugin Development Tips
|
|
|
|
|
2015-07-22 22:31:00 -04:00
|
|
|
Here are some tips for developing plugins, often answering common questions or
|
|
|
|
concerns.
|
2013-06-11 00:47:16 -04:00
|
|
|
|
2013-06-20 17:30:02 -04:00
|
|
|
### Naming Conventions
|
|
|
|
|
2015-07-22 22:31:00 -04:00
|
|
|
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.
|
2013-06-11 00:47:16 -04:00
|
|
|
|
2013-06-20 17:30:02 -04:00
|
|
|
### Testing Plugins
|
|
|
|
|
2015-07-22 22:31:00 -04:00
|
|
|
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:
|
2013-06-11 00:47:16 -04:00
|
|
|
|
2015-07-22 22:31:00 -04:00
|
|
|
``` {.javascript}
|
2013-06-11 00:47:16 -04:00
|
|
|
{
|
|
|
|
"builders": {
|
|
|
|
"custom-cloud": "/an/absolute/path/to/packer-builder-custom-cloud"
|
|
|
|
}
|
|
|
|
}
|
2014-10-20 13:55:16 -04:00
|
|
|
```
|
2013-06-11 00:47:16 -04:00
|
|
|
|
2015-07-22 22:31:00 -04:00
|
|
|
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.
|
2013-06-11 00:47:16 -04:00
|
|
|
|
2013-06-20 17:30:02 -04:00
|
|
|
### Distributing Plugins
|
|
|
|
|
2015-07-22 22:31:00 -04:00
|
|
|
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.
|