Packer Builders are the components of Packer responsible for creating a
machine, bringing it to a point where it can be provisioned, and then turning
that provisioned machine into some sort of machine image. Several builders are
officially distributed with Packer itself, such as the AMI builder, the VMware
builder, etc. However, it is possible to write custom builders using the Packer
plugin interface, and this page documents how to do that.
that provisioned machine into a machine image. Several builders are
officially maintained and distributed by the HashiCorp Packer team -- these
builders include builders for creating images on Amazon EC2, VMWare, Google
Compute Engine, and many more. It is also possible to write custom builders
using the Packer plugin interface, and this page documents how to do that.
Prior to reading this page, it is assumed you have read the page on [plugin
development basics](/docs/extending/plugins).
Prior to reading this page, you should read the page on [plugin development
basics](/docs/extending/plugins).
~> **Warning!** This is an advanced topic. If you're new to Packer, we
recommend getting a bit more comfortable before you dive into writing plugins.
recommend getting comfortable with using Packer and its officially maintained
plugins before before you dive into writing plugins of your own.
Custom plugins are written in [golang](https://golang.org/), so this guide
assumes that you have some familiarity with that programming language.
## The Interface
The interface that must be implemented for a builder is the `packer.Builder`
interface. It is reproduced below for reference. The actual interface in the
source code contains some basic documentation as well explaining what each
method should do.
To create your own builder, you must create a struct that implements the
`packer.Builder` interface. It is reproduced below for reference.
```go
type Builder interface {
@ -45,72 +48,100 @@ function, check our
### The "Prepare" Method
The `Prepare` method for each builder is called prior to any runs with the
configuration that was given in the template. This is passed in as an array of
`interface{}` types, but is generally `map[string]interface{}`. The prepare
method is responsible for translating this configuration into an internal
structure, validating it, and returning any errors.
For multiple parameters, they should be merged together into the final
configuration, with later parameters overwriting any previous configuration.
The exact semantics of the merge are left to the builder author.
For decoding the `interface{}` into a meaningful structure, the
[mapstructure](https://godoc.org/github.com/mitchellh/mapstructure) library is
recommended. Mapstructure will take an `interface{}` and decode it into an
arbitrarily complex struct. If there are any errors, it generates very human
friendly errors that can be returned directly from the prepare method.
While it is not actively enforced, **no side effects** should occur from
running the `Prepare` method. Specifically, don't create files, don't launch
virtual machines, etc. Prepare's purpose is solely to configure the builder and
validate the configuration.
In addition to normal configuration, Packer will inject a
`map[string]interface{}` with a key of `packer.DebugConfigKey` set to boolean
The `Prepare` method for each builder will be called by the Packer core
at the beginning of the build. Its purpose is to parse and validate the
configuration template provided to Packer with `packer build
your_packer_template.json`, but not to execute API calls or begin creating any
resources or artifacts.
The configuration from your Packer template is passed into the Prepare() method
as an array of `interface{}` types, but is generally `map[string]interface{}`.
The Prepare method is responsible for translating this configuration into an
internal structure, validating it, and returning any errors.
If multiple parameters are passed into Prepare(), they should be merged together
into the final configuration, with later parameters overwriting any previous
configuration. The exact semantics of the merge are left to the builder author.
We recommend that you use the
[mapstructure](https://godoc.org/github.com/mitchellh/mapstructure) library to
decode the interface{} into a meaningful structure. Mapstructure will take an
`interface{}` and decode it into an arbitrarily complex struct. If there are any
errors, it generates very human friendly errors that can be returned directly
from the prepare method. You can find many usage examples of this library within
the Prepare() methods of HashiCorp-maintained Packer plugins.
While Packer does not actively enforce this, **no side effects** should occur
from running the `Prepare` method. Specifically: don't create files, don't
launch virtual machines, etc. Prepare's purpose is solely to load the
configuration from the template into a format usable by your builder, to
validate that configuration, and to apply necessary defaults to that
configuration.
In addition to the configuration provided in the Packer template, Packer will
also supply a [common.PackerConfig](https://github.com/hashicorp/packer-plugin-sdk/blob/8a28198491f70deca3824ce452adf6f9bd507880/common/packer_config.go#L44)
containing meta-information such as the build name, builder type, core version,
etc, and coded into a `map[string]interface{}`. One important piece of
meta information in this map is the `packer.DebugConfigKey` set to boolean
`true` if debug mode is enabled for the build. If this is set to true, then the
builder should enable a debug mode which assists builder developers and
advanced users to introspect what is going on during a build. During debug
builds, parallelism is strictly disabled, so it is safe to request input from
stdin and so on.
Prepare() returns an array of strings and an error. The array of strings is a
special list of keys for variables created at runtime which your builder will
make accessible to provisioners using the generatedData mechanism (see below for
more details) An example could be an instance ID for the cloud instance created
by your builder. If you do not plan to make use of the generatedData feature,
just return an empty list. The error should be used if there is something wrong
with the user-provided configuration and the build should not proceed.
### The "Run" Method
`Run` is where all the interesting stuff happens. Run is executed, often in
parallel for multiple builders, to actually build the machine, provision it,
and create the resulting machine image, which is returned as an implementation
of the `packer.Artifact` interface.
`Run` is executed, often in parallel for multiple builders, to actually build
the machine, provision it, and create the resulting machine image, which is
returned as an implementation of the `packer.Artifact` interface.
The `Run` method takes three parameters. These are all very useful. The
`packer.Ui` object is used to send output to the console. `packer.Hook` is used
to execute hooks, which are covered in more detail in the hook section below.
And `packer.Cache` is used to store files between multiple Packer runs, and is
covered in more detail in the cache section below.
The `Run` method takes three parameters. The context.Context used to cancel the
build. The `packer.Ui` object is used to send output to the console.
`packer.Hook` is used to execute hooks, which are covered in more detail in the
Provisioning section below.
Because builder runs are typically a complex set of many steps, the