github.com/phobos182/packer@v0.2.3-0.20130819023704-c84d2aeffc68/website/source/docs/extend/builder.html.markdown (about)

     1  ---
     2  layout: "docs"
     3  page_title: "Custom Builder - Extend Packer"
     4  ---
     5  
     6  # Custom Builder Development
     7  
     8  Builders are the components of Packer responsible for creating a machine,
     9  bringing it to a point where it can be provisioned, and then turning
    10  that provisioned machine into some sort of machine image. Several builders
    11  are officially distributed with Packer itself, such as the AMI builder, the
    12  VMware builder, etc. However, it is possible to write custom builders using
    13  the Packer plugin interface, and this page documents how to do that.
    14  
    15  Prior to reading this page, it is assumed you have read the page on
    16  [plugin development basics](/docs/extend/developing-plugins.html).
    17  
    18  <div class="alert alert-block">
    19    <strong>Warning!</strong> This is an advanced topic. If you're new to Packer,
    20    we recommend getting a bit more comfortable before you dive into writing
    21    plugins.
    22  </div>
    23  
    24  ## The Interface
    25  
    26  The interface that must be implemented for a builder is the `packer.Builder`
    27  interface. It is reproduced below for easy reference. The actual interface
    28  in the source code contains some basic documentation as well explaining
    29  what each method should do.
    30  
    31  <pre class="prettyprint">
    32  type Builder interface {
    33  	Prepare(...interface{}) error
    34  	Run(ui Ui, hook Hook, cache Cache) (Artifact, error)
    35  	Cancel()
    36  }
    37  </pre>
    38  
    39  ### The "Prepare" Method
    40  
    41  The `Prepare` method for each builder is called prior to any runs with
    42  the configuration that was given in the template. This is passed in as
    43  an array of `interface{}` types, but is generally `map[string]interface{}`. The prepare
    44  method is responsible for translating this configuration into an internal
    45  structure, validating it, and returning any errors.
    46  
    47  For multiple parameters, they should be merged together into the final
    48  configuration, with later parameters overwriting any previous configuration.
    49  The exact semantics of the merge are left to the builder author.
    50  
    51  For decoding the `interface{}` into a meaningful structure, the
    52  [mapstructure](https://github.com/mitchellh/mapstructure) library is recommended.
    53  Mapstructure will take an `interface{}` and decode it into an arbitrarily
    54  complex struct. If there are any errors, it generates very human friendly
    55  errors that can be returned directly from the prepare method.
    56  
    57  While it is not actively enforced, **no side effects** should occur from
    58  running the `Prepare` method. Specifically, don't create files, don't launch
    59  virtual machines, etc. Prepare's purpose is solely to configure the builder
    60  and validate the configuration.
    61  
    62  In addition to normal configuration, Packer will inject a `map[string]interface{}`
    63  with a key of `packer.DebugConfigKey` set to boolean `true` if debug mode
    64  is enabled for the build. If this is set to true, then the builder
    65  should enable a debug mode which assists builder developers and advanced
    66  users to introspect what is going on during a build. During debug
    67  builds, parallelism is strictly disabled, so it is safe to request input
    68  from stdin and so on.
    69  
    70  ### The "Run" Method
    71  
    72  `Run` is where all the interesting stuff happens. Run is executed, often
    73  in parallel for multiple builders, to actually build the machine, provision
    74  it, and create the resulting machine image, which is returned as an
    75  implementation of the `packer.Artifact` interface.
    76  
    77  The `Run` method takes three parameters. These are all very useful. The
    78  `packer.Ui` object is used to send output to the console. `packer.Hook` is
    79  used to execute hooks, which are covered in more detail in the hook section
    80  below. And `packer.Cache` is used to store files between multiple Packer
    81  runs, and is covered in more detail in the cache section below.
    82  
    83  Because builder runs are typically a complex set of many steps, the
    84  [multistep](https://github.com/mitchellh/multistep) library is recommended
    85  to bring order to the complexity. Multistep is a library which allows you to
    86  separate your logic into multiple distinct "steps" and string them together.
    87  It fully supports cancellation mid-step and so on. Please check it out, it is
    88  how the built-in builders are all implemented.
    89  
    90  Finally, as a result of `Run`, an implementation of `packer.Artifact` should
    91  be returned. More details on creating a `packer.Artifact` are covered in the
    92  artifact section below. If something goes wrong during the build, an error
    93  can be returned, as well. Note that it is perfectly fine to produce no artifact
    94  and no error, although this is rare.
    95  
    96  ### The "Cancel" Method
    97  
    98  The `Run` method is often run in parallel. The `Cancel` method can be
    99  called at any time and requests cancellation of any builder run in progress.
   100  This method should block until the run actually stops.
   101  
   102  Cancels are most commonly triggered by external interrupts, such as the
   103  user pressing `Ctrl-C`. Packer will only exit once all the builders clean up,
   104  so it is important that you architect your builder in a way that it is quick
   105  to respond to these cancellations and clean up after itself.
   106  
   107  ## Creating an Artifact
   108  
   109  The `Run` method is expected to return an implementation of the
   110  `packer.Artifact` interface. Each builder must create their own
   111  implementation. The interface is very simple and the documentation on the
   112  interface is quite clear.
   113  
   114  The only part of an artifact that may be confusing is the `BuilderId`
   115  method. This method must return an absolutely unique ID for the builder.
   116  In general, I follow the practice of making the ID contain my GitHub username
   117  and then the platform it is building for. For example, the builder ID of
   118  the VMware builder is "mitchellh.vmware" or something similar.
   119  
   120  Post-processors use the builder ID value in order to make some assumptions
   121  about the artifact results, so it is important it never changes.
   122  
   123  Other than the builder ID, the rest should be self-explanatory by reading
   124  the [packer.Artifact interface documentation](#).
   125  
   126  ## Provisioning
   127  
   128  Packer has built-in support for provisioning, but the moment when provisioning
   129  runs must be invoked by the builder itself, since only the builder knows
   130  when the machine is running and ready for communication.
   131  
   132  When the machine is ready to be provisioned, run the `packer.HookProvision`
   133  hook, making sure the communicator is not nil, since this is required for
   134  provisioners. An example of calling the hook is shown below:
   135  
   136  <pre class="prettyprint">
   137  hook.Run(packer.HookProvision, ui, comm, nil)
   138  </pre>
   139  
   140  At this point, Packer will run the provisioners and no additional work
   141  is necessary.
   142  
   143  <div class="alert alert-info alert-block">
   144  <strong>Note:</strong> Hooks are still undergoing thought around their
   145  general design and will likely change in a future version. They aren't
   146  fully "baked" yet, so they aren't documented here other than to tell you
   147  how to hook in provisioners.
   148  </div>
   149  
   150  ## Caching Files
   151  
   152  It is common for some builders to deal with very large files, or files that
   153  take a long time to generate. For example, the VMware builder has the capability
   154  to download the operating system ISO from the internet. This is timely process,
   155  so it would be convenient to cache the file. This sort of caching is a core
   156  part of Packer that is exposed to builders.
   157  
   158  The cache interface is `packer.Cache`. It behaves much like a Go
   159  [RWMutex](http://golang.org/pkg/sync/#RWMutex). The builder requests a "lock"
   160  on certain cache keys, and is given exclusive access to that key for the
   161  duration of the lock. This locking mechanism allows multiple builders to
   162  share cache data even though they're running in parallel.
   163  
   164  For example, both the VMware and VirtualBox support downloading an operating
   165  system ISO from the internet. Most of the time, this ISO is identical. The
   166  locking mechanisms of the cache allow one of the builders to download it
   167  only once, but allow both builders to share the downloaded file.
   168  
   169  The [documentation for packer.Cache](#) is
   170  very detailed in how it works.