packer.py icon indicating copy to clipboard operation
packer.py copied to clipboard

use python to run hashicorp packer cli commands

============== packer.py

.. image:: https://img.shields.io/pypi/v/packer.py.svg :target: https://pypi.python.org/pypi/packer.py

.. image:: https://travis-ci.org/mayn/packer.py.svg?branch=master :target: https://travis-ci.org/mayn/packer.py

.. image:: https://ci.appveyor.com/api/projects/status/n1627wlm52q12db8/branch/master?svg=true :target: https://ci.appveyor.com/project/mayn/packer-py

.. image:: https://coveralls.io/repos/github/mayn/packer.py/badge.svg?branch=master :target: https://coveralls.io/github/mayn/packer.py

About

packer.py - python library for interacting with hashicorp packer_ CLI executable.

Project follows semantic versioning_ , v0.x.x API should be considered unstable, API will change frequently, please plan accordingly.

Installation

packer.py can be installed via pip:

.. code:: sh

$ pip install packer.py

Configuration

Packer Executable


Specify Packer Location ^^^^^^^^^^^^^^^^^^^^^^^ Access to hashicorp packer_ executable is needed in order to use packer.py_. When generating commands, if no location is specified, the following defaults are used.

:\*nix: /usr/local/packer
:macOS: /usr/local/packer
:windows: packer.exe

These defaults can be overridden by explicitly setting the location of packer for your environment.

.. code:: python

PackerExecutable(executable_path="/usr/local/bin/packer")

or

.. code:: python

PackerExecutable("/usr/local/bin/packer")

Machine Readable Output ^^^^^^^^^^^^^^^^^^^^^^^ Commands are executed with packer's machine readable format_ enabled by default. This can be disabled by setting

.. code:: python

PackerExecutable(machine_readable=False)

Running Commands

The following commands are currently supported:

  • build
  • inspect
  • validate
  • version

Below is the packer.py equivalent of running these packer CLI commands_

Configuration


Templates ^^^^^^^^^ Templates are specified by passing their filepath to the command.

.. code:: python

template = 'tests/templates/test_template1.json'
PackerExecutable().validate(template)

Templates can also be specified as a string literal.

.. code:: python

template = """
{
    "variables": {
        "my_var1": "{{env `key1`}}"
    },
    "builders": [
        {
            "type": "file",
            "content": "Lorem ipsum dolor sit amet {{user `my_var1`}} ",
            "target": "/tmp/packer.test"
        }
    ]
}
"""
PackerExecutable().validate(template)

packerlicious_ templates can also be used and combined with packer.py.

.. code:: python

from packerlicious import builder, Template, EnvVar
from packerpy import PackerExecutable
var1 = EnvVar("my_var1")
var2 = EnvVar("my_var2")
file_builder = builder.File()
file_builder = builder.File(content="{} more words {}".format(var2.ref().data, var1.ref().data),
                            target="/tmp/packer.test"
                            )
template = Template()
template.add_variable([var1, var2])
template.add_builder(file_builder)
p = PackerExecutable("/usr/local/bin/packer")
template_vars = {'my_var1': 'my_val1', 'my_var2': 'my_val2'}
p.build(template.to_json(),
        var=template_vars
        )

Command Arguments ^^^^^^^^^^^^^^^^^^ packer CLI commands_ arguments can be specified by passing them as packer.py method arguments.

$ packer validate -syntax-only -var "key1=my_value" tests/templates/test_template1.json

.. code:: python

p = PackerExecutable("/usr/local/bin/packer")
template = 'tests/templates/test_template1.json'
p.validate(template,
           syntax_only=True,
           var="key1=my_value"
           )

The following rules are used by packer.py when converting to packer CLI commands.

Dashes in Packer Command Option Names +++++++++++++++++++++++++++++++++++++ If the packer command option has a dash in it, pass it to packer.py with an underscore.

:-on-error=cleanup: on_error='cleanup'

Boolean Values and Implicit Value Command Options +++++++++++++++++++++++++++++++++++++++++++++++++ If the packer command option is either a boolean option or an option with an implicit value, pass it to packer.py as a boolean.

:-color=false: color=False :-force: force=True

Repeating Command Options +++++++++++++++++++++++++++

If the packer command options can be specified multiple times, pass the value as a dictionary to packer.py. Multiple -var option is an example of this.

$   packer build -var 'my_var1=my_val1' -var 'my_var2=my_val2' tests/templates/test_template1.json

.. code:: python

from packerpy import PackerExecutable
p = PackerExecutable("/usr/local/bin/packer")
template = 'tests/templates/test_template1.json'
template_vars = { 'my_var1': 'my_val1', 'my_var2': 'my_val2' }
p.build(template,
           var=template_vars
           )

Build


$   packer build template.json

.. code:: python

