packer-cn/website/source/docs/extending/custom-builders.html.md

156 lines
7.0 KiB
Markdown
Raw Normal View History

2013-06-11 01:15:06 -04:00
---
2017-06-14 21:04:16 -04:00
description: |
It is possible to write custom builders using the Packer plugin interface, and
this page documents how to do that.
2015-07-22 22:31:00 -04:00
layout: docs
2017-06-14 21:04:16 -04:00
page_title: 'Custom Builders - Extending'
sidebar_current: 'docs-extending-custom-builders'
---
2013-06-11 01:15:06 -04:00
# Custom Builders
2013-06-11 01:15:06 -04:00
2018-10-26 20:02:51 -04:00
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
2015-07-22 22:31:00 -04:00
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.
2013-06-11 01:15:06 -04:00
2015-07-22 22:31:00 -04:00
Prior to reading this page, it is assumed you have read the page on [plugin
2017-03-28 18:28:34 -04:00
development basics](/docs/extending/plugins.html).
2013-06-11 01:15:06 -04:00
2019-01-11 17:06:15 -05:00
\~> **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.
2013-06-11 01:15:06 -04:00
## 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
2015-07-22 22:31:00 -04:00
method should do.
2013-06-11 01:15:06 -04:00
2017-06-14 21:04:16 -04:00
``` go
2013-06-11 01:15:06 -04:00
type Builder interface {
2019-12-18 10:13:52 -05:00
ConfigSpec() hcldec.ObjectSpec
Prepare(...interface{}) ([]string, []string, error)
Run(context.Context, ui Ui, hook Hook) (Artifact, error)
2013-06-11 01:15:06 -04:00
}
```
2013-06-11 01:15:06 -04:00
### The "Prepare" Method
2015-07-22 22:31:00 -04:00
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
2013-06-11 01:15:06 -04:00
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
2018-10-26 20:02:51 -04:00
configuration, with later parameters overwriting any previous configuration.
The exact semantics of the merge are left to the builder author.
2013-06-11 01:15:06 -04:00
For decoding the `interface{}` into a meaningful structure, the
2015-07-22 22:31:00 -04:00
[mapstructure](https://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.
2018-10-26 20:02:51 -04:00
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.
2015-07-22 22:31:00 -04:00
In addition to normal configuration, Packer will inject a
`map[string]interface{}` with a key of `packer.DebugConfigKey` set to boolean
`true` if debug mode is enabled for the build. If this is set to true, then the
2018-10-26 20:02:51 -04:00
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.
2013-06-11 01:15:06 -04:00
### The "Run" Method
2015-07-22 22:31:00 -04:00
`Run` is where all the interesting stuff happens. Run is executed, often in
2018-10-26 20:02:51 -04:00
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.
2013-06-11 01:15:06 -04:00
The `Run` method takes three parameters. These are all very useful. The
2015-07-22 22:31:00 -04:00
`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.
2013-06-11 01:15:06 -04:00
Because builder runs are typically a complex set of many steps, the
2018-01-24 20:27:08 -05:00
[multistep](https://github.com/hashicorp/packer/blob/master/helper/multistep)
helper is recommended to bring order to the complexity. Multistep is a library
which allows you to separate your logic into multiple distinct "steps" and
string them together. It fully supports cancellation mid-step and so on. Please
check it out, it is how the built-in builders are all implemented.
2015-07-22 22:31:00 -04:00
Finally, as a result of `Run`, an implementation of `packer.Artifact` should be
returned. More details on creating a `packer.Artifact` are covered in the
artifact section below. If something goes wrong during the build, an error can
be returned, as well. Note that it is perfectly fine to produce no artifact and
no error, although this is rare.
2013-06-11 01:15:06 -04:00
### Cancellation
The `Run` method is often run in parallel.
2013-06-11 01:15:06 -04:00
#### With the "Cancel" Method ( up until packer 1.3 )
The `Cancel` method can be called at any time and requests cancellation of any
builder run in progress. This method should block until the run actually stops.
Not that the Cancel method will no longer be called since packer 1.4.0.
#### Context cancellation ( from packer 1.4 )
The `<-ctx.Done()` can unblock at any time and signifies request for
cancellation of any builder run in progress.
2013-06-11 01:15:06 -04:00
2015-07-22 22:31:00 -04:00
Cancels are most commonly triggered by external interrupts, such as the user
pressing `Ctrl-C`. Packer will only exit once all the builders clean up, so it
is important that you architect your builder in a way that it is quick to
respond to these cancellations and clean up after itself.
2013-06-11 01:15:06 -04:00
## Creating an Artifact
The `Run` method is expected to return an implementation of the
2015-07-22 22:31:00 -04:00
`packer.Artifact` interface. Each builder must create their own implementation.
The interface has ample documentation to help you get started.
2015-07-22 22:31:00 -04:00
The only part of an artifact that may be confusing is the `BuilderId` method.
This method must return an absolutely unique ID for the builder. In general, I
follow the practice of making the ID contain my GitHub username and then the
platform it is building for. For example, the builder ID of the VMware builder
is "hashicorp.vmware" or something similar.
2018-10-26 20:02:51 -04:00
Post-processors use the builder ID value in order to make some assumptions
about the artifact results, so it is important it never changes.
2015-07-22 22:31:00 -04:00
Other than the builder ID, the rest should be self-explanatory by reading the
2017-02-10 03:40:36 -05:00
[packer.Artifact interface
2017-04-04 16:39:01 -04:00
documentation](https://github.com/hashicorp/packer/blob/master/packer/artifact.go).
2013-06-11 01:15:06 -04:00
## Provisioning
Packer has built-in support for provisioning, but the moment when provisioning
2015-07-22 22:31:00 -04:00
runs must be invoked by the builder itself, since only the builder knows when
the machine is running and ready for communication.
2013-06-11 01:15:06 -04:00
When the machine is ready to be provisioned, run the `packer.HookProvision`
hook, making sure the communicator is not nil, since this is required for
provisioners. An example of calling the hook is shown below:
2013-06-11 01:15:06 -04:00
2017-06-14 21:04:16 -04:00
``` go
hook.Run(context.Context, packer.HookProvision, ui, comm, nil)
```
2013-06-11 01:15:06 -04:00
2015-07-22 22:31:00 -04:00
At this point, Packer will run the provisioners and no additional work is
necessary.
2017-06-14 21:04:16 -04:00
-&gt; **Note:** Hooks are still undergoing thought around their general design
2015-07-22 22:31:00 -04:00
and will likely change in a future version. They aren't fully "baked" yet, so
they aren't documented here other than to tell you how to hook in provisioners.
2013-06-24 12:36:55 -04:00