Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add optional Ansible provisioning for centos 7 #204

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading