Skip to content

Commit

Permalink
Add Ansible provisioning (optional) for centos 7
Browse files Browse the repository at this point in the history
  • Loading branch information
GR360RY committed Feb 7, 2024
1 parent 5b9b16b commit 5b49c49
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 6 deletions.
8 changes: 8 additions & 0 deletions ansible/playbook.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
- name: Customize Machine Image
hosts: all

tasks:
- name: Debug
ansible.builtin.debug:
msg: "Ansible provisiong is enabled!"
33 changes: 31 additions & 2 deletions centos7/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
54 changes: 52 additions & 2 deletions centos7/centos7.pkr.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ packer {
version = "~> 1.0"
source = "github.com/hashicorp/qemu"
}
ansible = {
version = ">= 1.1.1"
source = "github.com/hashicorp/ansible"
}
}
}

Expand Down Expand Up @@ -55,40 +59,86 @@ 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 = ["<up><tab> ", "inst.ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/centos7.ks ", "console=ttyS0 inst.cmdline", "<enter>"]
boot_wait = "3s"
communicator = "none"
communicator = local.communicator
disk_size = "4G"
headless = true
iso_checksum = "file:${var.centos7_sha256sum_url}"
iso_url = var.centos7_iso_url
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",
{
KS_PROXY = local.ks_proxy,
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}",
Expand Down
19 changes: 17 additions & 2 deletions centos7/http/centos7.ks.pkrtpl.hcl
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
url ${KS_OS_REPOS} ${KS_PROXY}
poweroff
firewall --enabled --service=ssh
firstboot --disable
ignoredisk --only-use=vda
Expand All @@ -19,20 +18,36 @@ 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
touch /etc/$f
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
Expand Down
15 changes: 15 additions & 0 deletions scripts/ssh_provisioning_cleanup.sh
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 5b49c49

Please sign in to comment.