From 5b49c49652d1f24a8f3efc797fd3ffd0c8c62df7 Mon Sep 17 00:00:00 2001 From: Gregory Shulov Date: Sat, 3 Feb 2024 07:58:17 +0200 Subject: [PATCH] Add Ansible provisioning (optional) for centos 7 --- ansible/playbook.yml | 8 +++++ centos7/README.md | 33 ++++++++++++++++-- centos7/centos7.pkr.hcl | 54 +++++++++++++++++++++++++++-- centos7/http/centos7.ks.pkrtpl.hcl | 19 ++++++++-- scripts/ssh_provisioning_cleanup.sh | 15 ++++++++ 5 files changed, 123 insertions(+), 6 deletions(-) create mode 100644 ansible/playbook.yml create mode 100644 scripts/ssh_provisioning_cleanup.sh diff --git a/ansible/playbook.yml b/ansible/playbook.yml new file mode 100644 index 0000000..cfb6a3d --- /dev/null +++ b/ansible/playbook.yml @@ -0,0 +1,8 @@ +--- +- name: Customize Machine Image + hosts: all + + tasks: + - name: Debug + ansible.builtin.debug: + msg: "Ansible provisiong is enabled!" diff --git a/centos7/README.md b/centos7/README.md index dbb02a0..d871ec9 100644 --- a/centos7/README.md +++ b/centos7/README.md @@ -15,9 +15,38 @@ The Packer template in this directory creates a CentOS 7 AMD64 image for use wit * [MAAS](https://maas.io) 2.3+ * [Curtin](https://launchpad.net/curtin) 18.1-59+ -## Customizing the Image +## Customizing the Image with Kickstart -The deployment image may be customized by modifying http/centos7.ks. See the [CentOS kickstart documentation](https://docs.centos.org/en-US/centos/install-guide/Kickstart2/) for more information. +The deployment image may be customized by modifying http/centos7.ks.pkrtpl.hcl. See the [CentOS kickstart documentation](https://docs.centos.org/en-US/centos/install-guide/Kickstart2/) for more information. + +## Customizing the Image with Ansible (Optional) + +Using Ansible as a provisioner in Packer, alongside modifications to the kickstart file, significantly simplifies the image-building process. +Writing complex configurations directly in the kickstart file, especially within the `%post` section, often leads to issues with escaping sequences and readability. +Inline scripts require careful handling of shell syntax, escape characters, and quotations, which can become cumbersome and error-prone for intricate configurations. +Ansible abstracts these complexities, allowing you to define configurations in a more readable and manageable YAML format. +This approach not only enhances maintainability but also reduces the risk of errors that can occur due to improper escaping or syntax issues in shell scripts. +Additionally, using Ansible as a provisioner allows for the maintenance of a single code base for provisioning across multiple operating systems. +This cross-platform capability simplifies management, reduces duplication of effort, +and ensures consistency in deployments, regardless of the operating system being provisioned. + +To run Ansible provisioner following kickstart installation, perform the follwoing steps: + +1. Make sure ansible is installed on the machine running packer +2. Add your ansible code to `ansible/playbook.yml` +3. Enable both ansible and ssh provisioners: + +```hcl +variable enable_ssh_provisioning { + type = bool + default = true +} + +variable enable_ansible_provisioning { + type = bool + default = true +} +``` ## Building the image using a proxy diff --git a/centos7/centos7.pkr.hcl b/centos7/centos7.pkr.hcl index 2a55748..bd8afa2 100644 --- a/centos7/centos7.pkr.hcl +++ b/centos7/centos7.pkr.hcl @@ -5,6 +5,10 @@ packer { version = "~> 1.0" source = "github.com/hashicorp/qemu" } + ansible = { + version = ">= 1.1.1" + source = "github.com/hashicorp/ansible" + } } } @@ -55,17 +59,43 @@ variable ks_mirror { default = "${env("KS_MIRROR")}" } +variable enable_ssh_provisioning { + type = bool + default = false +} + +variable enable_ansible_provisioning { + type = bool + default = false +} + +variable ssh_username { + type = string + default = "packer" +} + +variable ssh_password { + type = string + default = "packer" +} + +variable ssh_user_cleanup { + type = bool + default = true +} + locals { ks_proxy = var.ks_proxy != "" ? "--proxy=${var.ks_proxy}" : "" ks_os_repos = var.ks_mirror != "" ? "--url=${var.ks_mirror}/os/x86_64" : var.ks_os_repos ks_updates_repos = var.ks_mirror != "" ? "--baseurl=${var.ks_mirror}/updates/x86_64" : var.ks_updates_repos ks_extras_repos = var.ks_mirror != "" ? "--baseurl=${var.ks_mirror}/extras/x86_64" : var.ks_extras_repos + communicator = var.enable_ssh_provisioning == true ? "ssh" : "none" } source "qemu" "centos7" { boot_command = [" ", "inst.ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/centos7.ks ", "console=ttyS0 inst.cmdline", ""] boot_wait = "3s" - communicator = "none" + communicator = local.communicator disk_size = "4G" headless = true iso_checksum = "file:${var.centos7_sha256sum_url}" @@ -73,6 +103,9 @@ source "qemu" "centos7" { memory = 2048 qemuargs = [["-serial", "stdio"]] shutdown_timeout = "1h" + ssh_username = var.enable_ssh_provisioning == true ? var.ssh_username : null + ssh_password = var.enable_ssh_provisioning == true ? var.ssh_password : null + ssh_timeout = "30m" http_content = { "/centos7.ks" = templatefile("${path.root}/http/centos7.ks.pkrtpl.hcl", { @@ -80,15 +113,32 @@ source "qemu" "centos7" { KS_OS_REPOS = local.ks_os_repos, KS_UPDATES_REPOS = local.ks_updates_repos, KS_EXTRAS_REPOS = local.ks_extras_repos + SSH_USERNAME = var.ssh_username + SSH_PASSWORD = var.ssh_password + communicator = local.communicator } ) } - } build { sources = ["source.qemu.centos7"] + provisioner "ansible" { + playbook_file = "../ansible/playbook.yml" + skip_version_check = true + only = var.enable_ansible_provisioning == true ? ["qemu.centos7"] : [""] + } + + provisioner "shell" { + script = "../scripts/ssh_provisioning_cleanup.sh" + environment_vars = [ + "SSH_USERNAME=${var.ssh_username}", + "SSH_USER_CLEANUP=${var.ssh_user_cleanup}", + ] + only = var.enable_ssh_provisioning == true ? ["qemu.centos7"] : [""] + } + post-processor "shell-local" { inline = [ "SOURCE=${source.name}", diff --git a/centos7/http/centos7.ks.pkrtpl.hcl b/centos7/http/centos7.ks.pkrtpl.hcl index d6631f0..b421996 100644 --- a/centos7/http/centos7.ks.pkrtpl.hcl +++ b/centos7/http/centos7.ks.pkrtpl.hcl @@ -1,5 +1,4 @@ url ${KS_OS_REPOS} ${KS_PROXY} -poweroff firewall --enabled --service=ssh firstboot --disable ignoredisk --only-use=vda @@ -19,11 +18,22 @@ zerombr clearpart --all --initlabel part / --size=1 --grow --asprimary --fstype=ext4 +%{ if communicator == "none" } +poweroff +%{ else } +# Add a provisioner user +user --name='${SSH_USERNAME}' --groups=wheel --password='${SSH_PASSWORD}' --plaintext + +# Reboot the system for provisioning +reboot +%{ endif } + %post --erroronfail # workaround anaconda requirements and clear root password passwd -d root passwd -l root +%{ if communicator == "none" } # Clean up install config not applicable to deployed environments. for f in resolv.conf fstab; do rm -f /etc/$f @@ -31,8 +41,13 @@ for f in resolv.conf fstab; do chown root:root /etc/$f chmod 644 /etc/$f done - rm -f /etc/sysconfig/network-scripts/ifcfg-[^lo]* +%{ else } +# Passwordless sudo for provisioner user +echo "${SSH_USERNAME} ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/${SSH_PASSWORD} +chmod 440 /etc/sudoers.d/${SSH_USERNAME} + +%{ endif } # Kickstart copies install boot options. Serial is turned on for logging with # Packer which disables console output. Disable it so console output is shown diff --git a/scripts/ssh_provisioning_cleanup.sh b/scripts/ssh_provisioning_cleanup.sh new file mode 100644 index 0000000..0d95a9f --- /dev/null +++ b/scripts/ssh_provisioning_cleanup.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# Clean up install config not applicable to deployed environments. +for f in resolv.conf fstab; do + sudo rm -f /etc/$f + sudo touch /etc/$f + sudo chown root:root /etc/$f + sudo chmod 644 /etc/$f +done + +sudo rm -f /etc/sysconfig/network-scripts/ifcfg-[^lo]* + +if [ "$SSH_USER_CLEANUP" = "true" ]; then + sudo userdel -r $SSH_USERNAME +fi