github.com/hashicorp/packer@v1.14.3/website/content/docs/post-processors/shell-local.mdx (about)

     1  ---
     2  description: |
     3    The `shell-local` post-processor starts a local shell, letting you automate post-build actions after Packer builds your artifacts.
     4  page_title: shell-local post-processor reference
     5  ---
     6  
     7  <BadgesHeader>
     8    <PluginBadge type="official" />
     9  </BadgesHeader>
    10  
    11  # `shell-local` post-processor
    12  
    13  The `shell-local` post processor executes scripts locally during the post
    14  processing stage. Shell local provides a convenient way to automate executing
    15  some task with packer outputs and variables.
    16  
    17  ## Basic example
    18  
    19  The example below is a fully functional self-contained build.
    20  
    21  <Tabs>
    22  <Tab heading="HCL2">
    23  
    24  ```hcl
    25  source "file" "example" {
    26      content = "example content"
    27  }
    28  
    29  build {
    30    source "source.file.example" {
    31      target = "./test_artifact.txt"
    32    }
    33  
    34    post-processor "shell-local" {
    35      inline = ["echo foo"]
    36    }
    37  }
    38  ```
    39  
    40  </Tab>
    41  <Tab heading="JSON">
    42  
    43  ```json
    44  {
    45    "builders": [
    46      {
    47        "type": "file",
    48        "name": "example",
    49        "target": "./test_artifact.txt",
    50        "content": "example content"
    51      }
    52    ],
    53    "post-processors": [
    54      {
    55        "type": "shell-local",
    56        "inline": ["echo foo"]
    57      }
    58    ]
    59  }
    60  ```
    61  
    62  </Tab>
    63  </Tabs>
    64  
    65  ## Configuration Reference
    66  
    67  The reference of available configuration options is listed below. The only
    68  required element is either "inline" or "script". Every other option is
    69  optional.
    70  
    71  Exactly _one_ of the following is required:
    72  
    73  - `command` (string) - This is a single command to execute. It will be
    74    written to a temporary file and run using the `execute_command` call below.
    75  
    76  - `inline` (array of strings) - This is an array of commands to execute. The
    77    commands are concatenated by newlines and turned into a single file, so
    78    they are all executed within the same context. This allows you to change
    79    directories in one command and use something in the directory in the next
    80    and so on. Inline scripts are the easiest way to pull off simple tasks
    81    within the machine.
    82  
    83  - `script` (string) - The path to a script to execute. This path can be
    84    absolute or relative. If it is relative, it is relative to the working
    85    directory when Packer is executed.
    86  
    87  - `scripts` (array of strings) - An array of scripts to execute. The scripts
    88    will be executed in the order specified. Each script is executed in
    89    isolation, so state such as variables from one script won't carry on to the
    90    next.
    91  
    92  Optional parameters:
    93  
    94  - `env` (map of strings) - A map of key/value pairs to inject prior to the
    95    execute_command. Packer injects some environmental variables by default into
    96    the environment, as well, which are covered in the section below. Duplicate
    97    `env` settings override `environment_vars` settings.
    98  
    99  - `environment_vars` (array of strings) - An array of key/value pairs to
   100    inject prior to the `execute_command`. The format should be `key=value`.
   101    Packer injects some environmental variables by default into the
   102    environment, as well, which are covered in the section below.
   103  
   104  - `env_var_format` (string) - When we parse the environment_vars that you
   105    provide, this gives us a string template to use in order to make sure that
   106    we are setting the environment vars correctly. By default on Windows hosts
   107    this format is `set %s=%s &&` and on Unix, it is `%s='%s'`. You probably
   108    won't need to change this format, but you can see usage examples for where
   109    it is necessary below.
   110  
   111  - `execute_command` (array of strings) - The command used to execute the
   112    script. By default, on \*nix systems this is:
   113  
   114    ```text
   115    ["/bin/sh", "-c", "{{.Vars}} {{.Script}}"]
   116    ```
   117  
   118    While on Windows, `execute_command` defaults to:
   119  
   120    ```text
   121    ["cmd", "/V", "/C", "{{.Vars}}", "call", "{{.Script}}"]
   122    ```
   123  
   124    This is treated as a [template engine](/packer/docs/templates/legacy_json_templates/engine).
   125    There are several available variables: `Script`, which is the path to the
   126    script to run, and `Vars`, which is the list of `environment_vars`, if
   127    configured. In addition, you may access any of the variables stored in the
   128    generated data using the [build](/packer/docs/templates/legacy_json_templates/engine) template
   129    function. If you choose to set this option, make sure that the first
   130    element in the array is the shell program you want to use (for example,
   131    "sh" or "/usr/local/bin/zsh" or even "powershell.exe" although anything
   132    other than a flavor of the shell command language is not explicitly
   133    supported and may be broken by assumptions made within Packer). It's
   134    worth noting that if you choose to try to use shell-local for
   135    Powershell or other Windows commands, the environment variables will
   136    not be set properly for your environment.
   137  
   138    For backwards compatibility, `execute_command` will accept a string instead
   139    of an array of strings. If a single string or an array of strings with only
   140    one element is provided, Packer will replicate past behavior by appending
   141    your `execute_command` to the array of strings `["sh", "-c"]`. For example,
   142    if you set `"execute_command": "foo bar"`, the final `execute_command` that
   143    Packer runs will be \["sh", "-c", "foo bar"\]. If you set
   144    `"execute_command": ["foo", "bar"]`, the final execute_command will remain
   145    `["foo", "bar"]`.
   146  
   147    Again, the above is only provided as a backwards compatibility fix; we
   148    strongly recommend that you set execute_command as an array of strings.
   149  
   150  - `inline_shebang` (string) - The
   151    [shebang](http://en.wikipedia.org/wiki/Shebang_%28Unix%29) value to use
   152    when running commands specified by `inline`. By default, this is
   153    `/bin/sh -e`. If you're not using `inline`, then this configuration has no
   154    effect. **Important:** If you customize this, be sure to include something
   155    like the `-e` flag, otherwise individual steps failing won't fail the
   156    provisioner.
   157  
   158  - `keep_input_artifact` (boolean) - Unlike most other post-processors, the
   159    keep_input_artifact option will have no effect for the shell-local
   160    post-processor. Packer will always retain the input artifact for
   161    shell-local, since the shell-local post-processor merely passes forward the
   162    artifact it receives. If your shell-local post-processor produces a file or
   163    files which you would like to have replace the input artifact, you may
   164    overwrite the input artifact using the [artifice](/packer/docs/post-processors/artifice)
   165    post-processor after your shell-local processor has run.
   166  
   167  - `only_on` (array of strings) - This is an array of [runtime operating
   168    systems](https://go.dev/doc/install/source#environment) where
   169    `shell-local` will execute. This allows you to execute `shell-local` _only_
   170    on specific operating systems. By default, shell-local will always run if
   171    `only_on` is not set."
   172  
   173  - `use_linux_pathing` (bool) - This is only relevant to Windows hosts. If you
   174    are running Packer in a Windows environment with the Windows Subsystem for
   175    Linux feature enabled, and would like to invoke a bash script rather than
   176    invoking a Cmd script, you'll need to set this flag to true; it tells
   177    Packer to use the Linux subsystem path for your script rather than the
   178    Windows path. (e.g. /mnt/c/path/to/your/file instead of
   179    C:/path/to/your/file). Please see the example below for more guidance on
   180    how to use this feature. If you are not on a Windows host, or you do not
   181    intend to use the shell-local post-processor to run a bash script, please
   182    ignore this option. If you set this flag to true, you still need to provide
   183    the standard Windows path to the script when providing a `script`. This is
   184    a beta feature.
   185  
   186  - `valid_exit_codes` (list of ints) - Valid exit codes for the script. By
   187    default this is `0`.
   188  
   189  ## Execute Command
   190  
   191  To many new users, the `execute_command` is puzzling. However, it provides an
   192  important function: customization of how the command is executed. The most
   193  common use case for this is dealing with **sudo password prompts**. You may
   194  also need to customize this if you use a non-POSIX shell, such as `tcsh` on
   195  FreeBSD.
   196  
   197  ### The Windows Linux Subsystem
   198  
   199  The shell-local post-processor was designed with the idea of allowing you to
   200  run commands in your local operating system's native shell. For Windows, we've
   201  assumed in our defaults that this is Cmd. However, it is possible to run a bash
   202  script as part of the Windows Linux Subsystem from the shell-local
   203  post-processor, by modifying the `execute_command` and the `use_linux_pathing`
   204  options in the post-processor config.
   205  
   206  The example below is a fully functional test config.
   207  
   208  One limitation of this offering is that "inline" and "command" options are not
   209  available to you; please limit yourself to using the "script" or "scripts"
   210  options instead.
   211  
   212  Please note that this feature is still in beta, as the underlying WSL is also
   213  still in beta. There will be some limitations as a result. For example, it will
   214  likely not work unless both Packer and the scripts you want to run are both on
   215  the C drive.
   216  
   217  <Tabs>
   218  <Tab heading="HCL2">
   219  
   220  ```hcl
   221  source "null" "example" {
   222      communicator = "none"
   223  }
   224  
   225  build {
   226      sources = [
   227          "source.null.example"
   228      ]
   229  
   230      post-processor "shell-local"{
   231          environment_vars  = ["PROVISIONERTEST=ProvisionerTest1"]
   232          execute_command   = ["bash", "-c", "{{.Vars}} {{.Script}}"]
   233          use_linux_pathing = true
   234          scripts           = ["C:/Users/me/scripts/example_bash.sh"]
   235      }
   236      post-processor "shell-local"{
   237          environment_vars  = ["PROVISIONERTEST=ProvisionerTest2"]
   238          execute_command   = ["bash", "-c", "{{.Vars}} {{.Script}}"]
   239          use_linux_pathing = true
   240          script            = "C:/Users/me/scripts/example_bash.sh"
   241      }
   242  }
   243  ```
   244  
   245  </Tab>
   246  <Tab heading="JSON">
   247  
   248  ```json
   249  {
   250    "builders": [
   251      {
   252        "type": "null",
   253        "communicator": "none"
   254      }
   255    ],
   256    "post-processors": [
   257      {
   258        "type": "shell-local",
   259        "environment_vars": ["PROVISIONERTEST=ProvisionerTest1"],
   260        "execute_command": ["bash", "-c", "{{.Vars}} {{.Script}}"],
   261        "use_linux_pathing": true,
   262        "scripts": ["C:/Users/me/scripts/example_bash.sh"]
   263      },
   264      {
   265        "type": "shell-local",
   266        "environment_vars": ["PROVISIONERTEST=ProvisionerTest2"],
   267        "execute_command": ["bash", "-c", "{{.Vars}} {{.Script}}"],
   268        "use_linux_pathing": true,
   269        "script": "C:/Users/me/scripts/example_bash.sh"
   270      }
   271    ]
   272  }
   273  ```
   274  
   275  </Tab>
   276  </Tabs>
   277  
   278  ## Default Environmental Variables
   279  
   280  In addition to being able to specify custom environmental variables using the
   281  `environment_vars` configuration, the provisioner automatically defines certain
   282  commonly useful environmental variables:
   283  
   284  - `PACKER_BUILD_NAME` is set to the [name of the
   285    build](/packer/docs/templates/legacy_json_templates/builders#named-builds) that Packer is running.
   286    This is most useful when Packer is making multiple builds and you want to
   287    distinguish them slightly from a common provisioning script.
   288  
   289  - `PACKER_BUILDER_TYPE` is the type of the builder that was used to create
   290    the machine that the script is running on. This is useful if you want to
   291    run only certain parts of the script on systems built with certain
   292    builders.
   293  
   294  ## Safely Writing A Script
   295  
   296  Whether you use the `inline` option, or pass it a direct `script` or `scripts`,
   297  it is important to understand a few things about how the shell-local
   298  post-processor works to run it safely and easily. This understanding will save
   299  you much time in the process.
   300  
   301  ### Once Per Builder
   302  
   303  The `shell-local` script(s) you pass are run once per builder. This means that
   304  if you have an `amazon-ebs` builder and a `docker` builder, your script will be
   305  run twice. If you have 3 builders, it will run 3 times, once for each builder.
   306  
   307  ### Interacting with Build Artifacts
   308  
   309  In order to interact with build artifacts, you may want to use the [manifest
   310  post-processor](/packer/docs/post-processors/manifest). This will write the list
   311  of files produced by a `builder` to a json file after each `builder` is run.
   312  
   313  For example, if you wanted to package a file from the file builder into a
   314  tarball, you might write this:
   315  
   316  <Tabs>
   317  <Tab heading="JSON">
   318  
   319  ```json
   320  {
   321    "builders": [
   322      {
   323        "content": "Lorem ipsum dolor sit amet",
   324        "target": "dummy_artifact",
   325        "type": "file"
   326      }
   327    ],
   328    "post-processors": [
   329      [
   330        {
   331          "output": "manifest.json",
   332          "strip_path": true,
   333          "type": "manifest"
   334        },
   335        {
   336          "inline": [
   337            "jq \".builds[].files[].name\" manifest.json | xargs tar cfz artifacts.tgz"
   338          ],
   339          "type": "shell-local"
   340        }
   341      ]
   342    ]
   343  }
   344  ```
   345  
   346  </Tab>
   347  <Tab heading="HCL2">
   348  
   349  ```hcl
   350  source "file" "example" {
   351      content = "Lorem ipsum dolor sit amet"
   352      target  = "dummy_artifact.txt"
   353  }
   354  build {
   355    sources = [
   356      "source.file.example"
   357    ]
   358    post-processor "manifest" {
   359      output     = "manifest.json"
   360      strip_path = true
   361    }
   362  
   363    post-processor "shell-local" {
   364      inline = [
   365          "jq \".builds[].files[].name\" manifest.json | xargs tar cfz artifacts.tgz"
   366      ]
   367    }
   368  }
   369  ```
   370  
   371  </Tab>
   372  </Tabs>
   373  
   374  This uses the [jq](https://stedolan.github.io/jq/) tool to extract all of the
   375  file names from the manifest file and passes them to tar.
   376  
   377  ### Always Exit Intentionally
   378  
   379  If any post-processor fails, the `packer build` stops and all interim artifacts
   380  are cleaned up.
   381  
   382  For a shell script, that means the script **must** exit with a zero code. You
   383  _must_ be extra careful to `exit 0` when necessary.
   384  
   385  ## Usage Examples:
   386  
   387  ### Windows Host
   388  
   389  Example of running a .cmd file on Windows:
   390  
   391  <Tabs>
   392  <Tab heading="HCL2">
   393  
   394  ```hcl
   395  post-processor "shell-local" {
   396    environment_vars = ["SHELLLOCALTEST=ShellTest1"]
   397    scripts          = ["./scripts/test_cmd.cmd"]
   398  }
   399  ```
   400  
   401  </Tab>
   402  <Tab heading="JSON">
   403  
   404  ```json
   405  {
   406    "type": "shell-local",
   407    "environment_vars": ["SHELLLOCALTEST=ShellTest1"],
   408    "scripts": ["./scripts/test_cmd.cmd"]
   409  }
   410  ```
   411  
   412  </Tab>
   413  </Tabs>
   414  
   415  Contents of `test_cmd.cmd`:
   416  
   417      echo %SHELLLOCALTEST%
   418  
   419  Example of running an inline command on Windows: Required customization:
   420  tempfile_extension
   421  
   422  <Tabs>
   423  <Tab heading="HCL2">
   424  
   425  ```hcl
   426  post-processor "shell-local" {
   427    environment_vars   = ["SHELLLOCALTEST=ShellTest2"],
   428    tempfile_extension = ".cmd",
   429    inline             = ["echo %SHELLLOCALTEST%"]
   430  }
   431  ```
   432  
   433  </Tab>
   434  <Tab heading="JSON">
   435  
   436  ```json
   437  {
   438    "type": "shell-local",
   439    "environment_vars": ["SHELLLOCALTEST=ShellTest2"],
   440    "tempfile_extension": ".cmd",
   441    "inline": ["echo %SHELLLOCALTEST%"]
   442  }
   443  ```
   444  
   445  </Tab>
   446  </Tabs>
   447  
   448  Example of running a bash command on Windows using WSL: Required
   449  customizations: `use_linux_pathing` and `execute_command`:
   450  
   451  <Tabs>
   452  <Tab heading="HCL2">
   453  
   454  ```hcl
   455  post-processor "shell-local" {
   456    environment_vars  = ["SHELLLOCALTEST=ShellTest3"],
   457    execute_command   = ["bash", "-c", "{{.Vars}} {{.Script}}"]
   458    use_linux_pathing = true
   459    script            = "./scripts/example_bash.sh"
   460  }
   461  ```
   462  
   463  </Tab>
   464  <Tab heading="JSON">
   465  
   466  ```json
   467  {
   468    "type": "shell-local",
   469    "environment_vars": ["SHELLLOCALTEST=ShellTest3"],
   470    "execute_command": ["bash", "-c", "{{.Vars}} {{.Script}}"],
   471    "use_linux_pathing": true,
   472    "script": "./scripts/example_bash.sh"
   473  }
   474  ```
   475  
   476  </Tab>
   477  </Tabs>
   478  
   479  Contents of `example_bash.sh`:
   480  
   481      #!/bin/bash
   482      echo $SHELLLOCALTEST
   483  
   484  Example of running a PowerShell script on Windows:
   485  Required customizations: `env_var_format` and `execute_command`.
   486  
   487  <Tabs>
   488  <Tab heading="HCL2">
   489  
   490  ```hcl
   491  post-processor "shell-local" {
   492    environment_vars = ["SHELLLOCALTEST=ShellTest4"]
   493    execute_command  = ["powershell.exe", "{{.Vars}} {{.Script}}"]
   494    env_var_format   = "$env:%s=\"%s\"; "
   495    script           = "./scripts/example_ps.ps1"
   496  }
   497  ```
   498  
   499  </Tab>
   500  <Tab heading="JSON">
   501  
   502  ```json
   503  {
   504    "type": "shell-local",
   505    "environment_vars": ["SHELLLOCALTEST=ShellTest4"],
   506    "execute_command": ["powershell.exe", "{{.Vars}} {{.Script}}"],
   507    "env_var_format": "$env:%s=\"%s\"; ",
   508    "script": "./scripts/example_ps.ps1"
   509  }
   510  ```
   511  
   512  </Tab>
   513  </Tabs>
   514  
   515  Example of running a PowerShell script on Windows as "inline": Required
   516  customizations: `env_var_format`, `tempfile_extension`, and `execute_command`
   517  
   518  <Tabs>
   519  <Tab heading="HCL2">
   520  
   521  ```hcl
   522  post-processor "shell-local" {
   523    tempfile_extension = ".ps1"
   524    environment_vars   = ["SHELLLOCALTEST=ShellTest5"]
   525    execute_command    = ["powershell.exe", "{{.Vars}} {{.Script}}"]
   526    env_var_format     = "$env:%s=\"%s\"; "
   527    inline             = ["write-output $env:SHELLLOCALTEST"]
   528  }
   529  ```
   530  
   531  </Tab>
   532  <Tab heading="JSON">
   533  
   534  ```json
   535  {
   536    "type": "shell-local",
   537    "tempfile_extension": ".ps1",
   538    "environment_vars": ["SHELLLOCALTEST=ShellTest5"],
   539    "execute_command": ["powershell.exe", "{{.Vars}} {{.Script}}"],
   540    "env_var_format": "$env:%s=\"%s\"; ",
   541    "inline": ["write-output $env:SHELLLOCALTEST"]
   542  }
   543  ```
   544  
   545  </Tab>
   546  </Tabs>
   547  
   548  ### Unix Host
   549  
   550  Example of running a Shell script on Unix:
   551  
   552  <Tabs>
   553  <Tab heading="HCL2">
   554  
   555  ```hcl
   556  post-processor "shell-local" {
   557    environment_vars = ["PROVISIONERTEST=ProvisionerTest1"]
   558    scripts = ["./scripts/example_bash.sh"]
   559  }
   560  ```
   561  
   562  </Tab>
   563  <Tab heading="JSON">
   564  
   565  ```json
   566  {
   567    "type": "shell-local",
   568    "environment_vars": ["PROVISIONERTEST=ProvisionerTest1"],
   569    "scripts": ["./scripts/example_bash.sh"]
   570  }
   571  ```
   572  
   573  </Tab>
   574  </Tabs>
   575  
   576  Example of running a bash "inline" on Unix:
   577  
   578  <Tabs>
   579  <Tab heading="HCL2">
   580  
   581  ```hcl
   582  post-processor "shell-local" {
   583    environment_vars = ["PROVISIONERTEST=ProvisionerTest2"]
   584    inline           = ["echo hello", "echo $PROVISIONERTEST"]
   585  }
   586  
   587  ```
   588  
   589  </Tab>
   590  <Tab heading="JSON">
   591  
   592  ```json
   593  {
   594    "type": "shell-local",
   595    "environment_vars": ["PROVISIONERTEST=ProvisionerTest2"],
   596    "inline": ["echo hello", "echo $PROVISIONERTEST"]
   597  }
   598  ```
   599  
   600  </Tab>
   601  </Tabs>
   602  
   603  Example of running a Python script on Unix:
   604  
   605  <Tabs>
   606  <Tab heading="HCL2">
   607  
   608  ```hcl
   609  post-processor "shell-local" {
   610    script           = "hello.py"
   611    environment_vars = ["HELLO_USER=packeruser"]
   612    execute_command  = [
   613      "/bin/sh",
   614      "-c",
   615      "{{.Vars}} /usr/local/bin/python {{.Script}}"
   616    ]
   617  }
   618  
   619  ```
   620  
   621  </Tab>
   622  <Tab heading="JSON">
   623  
   624  ```json
   625  {
   626    "type": "shell-local",
   627    "script": "hello.py",
   628    "environment_vars": ["HELLO_USER=packeruser"],
   629    "execute_command": [
   630      "/bin/sh",
   631      "-c",
   632      "{{.Vars}} /usr/local/bin/python {{.Script}}"
   633    ]
   634  }
   635  ```
   636  
   637  </Tab>
   638  </Tabs>
   639  
   640  ```text
   641  Where "hello.py" contains:
   642  
   643      import os
   644  
   645      print('Hello, %s!' % os.getenv("HELLO_USER"))
   646  ```