diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9061a982179526101b373e5b68583bebb8471e4e..bc2bc321e523d1f946ef2a3f66d62453b3d7920a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -21,7 +21,7 @@ pre-commit-try-repo: /etc/apt/sources.list.d/hashicorp.list # yamllint enable rule:line-length - apt-get update - - apt-get install -y terraform + - apt-get install -y terraform packer script: - pre-commit try-repo --all-files ./ cache: diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml index 8deb7d41f449f6ab82acfcbaa4a5de90aeede148..6b2ad4edac3db51ae99e06b4b010599c1f6fa744 100644 --- a/.pre-commit-hooks.yaml +++ b/.pre-commit-hooks.yaml @@ -37,6 +37,27 @@ types: [terraform] entry: terraform-validate +- id: packer-fix + name: Fix Packer templates + description: Fix known backwards incompatibilities in Packer templates + language: python + entry: packer-fix + types: [json, hcl] + +- id: packer-fmt + name: Format Packer templates + description: Rewrites all Packer configuration files to a canonical format + language: python + entry: packer-fmt + types: [hcl] + +- id: packer-validate + name: Validate Packer templates + description: Checks that the Packer template is valid + language: python + entry: packer-validate + types: [json, hcl] + - id: poetry-check name: poetry check description: Validate pyproject.toml files using Poetry diff --git a/README.md b/README.md index 0cf0a2e8a2409034a2bbc44ab112a20acd77aa05..143df4f5e8bbb29c123ce25cd0830480c2982c43 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,9 @@ A collection of [pre-commit](https://pre-commit.com/) hooks. - id: docker-compose - id: terraform-fmt - id: terraform-validate + - id: packer-fmt + - id: packer-fix + - id: packer-validate - id: poetry-check - id: branch-merge-conflict ``` @@ -50,6 +53,18 @@ Requires an installed `terraform`. Validate Terraform modules using `terraform validate`. Requires an installed `terraform`. +### `packer-fix` + +Fix known backwards incompatibilities in Packer templates. + +### `packer-fmt` + +Rewrites all Packer configuration files to a canonical format (just HCL files). + +### `packer-validate` + +Checks that the Packer template is valid. + ### `poetry-check` Validate `pyproject.toml` files using Poetry. diff --git a/hooks/packer_fix.py b/hooks/packer_fix.py new file mode 100644 index 0000000000000000000000000000000000000000..c8d8aee53890457df11878ede2006b3aa7cf4963 --- /dev/null +++ b/hooks/packer_fix.py @@ -0,0 +1,38 @@ +"""Fix known backwards incompatibilities in Packer templates.""" + +import argparse +import locale +import pathlib +import sys +import hooks.utils + + +def packer_fix(file): + """Runs packer fix. + + If the invocation succeeds, overwrite the file with the fixed output from + packer. If it fails, fail. + """ + proc = hooks.utils.run(["packer", "fix", file]) + if proc.returncode > 0: + return 1 + # pylint: disable=invalid-name + with open(file, "w", encoding=locale.getpreferredencoding()) as fh: + fh.write(proc.stdout) + return 0 + + +def main(): + """Main entrypoint.""" + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("file", nargs="+", type=pathlib.Path) + args = parser.parse_args() + hooks.utils.check_executable("packer") + return hooks.utils.bulk_check( + packer_fix, + args.file, + ) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/hooks/packer_fmt.py b/hooks/packer_fmt.py new file mode 100644 index 0000000000000000000000000000000000000000..a9e2a214baf99433b59ec5964de4a6817f9d7311 --- /dev/null +++ b/hooks/packer_fmt.py @@ -0,0 +1,22 @@ +"""Rewrites all Packer configuration files to a canonical format.""" + +import argparse +import pathlib +import sys +import hooks.utils + + +def main(): + """Main entrypoint.""" + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("file", nargs="+", type=pathlib.Path) + args = parser.parse_args() + hooks.utils.check_executable("packer") + return hooks.utils.bulk_check( + lambda x: hooks.utils.check_file(["packer", "fmt", "-diff", x]), + args.file, + ) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/hooks/packer_validate.py b/hooks/packer_validate.py new file mode 100644 index 0000000000000000000000000000000000000000..7df19eb0fc6950ca736d0d0bb1a7f1feeba18db2 --- /dev/null +++ b/hooks/packer_validate.py @@ -0,0 +1,22 @@ +"""Checks that the Packer template is valid.""" + +import argparse +import pathlib +import sys +import hooks.utils + + +def main(): + """Main entrypoint.""" + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("file", nargs="+", type=pathlib.Path) + args = parser.parse_args() + hooks.utils.check_executable("packer") + return hooks.utils.bulk_check( + lambda x: hooks.utils.check_file(["packer", "validate", x]), + args.file, + ) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/setup.py b/setup.py index 1b48a0a584e6b66b7a0945e153e48033853d6f7a..de3c388eb1b39210cefc725e71fc002ddc4933e6 100644 --- a/setup.py +++ b/setup.py @@ -19,6 +19,9 @@ setup( "docker-compose-validate=hooks.docker_compose_validate:main", "terraform-validate=hooks.terraform_validate:main", "terraform-fmt=hooks.terraform_fmt:main", + "packer-fix=hooks.packer_fix:main", + "packer-fmt=hooks.packer_fmt:main", + "packer-validate=hooks.packer_validate:main", "poetry-check=hooks.poetry_check:main", ] }, diff --git a/test_files/packer.json b/test_files/packer.json new file mode 100644 index 0000000000000000000000000000000000000000..e26c6e1c5b18fb042ab7546b07d544df09bb5364 --- /dev/null +++ b/test_files/packer.json @@ -0,0 +1,16 @@ +{ + "variables": { + "access_key": "{{env `AWS_ACCESS_KEY_ID`}}", + "secret_key": "{{env `AWS_SECRET_ACCESS_KEY`}}" + }, + "builders": [{ + "type": "amazon-ebs", + "access_key": "{{user `access_key`}}", + "secret_key": "{{user `access_key`}}", + "region": "us-east-1", + "source_ami": "ami-de0d9eb7", + "instance_type": "t1.micro", + "ssh_username": "ubuntu", + "ami_name": "packer-example {{timestamp}}" + }] +} diff --git a/test_files/template.pkr.hcl b/test_files/template.pkr.hcl new file mode 100644 index 0000000000000000000000000000000000000000..06f4a867cafc014ef5006f39a5faaf7006de937c --- /dev/null +++ b/test_files/template.pkr.hcl @@ -0,0 +1,42 @@ + +build { + name = "alpine" + description = <<EOF +This build creates alpine images for versions : +* v3.12 +For the following builders : +* virtualbox-iso +EOF + + // the common fields of the source blocks are defined in the + // source.builder-type.pkr.hcl files, here we only set the fields specific to + // the different versions of ubuntu. + source "source.virtualbox-iso.base-alpine-amd64" { + name = "3.12" + iso_url = local.iso_url_alpine_312 + iso_checksum = "file:${local.iso_checksum_url_alpine_312}" + output_directory = "virtualbox_iso_alpine_312_amd64" + boot_command = local.alpine_312_floppy_boot_command + boot_wait = "10s" + } + + source "source.vsphere-iso.base-alpine-amd64" { + name = "3.12" + vm_name = "alpine-3.12" + iso_url = local.iso_url_alpine_312 + iso_checksum = "file:${local.iso_checksum_url_alpine_312}" + boot_command = local.alpine_312_floppy_boot_command_vsphere + boot_wait = "10s" + } + + source "source.vmware-iso.esxi-base-alpine-amd64" { + name = "3.12-from-esxi" + iso_url = local.iso_url_alpine_312 + iso_checksum = "file:${local.iso_checksum_url_alpine_312}" + boot_command = local.alpine_312_floppy_boot_command_vsphere + } + + provisioner "shell" { + inline = ["echo hi"] + } +}