github.com/hashicorp/packer@v1.14.3/website/content/docs/plugins/creation/custom-post-processors.mdx (about) 1 --- 2 description: > 3 Post-processors compress files, upload files, and perform other tasks that transform artifacts. Learn how to create customm post-processors that extend Packer. 4 page_title: Create custom post-processors 5 --- 6 7 # Create custom post-processors 8 9 Packer post-processors transform one artifact into another. For example, a post-processor might compress or upload files. 10 11 In the compression example, the transformation would be taking an artifact with 12 a set of files, compressing those files, and returning a new artifact with only 13 a single file (the compressed archive). For the upload example, the 14 transformation would be taking an artifact with some set of files, uploading 15 those files, and returning an artifact with a single ID: the URL of the upload. 16 17 Post-processor plugins implement the [`packer.PostProcessor`](https://pkg.go.dev/github.com/hashicorp/packer-plugin-sdk/packer#PostProcessor) interface and are 18 served using the `plugin.ServePostProcessor` function. 19 20 This page explains how to implement and serve custom post-processors. If you want your post-processor to support HashiCorp Cloud Platform (HCP) Packer, you should also review the [HCP Packer Support](/packer/docs/plugins/creation/hcp-support) documentation. 21 22 ~> **Warning:** This is an advanced topic that requires strong knowledge of Packer and Packer plugins. 23 24 ## Before You Begin 25 26 We recommend reviewing the following resources before you begin development: 27 - [Developing Plugins - Overview](/packer/docs/plugins/creation) 28 - The [Go](https://go.dev/) language. You must write custom plugins in Go, so this guide assumes you are familiar with the language. 29 30 ## The Interface 31 32 The interface that must be implemented for a post-processor is the 33 [`packer.PostProcessor`](https://pkg.go.dev/github.com/hashicorp/packer-plugin-sdk/packer#PostProcessor) interface. It is reproduced below for reference. The 34 actual interface in the source code contains some basic documentation as well 35 explaining what each method should do. 36 37 ```go 38 type PostProcessor interface { 39 ConfigSpec() hcldec.ObjectSpec 40 Configure(interface{}) error 41 PostProcess(context.Context, Ui, Artifact) (a Artifact, keep, mustKeep bool, err error) 42 } 43 ``` 44 45 ### The "ConfigSpec" Method 46 47 This method returns a hcldec.ObjectSpec, which is a spec necessary for using 48 HCL2 templates with Packer. For information on how to use and implement this 49 function, check our 50 [object spec docs](/packer/guides/hcl/component-object-spec) 51 52 ### The "Configure" Method 53 54 The `Configure` method for each post-processor is called early in the build 55 process to configure the post-processor. The configuration is passed in as a 56 raw `interface{}`. The configure method is responsible for translating this 57 configuration into an internal structure, validating it, and returning any 58 errors. 59 60 For decoding the `interface{}` into a meaningful structure, the 61 [mapstructure](https://github.com/mitchellh/mapstructure) library is 62 recommended. Mapstructure will take an `interface{}` and decode it into an 63 arbitrarily complex struct. If there are any errors, it generates very 64 human-friendly errors that can be returned directly from the configure method. 65 66 While it is not actively enforced, **no side effects** should occur from 67 running the `Configure` method. Specifically, don't create files, don't create 68 network connections, etc. Configure's purpose is solely to setup internal state 69 and validate the configuration as much as possible. 70 71 `Configure` being run is not an indication that `PostProcess` will ever run. 72 For example, `packer validate` will run `Configure` to verify the configuration 73 validates, but will never actually run the build. 74 75 ### The "PostProcess" Method 76 77 The `PostProcess` method is where the real work goes. PostProcess is 78 responsible for taking one `packer.Artifact` implementation, and transforming 79 it into another. 80 A `PostProcess` call can be cancelled at any moment. Cancellation is triggered 81 when the done chan of the context struct (`<-ctx.Done()`) unblocks . 82 83 When we say "transform," we don't mean actually modifying the existing 84 `packer.Artifact` value itself. We mean taking the contents of the artifact and 85 creating a new artifact from that. For example, if we were creating a 86 "compress" post-processor that is responsible for compressing files, the 87 transformation would be taking the `Files()` from the original artifact, 88 compressing them, and creating a new artifact with a single file: the 89 compressed archive. 90 91 The result signature of this method is `(Artifact, bool, bool, error)`. Each 92 return value is explained below: 93 94 - `Artifact` - The newly created artifact if no errors occurred. 95 - `bool` - If keep true, the input artifact will forcefully be kept. By default, 96 Packer typically deletes all input artifacts, since the user doesn't 97 generally want intermediary artifacts. However, some post-processors depend 98 on the previous artifact existing. If this is `true`, it forces packer to 99 keep the artifact around. 100 - `bool` - If forceOverride is true, then any user input for 101 keep_input_artifact is ignored and the artifact is either kept or discarded 102 according to the value set in `keep`. 103 - `error` - Non-nil if there was an error in any way. If this is the case, 104 the other two return values are ignored.