github.com/hashicorp/packer@v1.14.3/website/content/docs/plugins/creation/custom-provisioners.mdx (about)

     1  ---
     2  description: >
     3    Provisioners install and configure software prior to turning a machine into an image. Learn how to create custom provisioners that extend Packer functionality. 
     4  
     5  page_title: Create custom provisioners
     6  ---
     7  
     8  # Create Custom Provisioners
     9  
    10  Packer provisioners install and configure software into a running machine prior to turning that machine into an image. For example, the [shell provisioner](/packer/docs/provisioners/shell) runs shell scripts within machines.
    11  
    12  Provisioner plugins implement the [`packer.Provisioner`](https://pkg.go.dev/github.com/hashicorp/packer-plugin-sdk/packer#Provisioner) interface and are served
    13  using the `plugin.ServeProvisioner` function.
    14  
    15  ~> **Warning:** This is an advanced topic that requires strong knowledge of Packer and Packer plugins.
    16  
    17  ## Before You Begin
    18  
    19  We recommend reviewing the following resources before you begin development:
    20  - [Developing Plugins - Overview](/packer/docs/plugins/creation)
    21  - The [Go](https://go.dev/) language. You must write custom plugins in Go, so this guide assumes you are familiar with the language.
    22  
    23  ## The Interface
    24  
    25  The interface that must be implemented for a provisioner is the
    26  [`packer.Provisioner`](https://pkg.go.dev/github.com/hashicorp/packer-plugin-sdk/packer#Provisioner) interface. It is reproduced below for reference. The
    27  actual interface in the source code contains some basic documentation as well
    28  explaining what each method should do.
    29  
    30  ```go
    31  type Provisioner interface {
    32    ConfigSpec() hcldec.ObjectSpec
    33    Prepare(...interface{}) error
    34    Provision(context.Context, Ui, Communicator, map[string]interface{}) error
    35  }
    36  ```
    37  
    38  ### The `Prepare` Method
    39  
    40  The `Prepare` method for each provisioner is called prior to any runs with the
    41  configuration that was given in the template. This is passed in as an array of
    42  `interface{}` types, but is generally `map[string]interface{}`. The prepare
    43  method is responsible for translating this configuration into an internal
    44  structure, validating it, and returning any errors.
    45  
    46  For multiple parameters, they should be merged together into the final
    47  configuration, with later parameters overwriting any previous configuration.
    48  The exact semantics of the merge are left to the builder author.
    49  
    50  For decoding the `interface{}` into a meaningful structure, the
    51  [mapstructure](https://github.com/mitchellh/mapstructure) library is
    52  recommended. Mapstructure will take an `interface{}` and decode it into an
    53  arbitrarily complex struct. If there are any errors, it generates very human
    54  friendly errors that can be returned directly from the prepare method.
    55  
    56  While it is not actively enforced, **no side effects** should occur from
    57  running the `Prepare` method. Specifically, don't create files, don't launch
    58  virtual machines, etc. Prepare's purpose is solely to configure the builder and
    59  validate the configuration.
    60  
    61  The `Prepare` method is called very early in the build process so that errors
    62  may be displayed to the user before anything actually happens.
    63  
    64  ### The `ConfigSpec` Method
    65  
    66  This method returns a `hcldec.ObjectSpec`, which is a spec necessary for using
    67  HCL2 templates with Packer. For information on how to use and implement this
    68  function, check our
    69  [object spec docs](/packer/guides/hcl/component-object-spec)
    70  
    71  ### The `Provision` Method
    72  
    73  The `Provision` method is called when a machine is running and ready to be
    74  provisioned. The provisioner should do its real work here.
    75  
    76  The method takes two parameters: a `packer.Ui` and a `packer.Communicator`. The
    77  UI can be used to communicate with the user what is going on. The communicator
    78  is used to communicate with the running machine, and is guaranteed to be
    79  connected at this point.
    80  
    81  The provision method should not return until provisioning is complete.
    82  
    83  The map[string]interface{} provides users with build-specific information,
    84  like host and IP, provided by the `build` template engine. Provisioners may use
    85  this information however they please, or not use it.
    86  
    87  ## Using the Communicator
    88  
    89  The `packer.Communicator` parameter and interface is used to communicate with
    90  running machine. The machine may be local (in a virtual machine or container of
    91  some sort) or it may be remote (in a cloud). The communicator interface
    92  abstracts this away so that communication is the same overall.
    93  
    94  The documentation around the [code
    95  itself](https://godoc.org/github.com/hashicorp/packer-plugin-sdk/packer#Communicator)
    96  is really great as an overview of how to use the interface. You should begin by
    97  reading this. Once you have read it, you can see some example usage below:
    98  
    99  ```go
   100  // Build the remote command.
   101  var cmd packer.RemoteCmd
   102  cmd.Command = "echo foo"
   103  
   104  // We care about stdout, so lets collect that into a buffer. Since
   105  // we don't set stderr, that will just be discarded.
   106  var stdout bytes.Buffer
   107  cmd.Stdout = &stdout
   108  
   109  // Start the command
   110  if err := comm.Start(&cmd); err != nil {
   111    panic(err)
   112  }
   113  
   114  // Wait for it to complete
   115  cmd.Wait()
   116  
   117  // Read the stdout!
   118  fmt.Printf("Command output: %s", stdout.String())
   119  ```