>>> from packerpy import PackerExecutable
>>> p = PackerExecutable("/usr/local/bin/packer")
>>> (ret, out, err) = p.build('tests/templates/test_template1.json')
>>> ret==0
True
>>> print(ret)
0
>>> print(out)
b"1552841678,,ui,say,Build 'file' finished.\n1552841678,,ui,say,\\n==> Builds finished. The artifacts of successful builds are:\n1552841678,file,artifact-count,1\n1552841678,file,artifact,0,builder-id,packer.file\n1552841678,file,artifact,0,id,File\n1552841678,file,artifact,0,string,Stored file: /tmp/packer.test \n1552841678,file,artifact,0,files-count,1\n1552841678,file,artifact,0,file,0,/tmp/packer.test \n1552841678,file,artifact,0,end\n1552841678,,ui,say,--> file: Stored file: /tmp/packer.test \n"
>>> print(err)
b''

Example of a failed build.

.. code:: python

>>> from packerpy import PackerExecutable
>>> p = PackerExecutable("/usr/local/bin/packer")
>>> bad_template = """{
...     "builders": [
...         {
...             "type": "amazon-ebs",
...             "access_key": "..."
...         }
...     ]
... }
... """
>>> (ret, out, err) = p.build(bad_template)
>>> ret==0
False
>>> print(ret)
1
>>> print(out)
b'1552841800,,ui,error,5 error(s) occurred:\\n\\n* ami_name must be specified\\n* ami_name must be between 3 and 128 characters long\\n* An ssh_username must be specified\\n  Note: some builders used to default ssh_username to "root".\\n* A source_ami or source_ami_filter must be specified\\n* An instance_type must be specified\n'
>>> print(err)
b''

Inspect


$   packer inspect template.json

.. code:: python

>>> from packerpy import PackerExecutable
>>> p = PackerExecutable("/usr/local/bin/packer")
>>> (ret, out, err) = p.inspect('tests/templates/test_template1.json')
>>> ret==0
True
>>> print(ret)
0
>>> print(out)
b"1552841499,,ui,say,Optional variables and their defaults:\\n\n1552841499,,template-variable,my_var1,{{env `key1`}},0\n1552841499,,ui,say,  my_var1 = {{env `key1`}}\n1552841499,,ui,say,\n1552841499,,ui,say,Builders:\\n\n1552841499,,template-builder,file,file\n1552841499,,ui,say,  file\n1552841499,,ui,say,\n1552841499,,ui,say,Provisioners:\\n\n1552841499,,ui,say,  <No provisioners>\n1552841499,,ui,say,\\nNote: If your build names contain user variables or template\\nfunctions such as 'timestamp'%!(PACKER_COMMA) these are processed at build time%!(PACKER_COMMA)\\nand therefore only show in their raw form here.\n"
>>> print(err)
b''

Validate


$   packer validate template.json

.. code:: python

>>> from packerpy import PackerExecutable
>>> p = PackerExecutable("/usr/local/bin/packer")
>>> (ret, out, err) = p.validate('tests/templates/test_template1.json')
>>> ret==0
True
>>> print(ret)
0
>>> print(out)
b'1552840497,,ui,say,Template validated successfully.\n'
>>> print(err)
b''

Example of a template which failed to validation.

.. code:: python

>>> from packerpy import PackerExecutable
>>> p = PackerExecutable("/usr/local/bin/packer")
>>> bad_template = """{
...     "builders": [
...         {
...             "type": "amazon-ebs",
...             "access_key": "..."
...         }
...     ]
... }
... """
>>> (ret, out, err) = p.validate(bad_template)
>>> ret==0
False
>>> print(ret)
1
>>> print(out)
b'1552840892,,ui,error,Template validation failed. Errors are shown below.\\n\n1552840892,,ui,error,Errors validating build \'amazon-ebs\'. 5 error(s) occurred:\\n\\n* ami_name must be specified\\n* ami_name must be between 3 and 128 characters long\\n* An ssh_username must be specified\\n  Note: some builders used to default ssh_username to "root".\\n* A source_ami or source_ami_filter must be specified\\n* An instance_type must be specified\n'
>>> print(err)
b''

Version


$   packer version

.. code:: python

>>> from packerpy import PackerExecutable
>>> p = PackerExecutable("/usr/local/bin/packer")
>>> (ret, out, err) = p.version()
>>> ret==0
True
>>> print(ret)
0
>>> print(out)
b'1552840138,,version,1.0.3\n1552840138,,version-prelease,\n1552840138,,version-commit,c0ddb4a+CHANGES\n1552840138,,ui,say,Packer v1.0.3\n1552840138,,ui,say,\\nYour version of Packer is out of date! The latest version\\nis 1.3.5. You can update by downloading from www.packer.io\n'
>>> print(err)
b''

Licensing

packer.py is licensed under the Apache license 2.0. See LICENSE for the full license text.

.. _packer: https://www.packer.io/ .. _packer.py: https://github.com/mayn/packer.py .. _packerlicious: https://github.com/mayn/packerlicious .. _machine readable format: https://www.packer.io/docs/commands/index.html#machine-readable-output .. _packer CLI commands: https://www.packer.io/docs/commands/index.html .. _LICENSE: https://github.com/mayn/packer.py/blob/master/LICENSE .. _Apache license 2.0: https://opensource.org/licenses/Apache-2.0 .. _BSD 2-Clause license: http://opensource.org/licenses/BSD-2-Clause .. _semantic versioning: http://semver.org/