History rewrite

This commit is contained in:
AJ Schroeder
2023-11-21 20:27:31 -06:00
parent 25255fd6b8
commit 397034b53e
69 changed files with 6568 additions and 8 deletions

View File

@@ -0,0 +1,9 @@
/*
DESCRIPTION:
Ansible credential variables used for Linux builds.
- Variables are passed to and used by configuration scripts.
*/
// Ansible Credentials
ansible_username = "ansible"
ansible_key = "<SSH public key for Ansible user goes here>"

View File

@@ -0,0 +1,12 @@
/*
DESCRIPTION:
Build account variables used for all builds.
- Variables are passed to and used by guest operating system configuration files (e.g., ks.cfg, autounattend.xml).
- Variables are passed to and used by configuration scripts.
*/
// Default Account Credentials
build_username = "ubuntu"
build_password = "ubuntu"
build_password_encrypted = "$6$Gg0b6uacy6apqKTP$OIvG1n8YUNpiDpsQgS02PgGgGY0egsYM0lqQq1lvOLKCAhMQcrY6SXq2K6ynt6RI8GVvmiagbKkcN6YXRzQtb1"
build_key = "Your public SSH key goes here"

View File

@@ -0,0 +1,19 @@
/*
DESCRIPTION:
Common variables used for all builds.
- Variables are use by the source blocks.
*/
// Removable Media Settings
common_iso_storage = "OS"
// Boot and Provisioning Settings
common_data_source = "http"
common_http_ip = null
common_http_port_min = 8000
common_http_port_max = 8099
common_ip_wait_timeout = "20m"
common_shutdown_timeout = "15m"
// HCP Packer
common_hcp_packer_registry_enabled = false

View File

@@ -0,0 +1,169 @@
/*
DESCRIPTION:
Storage variables used for Linux builds.
- Variables are passed to and used by guest operating system configuration files (e.g., ks.cfg).
*/
vm_efi_storage_pool = "vm-data"
vm_efi_type = "4m"
vm_efi_pre_enrolled_keys = false
// VM Storage Settings
vm_disk_device = "vda"
vm_disk_use_swap = true
vm_disk_partitions = [
{
name = "efi"
size = 1024,
format = {
label = "EFIFS",
fstype = "fat32",
},
mount = {
path = "/boot/efi",
options = "",
},
volume_group = "",
},
{
name = "boot"
size = 1024,
format = {
label = "BOOTFS",
fstype = "ext4",
},
mount = {
path = "/boot",
options = "",
},
volume_group = "",
},
{
name = "vg_root"
size = -1,
format = {
label = "",
fstype = "",
},
mount = {
path = "",
options = "",
},
volume_group = "vg_root",
},
]
vm_disk_lvm = [
{
name: "vg_root",
partitions: [
{
name = "lv_swap",
size = 1024,
format = {
label = "SWAPFS",
fstype = "swap",
},
mount = {
path = "",
options = "",
},
},
{
name = "lv_root",
size = 3000,
format = {
label = "ROOTFS",
fstype = "ext4",
},
mount = {
path = "/",
options = "",
},
},
{
name = "lv_home",
size = 1200,
format = {
label = "HOMEFS",
fstype = "ext4",
},
mount = {
path = "/home",
options = "nodev,nosuid",
},
},
{
name = "lv_opt",
size = 2048,
format = {
label = "OPTFS",
fstype = "ext4",
},
mount = {
path = "/opt",
options = "nodev",
},
},
{
name = "lv_tmp",
size = 2500,
format = {
label = "TMPFS",
fstype = "ext4",
},
mount = {
path = "/tmp",
options = "nodev,noexec,nosuid",
},
},
{
name = "lv_var",
size = 3072,
format = {
label = "VARFS",
fstype = "ext4",
},
mount = {
path = "/var",
options = "nodev",
},
},
{
name = "lv_var_tmp",
size = 4096,
format = {
label = "VARTMPFS",
fstype = "ext4",
},
mount = {
path = "/var/tmp",
options = "nodev,noexec,nosuid",
},
},
{
name = "lv_var_log",
size = 1024,
format = {
label = "VARLOGFS",
fstype = "ext4",
},
mount = {
path = "/var/log",
options = "nodev,noexec,nosuid",
},
},
{
name = "lv_var_audit",
size = 500,
format = {
label = "AUDITFS",
fstype = "ext4",
},
mount = {
path = "/var/log/audit",
options = "nodev,noexec,nosuid",
},
},
],
}
]

View File

@@ -0,0 +1,84 @@
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# CentOS Stream 8
### Installs from the first attached CD-ROM/DVD on the system.
cdrom
### Performs the kickstart installation in text mode.
### By default, kickstart installations are performed in graphical mode.
text
### Accepts the End User License Agreement.
eula --agreed
### Sets the language to use during installation and the default language to use on the installed system.
lang ${vm_os_language}
### Sets the default keyboard type for the system.
keyboard ${vm_os_keyboard}
### Configure network information for target system and activate network devices in the installer environment (optional)
### --onboot enable device at a boot time
### --device device to be activated and / or configured with the network command
### --bootproto method to obtain networking configuration for device (default dhcp)
### --noipv6 disable IPv6 on this device
###
### network --bootproto=static --ip=172.16.11.200 --netmask=255.255.255.0 --gateway=172.16.11.200 --nameserver=172.16.11.4 --hostname centos-linux-8
network --bootproto=dhcp
### Lock the root account.
rootpw --lock
### The selected profile will restrict root login.
### Add a user that can login and escalate privileges.
user --name=${build_username} --iscrypted --password=${build_password_encrypted} --groups=wheel
### Configure firewall settings for the system.
### --enabled reject incoming connections that are not in response to outbound requests
### --ssh allow sshd service through the firewall
firewall --enabled --ssh
### Sets up the authentication options for the system.
### The SSDD profile sets sha512 to hash passwords. Passwords are shadowed by default
### See the manual page for authselect-profile for a complete list of possible options.
authselect select sssd
### Sets the state of SELinux on the installed system.
### Defaults to enforcing.
selinux --enforcing
### Sets the system time zone.
timezone ${vm_os_timezone}
### Partitioning
${storage}
### Modifies the default set of services that will run under the default runlevel.
services --enabled=NetworkManager,sshd
### Do not configure X on the installed system.
skipx
### Packages selection.
%packages --ignoremissing --excludedocs
@core
-iwl*firmware
%end
### Post-installation commands.
%post
dnf makecache
dnf install epel-release -y
dnf makecache
dnf install -y sudo qemu-guest-tools
echo "${build_username} ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/${build_username}
sed -i "s/^.*requiretty/#Defaults requiretty/" /etc/sudoers
%end
### Reboot after the installation is complete.
### --eject attempt to eject the media before rebooting.
reboot --eject

View File

@@ -0,0 +1,66 @@
### Sets how the boot loader should be installed.
bootloader --location=mbr
### Initialize any invalid partition tables found on disks.
zerombr
### Removes partitions from the system, prior to creation of new partitions.
### By default, no partitions are removed.
### --all Erases all partitions from the system
### --initlabel Initializes a disk (or disks) by creating a default disk label for all disks in their respective architecture.
clearpart --all --initlabel
### Modify partition sizes for the virtual machine hardware.
### Create primary system partitions.
%{~ if length(partitions) == 1 && partitions[0].name == "autopart" ~}
%{~ if partitions[0].format.fstype == "lvm" ~}
autopart --type=lvm
%{ endif }
%{~ if partitions[0].format.fstype == "simple" ~}
autopart --type=plain
%{ endif }
%{~ if partitions[0].format.fstype == "" ~}
autopart --type=plain
%{ endif }
%{ else }
%{~ for partition in partitions ~}
%{~ if partition.format.fstype == "swap" ~}
part swap --size=${partition.size}
%{~ endif ~}
%{~ if partition.mount.path == "/boot/efi" ~}
part ${partition.mount.path} --fstype vfat --size=${partition.size} --label=${partition.format.label}
%{~ endif ~}
%{~ if partition.mount.path != "" ~}
part ${partition.mount.path} --fstype ${partition.format.fstype} --size=${partition.size} --label=${partition.format.label} %{~ if partition.mount.options != "" ~}--fsoptions="${partition.mount.options}"%{~ endif ~}
%{~ endif ~}
%{~ if partition.volume_group != "" ~}
%{~ if partition.size == -1 ~}
part pv.${partition.volume_group} --size=100 --grow
%{~ else ~}
part pv.${partition.volume_group} --size=${partition.size}
%{~ endif ~}
### Create a logical volume management (LVM) group.
### Modify logical volume sizes for the virtual machine hardware.
%{~ for index, volume_group in lvm ~}
%{~ if partition.volume_group != "" ~}
volgroup ${volume_group.name} --pesize=4096 pv.${partition.volume_group}
%{~ endif ~}
### Create logical volumes.
%{~ for partition in volume_group.partitions ~}
%{~ if partition.format.fstype == "swap" ~}
logvol swap --fstype ${partition.format.fstype} --name=${partition.name} --vgname=${volume_group.name} --size=${partition.size} --label=${partition.format.label}
%{~ else ~}
logvol ${partition.mount.path} %{ if partition.format.fstype == "fat32" } --fstype vfat %{ else } --fstype ${partition.format.fstype} %{ endif } %{ if partition.size != -1 } --size=${partition.size} %{ else } --size=100 --grow %{ endif } --name=${partition.name} --vgname=${volume_group.name} --label=${partition.format.label} %{ if partition.mount.options != "" ~} --fsoptions="${partition.mount.options}" %{~ endif ~}
%{~ endif ~}
%{~ endfor ~}
%{~ endfor ~}
%{~ endif ~}
%{~ endfor ~}
%{~ endif }

View File

@@ -0,0 +1,45 @@
/*
DESCRIPTION:
Ubuntu Server 22.04 LTS variables used by the Packer Plugin for Proxmox (proxmox-iso).
*/
// Guest Operating System Metadata
vm_os_language = "en_US"
vm_os_keyboard = "us"
vm_os_timezone = "UTC"
vm_os_family = "linux"
vm_os_name = "centos-stream"
vm_os_version = "8"
// Virtual Machine Guest Operating System Setting
vm_os_type = "l26"
// Virtual Machine Hardware Settings
vm_bios = "seabios"
vm_cpu_count = 1
vm_cpu_sockets = 1
vm_cpu_type = "kvm64"
vm_mem_size = 2048
vm_disk_type = "virtio"
vm_disk_size = "32G"
vm_disk_format = "raw"
vm_storage_pool = "vm-data"
vm_disk_controller_type = "virtio-scsi-pci"
vm_network_card_model = "virtio"
vm_bridge_interface = "vmbr0"
vm_vlan_tag = "102"
// Removable Media Settings
iso_path = "iso"
iso_file = "CentOS-Stream-8-x86_64-latest-dvd1.iso"
iso_checksum = "file:http://centos.mirror.ndchost.com/8-stream/isos/x86_64/CHECKSUM"
// Boot Settings
vm_boot = "order=virtio0;ide2;net0"
vm_boot_wait = "10s"
// EFI Settings
vm_firmware_path = "./OVMF.fd"
vm_efi_storage_pool = "vm-data"
vm_efi_pre_enrolled_keys = false
vm_efi_type = "4m"

View File

@@ -0,0 +1,197 @@
/*
DESCRIPTION:
Debian 11 template using the Packer Builder for Proxmox (proxmox-iso).
*/
// BLOCK: packer
// The Packer configuration.
packer {
required_version = ">= 1.9.1"
required_plugins {
ansible = {
source = "github.com/hashicorp/ansible"
version = "~> 1"
}
git = {
version = ">= 0.4.2"
source = "github.com/ethanmdavidson/git"
}
proxmox = {
version = ">= 1.0.6"
source = "github.com/hashicorp/proxmox"
}
}
}
// BLOCK: data
// Defines the data sources.
data "git-repository" "cwd" {}
// BLOCK: locals
// Defines the local variables.
locals {
build_by = "Built by: HashiCorp Packer ${packer.version}"
build_date = formatdate("DD-MM-YYYY hh:mm ZZZ", "${timestamp()}" )
build_version = data.git-repository.cwd.head
build_description = "Version: ${local.build_version}\nBuilt on: ${local.build_date}\n${local.build_by}\nCloud-Init: ${var.vm_cloud_init_enable}"
vm_disk_type = var.vm_disk_type == "virtio" ? "vda" : "sda"
manifest_date = formatdate("YYYY-MM-DD hh:mm:ss", timestamp())
manifest_path = "${path.cwd}/manifests/"
manifest_output = "${local.manifest_path}${local.manifest_date}.json"
data_source_content = {
"/ks.cfg" = templatefile("${abspath(path.root)}/data/ks.pkrtpl.hcl", {
build_username = var.build_username
build_password = var.build_password
build_password_encrypted = var.build_password_encrypted
vm_disk_type = local.vm_disk_type
vm_os_language = var.vm_os_language
vm_os_keyboard = var.vm_os_keyboard
vm_os_timezone = var.vm_os_timezone
common_data_source = var.common_data_source
# lvm needs to be here so late commands can access vg names
lvm = var.vm_disk_lvm
storage = templatefile("${abspath(path.root)}/data/storage.pkrtpl.hcl", {
device = var.vm_disk_device
swap = var.vm_disk_use_swap
partitions = var.vm_disk_partitions
lvm = var.vm_disk_lvm
vm_bios = var.vm_bios
})
})
}
data_source_command = var.common_data_source == "http" ? "inst.ks=http://{{.HTTPIP}}:{{.HTTPPort}}/ks.cfg" : "inst.ks=/cdrom/ks.cfg"
vm_name = "${var.vm_os_family}-${var.vm_os_name}-${var.vm_os_version}"
vm_bios = var.vm_bios == "ovmf" ? var.vm_firmware_path : null
}
// BLOCK: source
// Defines the builder configuration blocks.
source "proxmox-iso" "linux-centos-stream" {
// Proxmox Connection Settings and Credentials
proxmox_url = "https://${var.proxmox_hostname}:8006/api2/json"
username = "${var.proxmox_api_token_id}"
token = "${var.proxmox_api_token_secret}"
insecure_skip_tls_verify = "${var.proxmox_insecure_connection}"
// Proxmox Settings
node = "${var.proxmox_node}"
// Virtual Machine Settings
vm_name = "${local.vm_name}"
bios = "${var.vm_bios}"
sockets = "${var.vm_cpu_sockets}"
cores = "${var.vm_cpu_count}"
cpu_type = "${var.vm_cpu_type}"
memory = "${var.vm_mem_size}"
os = "${var.vm_os_type}"
scsi_controller = "${var.vm_disk_controller_type}"
disks {
disk_size = "${var.vm_disk_size}"
type = "${var.vm_disk_type}"
storage_pool = "${var.vm_storage_pool}"
format = "${var.vm_disk_format}"
}
dynamic "efi_config" {
for_each = var.vm_bios == "ovmf" ? [1] : []
content {
efi_storage_pool = var.vm_bios == "ovmf" ? var.vm_efi_storage_pool : null
efi_type = var.vm_bios == "ovmf" ? var.vm_efi_type : null
pre_enrolled_keys = var.vm_bios == "ovmf" ? var.vm_efi_pre_enrolled_keys : null
}
}
unmount_iso = true
ssh_username = "${var.build_username}"
ssh_password = "${var.build_password}"
ssh_timeout = "${var.timeout}"
ssh_port = "22"
iso_file = "${var.common_iso_storage}:${var.iso_path}/${var.iso_file}"
iso_checksum = "${var.iso_checksum}"
qemu_agent = true
network_adapters {
bridge = "${var.vm_bridge_interface}"
model = "${var.vm_network_card_model}"
vlan_tag = "${var.vm_vlan_tag}"
}
// Removable Media Settings
http_content = "${var.common_data_source}" == "http" ? "${local.data_source_content}" : null
// Boot and Provisioning Settings
http_bind_address = var.common_data_source == "http" ? var.common_http_bind_address : null
http_port_min = var.common_data_source == "http" ? var.common_http_port_min : null
http_port_max = var.common_data_source == "http" ? var.common_http_port_max : null
boot = var.vm_boot
boot_wait = var.vm_boot_wait
boot_command = [
"<up><wait>",
"<tab><wait>",
" text ${local.data_source_command}",
"<enter><wait>"
]
dynamic "additional_iso_files" {
for_each = var.common_data_source == "disk" ? [1] : []
content {
cd_files = var.common_data_source == "disk" ? local.data_source_content : null
cd_label = var.common_data_source == "disk" ? "cidata" : null
iso_storage_pool = var.common_data_source == "disk" ? "local" : null
}
}
template_name = "${local.vm_name}"
template_description = "${local.build_description}"
# VM Cloud Init Settings
cloud_init = var.vm_cloud_init_enable
cloud_init_storage_pool = var.vm_cloud_init_enable == true ? var.vm_storage_pool : null
}
# Build Definition to create the VM Template
build {
sources = ["source.proxmox-iso.linux-centos-stream"]
provisioner "ansible" {
user = "${var.build_username}"
playbook_file = "${path.cwd}/ansible/main.yml"
roles_path = "${path.cwd}/ansible/roles"
ansible_env_vars = [
"ANSIBLE_CONFIG=${path.cwd}/ansible/ansible.cfg"
]
extra_arguments = [
"--extra-vars", "display_skipped_hosts=false",
"--extra-vars", "BUILD_USERNAME=${var.build_username}",
"--extra-vars", "BUILD_SECRET='${var.build_key}'",
"--extra-vars", "ANSIBLE_USERNAME=${var.ansible_username}",
"--extra-vars", "ANSIBLE_SECRET='${var.ansible_key}'",
"--extra-vars", "cloud_init='${var.vm_cloud_init_enable}'",
]
}
post-processor "manifest" {
output = local.manifest_output
strip_path = true
strip_time = true
custom_data = {
ansible_username = "${var.ansible_username}"
build_username = "${var.build_username}"
build_date = "${local.build_date}"
build_version = "${local.build_version}"
common_data_source = "${var.common_data_source}"
vm_cpu_sockets = "${var.vm_cpu_sockets}"
vm_cpu_count = "${var.vm_cpu_count}"
vm_disk_size = "${var.vm_disk_size}"
vm_bios = "${var.vm_bios}"
vm_os_type = "${var.vm_os_type}"
vm_mem_size = "${var.vm_mem_size}"
vm_network_card_model = "${var.vm_network_card_model}"
vm_cloud_init_enable = "${var.vm_cloud_init_enable}"
}
}
}

View File

@@ -0,0 +1,53 @@
/*
DESCRIPTION:
Debian 11 storage variables used by the Packer Plugin for Proxmox (proxmox-iso).
*/
// VM Storage Settings
variable "vm_disk_device" {
type = string
description = "The device for the virtual disk. (e.g. 'sda')"
}
variable "vm_disk_use_swap" {
type = bool
description = "Whether to use a swap partition."
}
variable "vm_disk_partitions" {
type = list(object({
name = string
size = number
format = object({
label = string
fstype = string
})
mount = object({
path = string
options = string
})
volume_group = string
}))
description = "The disk partitions for the virtual disk."
}
variable "vm_disk_lvm" {
type = list(object({
name = string
partitions = list(object({
name = string
size = number
format = object({
label = string
fstype = string
})
mount = object({
path = string
options = string
})
}))
}))
description = "The LVM configuration for the virtual disk."
default = []
}

View File

@@ -0,0 +1,297 @@
/*
DESCRIPTION:
Debian 11 variables using the Packer Builder for Proxmox (proxmox-iso).
*/
// BLOCK: variable
// Defines the input variables.
// Proxmox Credentials
variable "proxmox_hostname" {
type = string
description = "The FQDN or IP address of a Proxmox node. Only one node should be specified in a cluster."
}
variable "proxmox_api_token_id" {
type = string
description = "The token to login to the Proxmox node/cluster. The format is USER@REALM!TOKENID. (e.g. packer@pam!packer_pve_token)"
}
variable "proxmox_api_token_secret" {
type = string
description = "The secret for the API token used to login to the Proxmox API."
# sensitive = true
}
variable "proxmox_insecure_connection" {
description = "true/false to skip Proxmox TLS certificate checks."
type = bool
default = true
}
// Proxmox Settings
variable "proxmox_node" {
type = string
description = "The name of the Proxmox node that Packer will build templates on."
}
// Virtual Machine Settings
variable "vm_os_language" {
type = string
description = "The guest operating system language."
default = "en_US"
}
variable "vm_os_keyboard" {
type = string
description = "The guest operating system keyboard layout."
default = "us"
}
variable "vm_os_timezone" {
type = string
description = "The guest operating system timezone."
default = "UTC"
}
variable "vm_os_family" {
type = string
description = "The guest operating system family. Used for naming. (e.g. 'linux')"
}
variable "vm_os_name" {
type = string
description = "The guest operating system name. Used for naming. (e.g. 'ubuntu')"
}
variable "vm_os_version" {
type = string
description = "The guest operating system version. Used for naming. (e.g. '22-04-lts')"
}
variable "vm_os_type" {
type = string
description = "The guest operating system type. (e.g. 'l26')"
}
variable "vm_bios" {
type = string
description = "The firmware type. Allowed values 'ovmf' or 'seabios'"
default = "OVMF"
validation {
condition = contains(["ovmf", "seabios"], var.vm_bios)
error_message = "The vm_bios value must be 'ovmf' or 'seabios'."
}
}
variable "vm_firmware_path" {
type = string
description = "The firmware file to be used. Needed for EFI"
default = "/usr/share/ovmf/OVMF.fd"
}
variable "vm_efi_storage_pool" {
type = string
description = "Set the UEFI disk storage location. (e.g. 'local-lvm')"
}
variable "vm_efi_type" {
type = string
description = "Specifies the version of the OVMF firmware to be used. (e.g. '4m')"
}
variable "vm_efi_pre_enrolled_keys" {
type = bool
description = "Whether Microsoft Standard Secure Boot keys should be pre-loaded on the EFI disk. (e.g. false)"
}
variable "vm_cpu_count" {
type = number
description = "The number of virtual CPUs. (e.g. '2')"
}
variable "vm_cpu_sockets" {
type = number
description = "The number of virtual CPU sockets. (e.g. '1')"
}
variable "vm_cpu_type" {
type = string
description = "The CPU type to emulate. See the Proxmox API documentation for the complete list of accepted values. For best performance, set this to host. Defaults to kvm64."
}
variable "vm_mem_size" {
type = number
description = "The size for the virtual memory in MB. (e.g. '2048')"
}
variable "vm_disk_controller_type" {
type = string
description = "The SCSI controller model to emulate. (e.g. 'virtio-scsi-pci')"
}
variable "vm_disk_type" {
type = string
description = "The type of disk to emulate. (e.g. 'virtio')"
}
variable "vm_storage_pool" {
type = string
description = "The name of the Proxmox storage pool to store the VM template. (e.g. 'local-lvm')"
}
variable "vm_disk_size" {
type = string
description = "The size for the virtual disk in GB. (e.g. '32G')"
}
variable "vm_disk_format" {
type = string
description = "The format of the file backing the disk. (e.g. 'qcow2')"
}
variable "vm_network_card_model" {
type = string
description = "The model of the virtual network adapter to emulate. (e.g. 'virtio')"
}
variable "vm_bridge_interface" {
type = string
description = "The name of the Proxmox bridge to attach the adapter to."
}
variable "vm_vlan_tag" {
type = string
description = "If the adapter should tag packets, give the VLAN ID. (e.g. '102')"
}
// Cloud-Init Settings
variable "vm_cloud_init_enable" {
type = bool
description = "Enable or disable cloud-init drive in Proxmox. (e.g. false)"
default = false
}
// Removable Media Settings
variable "common_iso_storage" {
type = string
description = "The name of the source Proxmox storage location for ISO images. (e.g. 'local-lvm')"
}
variable "iso_path" {
type = string
description = "The path on the source Proxmox storage location for ISO images. (e.g. 'iso')"
}
variable "iso_file" {
type = string
description = "The file name of the ISO image used by the vendor. (e.g. 'ubuntu-<version>-live-server-amd64.iso')"
}
variable "iso_checksum" {
type = string
description = "The checksum value of the ISO image provided by the vendor."
}
// Boot Settings
variable "common_data_source" {
type = string
description = "The provisioning data source. (e.g. 'http' or 'disk')"
}
variable "common_http_bind_address" {
type = string
description = "Define an IP address on the host to use for the HTTP server."
default = null
}
variable "common_http_port_min" {
type = number
description = "The start of the HTTP port range."
}
variable "common_http_port_max" {
type = number
description = "The end of the HTTP port range."
}
variable "vm_boot" {
type = string
description = "The boot order for virtual machine devices. (e.g. 'order=virtio0;ide2;net0')"
}
variable "vm_boot_wait" {
type = string
description = "The time to wait after booting the initial VM before typing the boot_command (e.g '10s')"
}
variable "common_ip_wait_timeout" {
type = string
description = "Time to wait for guest operating system IP address response."
}
variable "common_shutdown_timeout" {
type = string
description = "Time to wait for guest operating system shutdown."
}
// Communicator Settings and Credentials
variable "build_username" {
type = string
description = "The username to login to the guest operating system. (e.g. 'ubuntu')"
# sensitive = true
}
variable "build_password" {
type = string
description = "The password to login to the guest operating system."
# sensitive = true
}
variable "build_password_encrypted" {
type = string
description = "The encrypted password to login to the guest operating system."
# sensitive = true
}
variable "build_key" {
type = string
description = "The SSH public key to login to the guest operating system."
# sensitive = true
}
variable "timeout" {
description = "not sure why I need so high a timeout but here we are"
default = "90m"
}
// Ansible Credentials
variable "ansible_username" {
type = string
description = "The username for Ansible to login to the guest operating system. (e.g. 'ansible')"
# sensitive = true
}
variable "ansible_key" {
type = string
description = "The public key for Ansible to login to the guest operating system."
# sensitive = true
}
// HCP Packer Settings
variable "common_hcp_packer_registry_enabled" {
type = bool
description = "Enable the HCP Packer registry."
default = false
}

View File

@@ -0,0 +1,84 @@
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# CentOS Stream 9
### Installs from the first attached CD-ROM/DVD on the system.
cdrom
### Performs the kickstart installation in text mode.
### By default, kickstart installations are performed in graphical mode.
text
### Accepts the End User License Agreement.
eula --agreed
### Sets the language to use during installation and the default language to use on the installed system.
lang ${vm_os_language}
### Sets the default keyboard type for the system.
keyboard ${vm_os_keyboard}
### Configure network information for target system and activate network devices in the installer environment (optional)
### --onboot enable device at a boot time
### --device device to be activated and / or configured with the network command
### --bootproto method to obtain networking configuration for device (default dhcp)
### --noipv6 disable IPv6 on this device
###
### network --bootproto=static --ip=172.16.11.200 --netmask=255.255.255.0 --gateway=172.16.11.200 --nameserver=172.16.11.4 --hostname centos-linux-8
network --bootproto=dhcp
### Lock the root account.
rootpw --lock
### The selected profile will restrict root login.
### Add a user that can login and escalate privileges.
user --name=${build_username} --iscrypted --password=${build_password_encrypted} --groups=wheel
### Configure firewall settings for the system.
### --enabled reject incoming connections that are not in response to outbound requests
### --ssh allow sshd service through the firewall
firewall --enabled --ssh
### Sets up the authentication options for the system.
### The SSDD profile sets sha512 to hash passwords. Passwords are shadowed by default
### See the manual page for authselect-profile for a complete list of possible options.
authselect select sssd
### Sets the state of SELinux on the installed system.
### Defaults to enforcing.
selinux --enforcing
### Sets the system time zone.
timezone ${vm_os_timezone}
### Partitioning
${storage}
### Modifies the default set of services that will run under the default runlevel.
services --enabled=NetworkManager,sshd
### Do not configure X on the installed system.
skipx
### Packages selection.
%packages --ignoremissing --excludedocs
@core
-iwl*firmware
%end
### Post-installation commands.
%post
dnf makecache
dnf install epel-release -y
dnf makecache
dnf install -y sudo qemu-guest-tools
echo "${build_username} ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/${build_username}
sed -i "s/^.*requiretty/#Defaults requiretty/" /etc/sudoers
%end
### Reboot after the installation is complete.
### --eject attempt to eject the media before rebooting.
reboot --eject

View File

@@ -0,0 +1,66 @@
### Sets how the boot loader should be installed.
bootloader --location=mbr
### Initialize any invalid partition tables found on disks.
zerombr
### Removes partitions from the system, prior to creation of new partitions.
### By default, no partitions are removed.
### --all Erases all partitions from the system
### --initlabel Initializes a disk (or disks) by creating a default disk label for all disks in their respective architecture.
clearpart --all --initlabel
### Modify partition sizes for the virtual machine hardware.
### Create primary system partitions.
%{~ if length(partitions) == 1 && partitions[0].name == "autopart" ~}
%{~ if partitions[0].format.fstype == "lvm" ~}
autopart --type=lvm
%{ endif }
%{~ if partitions[0].format.fstype == "simple" ~}
autopart --type=plain
%{ endif }
%{~ if partitions[0].format.fstype == "" ~}
autopart --type=plain
%{ endif }
%{ else }
%{~ for partition in partitions ~}
%{~ if partition.format.fstype == "swap" ~}
part swap --size=${partition.size}
%{~ endif ~}
%{~ if partition.mount.path == "/boot/efi" ~}
part ${partition.mount.path} --fstype vfat --size=${partition.size} --label=${partition.format.label}
%{~ endif ~}
%{~ if partition.mount.path != "" ~}
part ${partition.mount.path} --fstype ${partition.format.fstype} --size=${partition.size} --label=${partition.format.label} %{~ if partition.mount.options != "" ~}--fsoptions="${partition.mount.options}"%{~ endif ~}
%{~ endif ~}
%{~ if partition.volume_group != "" ~}
%{~ if partition.size == -1 ~}
part pv.${partition.volume_group} --size=100 --grow
%{~ else ~}
part pv.${partition.volume_group} --size=${partition.size}
%{~ endif ~}
### Create a logical volume management (LVM) group.
### Modify logical volume sizes for the virtual machine hardware.
%{~ for index, volume_group in lvm ~}
%{~ if partition.volume_group != "" ~}
volgroup ${volume_group.name} --pesize=4096 pv.${partition.volume_group}
%{~ endif ~}
### Create logical volumes.
%{~ for partition in volume_group.partitions ~}
%{~ if partition.format.fstype == "swap" ~}
logvol swap --fstype ${partition.format.fstype} --name=${partition.name} --vgname=${volume_group.name} --size=${partition.size} --label=${partition.format.label}
%{~ else ~}
logvol ${partition.mount.path} %{ if partition.format.fstype == "fat32" } --fstype vfat %{ else } --fstype ${partition.format.fstype} %{ endif } %{ if partition.size != -1 } --size=${partition.size} %{ else } --size=100 --grow %{ endif } --name=${partition.name} --vgname=${volume_group.name} --label=${partition.format.label} %{ if partition.mount.options != "" ~} --fsoptions="${partition.mount.options}" %{~ endif ~}
%{~ endif ~}
%{~ endfor ~}
%{~ endfor ~}
%{~ endif ~}
%{~ endfor ~}
%{~ endif }

View File

@@ -0,0 +1,45 @@
/*
DESCRIPTION:
Ubuntu Server 22.04 LTS variables used by the Packer Plugin for Proxmox (proxmox-iso).
*/
// Guest Operating System Metadata
vm_os_language = "en_US"
vm_os_keyboard = "us"
vm_os_timezone = "UTC"
vm_os_family = "linux"
vm_os_name = "centos-stream"
vm_os_version = "9"
// Virtual Machine Guest Operating System Setting
vm_os_type = "l26"
// Virtual Machine Hardware Settings
vm_bios = "seabios"
vm_cpu_count = 1
vm_cpu_sockets = 1
vm_cpu_type = "x86-64-v2-AES"
vm_mem_size = 2048
vm_disk_type = "virtio"
vm_disk_size = "32G"
vm_disk_format = "raw"
vm_storage_pool = "vm-data"
vm_disk_controller_type = "virtio-scsi-pci"
vm_network_card_model = "virtio"
vm_bridge_interface = "vmbr0"
vm_vlan_tag = "102"
// Removable Media Settings
iso_path = "iso"
iso_file = "CentOS-Stream-9-latest-x86_64-dvd1.iso"
iso_checksum = "file:https://mirror.stream.centos.org/9-stream/BaseOS/x86_64/iso/SHA256SUM"
// Boot Settings
vm_boot = "order=virtio0;ide2;net0"
vm_boot_wait = "5s"
// EFI Settings
vm_firmware_path = "./OVMF.fd"
vm_efi_storage_pool = "vm-data"
vm_efi_pre_enrolled_keys = false
vm_efi_type = "4m"

View File

@@ -0,0 +1,197 @@
/*
DESCRIPTION:
Debian 11 template using the Packer Builder for Proxmox (proxmox-iso).
*/
// BLOCK: packer
// The Packer configuration.
packer {
required_version = ">= 1.9.1"
required_plugins {
ansible = {
source = "github.com/hashicorp/ansible"
version = "~> 1"
}
git = {
version = ">= 0.4.2"
source = "github.com/ethanmdavidson/git"
}
proxmox = {
version = ">= 1.0.6"
source = "github.com/hashicorp/proxmox"
}
}
}
// BLOCK: data
// Defines the data sources.
data "git-repository" "cwd" {}
// BLOCK: locals
// Defines the local variables.
locals {
build_by = "Built by: HashiCorp Packer ${packer.version}"
build_date = formatdate("DD-MM-YYYY hh:mm ZZZ", "${timestamp()}" )
build_version = data.git-repository.cwd.head
build_description = "Version: ${local.build_version}\nBuilt on: ${local.build_date}\n${local.build_by}\nCloud-Init: ${var.vm_cloud_init_enable}"
vm_disk_type = var.vm_disk_type == "virtio" ? "vda" : "sda"
manifest_date = formatdate("YYYY-MM-DD hh:mm:ss", timestamp())
manifest_path = "${path.cwd}/manifests/"
manifest_output = "${local.manifest_path}${local.manifest_date}.json"
data_source_content = {
"/ks.cfg" = templatefile("${abspath(path.root)}/data/ks.pkrtpl.hcl", {
build_username = var.build_username
build_password = var.build_password
build_password_encrypted = var.build_password_encrypted
vm_disk_type = local.vm_disk_type
vm_os_language = var.vm_os_language
vm_os_keyboard = var.vm_os_keyboard
vm_os_timezone = var.vm_os_timezone
common_data_source = var.common_data_source
# lvm needs to be here so late commands can access vg names
lvm = var.vm_disk_lvm
storage = templatefile("${abspath(path.root)}/data/storage.pkrtpl.hcl", {
device = var.vm_disk_device
swap = var.vm_disk_use_swap
partitions = var.vm_disk_partitions
lvm = var.vm_disk_lvm
vm_bios = var.vm_bios
})
})
}
data_source_command = var.common_data_source == "http" ? "inst.ks=http://{{.HTTPIP}}:{{.HTTPPort}}/ks.cfg" : "inst.ks=/cdrom/ks.cfg"
vm_name = "${var.vm_os_family}-${var.vm_os_name}-${var.vm_os_version}"
vm_bios = var.vm_bios == "ovmf" ? var.vm_firmware_path : null
}
// BLOCK: source
// Defines the builder configuration blocks.
source "proxmox-iso" "linux-centos-stream" {
// Proxmox Connection Settings and Credentials
proxmox_url = "https://${var.proxmox_hostname}:8006/api2/json"
username = "${var.proxmox_api_token_id}"
token = "${var.proxmox_api_token_secret}"
insecure_skip_tls_verify = "${var.proxmox_insecure_connection}"
// Proxmox Settings
node = "${var.proxmox_node}"
// Virtual Machine Settings
vm_name = "${local.vm_name}"
bios = "${var.vm_bios}"
sockets = "${var.vm_cpu_sockets}"
cores = "${var.vm_cpu_count}"
cpu_type = "${var.vm_cpu_type}"
memory = "${var.vm_mem_size}"
os = "${var.vm_os_type}"
scsi_controller = "${var.vm_disk_controller_type}"
disks {
disk_size = "${var.vm_disk_size}"
type = "${var.vm_disk_type}"
storage_pool = "${var.vm_storage_pool}"
format = "${var.vm_disk_format}"
}
dynamic "efi_config" {
for_each = var.vm_bios == "ovmf" ? [1] : []
content {
efi_storage_pool = var.vm_bios == "ovmf" ? var.vm_efi_storage_pool : null
efi_type = var.vm_bios == "ovmf" ? var.vm_efi_type : null
pre_enrolled_keys = var.vm_bios == "ovmf" ? var.vm_efi_pre_enrolled_keys : null
}
}
unmount_iso = true
ssh_username = "${var.build_username}"
ssh_password = "${var.build_password}"
ssh_timeout = "${var.timeout}"
ssh_port = "22"
iso_file = "${var.common_iso_storage}:${var.iso_path}/${var.iso_file}"
iso_checksum = "${var.iso_checksum}"
qemu_agent = true
network_adapters {
bridge = "${var.vm_bridge_interface}"
model = "${var.vm_network_card_model}"
vlan_tag = "${var.vm_vlan_tag}"
}
// Removable Media Settings
http_content = "${var.common_data_source}" == "http" ? "${local.data_source_content}" : null
// Boot and Provisioning Settings
http_bind_address = var.common_data_source == "http" ? var.common_http_bind_address : null
http_port_min = var.common_data_source == "http" ? var.common_http_port_min : null
http_port_max = var.common_data_source == "http" ? var.common_http_port_max : null
boot = var.vm_boot
boot_wait = var.vm_boot_wait
boot_command = [
"<up><wait>",
"<tab><wait>",
" text ${local.data_source_command}",
"<enter><wait>"
]
dynamic "additional_iso_files" {
for_each = var.common_data_source == "disk" ? [1] : []
content {
cd_files = var.common_data_source == "disk" ? local.data_source_content : null
cd_label = var.common_data_source == "disk" ? "cidata" : null
iso_storage_pool = var.common_data_source == "disk" ? "local" : null
}
}
template_name = "${local.vm_name}"
template_description = "${local.build_description}"
# VM Cloud Init Settings
cloud_init = var.vm_cloud_init_enable
cloud_init_storage_pool = var.vm_cloud_init_enable == true ? var.vm_storage_pool : null
}
# Build Definition to create the VM Template
build {
sources = ["source.proxmox-iso.linux-centos-stream"]
provisioner "ansible" {
user = "${var.build_username}"
playbook_file = "${path.cwd}/ansible/main.yml"
roles_path = "${path.cwd}/ansible/roles"
ansible_env_vars = [
"ANSIBLE_CONFIG=${path.cwd}/ansible/ansible.cfg"
]
extra_arguments = [
"--extra-vars", "display_skipped_hosts=false",
"--extra-vars", "BUILD_USERNAME=${var.build_username}",
"--extra-vars", "BUILD_SECRET='${var.build_key}'",
"--extra-vars", "ANSIBLE_USERNAME=${var.ansible_username}",
"--extra-vars", "ANSIBLE_SECRET='${var.ansible_key}'",
"--extra-vars", "cloud_init='${var.vm_cloud_init_enable}'",
]
}
post-processor "manifest" {
output = local.manifest_output
strip_path = true
strip_time = true
custom_data = {
ansible_username = "${var.ansible_username}"
build_username = "${var.build_username}"
build_date = "${local.build_date}"
build_version = "${local.build_version}"
common_data_source = "${var.common_data_source}"
vm_cpu_sockets = "${var.vm_cpu_sockets}"
vm_cpu_count = "${var.vm_cpu_count}"
vm_disk_size = "${var.vm_disk_size}"
vm_bios = "${var.vm_bios}"
vm_os_type = "${var.vm_os_type}"
vm_mem_size = "${var.vm_mem_size}"
vm_network_card_model = "${var.vm_network_card_model}"
vm_cloud_init_enable = "${var.vm_cloud_init_enable}"
}
}
}

View File

@@ -0,0 +1,53 @@
/*
DESCRIPTION:
Debian 11 storage variables used by the Packer Plugin for Proxmox (proxmox-iso).
*/
// VM Storage Settings
variable "vm_disk_device" {
type = string
description = "The device for the virtual disk. (e.g. 'sda')"
}
variable "vm_disk_use_swap" {
type = bool
description = "Whether to use a swap partition."
}
variable "vm_disk_partitions" {
type = list(object({
name = string
size = number
format = object({
label = string
fstype = string
})
mount = object({
path = string
options = string
})
volume_group = string
}))
description = "The disk partitions for the virtual disk."
}
variable "vm_disk_lvm" {
type = list(object({
name = string
partitions = list(object({
name = string
size = number
format = object({
label = string
fstype = string
})
mount = object({
path = string
options = string
})
}))
}))
description = "The LVM configuration for the virtual disk."
default = []
}

View File

@@ -0,0 +1,297 @@
/*
DESCRIPTION:
Debian 11 variables using the Packer Builder for Proxmox (proxmox-iso).
*/
// BLOCK: variable
// Defines the input variables.
// Proxmox Credentials
variable "proxmox_hostname" {
type = string
description = "The FQDN or IP address of a Proxmox node. Only one node should be specified in a cluster."
}
variable "proxmox_api_token_id" {
type = string
description = "The token to login to the Proxmox node/cluster. The format is USER@REALM!TOKENID. (e.g. packer@pam!packer_pve_token)"
}
variable "proxmox_api_token_secret" {
type = string
description = "The secret for the API token used to login to the Proxmox API."
# sensitive = true
}
variable "proxmox_insecure_connection" {
description = "true/false to skip Proxmox TLS certificate checks."
type = bool
default = true
}
// Proxmox Settings
variable "proxmox_node" {
type = string
description = "The name of the Proxmox node that Packer will build templates on."
}
// Virtual Machine Settings
variable "vm_os_language" {
type = string
description = "The guest operating system language."
default = "en_US"
}
variable "vm_os_keyboard" {
type = string
description = "The guest operating system keyboard layout."
default = "us"
}
variable "vm_os_timezone" {
type = string
description = "The guest operating system timezone."
default = "UTC"
}
variable "vm_os_family" {
type = string
description = "The guest operating system family. Used for naming. (e.g. 'linux')"
}
variable "vm_os_name" {
type = string
description = "The guest operating system name. Used for naming. (e.g. 'ubuntu')"
}
variable "vm_os_version" {
type = string
description = "The guest operating system version. Used for naming. (e.g. '22-04-lts')"
}
variable "vm_os_type" {
type = string
description = "The guest operating system type. (e.g. 'l26')"
}
variable "vm_bios" {
type = string
description = "The firmware type. Allowed values 'ovmf' or 'seabios'"
default = "OVMF"
validation {
condition = contains(["ovmf", "seabios"], var.vm_bios)
error_message = "The vm_bios value must be 'ovmf' or 'seabios'."
}
}
variable "vm_firmware_path" {
type = string
description = "The firmware file to be used. Needed for EFI"
default = "/usr/share/ovmf/OVMF.fd"
}
variable "vm_efi_storage_pool" {
type = string
description = "Set the UEFI disk storage location. (e.g. 'local-lvm')"
}
variable "vm_efi_type" {
type = string
description = "Specifies the version of the OVMF firmware to be used. (e.g. '4m')"
}
variable "vm_efi_pre_enrolled_keys" {
type = bool
description = "Whether Microsoft Standard Secure Boot keys should be pre-loaded on the EFI disk. (e.g. false)"
}
variable "vm_cpu_count" {
type = number
description = "The number of virtual CPUs. (e.g. '2')"
}
variable "vm_cpu_sockets" {
type = number
description = "The number of virtual CPU sockets. (e.g. '1')"
}
variable "vm_cpu_type" {
type = string
description = "The CPU type to emulate. See the Proxmox API documentation for the complete list of accepted values. For best performance, set this to host. Defaults to kvm64."
}
variable "vm_mem_size" {
type = number
description = "The size for the virtual memory in MB. (e.g. '2048')"
}
variable "vm_disk_controller_type" {
type = string
description = "The SCSI controller model to emulate. (e.g. 'virtio-scsi-pci')"
}
variable "vm_disk_type" {
type = string
description = "The type of disk to emulate. (e.g. 'virtio')"
}
variable "vm_storage_pool" {
type = string
description = "The name of the Proxmox storage pool to store the VM template. (e.g. 'local-lvm')"
}
variable "vm_disk_size" {
type = string
description = "The size for the virtual disk in GB. (e.g. '32G')"
}
variable "vm_disk_format" {
type = string
description = "The format of the file backing the disk. (e.g. 'qcow2')"
}
variable "vm_network_card_model" {
type = string
description = "The model of the virtual network adapter to emulate. (e.g. 'virtio')"
}
variable "vm_bridge_interface" {
type = string
description = "The name of the Proxmox bridge to attach the adapter to."
}
variable "vm_vlan_tag" {
type = string
description = "If the adapter should tag packets, give the VLAN ID. (e.g. '102')"
}
// Cloud-Init Settings
variable "vm_cloud_init_enable" {
type = bool
description = "Enable or disable cloud-init drive in Proxmox. (e.g. false)"
default = false
}
// Removable Media Settings
variable "common_iso_storage" {
type = string
description = "The name of the source Proxmox storage location for ISO images. (e.g. 'local-lvm')"
}
variable "iso_path" {
type = string
description = "The path on the source Proxmox storage location for ISO images. (e.g. 'iso')"
}
variable "iso_file" {
type = string
description = "The file name of the ISO image used by the vendor. (e.g. 'ubuntu-<version>-live-server-amd64.iso')"
}
variable "iso_checksum" {
type = string
description = "The checksum value of the ISO image provided by the vendor."
}
// Boot Settings
variable "common_data_source" {
type = string
description = "The provisioning data source. (e.g. 'http' or 'disk')"
}
variable "common_http_bind_address" {
type = string
description = "Define an IP address on the host to use for the HTTP server."
default = null
}
variable "common_http_port_min" {
type = number
description = "The start of the HTTP port range."
}
variable "common_http_port_max" {
type = number
description = "The end of the HTTP port range."
}
variable "vm_boot" {
type = string
description = "The boot order for virtual machine devices. (e.g. 'order=virtio0;ide2;net0')"
}
variable "vm_boot_wait" {
type = string
description = "The time to wait after booting the initial VM before typing the boot_command (e.g '10s')"
}
variable "common_ip_wait_timeout" {
type = string
description = "Time to wait for guest operating system IP address response."
}
variable "common_shutdown_timeout" {
type = string
description = "Time to wait for guest operating system shutdown."
}
// Communicator Settings and Credentials
variable "build_username" {
type = string
description = "The username to login to the guest operating system. (e.g. 'ubuntu')"
# sensitive = true
}
variable "build_password" {
type = string
description = "The password to login to the guest operating system."
# sensitive = true
}
variable "build_password_encrypted" {
type = string
description = "The encrypted password to login to the guest operating system."
# sensitive = true
}
variable "build_key" {
type = string
description = "The SSH public key to login to the guest operating system."
# sensitive = true
}
variable "timeout" {
description = "not sure why I need so high a timeout but here we are"
default = "90m"
}
// Ansible Credentials
variable "ansible_username" {
type = string
description = "The username for Ansible to login to the guest operating system. (e.g. 'ansible')"
# sensitive = true
}
variable "ansible_key" {
type = string
description = "The public key for Ansible to login to the guest operating system."
# sensitive = true
}
// HCP Packer Settings
variable "common_hcp_packer_registry_enabled" {
type = bool
description = "Enable the HCP Packer registry."
default = false
}

View File

@@ -0,0 +1,97 @@
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# Debian 11 (Bullseye) Preseed File
# https://www.debian.org/releases/bullseye/amd64/
# Locale and Keyboard
d-i debian-installer/locale string ${vm_os_language}
d-i keyboard-configuration/xkb-keymap select ${vm_os_keyboard}
# Clock and Timezone
d-i clock-setup/utc boolean true
d-i clock-setup/ntp boolean true
d-i time/zone string ${vm_os_timezone}
# Grub and Reboot Message
d-i finish-install/reboot_in_progress note
d-i grub-installer/only_debian boolean true
# Partitioning
${storage}
# Network configuration
d-i netcfg/choose_interface select auto
d-i netcfg/get_hostname string unassigned-hostname
d-i netcfg/get_domain string unassigned-domain
### Apt setup
# Choose, if you want to scan additional installation media
# (default: false).
d-i apt-setup/cdrom/set-first boolean false
# You can choose to install non-free firmware.
#d-i apt-setup/non-free-firmware boolean true
# You can choose to install non-free and contrib software.
#d-i apt-setup/non-free boolean true
#d-i apt-setup/contrib boolean true
# Uncomment the following line, if you don't want to have the sources.list
# entry for a DVD/BD installation image active in the installed system
# (entries for netinst or CD images will be disabled anyway, regardless of
# this setting).
#d-i apt-setup/disable-cdrom-entries boolean true
# Uncomment this if you don't want to use a network mirror.
#d-i apt-setup/use_mirror boolean false
# Select which update services to use; define the mirrors to be used.
# Values shown below are the normal defaults.
#d-i apt-setup/services-select multiselect security, updates
#d-i apt-setup/security_host string security.debian.org
# Mirror settings
d-i mirror/country string manual
d-i mirror/http/hostname string cdn-fastly.deb.debian.org
d-i mirror/http/directory string /debian
d-i mirror/http/proxy string
# User Configuration
d-i passwd/root-login boolean false
d-i passwd/user-fullname string ${build_username}
d-i passwd/username string ${build_username}
d-i passwd/user-password-crypted password ${build_password_encrypted}
# Package Configuration
d-i pkgsel/run_tasksel boolean false
d-i pkgsel/include string openssh-server qemu-guest-agent python3
# You can choose, if your system will report back on what software you have
# installed, and what software you use. The default is not to report back,
# but sending reports helps the project determine what software is most
# popular and should be included on the first CD/DVD.
popularity-contest popularity-contest/participate boolean false
### Boot loader installation
# Grub is the boot loader (for x86).
# This is fairly safe to set, it makes grub install automatically to the UEFI
# partition/boot record if no other operating system is detected on the machine.
d-i grub-installer/only_debian boolean true
# Avoid that last message about the install being complete.
d-i finish-install/reboot_in_progress note
# Post-install script
# - Add User to Sudoers
# - Remove lv_delete volume group
d-i preseed/late_command string \
echo '${build_username} ALL=(ALL) NOPASSWD: ALL' > /target/etc/sudoers.d/${build_username} ; \
in-target chmod 440 /etc/sudoers.d/${build_username}%{ if length(lvm) != 0 ~} ; \
lvremove -f /dev/%{ for volume_group in lvm ~}${volume_group.name}%{ endfor ~}/lv_delete > /dev/null 2>&1%{ endif }
%{ if common_data_source == "disk" ~}
# Umount preseed media early
d-i preseed/early_command string \
umount /media && echo 1 > /sys/block/sr1/device/delete ;
%{ endif ~}

View File

@@ -0,0 +1,157 @@
%{~ if length(lvm) != 0 ~}
d-i partman-auto/method string lvm
d-i partman-auto-lvm/guided_size string max
d-i partman-lvm/confirm boolean true
d-i partman-lvm/confirm_nooverwrite boolean true
d-i partman-lvm/device_remove_lvm boolean true
%{~ for volume_group in lvm ~}
d-i partman-auto-lvm/new_vg_name string ${volume_group.name}
%{~ endfor ~}
%{~ endif ~}
d-i partman-efi/non_efi_system boolean true
# Ensure the partition table is GPT - this is required for EFI
d-i partman-partitioning/choose_label select gpt
d-i partman-partitioning/default_label string gpt
# If there is only one partition defined and its name is 'autopart'
# then use auto partitioning
%{~ if length(partitions) == 1 && partitions[0].name == "autopart" ~}
d-i partman-auto/disk string /dev/${device}
%{~ if partitions[0].format.fstype == "lvm" ~}
d-i partman-auto/method string lvm
# You can define the amount of space that will be used for the LVM volume
# group. It can either be a size with its unit (eg. 20 GB), a percentage of
# free space or the 'max' keyword.
d-i partman-auto-lvm/guided_size string max
# If one of the disks that are going to be automatically partitioned
# contains an old LVM configuration, the user will normally receive a
# warning. This can be preseeded away...
d-i partman-lvm/device_remove_lvm boolean true
# And the same goes for the confirmation to write the lvm partitions.
d-i partman-lvm/confirm boolean true
d-i partman-lvm/confirm_nooverwrite boolean true
%{~ endif ~}
%{~ if partitions[0].format.fstype == "simple" ~}
d-i partman-auto/method string regular
%{~ endif ~}
%{ if partitions[0].format.fstype == "" ~}
d-i partman-auto/method string regular
%{~ endif ~}
# You can choose one of the three predefined partitioning recipes:
# - atomic: all files in one partition
# - home: separate /home partition
# - multi: separate /home, /var, and /tmp partitions
d-i partman-auto/choose_recipe select atomic
%{~ else ~} # if length(partitions) == 1 && partitions[0].name == "autopart"
%{~ if swap == false ~}
d-i partman-basicfilesystems/no_swap boolean false
%{~ endif ~}
d-i partman-auto/expert_recipe string \
custom :: \
%{~ for partition in partitions ~}
%{~ if lookup(partition, "volume_group", "") == "" ~}
%{~ if partition.size != -1 ~}
${partition.size} ${partition.size} ${partition.size} ${partition.format.fstype} \
%{~ else ~}
100 100 -1 ${partition.format.fstype} \
%{~ endif ~}
$primary{ } \
%{~ if partition.mount.path == "/boot" ~}
$bootable{ } \
mountpoint{ /boot } \
method{ format } \
%{~ endif ~}
%{~ if partition.mount.path == "/boot/efi" ~}
mountpoint{ /boot/efi } \
method{ efi } \
%{~ endif ~}
%{~ if partition.mount.path != "/boot" && partition.mount.path != "/boot/efi" ~}
%{~ if partition.mount.path != "" ~}
mountpoint{ ${partition.mount.path} } \
%{~ endif ~}
method{ ${partition.format.fstype} } \
%{~ endif ~}
format{ } \
%{~ if partition.format.fstype != "swap" ~}
use_filesystem{ } \
%{~ if partition.format.fstype == "fat32" ~}
filesystem{ vfat } \
%{~ else ~}
filesystem{ ${partition.format.fstype} } \
%{~ endif ~}
%{~ endif ~}
label { ${partition.format.label} } \
%{~ for option in split(",", lookup(partition.mount, "options", "")) ~}
%{~ if option != "" ~}
options/${option}{ ${option} } \
%{~ endif ~}
%{~ endfor ~}
. \
%{~ else /* if lookup(partition, "volume_group", "") == "" */ ~}
%{~ for volume_group in lvm ~}
%{~ if volume_group.name == partition.volume_group ~}
%{~ for partition in volume_group.partitions ~}
%{ if partition.size != -1 ~}
%{ if partition.format.fstype == "swap" ~}
${partition.size} ${partition.size} ${partition.size} linux-swap \
%{~ else ~}
${partition.size} ${partition.size} ${partition.size} ${partition.format.fstype} \
%{~ endif ~}
%{~ else ~}
%{~ if partition.format.fstype != "swap" /* I don't know who would fill their disk with swap but it could happen */ ~}
100 100 -1 ${partition.format.fstype} \
%{~ else ~}
100 100 -1 linux-swap \
%{~ endif ~}
%{ endif ~}
$lvmok{ } \
%{~ if partition.mount.path != "" ~}
mountpoint{ ${partition.mount.path} } \
%{~ endif ~}
lv_name{ ${partition.name} } \
in_vg { ${volume_group.name} } \
%{~ if partition.format.fstype == "swap" ~}
method{ swap } \
%{~ else ~}
method{ format } \
%{~ endif ~}
format{ } \
%{~ if partition.format.fstype != "swap" ~}
use_filesystem{ } \
filesystem{ ${partition.format.fstype} } \
%{~ endif ~}
label { ${partition.format.label} } \
%{~ for option in split(",", lookup(partition.mount, "options", "")) ~}
%{~ if option != "" ~}
options/${option}{ ${option} } \
%{~ endif ~}
%{~ endfor ~}
. \
%{~ endfor /* partition in volume_group.partitions */ ~}
1024 1024 1024 ext4 \
method{ lvm } \
$lvmok{ } \
lv_name{ lv_delete } \
mountpoint{ /tmp/lv_delete } \
. \
%{~ endif /* volume_group.name == partition.volume_group */ ~}
%{~ endfor /* for volume_group in lvm */ ~}
%{~ endif /* if lookup(partition, "volume_group", "") == "" */ ~}
%{~ endfor /* for partition in partitions */ ~}
%{~ endif /* if length(partitions) == 1 && partitions[0].name == "autopart" */ ~}
d-i partman-partitioning/confirm_write_new_label boolean true
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
d-i partman/confirm_nooverwrite boolean true
# To make sure the machine can boot we install grub on the first harddisk:
d-i grub-installer/bootdev string /dev/${device}

View File

@@ -0,0 +1,45 @@
/*
DESCRIPTION:
Ubuntu Server 22.04 LTS variables used by the Packer Plugin for Proxmox (proxmox-iso).
*/
// Guest Operating System Metadata
vm_os_language = "en_US"
vm_os_keyboard = "us"
vm_os_timezone = "UTC"
vm_os_family = "linux"
vm_os_name = "debian"
vm_os_version = "11"
// Virtual Machine Guest Operating System Setting
vm_os_type = "l26"
// Virtual Machine Hardware Settings
vm_bios = "seabios"
vm_cpu_count = 1
vm_cpu_sockets = 1
vm_cpu_type = "kvm64"
vm_mem_size = 2048
vm_disk_type = "virtio"
vm_disk_size = "32G"
vm_disk_format = "raw"
vm_storage_pool = "vm-data"
vm_disk_controller_type = "virtio-scsi-pci"
vm_network_card_model = "virtio"
vm_bridge_interface = "vmbr0"
vm_vlan_tag = "102"
// Removable Media Settings
iso_path = "iso"
iso_file = "debian-11.8.0-amd64-netinst.iso"
iso_checksum = "d7a74813a734083df30c8d35784926deaa36bc41e5c0766388e9f591ab056b72"
// Boot Settings
vm_boot = "order=virtio0;ide2;net0"
vm_boot_wait = "5s"
// EFI Settings
vm_firmware_path = "./OVMF.fd"
vm_efi_storage_pool = "vm-data"
vm_efi_pre_enrolled_keys = false
vm_efi_type = "4m"

View File

@@ -0,0 +1,201 @@
/*
DESCRIPTION:
Debian 11 template using the Packer Builder for Proxmox (proxmox-iso).
*/
// BLOCK: packer
// The Packer configuration.
packer {
required_version = ">= 1.9.1"
required_plugins {
ansible = {
source = "github.com/hashicorp/ansible"
version = "~> 1"
}
git = {
version = ">= 0.4.2"
source = "github.com/ethanmdavidson/git"
}
proxmox = {
version = ">= 1.0.6"
source = "github.com/hashicorp/proxmox"
}
}
}
// BLOCK: data
// Defines the data sources.
data "git-repository" "cwd" {}
// BLOCK: locals
// Defines the local variables.
locals {
build_by = "Built by: HashiCorp Packer ${packer.version}"
build_date = formatdate("DD-MM-YYYY hh:mm ZZZ", "${timestamp()}" )
build_version = data.git-repository.cwd.head
build_description = "Version: ${local.build_version}\nBuilt on: ${local.build_date}\n${local.build_by}\nCloud-Init: ${var.vm_cloud_init_enable}"
vm_disk_type = var.vm_disk_type == "virtio" ? "vda" : "sda"
manifest_date = formatdate("YYYY-MM-DD hh:mm:ss", timestamp())
manifest_path = "${path.cwd}/manifests/"
manifest_output = "${local.manifest_path}${local.manifest_date}.json"
data_source_content = {
"/preseed.cfg" = templatefile("${abspath(path.root)}/data/preseed.pkrtpl.hcl", {
build_username = var.build_username
build_password = var.build_password
build_password_encrypted = var.build_password_encrypted
vm_disk_type = local.vm_disk_type
vm_os_language = var.vm_os_language
vm_os_keyboard = var.vm_os_keyboard
vm_os_timezone = var.vm_os_timezone
common_data_source = var.common_data_source
# lvm needs to be here so late commands can access vg names
lvm = var.vm_disk_lvm
storage = templatefile("${abspath(path.root)}/data/storage.pkrtpl.hcl", {
device = var.vm_disk_device
swap = var.vm_disk_use_swap
partitions = var.vm_disk_partitions
lvm = var.vm_disk_lvm
vm_bios = var.vm_bios
})
})
}
data_source_command = var.common_data_source == "http" ? "url=http://{{.HTTPIP}}:{{.HTTPPort}}/preseed.cfg" : "file=/media/preseed.cfg"
vm_name = "${var.vm_os_family}-${var.vm_os_name}-${var.vm_os_version}"
vm_bios = var.vm_bios == "ovmf" ? var.vm_firmware_path : null
}
// BLOCK: source
// Defines the builder configuration blocks.
source "proxmox-iso" "debian" {
// Proxmox Connection Settings and Credentials
proxmox_url = "https://${var.proxmox_hostname}:8006/api2/json"
username = "${var.proxmox_api_token_id}"
token = "${var.proxmox_api_token_secret}"
insecure_skip_tls_verify = "${var.proxmox_insecure_connection}"
// Proxmox Settings
node = "${var.proxmox_node}"
// Virtual Machine Settings
vm_name = "${local.vm_name}"
bios = "${var.vm_bios}"
sockets = "${var.vm_cpu_sockets}"
cores = "${var.vm_cpu_count}"
cpu_type = "${var.vm_cpu_type}"
memory = "${var.vm_mem_size}"
os = "${var.vm_os_type}"
scsi_controller = "${var.vm_disk_controller_type}"
disks {
disk_size = "${var.vm_disk_size}"
type = "${var.vm_disk_type}"
storage_pool = "${var.vm_storage_pool}"
format = "${var.vm_disk_format}"
}
dynamic "efi_config" {
for_each = var.vm_bios == "ovmf" ? [1] : []
content {
efi_storage_pool = var.vm_bios == "ovmf" ? var.vm_efi_storage_pool : null
efi_type = var.vm_bios == "ovmf" ? var.vm_efi_type : null
pre_enrolled_keys = var.vm_bios == "ovmf" ? var.vm_efi_pre_enrolled_keys : null
}
}
unmount_iso = true
ssh_username = "${var.build_username}"
ssh_password = "${var.build_password}"
ssh_timeout = "${var.timeout}"
ssh_port = "22"
iso_file = "${var.common_iso_storage}:${var.iso_path}/${var.iso_file}"
iso_checksum = "${var.iso_checksum}"
qemu_agent = true
network_adapters {
bridge = "${var.vm_bridge_interface}"
model = "${var.vm_network_card_model}"
vlan_tag = "${var.vm_vlan_tag}"
}
// Removable Media Settings
http_content = "${var.common_data_source}" == "http" ? "${local.data_source_content}" : null
// Boot and Provisioning Settings
http_bind_address = var.common_data_source == "http" ? var.common_http_bind_address : null
http_port_min = var.common_data_source == "http" ? var.common_http_port_min : null
http_port_max = var.common_data_source == "http" ? var.common_http_port_max : null
boot = var.vm_boot
boot_wait = var.vm_boot_wait
boot_command = [
"<wait><wait><wait><esc><wait><wait><wait>",
"/install.amd/vmlinuz ",
"initrd=/install.amd/initrd.gz ",
"auto=true ",
"${local.data_source_command} ",
"netcfg/get_hostname=debian netcfg/get_domain=example.com ",
"interface=auto ",
"vga=788 noprompt quiet --<enter>"
]
dynamic "additional_iso_files" {
for_each = var.common_data_source == "disk" ? [1] : []
content {
cd_files = var.common_data_source == "disk" ? local.data_source_content : null
cd_label = var.common_data_source == "disk" ? "cidata" : null
iso_storage_pool = var.common_data_source == "disk" ? "local" : null
}
}
template_name = "${local.vm_name}"
template_description = "${local.build_description}"
# VM Cloud Init Settings
cloud_init = var.vm_cloud_init_enable
cloud_init_storage_pool = var.vm_cloud_init_enable == true ? var.vm_storage_pool : null
}
# Build Definition to create the VM Template
build {
sources = ["source.proxmox-iso.debian"]
provisioner "ansible" {
user = "${var.build_username}"
playbook_file = "${path.cwd}/ansible/main.yml"
roles_path = "${path.cwd}/ansible/roles"
ansible_env_vars = [
"ANSIBLE_CONFIG=${path.cwd}/ansible/ansible.cfg"
]
extra_arguments = [
"--extra-vars", "display_skipped_hosts=false",
"--extra-vars", "BUILD_USERNAME=${var.build_username}",
"--extra-vars", "BUILD_SECRET='${var.build_key}'",
"--extra-vars", "ANSIBLE_USERNAME=${var.ansible_username}",
"--extra-vars", "ANSIBLE_SECRET='${var.ansible_key}'",
"--extra-vars", "cloud_init='${var.vm_cloud_init_enable}'",
]
}
post-processor "manifest" {
output = local.manifest_output
strip_path = true
strip_time = true
custom_data = {
ansible_username = "${var.ansible_username}"
build_username = "${var.build_username}"
build_date = "${local.build_date}"
build_version = "${local.build_version}"
common_data_source = "${var.common_data_source}"
vm_cpu_sockets = "${var.vm_cpu_sockets}"
vm_cpu_count = "${var.vm_cpu_count}"
vm_disk_size = "${var.vm_disk_size}"
vm_bios = "${var.vm_bios}"
vm_os_type = "${var.vm_os_type}"
vm_mem_size = "${var.vm_mem_size}"
vm_network_card_model = "${var.vm_network_card_model}"
vm_cloud_init_enable = "${var.vm_cloud_init_enable}"
}
}
}

View File

@@ -0,0 +1,53 @@
/*
DESCRIPTION:
Debian 11 storage variables used by the Packer Plugin for Proxmox (proxmox-iso).
*/
// VM Storage Settings
variable "vm_disk_device" {
type = string
description = "The device for the virtual disk. (e.g. 'sda')"
}
variable "vm_disk_use_swap" {
type = bool
description = "Whether to use a swap partition."
}
variable "vm_disk_partitions" {
type = list(object({
name = string
size = number
format = object({
label = string
fstype = string
})
mount = object({
path = string
options = string
})
volume_group = string
}))
description = "The disk partitions for the virtual disk."
}
variable "vm_disk_lvm" {
type = list(object({
name = string
partitions = list(object({
name = string
size = number
format = object({
label = string
fstype = string
})
mount = object({
path = string
options = string
})
}))
}))
description = "The LVM configuration for the virtual disk."
default = []
}

View File

@@ -0,0 +1,297 @@
/*
DESCRIPTION:
Debian 11 variables using the Packer Builder for Proxmox (proxmox-iso).
*/
// BLOCK: variable
// Defines the input variables.
// Proxmox Credentials
variable "proxmox_hostname" {
type = string
description = "The FQDN or IP address of a Proxmox node. Only one node should be specified in a cluster."
}
variable "proxmox_api_token_id" {
type = string
description = "The token to login to the Proxmox node/cluster. The format is USER@REALM!TOKENID. (e.g. packer@pam!packer_pve_token)"
}
variable "proxmox_api_token_secret" {
type = string
description = "The secret for the API token used to login to the Proxmox API."
# sensitive = true
}
variable "proxmox_insecure_connection" {
description = "true/false to skip Proxmox TLS certificate checks."
type = bool
default = true
}
// Proxmox Settings
variable "proxmox_node" {
type = string
description = "The name of the Proxmox node that Packer will build templates on."
}
// Virtual Machine Settings
variable "vm_os_language" {
type = string
description = "The guest operating system language."
default = "en_US"
}
variable "vm_os_keyboard" {
type = string
description = "The guest operating system keyboard layout."
default = "us"
}
variable "vm_os_timezone" {
type = string
description = "The guest operating system timezone."
default = "UTC"
}
variable "vm_os_family" {
type = string
description = "The guest operating system family. Used for naming. (e.g. 'linux')"
}
variable "vm_os_name" {
type = string
description = "The guest operating system name. Used for naming. (e.g. 'ubuntu')"
}
variable "vm_os_version" {
type = string
description = "The guest operating system version. Used for naming. (e.g. '22-04-lts')"
}
variable "vm_os_type" {
type = string
description = "The guest operating system type. (e.g. 'l26')"
}
variable "vm_bios" {
type = string
description = "The firmware type. Allowed values 'ovmf' or 'seabios'"
default = "OVMF"
validation {
condition = contains(["ovmf", "seabios"], var.vm_bios)
error_message = "The vm_bios value must be 'ovmf' or 'seabios'."
}
}
variable "vm_firmware_path" {
type = string
description = "The firmware file to be used. Needed for EFI"
default = "/usr/share/ovmf/OVMF.fd"
}
variable "vm_efi_storage_pool" {
type = string
description = "Set the UEFI disk storage location. (e.g. 'local-lvm')"
}
variable "vm_efi_type" {
type = string
description = "Specifies the version of the OVMF firmware to be used. (e.g. '4m')"
}
variable "vm_efi_pre_enrolled_keys" {
type = bool
description = "Whether Microsoft Standard Secure Boot keys should be pre-loaded on the EFI disk. (e.g. false)"
}
variable "vm_cpu_count" {
type = number
description = "The number of virtual CPUs. (e.g. '2')"
}
variable "vm_cpu_sockets" {
type = number
description = "The number of virtual CPU sockets. (e.g. '1')"
}
variable "vm_cpu_type" {
type = string
description = "The CPU type to emulate. See the Proxmox API documentation for the complete list of accepted values. For best performance, set this to host. Defaults to kvm64."
}
variable "vm_mem_size" {
type = number
description = "The size for the virtual memory in MB. (e.g. '2048')"
}
variable "vm_disk_controller_type" {
type = string
description = "The SCSI controller model to emulate. (e.g. 'virtio-scsi-pci')"
}
variable "vm_disk_type" {
type = string
description = "The type of disk to emulate. (e.g. 'virtio')"
}
variable "vm_storage_pool" {
type = string
description = "The name of the Proxmox storage pool to store the VM template. (e.g. 'local-lvm')"
}
variable "vm_disk_size" {
type = string
description = "The size for the virtual disk in GB. (e.g. '32G')"
}
variable "vm_disk_format" {
type = string
description = "The format of the file backing the disk. (e.g. 'qcow2')"
}
variable "vm_network_card_model" {
type = string
description = "The model of the virtual network adapter to emulate. (e.g. 'virtio')"
}
variable "vm_bridge_interface" {
type = string
description = "The name of the Proxmox bridge to attach the adapter to."
}
variable "vm_vlan_tag" {
type = string
description = "If the adapter should tag packets, give the VLAN ID. (e.g. '102')"
}
// Cloud-Init Settings
variable "vm_cloud_init_enable" {
type = bool
description = "Enable or disable cloud-init drive in Proxmox. (e.g. false)"
default = false
}
// Removable Media Settings
variable "common_iso_storage" {
type = string
description = "The name of the source Proxmox storage location for ISO images. (e.g. 'local-lvm')"
}
variable "iso_path" {
type = string
description = "The path on the source Proxmox storage location for ISO images. (e.g. 'iso')"
}
variable "iso_file" {
type = string
description = "The file name of the ISO image used by the vendor. (e.g. 'ubuntu-<version>-live-server-amd64.iso')"
}
variable "iso_checksum" {
type = string
description = "The checksum value of the ISO image provided by the vendor."
}
// Boot Settings
variable "common_data_source" {
type = string
description = "The provisioning data source. (e.g. 'http' or 'disk')"
}
variable "common_http_bind_address" {
type = string
description = "Define an IP address on the host to use for the HTTP server."
default = null
}
variable "common_http_port_min" {
type = number
description = "The start of the HTTP port range."
}
variable "common_http_port_max" {
type = number
description = "The end of the HTTP port range."
}
variable "vm_boot" {
type = string
description = "The boot order for virtual machine devices. (e.g. 'order=virtio0;ide2;net0')"
}
variable "vm_boot_wait" {
type = string
description = "The time to wait after booting the initial VM before typing the boot_command (e.g '10s')"
}
variable "common_ip_wait_timeout" {
type = string
description = "Time to wait for guest operating system IP address response."
}
variable "common_shutdown_timeout" {
type = string
description = "Time to wait for guest operating system shutdown."
}
// Communicator Settings and Credentials
variable "build_username" {
type = string
description = "The username to login to the guest operating system. (e.g. 'ubuntu')"
# sensitive = true
}
variable "build_password" {
type = string
description = "The password to login to the guest operating system."
# sensitive = true
}
variable "build_password_encrypted" {
type = string
description = "The encrypted password to login to the guest operating system."
# sensitive = true
}
variable "build_key" {
type = string
description = "The SSH public key to login to the guest operating system."
# sensitive = true
}
variable "timeout" {
description = "not sure why I need so high a timeout but here we are"
default = "90m"
}
// Ansible Credentials
variable "ansible_username" {
type = string
description = "The username for Ansible to login to the guest operating system. (e.g. 'ansible')"
# sensitive = true
}
variable "ansible_key" {
type = string
description = "The public key for Ansible to login to the guest operating system."
# sensitive = true
}
// HCP Packer Settings
variable "common_hcp_packer_registry_enabled" {
type = bool
description = "Enable the HCP Packer registry."
default = false
}

View File

@@ -0,0 +1,97 @@
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# Debian 11 (Bullseye) Preseed File
# https://www.debian.org/releases/bullseye/amd64/
# Locale and Keyboard
d-i debian-installer/locale string ${vm_os_language}
d-i keyboard-configuration/xkb-keymap select ${vm_os_keyboard}
# Clock and Timezone
d-i clock-setup/utc boolean true
d-i clock-setup/ntp boolean true
d-i time/zone string ${vm_os_timezone}
# Grub and Reboot Message
d-i finish-install/reboot_in_progress note
d-i grub-installer/only_debian boolean true
# Partitioning
${storage}
# Network configuration
d-i netcfg/choose_interface select auto
d-i netcfg/get_hostname string unassigned-hostname
d-i netcfg/get_domain string unassigned-domain
### Apt setup
# Choose, if you want to scan additional installation media
# (default: false).
d-i apt-setup/cdrom/set-first boolean false
# You can choose to install non-free firmware.
#d-i apt-setup/non-free-firmware boolean true
# You can choose to install non-free and contrib software.
#d-i apt-setup/non-free boolean true
#d-i apt-setup/contrib boolean true
# Uncomment the following line, if you don't want to have the sources.list
# entry for a DVD/BD installation image active in the installed system
# (entries for netinst or CD images will be disabled anyway, regardless of
# this setting).
#d-i apt-setup/disable-cdrom-entries boolean true
# Uncomment this if you don't want to use a network mirror.
#d-i apt-setup/use_mirror boolean false
# Select which update services to use; define the mirrors to be used.
# Values shown below are the normal defaults.
#d-i apt-setup/services-select multiselect security, updates
#d-i apt-setup/security_host string security.debian.org
# Mirror settings
d-i mirror/country string manual
d-i mirror/http/hostname string cdn-fastly.deb.debian.org
d-i mirror/http/directory string /debian
d-i mirror/http/proxy string
# User Configuration
d-i passwd/root-login boolean false
d-i passwd/user-fullname string ${build_username}
d-i passwd/username string ${build_username}
d-i passwd/user-password-crypted password ${build_password_encrypted}
# Package Configuration
d-i pkgsel/run_tasksel boolean false
d-i pkgsel/include string openssh-server qemu-guest-agent python3
# You can choose, if your system will report back on what software you have
# installed, and what software you use. The default is not to report back,
# but sending reports helps the project determine what software is most
# popular and should be included on the first CD/DVD.
popularity-contest popularity-contest/participate boolean false
### Boot loader installation
# Grub is the boot loader (for x86).
# This is fairly safe to set, it makes grub install automatically to the UEFI
# partition/boot record if no other operating system is detected on the machine.
d-i grub-installer/only_debian boolean true
# Avoid that last message about the install being complete.
d-i finish-install/reboot_in_progress note
# Post-install script
# - Add User to Sudoers
# - Remove lv_delete volume group
d-i preseed/late_command string \
echo '${build_username} ALL=(ALL) NOPASSWD: ALL' > /target/etc/sudoers.d/${build_username} ; \
in-target chmod 440 /etc/sudoers.d/${build_username}%{ if length(lvm) != 0 ~} ; \
lvremove -f /dev/%{ for volume_group in lvm ~}${volume_group.name}%{ endfor ~}/lv_delete > /dev/null 2>&1%{ endif }
%{ if common_data_source == "disk" ~}
# Umount preseed media early
d-i preseed/early_command string \
umount /media && echo 1 > /sys/block/sr1/device/delete ;
%{ endif ~}

View File

@@ -0,0 +1,157 @@
%{~ if length(lvm) != 0 ~}
d-i partman-auto/method string lvm
d-i partman-auto-lvm/guided_size string max
d-i partman-lvm/confirm boolean true
d-i partman-lvm/confirm_nooverwrite boolean true
d-i partman-lvm/device_remove_lvm boolean true
%{~ for volume_group in lvm ~}
d-i partman-auto-lvm/new_vg_name string ${volume_group.name}
%{~ endfor ~}
%{~ endif ~}
d-i partman-efi/non_efi_system boolean true
# Ensure the partition table is GPT - this is required for EFI
d-i partman-partitioning/choose_label select gpt
d-i partman-partitioning/default_label string gpt
# If there is only one partition defined and its name is 'autopart'
# then use auto partitioning
%{~ if length(partitions) == 1 && partitions[0].name == "autopart" ~}
d-i partman-auto/disk string /dev/${device}
%{~ if partitions[0].format.fstype == "lvm" ~}
d-i partman-auto/method string lvm
# You can define the amount of space that will be used for the LVM volume
# group. It can either be a size with its unit (eg. 20 GB), a percentage of
# free space or the 'max' keyword.
d-i partman-auto-lvm/guided_size string max
# If one of the disks that are going to be automatically partitioned
# contains an old LVM configuration, the user will normally receive a
# warning. This can be preseeded away...
d-i partman-lvm/device_remove_lvm boolean true
# And the same goes for the confirmation to write the lvm partitions.
d-i partman-lvm/confirm boolean true
d-i partman-lvm/confirm_nooverwrite boolean true
%{~ endif ~}
%{~ if partitions[0].format.fstype == "simple" ~}
d-i partman-auto/method string regular
%{~ endif ~}
%{ if partitions[0].format.fstype == "" ~}
d-i partman-auto/method string regular
%{~ endif ~}
# You can choose one of the three predefined partitioning recipes:
# - atomic: all files in one partition
# - home: separate /home partition
# - multi: separate /home, /var, and /tmp partitions
d-i partman-auto/choose_recipe select atomic
%{~ else ~} # if length(partitions) == 1 && partitions[0].name == "autopart"
%{~ if swap == false ~}
d-i partman-basicfilesystems/no_swap boolean false
%{~ endif ~}
d-i partman-auto/expert_recipe string \
custom :: \
%{~ for partition in partitions ~}
%{~ if lookup(partition, "volume_group", "") == "" ~}
%{~ if partition.size != -1 ~}
${partition.size} ${partition.size} ${partition.size} ${partition.format.fstype} \
%{~ else ~}
100 100 -1 ${partition.format.fstype} \
%{~ endif ~}
$primary{ } \
%{~ if partition.mount.path == "/boot" ~}
$bootable{ } \
mountpoint{ /boot } \
method{ format } \
%{~ endif ~}
%{~ if partition.mount.path == "/boot/efi" ~}
mountpoint{ /boot/efi } \
method{ efi } \
%{~ endif ~}
%{~ if partition.mount.path != "/boot" && partition.mount.path != "/boot/efi" ~}
%{~ if partition.mount.path != "" ~}
mountpoint{ ${partition.mount.path} } \
%{~ endif ~}
method{ ${partition.format.fstype} } \
%{~ endif ~}
format{ } \
%{~ if partition.format.fstype != "swap" ~}
use_filesystem{ } \
%{~ if partition.format.fstype == "fat32" ~}
filesystem{ vfat } \
%{~ else ~}
filesystem{ ${partition.format.fstype} } \
%{~ endif ~}
%{~ endif ~}
label { ${partition.format.label} } \
%{~ for option in split(",", lookup(partition.mount, "options", "")) ~}
%{~ if option != "" ~}
options/${option}{ ${option} } \
%{~ endif ~}
%{~ endfor ~}
. \
%{~ else /* if lookup(partition, "volume_group", "") == "" */ ~}
%{~ for volume_group in lvm ~}
%{~ if volume_group.name == partition.volume_group ~}
%{~ for partition in volume_group.partitions ~}
%{ if partition.size != -1 ~}
%{ if partition.format.fstype == "swap" ~}
${partition.size} ${partition.size} ${partition.size} linux-swap \
%{~ else ~}
${partition.size} ${partition.size} ${partition.size} ${partition.format.fstype} \
%{~ endif ~}
%{~ else ~}
%{~ if partition.format.fstype != "swap" /* I don't know who would fill their disk with swap but it could happen */ ~}
100 100 -1 ${partition.format.fstype} \
%{~ else ~}
100 100 -1 linux-swap \
%{~ endif ~}
%{ endif ~}
$lvmok{ } \
%{~ if partition.mount.path != "" ~}
mountpoint{ ${partition.mount.path} } \
%{~ endif ~}
lv_name{ ${partition.name} } \
in_vg { ${volume_group.name} } \
%{~ if partition.format.fstype == "swap" ~}
method{ swap } \
%{~ else ~}
method{ format } \
%{~ endif ~}
format{ } \
%{~ if partition.format.fstype != "swap" ~}
use_filesystem{ } \
filesystem{ ${partition.format.fstype} } \
%{~ endif ~}
label { ${partition.format.label} } \
%{~ for option in split(",", lookup(partition.mount, "options", "")) ~}
%{~ if option != "" ~}
options/${option}{ ${option} } \
%{~ endif ~}
%{~ endfor ~}
. \
%{~ endfor /* partition in volume_group.partitions */ ~}
1024 1024 1024 ext4 \
method{ lvm } \
$lvmok{ } \
lv_name{ lv_delete } \
mountpoint{ /tmp/lv_delete } \
. \
%{~ endif /* volume_group.name == partition.volume_group */ ~}
%{~ endfor /* for volume_group in lvm */ ~}
%{~ endif /* if lookup(partition, "volume_group", "") == "" */ ~}
%{~ endfor /* for partition in partitions */ ~}
%{~ endif /* if length(partitions) == 1 && partitions[0].name == "autopart" */ ~}
d-i partman-partitioning/confirm_write_new_label boolean true
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
d-i partman/confirm_nooverwrite boolean true
# To make sure the machine can boot we install grub on the first harddisk:
d-i grub-installer/bootdev string /dev/${device}

View File

@@ -0,0 +1,45 @@
/*
DESCRIPTION:
Ubuntu Server 22.04 LTS variables used by the Packer Plugin for Proxmox (proxmox-iso).
*/
// Guest Operating System Metadata
vm_os_language = "en_US"
vm_os_keyboard = "us"
vm_os_timezone = "UTC"
vm_os_family = "linux"
vm_os_name = "debian"
vm_os_version = "12"
// Virtual Machine Guest Operating System Setting
vm_os_type = "l26"
// Virtual Machine Hardware Settings
vm_bios = "seabios"
vm_cpu_count = 1
vm_cpu_sockets = 1
vm_cpu_type = "kvm64"
vm_mem_size = 2048
vm_disk_type = "virtio"
vm_disk_size = "32G"
vm_disk_format = "raw"
vm_storage_pool = "vm-data"
vm_disk_controller_type = "virtio-scsi-pci"
vm_network_card_model = "virtio"
vm_bridge_interface = "vmbr0"
vm_vlan_tag = "102"
// Removable Media Settings
iso_path = "iso"
iso_file = "debian-12.2.0-amd64-netinst.iso"
iso_checksum = "file:https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/SHA512SUMS"
// Boot Settings
vm_boot = "order=virtio0;ide2;net0"
vm_boot_wait = "5s"
// EFI Settings
vm_firmware_path = "./OVMF.fd"
vm_efi_storage_pool = "vm-data"
vm_efi_pre_enrolled_keys = false
vm_efi_type = "4m"

View File

@@ -0,0 +1,202 @@
/*
DESCRIPTION:
Debian 11 template using the Packer Builder for Proxmox (proxmox-iso).
*/
// BLOCK: packer
// The Packer configuration.
packer {
required_version = ">= 1.9.1"
required_plugins {
ansible = {
source = "github.com/hashicorp/ansible"
version = "~> 1"
}
git = {
version = ">= 0.4.2"
source = "github.com/ethanmdavidson/git"
}
proxmox = {
version = ">= 1.0.6"
source = "github.com/hashicorp/proxmox"
}
}
}
// BLOCK: data
// Defines the data sources.
data "git-repository" "cwd" {}
// BLOCK: locals
// Defines the local variables.
locals {
build_by = "Built by: HashiCorp Packer ${packer.version}"
build_date = formatdate("DD-MM-YYYY hh:mm ZZZ", "${timestamp()}" )
build_version = data.git-repository.cwd.head
build_description = "Version: ${local.build_version}\nBuilt on: ${local.build_date}\n${local.build_by}\nCloud-Init: ${var.vm_cloud_init_enable}"
vm_disk_type = var.vm_disk_type == "virtio" ? "vda" : "sda"
manifest_date = formatdate("YYYY-MM-DD hh:mm:ss", timestamp())
manifest_path = "${path.cwd}/manifests/"
manifest_output = "${local.manifest_path}${local.manifest_date}.json"
data_source_content = {
"/preseed.cfg" = templatefile("${abspath(path.root)}/data/preseed.pkrtpl.hcl", {
build_username = var.build_username
build_password = var.build_password
build_password_encrypted = var.build_password_encrypted
vm_disk_type = local.vm_disk_type
vm_os_language = var.vm_os_language
vm_os_keyboard = var.vm_os_keyboard
vm_os_timezone = var.vm_os_timezone
common_data_source = var.common_data_source
# lvm needs to be here so late commands can access vg names
lvm = var.vm_disk_lvm
storage = templatefile("${abspath(path.root)}/data/storage.pkrtpl.hcl", {
device = var.vm_disk_device
swap = var.vm_disk_use_swap
partitions = var.vm_disk_partitions
lvm = var.vm_disk_lvm
vm_bios = var.vm_bios
})
})
}
data_source_command = var.common_data_source == "http" ? "url=http://{{.HTTPIP}}:{{.HTTPPort}}/preseed.cfg" : "file=/media/preseed.cfg"
vm_name = "${var.vm_os_family}-${var.vm_os_name}-${var.vm_os_version}"
vm_bios = var.vm_bios == "ovmf" ? var.vm_firmware_path : null
}
// BLOCK: source
// Defines the builder configuration blocks.
source "proxmox-iso" "debian" {
// Proxmox Connection Settings and Credentials
proxmox_url = "https://${var.proxmox_hostname}:8006/api2/json"
username = "${var.proxmox_api_token_id}"
token = "${var.proxmox_api_token_secret}"
insecure_skip_tls_verify = "${var.proxmox_insecure_connection}"
// Proxmox Settings
node = "${var.proxmox_node}"
// Virtual Machine Settings
vm_name = "${local.vm_name}"
bios = "${var.vm_bios}"
sockets = "${var.vm_cpu_sockets}"
cores = "${var.vm_cpu_count}"
cpu_type = "${var.vm_cpu_type}"
memory = "${var.vm_mem_size}"
os = "${var.vm_os_type}"
scsi_controller = "${var.vm_disk_controller_type}"
disks {
disk_size = "${var.vm_disk_size}"
type = "${var.vm_disk_type}"
storage_pool = "${var.vm_storage_pool}"
format = "${var.vm_disk_format}"
}
dynamic "efi_config" {
for_each = var.vm_bios == "ovmf" ? [1] : []
content {
efi_storage_pool = var.vm_bios == "ovmf" ? var.vm_efi_storage_pool : null
efi_type = var.vm_bios == "ovmf" ? var.vm_efi_type : null
pre_enrolled_keys = var.vm_bios == "ovmf" ? var.vm_efi_pre_enrolled_keys : null
}
}
unmount_iso = true
ssh_username = "${var.build_username}"
ssh_password = "${var.build_password}"
ssh_timeout = "${var.timeout}"
ssh_port = "22"
iso_file = "${var.common_iso_storage}:${var.iso_path}/${var.iso_file}"
iso_checksum = "${var.iso_checksum}"
qemu_agent = true
network_adapters {
bridge = "${var.vm_bridge_interface}"
model = "${var.vm_network_card_model}"
vlan_tag = "${var.vm_vlan_tag}"
}
// Removable Media Settings
http_content = "${var.common_data_source}" == "http" ? "${local.data_source_content}" : null
// Boot and Provisioning Settings
http_bind_address = var.common_data_source == "http" ? var.common_http_bind_address : null
http_port_min = var.common_data_source == "http" ? var.common_http_port_min : null
http_port_max = var.common_data_source == "http" ? var.common_http_port_max : null
boot = var.vm_boot
boot_wait = var.vm_boot_wait
boot_command = [
"<wait><wait><wait><esc><wait><wait><wait>",
"/install.amd/vmlinuz ",
"initrd=/install.amd/initrd.gz ",
"auto=true ",
"${local.data_source_command} ",
// "hostname=${var.vm_os_name}-${var.vm_os_version} ",
"netcfg/get_hostname=debian netcfg/get_domain=example.com ",
"interface=auto ",
"vga=788 noprompt quiet --<enter>"
]
dynamic "additional_iso_files" {
for_each = var.common_data_source == "disk" ? [1] : []
content {
cd_files = var.common_data_source == "disk" ? local.data_source_content : null
cd_label = var.common_data_source == "disk" ? "cidata" : null
iso_storage_pool = var.common_data_source == "disk" ? "local" : null
}
}
template_name = "${local.vm_name}"
template_description = "${local.build_description}"
# VM Cloud Init Settings
cloud_init = var.vm_cloud_init_enable
cloud_init_storage_pool = var.vm_cloud_init_enable == true ? var.vm_storage_pool : null
}
# Build Definition to create the VM Template
build {
sources = ["source.proxmox-iso.debian"]
provisioner "ansible" {
user = "${var.build_username}"
playbook_file = "${path.cwd}/ansible/main.yml"
roles_path = "${path.cwd}/ansible/roles"
ansible_env_vars = [
"ANSIBLE_CONFIG=${path.cwd}/ansible/ansible.cfg"
]
extra_arguments = [
"--extra-vars", "display_skipped_hosts=false",
"--extra-vars", "BUILD_USERNAME=${var.build_username}",
"--extra-vars", "BUILD_SECRET='${var.build_key}'",
"--extra-vars", "ANSIBLE_USERNAME=${var.ansible_username}",
"--extra-vars", "ANSIBLE_SECRET='${var.ansible_key}'",
"--extra-vars", "cloud_init='${var.vm_cloud_init_enable}'",
]
}
post-processor "manifest" {
output = local.manifest_output
strip_path = true
strip_time = true
custom_data = {
ansible_username = "${var.ansible_username}"
build_username = "${var.build_username}"
build_date = "${local.build_date}"
build_version = "${local.build_version}"
common_data_source = "${var.common_data_source}"
vm_cpu_sockets = "${var.vm_cpu_sockets}"
vm_cpu_count = "${var.vm_cpu_count}"
vm_disk_size = "${var.vm_disk_size}"
vm_bios = "${var.vm_bios}"
vm_os_type = "${var.vm_os_type}"
vm_mem_size = "${var.vm_mem_size}"
vm_network_card_model = "${var.vm_network_card_model}"
vm_cloud_init_enable = "${var.vm_cloud_init_enable}"
}
}
}

View File

@@ -0,0 +1,53 @@
/*
DESCRIPTION:
Debian 11 storage variables used by the Packer Plugin for Proxmox (proxmox-iso).
*/
// VM Storage Settings
variable "vm_disk_device" {
type = string
description = "The device for the virtual disk. (e.g. 'sda')"
}
variable "vm_disk_use_swap" {
type = bool
description = "Whether to use a swap partition."
}
variable "vm_disk_partitions" {
type = list(object({
name = string
size = number
format = object({
label = string
fstype = string
})
mount = object({
path = string
options = string
})
volume_group = string
}))
description = "The disk partitions for the virtual disk."
}
variable "vm_disk_lvm" {
type = list(object({
name = string
partitions = list(object({
name = string
size = number
format = object({
label = string
fstype = string
})
mount = object({
path = string
options = string
})
}))
}))
description = "The LVM configuration for the virtual disk."
default = []
}

View File

@@ -0,0 +1,297 @@
/*
DESCRIPTION:
Debian 11 variables using the Packer Builder for Proxmox (proxmox-iso).
*/
// BLOCK: variable
// Defines the input variables.
// Proxmox Credentials
variable "proxmox_hostname" {
type = string
description = "The FQDN or IP address of a Proxmox node. Only one node should be specified in a cluster."
}
variable "proxmox_api_token_id" {
type = string
description = "The token to login to the Proxmox node/cluster. The format is USER@REALM!TOKENID. (e.g. packer@pam!packer_pve_token)"
}
variable "proxmox_api_token_secret" {
type = string
description = "The secret for the API token used to login to the Proxmox API."
# sensitive = true
}
variable "proxmox_insecure_connection" {
description = "true/false to skip Proxmox TLS certificate checks."
type = bool
default = true
}
// Proxmox Settings
variable "proxmox_node" {
type = string
description = "The name of the Proxmox node that Packer will build templates on."
}
// Virtual Machine Settings
variable "vm_os_language" {
type = string
description = "The guest operating system language."
default = "en_US"
}
variable "vm_os_keyboard" {
type = string
description = "The guest operating system keyboard layout."
default = "us"
}
variable "vm_os_timezone" {
type = string
description = "The guest operating system timezone."
default = "UTC"
}
variable "vm_os_family" {
type = string
description = "The guest operating system family. Used for naming. (e.g. 'linux')"
}
variable "vm_os_name" {
type = string
description = "The guest operating system name. Used for naming. (e.g. 'ubuntu')"
}
variable "vm_os_version" {
type = string
description = "The guest operating system version. Used for naming. (e.g. '22-04-lts')"
}
variable "vm_os_type" {
type = string
description = "The guest operating system type. (e.g. 'l26')"
}
variable "vm_bios" {
type = string
description = "The firmware type. Allowed values 'ovmf' or 'seabios'"
default = "OVMF"
validation {
condition = contains(["ovmf", "seabios"], var.vm_bios)
error_message = "The vm_bios value must be 'ovmf' or 'seabios'."
}
}
variable "vm_firmware_path" {
type = string
description = "The firmware file to be used. Needed for EFI"
default = "/usr/share/ovmf/OVMF.fd"
}
variable "vm_efi_storage_pool" {
type = string
description = "Set the UEFI disk storage location. (e.g. 'local-lvm')"
}
variable "vm_efi_type" {
type = string
description = "Specifies the version of the OVMF firmware to be used. (e.g. '4m')"
}
variable "vm_efi_pre_enrolled_keys" {
type = bool
description = "Whether Microsoft Standard Secure Boot keys should be pre-loaded on the EFI disk. (e.g. false)"
}
variable "vm_cpu_count" {
type = number
description = "The number of virtual CPUs. (e.g. '2')"
}
variable "vm_cpu_sockets" {
type = number
description = "The number of virtual CPU sockets. (e.g. '1')"
}
variable "vm_cpu_type" {
type = string
description = "The CPU type to emulate. See the Proxmox API documentation for the complete list of accepted values. For best performance, set this to host. Defaults to kvm64."
}
variable "vm_mem_size" {
type = number
description = "The size for the virtual memory in MB. (e.g. '2048')"
}
variable "vm_disk_controller_type" {
type = string
description = "The SCSI controller model to emulate. (e.g. 'virtio-scsi-pci')"
}
variable "vm_disk_type" {
type = string
description = "The type of disk to emulate. (e.g. 'virtio')"
}
variable "vm_storage_pool" {
type = string
description = "The name of the Proxmox storage pool to store the VM template. (e.g. 'local-lvm')"
}
variable "vm_disk_size" {
type = string
description = "The size for the virtual disk in GB. (e.g. '32G')"
}
variable "vm_disk_format" {
type = string
description = "The format of the file backing the disk. (e.g. 'qcow2')"
}
variable "vm_network_card_model" {
type = string
description = "The model of the virtual network adapter to emulate. (e.g. 'virtio')"
}
variable "vm_bridge_interface" {
type = string
description = "The name of the Proxmox bridge to attach the adapter to."
}
variable "vm_vlan_tag" {
type = string
description = "If the adapter should tag packets, give the VLAN ID. (e.g. '102')"
}
// Cloud-Init Settings
variable "vm_cloud_init_enable" {
type = bool
description = "Enable or disable cloud-init drive in Proxmox. (e.g. false)"
default = false
}
// Removable Media Settings
variable "common_iso_storage" {
type = string
description = "The name of the source Proxmox storage location for ISO images. (e.g. 'local-lvm')"
}
variable "iso_path" {
type = string
description = "The path on the source Proxmox storage location for ISO images. (e.g. 'iso')"
}
variable "iso_file" {
type = string
description = "The file name of the ISO image used by the vendor. (e.g. 'ubuntu-<version>-live-server-amd64.iso')"
}
variable "iso_checksum" {
type = string
description = "The checksum value of the ISO image provided by the vendor."
}
// Boot Settings
variable "common_data_source" {
type = string
description = "The provisioning data source. (e.g. 'http' or 'disk')"
}
variable "common_http_bind_address" {
type = string
description = "Define an IP address on the host to use for the HTTP server."
default = null
}
variable "common_http_port_min" {
type = number
description = "The start of the HTTP port range."
}
variable "common_http_port_max" {
type = number
description = "The end of the HTTP port range."
}
variable "vm_boot" {
type = string
description = "The boot order for virtual machine devices. (e.g. 'order=virtio0;ide2;net0')"
}
variable "vm_boot_wait" {
type = string
description = "The time to wait after booting the initial VM before typing the boot_command (e.g '10s')"
}
variable "common_ip_wait_timeout" {
type = string
description = "Time to wait for guest operating system IP address response."
}
variable "common_shutdown_timeout" {
type = string
description = "Time to wait for guest operating system shutdown."
}
// Communicator Settings and Credentials
variable "build_username" {
type = string
description = "The username to login to the guest operating system. (e.g. 'ubuntu')"
# sensitive = true
}
variable "build_password" {
type = string
description = "The password to login to the guest operating system."
# sensitive = true
}
variable "build_password_encrypted" {
type = string
description = "The encrypted password to login to the guest operating system."
# sensitive = true
}
variable "build_key" {
type = string
description = "The SSH public key to login to the guest operating system."
# sensitive = true
}
variable "timeout" {
description = "not sure why I need so high a timeout but here we are"
default = "90m"
}
// Ansible Credentials
variable "ansible_username" {
type = string
description = "The username for Ansible to login to the guest operating system. (e.g. 'ansible')"
# sensitive = true
}
variable "ansible_key" {
type = string
description = "The public key for Ansible to login to the guest operating system."
# sensitive = true
}
// HCP Packer Settings
variable "common_hcp_packer_registry_enabled" {
type = bool
description = "Enable the HCP Packer registry."
default = false
}

View File

@@ -0,0 +1,109 @@
%{~ if length(partitions) == 1 && partitions[0].name == "autopart" ~}
%{~ if partitions[0].format.fstype == "lvm" ~}
storage:
layout:
name: lvm
%{~ endif ~}
%{~ if partitions[0].format.fstype == "simple" ~}
storage:
layout:
name: direct
%{~ endif ~}
%{~ if partitions[0].format.fstype == "" ~}
storage:
layout:
name: direct
%{~ endif ~}
%{~ else ~}
storage:
config:
- ptable: gpt
path: /dev/${device}
wipe: superblock
preserve: false
name: ''
%{ if vm_bios == "ovmf" ~}
grub_device: false
%{ endif ~}
%{ if vm_bios == "seabios" ~}
grub_device: true
%{ endif ~}
type: disk
id: disk-${device}
# BIOS boot partition
%{ for index, partition in partitions ~}
- device: disk-${device}
%{ if partition.size != -1 ~}
size: ${partition.size}M
%{ else ~}
size: ${partition.size}
%{ endif ~}
wipe: superblock
preserve: false
%{ if partition.name == "bios_grub" && vm_bios == "seabios" && index == 0 ~}
flag: bios_grub
grub_device: false
%{ endif ~}
%{ if partition.mount.path == "/boot/efi" && index == 0 ~}
flag: boot
grub_device: true
%{ endif ~}
type: partition
id: partition-${partition.name}
%{ if partition.format.fstype != "" ~}
- id: format-${partition.name}
type: format
volume: partition-${partition.name}
label: ${partition.format.label}
fstype: ${partition.format.fstype}
%{ endif ~}
# Don't create a mount for the GRUB partition when using BIOS
%{ if partition.volume_group == "" && partition.name != "bios_grub" ~}
- id: mount-${partition.name}
type: mount
%{ if partition.mount.path == "" ~}
path: none
%{ else ~}
path: ${partition.mount.path}
%{ endif ~}
device: format-${partition.name}
%{ if partition.mount.options != "" ~}
options: ${partition.mount.options}
%{ endif ~}
%{ endif ~}
%{ endfor ~}
%{ for index, volume_group in lvm ~}
- id: volgroup-${volume_group.name}
type: lvm_volgroup
name: ${volume_group.name}
devices:
%{ for index, partition in partitions ~}
%{ if lookup(partition, "volume_group", "") == volume_group.name ~}
- partition-${partition.name}
%{ endif ~}
%{ endfor ~}
%{ for index, partition in volume_group.partitions ~}
- id: partition-${partition.name}
type: lvm_partition
name: ${partition.name}
size: ${partition.size}M
volgroup: volgroup-${volume_group.name}
- id: format-${partition.name}
type: format
volume: partition-${partition.name}
label: ${partition.format.label}
fstype: ${partition.format.fstype}
- id: mount-${partition.name}
type: mount
%{ if partition.mount.path == "" ~}
path: none
%{ else ~}
path: ${partition.mount.path}
%{ endif ~}
device: format-${partition.name}
%{ if partition.mount.options != "" ~}
options: ${partition.mount.options}
%{ endif ~}
%{ endfor ~}
%{ endfor ~}
%{~ endif ~}

View File

@@ -0,0 +1,35 @@
#cloud-config
autoinstall:
version: 1
apt:
geoip: true
preserve_sources_list: false
primary:
- arches: [amd64, i386]
uri: http://archive.ubuntu.com/ubuntu
- arches: [default]
uri: http://ports.ubuntu.com/ubuntu-ports
early-commands:
- sudo systemctl stop ssh
locale: ${vm_os_language}
keyboard:
layout: ${vm_os_keyboard}
${storage}
identity:
hostname: ubuntu-server
username: ${build_username}
password: ${build_password_encrypted}
ssh:
install-server: true
allow-pw: true
packages:
- openssh-server
- qemu-guest-agent
- cloud-init
user-data:
disable_root: false
timezone: ${vm_os_timezone}
late-commands:
- sed -i -e 's/^#\?PasswordAuthentication.*/PasswordAuthentication yes/g' /target/etc/ssh/sshd_config
- echo '${build_username} ALL=(ALL) NOPASSWD:ALL' > /target/etc/sudoers.d/${build_username}
- curtin in-target --target=/target -- chmod 440 /etc/sudoers.d/${build_username}

View File

@@ -0,0 +1,45 @@
/*
DESCRIPTION:
Ubuntu Server 20.04 LTS variables used by the Packer Plugin for Proxmox (proxmox-iso).
*/
// Guest Operating System Metadata
vm_os_language = "en_US"
vm_os_keyboard = "us"
vm_os_timezone = "UTC"
vm_os_family = "linux"
vm_os_name = "ubuntu"
vm_os_version = "20.04-lts"
// Virtual Machine Guest Operating System Setting
vm_os_type = "l26"
// Virtual Machine Hardware Settings
vm_bios = "seabios"
vm_cpu_count = 1
vm_cpu_sockets = 1
vm_cpu_type = "kvm64"
vm_mem_size = 2048
vm_disk_type = "virtio"
vm_disk_size = "32G"
vm_disk_format = "raw"
vm_storage_pool = "vm-data"
vm_disk_controller_type = "virtio-scsi-pci"
vm_network_card_model = "virtio"
vm_bridge_interface = "vmbr0"
vm_vlan_tag = "102"
// Removable Media Settings
iso_path = "iso"
iso_file = "ubuntu-20.04-live-server-amd64.iso"
iso_checksum = "caf3fd69c77c439f162e2ba6040e9c320c4ff0d69aad1340a514319a9264df9f"
// Boot Settings
vm_boot = "order=virtio0;ide2;net0"
vm_boot_wait = "5s"
// EFI Settings
vm_firmware_path = "./OVMF.fd"
vm_efi_storage_pool = "vm-data"
vm_efi_pre_enrolled_keys = false
vm_efi_type = "4m"

View File

@@ -0,0 +1,200 @@
/*
DESCRIPTION:
Ubuntu Server 20.04 LTS template using the Packer Builder for Proxmox (proxmox-iso).
*/
// BLOCK: packer
// The Packer configuration.
packer {
required_version = ">= 1.9.1"
required_plugins {
ansible = {
source = "github.com/hashicorp/ansible"
version = "~> 1"
}
git = {
version = ">= 0.4.2"
source = "github.com/ethanmdavidson/git"
}
proxmox = {
version = ">= 1.0.6"
source = "github.com/hashicorp/proxmox"
}
}
}
// BLOCK: data
// Defines the data sources.
data "git-repository" "cwd" {}
// BLOCK: locals
// Defines the local variables.
locals {
build_by = "Built by: HashiCorp Packer ${packer.version}"
build_date = formatdate("DD-MM-YYYY hh:mm ZZZ", "${timestamp()}" )
build_version = data.git-repository.cwd.head
build_description = "Version: ${local.build_version}\nBuilt on: ${local.build_date}\n${local.build_by}\nCloud-Init: ${var.vm_cloud_init_enable}"
vm_disk_type = var.vm_disk_type == "virtio" ? "vda" : "sda"
manifest_date = formatdate("YYYY-MM-DD hh:mm:ss", timestamp())
manifest_path = "${path.cwd}/manifests/"
manifest_output = "${local.manifest_path}${local.manifest_date}.json"
data_source_content = {
"/meta-data" = file("${abspath(path.root)}/data/meta-data")
"/user-data" = templatefile("${abspath(path.root)}/data/user-data.pkrtpl.hcl", {
build_username = var.build_username
build_password = var.build_password
build_password_encrypted = var.build_password_encrypted
vm_disk_type = local.vm_disk_type
vm_os_language = var.vm_os_language
vm_os_keyboard = var.vm_os_keyboard
vm_os_timezone = var.vm_os_timezone
storage = templatefile("${abspath(path.root)}/data/storage.pkrtpl.hcl", {
device = var.vm_disk_device
swap = var.vm_disk_use_swap
partitions = var.vm_disk_partitions
lvm = var.vm_disk_lvm
vm_bios = var.vm_bios
})
})
}
# For some reason 20.04 doesn't like quotes in the boot commands
data_source_command = var.common_data_source == "http" ? "ds=nocloud-net;seedfrom=http://{{.HTTPIP}}:{{.HTTPPort}}/" : "ds=nocloud"
vm_name = "${var.vm_os_family}-${var.vm_os_name}-${var.vm_os_version}"
vm_bios = var.vm_bios == "ovmf" ? var.vm_firmware_path : null
}
// BLOCK: source
// Defines the builder configuration blocks.
source "proxmox-iso" "ubuntu" {
// Proxmox Connection Settings and Credentials
proxmox_url = "https://${var.proxmox_hostname}:8006/api2/json"
username = "${var.proxmox_api_token_id}"
token = "${var.proxmox_api_token_secret}"
insecure_skip_tls_verify = "${var.proxmox_insecure_connection}"
// Proxmox Settings
node = "${var.proxmox_node}"
// Virtual Machine Settings
vm_name = "${local.vm_name}"
bios = "${var.vm_bios}"
sockets = "${var.vm_cpu_sockets}"
cores = "${var.vm_cpu_count}"
cpu_type = "${var.vm_cpu_type}"
memory = "${var.vm_mem_size}"
os = "${var.vm_os_type}"
scsi_controller = "${var.vm_disk_controller_type}"
disks {
disk_size = "${var.vm_disk_size}"
type = "${var.vm_disk_type}"
storage_pool = "${var.vm_storage_pool}"
format = "${var.vm_disk_format}"
}
dynamic "efi_config" {
for_each = var.vm_bios == "ovmf" ? [1] : []
content {
efi_storage_pool = var.vm_bios == "ovmf" ? var.vm_efi_storage_pool : null
efi_type = var.vm_bios == "ovmf" ? var.vm_efi_type : null
pre_enrolled_keys = var.vm_bios == "ovmf" ? var.vm_efi_pre_enrolled_keys : null
}
}
unmount_iso = true
ssh_username = "${var.build_username}"
ssh_password = "${var.build_password}"
ssh_timeout = "${var.timeout}"
ssh_port = "22"
iso_file = "${var.common_iso_storage}:${var.iso_path}/${var.iso_file}"
iso_checksum = "${var.iso_checksum}"
qemu_agent = true
network_adapters {
bridge = "${var.vm_bridge_interface}"
model = "${var.vm_network_card_model}"
vlan_tag = "${var.vm_vlan_tag}"
}
// Removable Media Settings
http_content = "${var.common_data_source}" == "http" ? "${local.data_source_content}" : null
// Boot and Provisioning Settings
http_bind_address = var.common_data_source == "http" ? var.common_http_bind_address : null
http_port_min = var.common_data_source == "http" ? var.common_http_port_min : null
http_port_max = var.common_data_source == "http" ? var.common_http_port_max : null
boot = var.vm_boot
boot_wait = var.vm_boot_wait
boot_command = [
"<esc><esc><esc>",
"<enter><wait>",
"/casper/vmlinuz ",
"root=/dev/sr0 ",
"initrd=/casper/initrd ",
"autoinstall ",
"${local.data_source_command}",
"<enter>"
]
dynamic "additional_iso_files" {
for_each = var.common_data_source == "disk" ? [1] : []
content {
cd_files = var.common_data_source == "disk" ? local.data_source_content : null
cd_label = var.common_data_source == "disk" ? "cidata" : null
iso_storage_pool = var.common_data_source == "disk" ? "local" : null
}
}
template_name = "${local.vm_name}"
template_description = "${local.build_description}"
# VM Cloud Init Settings
cloud_init = var.vm_cloud_init_enable
cloud_init_storage_pool = var.vm_cloud_init_enable == true ? var.vm_storage_pool : null
}
# Build Definition to create the VM Template
build {
sources = ["source.proxmox-iso.ubuntu"]
provisioner "ansible" {
user = "${var.build_username}"
playbook_file = "${path.cwd}/ansible/main.yml"
roles_path = "${path.cwd}/ansible/roles"
ansible_env_vars = [
"ANSIBLE_CONFIG=${path.cwd}/ansible/ansible.cfg"
]
extra_arguments = [
"--extra-vars", "display_skipped_hosts=false",
"--extra-vars", "BUILD_USERNAME=${var.build_username}",
"--extra-vars", "BUILD_SECRET='${var.build_key}'",
"--extra-vars", "ANSIBLE_USERNAME=${var.ansible_username}",
"--extra-vars", "ANSIBLE_SECRET='${var.ansible_key}'",
"--extra-vars", "cloud_init='${var.vm_cloud_init_enable}'",
]
}
post-processor "manifest" {
output = local.manifest_output
strip_path = true
strip_time = true
custom_data = {
ansible_username = "${var.ansible_username}"
build_username = "${var.build_username}"
build_date = "${local.build_date}"
build_version = "${local.build_version}"
common_data_source = "${var.common_data_source}"
vm_cpu_sockets = "${var.vm_cpu_sockets}"
vm_cpu_count = "${var.vm_cpu_count}"
vm_disk_size = "${var.vm_disk_size}"
vm_bios = "${var.vm_bios}"
vm_os_type = "${var.vm_os_type}"
vm_mem_size = "${var.vm_mem_size}"
vm_network_card_model = "${var.vm_network_card_model}"
vm_cloud_init_enable = "${var.vm_cloud_init_enable}"
}
}
}

View File

@@ -0,0 +1,53 @@
/*
DESCRIPTION:
Ubuntu Server 20.04 LTS storage variables used by the Packer Plugin for Proxmox (proxmox-iso).
*/
// VM Storage Settings
variable "vm_disk_device" {
type = string
description = "The device for the virtual disk. (e.g. 'sda')"
}
variable "vm_disk_use_swap" {
type = bool
description = "Whether to use a swap partition."
}
variable "vm_disk_partitions" {
type = list(object({
name = string
size = number
format = object({
label = string
fstype = string
})
mount = object({
path = string
options = string
})
volume_group = string
}))
description = "The disk partitions for the virtual disk."
}
variable "vm_disk_lvm" {
type = list(object({
name = string
partitions = list(object({
name = string
size = number
format = object({
label = string
fstype = string
})
mount = object({
path = string
options = string
})
}))
}))
description = "The LVM configuration for the virtual disk."
default = []
}

View File

@@ -0,0 +1,297 @@
/*
DESCRIPTION:
Ubuntu Server 20.04 LTS variables using the Packer Builder for Proxmox (proxmox-iso).
*/
// BLOCK: variable
// Defines the input variables.
// Proxmox Credentials
variable "proxmox_hostname" {
type = string
description = "The FQDN or IP address of a Proxmox node. Only one node should be specified in a cluster."
}
variable "proxmox_api_token_id" {
type = string
description = "The token to login to the Proxmox node/cluster. The format is USER@REALM!TOKENID. (e.g. packer@pam!packer_pve_token)"
}
variable "proxmox_api_token_secret" {
type = string
description = "The secret for the API token used to login to the Proxmox API."
# sensitive = true
}
variable "proxmox_insecure_connection" {
description = "true/false to skip Proxmox TLS certificate checks."
type = bool
default = true
}
// Proxmox Settings
variable "proxmox_node" {
type = string
description = "The name of the Proxmox node that Packer will build templates on."
}
// Virtual Machine Settings
variable "vm_os_language" {
type = string
description = "The guest operating system language."
default = "en_US"
}
variable "vm_os_keyboard" {
type = string
description = "The guest operating system keyboard layout."
default = "us"
}
variable "vm_os_timezone" {
type = string
description = "The guest operating system timezone."
default = "UTC"
}
variable "vm_os_family" {
type = string
description = "The guest operating system family. Used for naming. (e.g. 'linux')"
}
variable "vm_os_name" {
type = string
description = "The guest operating system name. Used for naming. (e.g. 'ubuntu')"
}
variable "vm_os_version" {
type = string
description = "The guest operating system version. Used for naming. (e.g. '22-04-lts')"
}
variable "vm_os_type" {
type = string
description = "The guest operating system type. (e.g. 'l26')"
}
variable "vm_bios" {
type = string
description = "The firmware type. Allowed values 'ovmf' or 'seabios'"
default = "OVMF"
validation {
condition = contains(["ovmf", "seabios"], var.vm_bios)
error_message = "The vm_bios value must be 'ovmf' or 'seabios'."
}
}
variable "vm_firmware_path" {
type = string
description = "The firmware file to be used. Needed for EFI"
default = "/usr/share/ovmf/OVMF.fd"
}
variable "vm_efi_storage_pool" {
type = string
description = "Set the UEFI disk storage location. (e.g. 'local-lvm')"
}
variable "vm_efi_type" {
type = string
description = "Specifies the version of the OVMF firmware to be used. (e.g. '4m')"
}
variable "vm_efi_pre_enrolled_keys" {
type = bool
description = "Whether Microsoft Standard Secure Boot keys should be pre-loaded on the EFI disk. (e.g. false)"
}
variable "vm_cpu_count" {
type = number
description = "The number of virtual CPUs. (e.g. '2')"
}
variable "vm_cpu_sockets" {
type = number
description = "The number of virtual CPU sockets. (e.g. '1')"
}
variable "vm_cpu_type" {
type = string
description = "The CPU type to emulate. See the Proxmox API documentation for the complete list of accepted values. For best performance, set this to host. Defaults to kvm64."
}
variable "vm_mem_size" {
type = number
description = "The size for the virtual memory in MB. (e.g. '2048')"
}
variable "vm_disk_controller_type" {
type = string
description = "The SCSI controller model to emulate. (e.g. 'virtio-scsi-pci')"
}
variable "vm_disk_type" {
type = string
description = "The type of disk to emulate. (e.g. 'virtio')"
}
variable "vm_storage_pool" {
type = string
description = "The name of the Proxmox storage pool to store the VM template. (e.g. 'local-lvm')"
}
variable "vm_disk_size" {
type = string
description = "The size for the virtual disk in GB. (e.g. '32G')"
}
variable "vm_disk_format" {
type = string
description = "The format of the file backing the disk. (e.g. 'qcow2')"
}
variable "vm_network_card_model" {
type = string
description = "The model of the virtual network adapter to emulate. (e.g. 'virtio')"
}
variable "vm_bridge_interface" {
type = string
description = "The name of the Proxmox bridge to attach the adapter to."
}
variable "vm_vlan_tag" {
type = string
description = "If the adapter should tag packets, give the VLAN ID. (e.g. '102')"
}
// Cloud-Init Settings
variable "vm_cloud_init_enable" {
type = bool
description = "Enable or disable cloud-init drive in Proxmox. (e.g. false)"
default = false
}
// Removable Media Settings
variable "common_iso_storage" {
type = string
description = "The name of the source Proxmox storage location for ISO images. (e.g. 'local-lvm')"
}
variable "iso_path" {
type = string
description = "The path on the source Proxmox storage location for ISO images. (e.g. 'iso')"
}
variable "iso_file" {
type = string
description = "The file name of the ISO image used by the vendor. (e.g. 'ubuntu-<version>-live-server-amd64.iso')"
}
variable "iso_checksum" {
type = string
description = "The checksum value of the ISO image provided by the vendor."
}
// Boot Settings
variable "common_data_source" {
type = string
description = "The provisioning data source. (e.g. 'http' or 'disk')"
}
variable "common_http_bind_address" {
type = string
description = "Define an IP address on the host to use for the HTTP server."
default = null
}
variable "common_http_port_min" {
type = number
description = "The start of the HTTP port range."
}
variable "common_http_port_max" {
type = number
description = "The end of the HTTP port range."
}
variable "vm_boot" {
type = string
description = "The boot order for virtual machine devices. (e.g. 'order=virtio0;ide2;net0')"
}
variable "vm_boot_wait" {
type = string
description = "The time to wait after booting the initial VM before typing the boot_command (e.g '10s')"
}
variable "common_ip_wait_timeout" {
type = string
description = "Time to wait for guest operating system IP address response."
}
variable "common_shutdown_timeout" {
type = string
description = "Time to wait for guest operating system shutdown."
}
// Communicator Settings and Credentials
variable "build_username" {
type = string
description = "The username to login to the guest operating system. (e.g. 'ubuntu')"
# sensitive = true
}
variable "build_password" {
type = string
description = "The password to login to the guest operating system."
# sensitive = true
}
variable "build_password_encrypted" {
type = string
description = "The encrypted password to login to the guest operating system."
# sensitive = true
}
variable "build_key" {
type = string
description = "The SSH public key to login to the guest operating system."
# sensitive = true
}
variable "timeout" {
description = "not sure why I need so high a timeout but here we are"
default = "90m"
}
// Ansible Credentials
variable "ansible_username" {
type = string
description = "The username for Ansible to login to the guest operating system. (e.g. 'ansible')"
# sensitive = true
}
variable "ansible_key" {
type = string
description = "The public key for Ansible to login to the guest operating system."
# sensitive = true
}
// HCP Packer Settings
variable "common_hcp_packer_registry_enabled" {
type = bool
description = "Enable the HCP Packer registry."
default = false
}

View File

@@ -0,0 +1,109 @@
%{~ if length(partitions) == 1 && partitions[0].name == "autopart" ~}
%{~ if partitions[0].format.fstype == "lvm" ~}
storage:
layout:
name: lvm
%{~ endif ~}
%{~ if partitions[0].format.fstype == "simple" ~}
storage:
layout:
name: direct
%{~ endif ~}
%{~ if partitions[0].format.fstype == "" ~}
storage:
layout:
name: direct
%{~ endif ~}
%{~ else ~}
storage:
config:
- ptable: gpt
path: /dev/${device}
wipe: superblock
preserve: false
name: ''
%{ if vm_bios == "ovmf" ~}
grub_device: false
%{ endif ~}
%{ if vm_bios == "seabios" ~}
grub_device: true
%{ endif ~}
type: disk
id: disk-${device}
# BIOS boot partition
%{ for index, partition in partitions ~}
- device: disk-${device}
%{ if partition.size != -1 ~}
size: ${partition.size}M
%{ else ~}
size: ${partition.size}
%{ endif ~}
wipe: superblock
preserve: false
%{ if partition.name == "bios_grub" && vm_bios == "seabios" && index == 0 ~}
flag: bios_grub
grub_device: false
%{ endif ~}
%{ if partition.mount.path == "/boot/efi" && index == 0 ~}
flag: boot
grub_device: true
%{ endif ~}
type: partition
id: partition-${partition.name}
%{ if partition.format.fstype != "" ~}
- id: format-${partition.name}
type: format
volume: partition-${partition.name}
label: ${partition.format.label}
fstype: ${partition.format.fstype}
%{ endif ~}
# Don't create a mount for the GRUB partition when using BIOS
%{ if partition.volume_group == "" && partition.name != "bios_grub" ~}
- id: mount-${partition.name}
type: mount
%{ if partition.mount.path == "" ~}
path: none
%{ else ~}
path: ${partition.mount.path}
%{ endif ~}
device: format-${partition.name}
%{ if partition.mount.options != "" ~}
options: ${partition.mount.options}
%{ endif ~}
%{ endif ~}
%{ endfor ~}
%{ for index, volume_group in lvm ~}
- id: volgroup-${volume_group.name}
type: lvm_volgroup
name: ${volume_group.name}
devices:
%{ for index, partition in partitions ~}
%{ if lookup(partition, "volume_group", "") == volume_group.name ~}
- partition-${partition.name}
%{ endif ~}
%{ endfor ~}
%{ for index, partition in volume_group.partitions ~}
- id: partition-${partition.name}
type: lvm_partition
name: ${partition.name}
size: ${partition.size}M
volgroup: volgroup-${volume_group.name}
- id: format-${partition.name}
type: format
volume: partition-${partition.name}
label: ${partition.format.label}
fstype: ${partition.format.fstype}
- id: mount-${partition.name}
type: mount
%{ if partition.mount.path == "" ~}
path: none
%{ else ~}
path: ${partition.mount.path}
%{ endif ~}
device: format-${partition.name}
%{ if partition.mount.options != "" ~}
options: ${partition.mount.options}
%{ endif ~}
%{ endfor ~}
%{ endfor ~}
%{~ endif ~}

View File

@@ -0,0 +1,27 @@
#cloud-config
autoinstall:
version: 1
early-commands:
- sudo systemctl stop ssh
locale: ${vm_os_language}
keyboard:
layout: ${vm_os_keyboard}
${storage}
identity:
hostname: ubuntu-server
username: ${build_username}
password: ${build_password_encrypted}
ssh:
install-server: true
allow-pw: true
packages:
- openssh-server
- qemu-guest-agent
- cloud-init
user-data:
disable_root: false
timezone: ${vm_os_timezone}
late-commands:
- sed -i -e 's/^#\?PasswordAuthentication.*/PasswordAuthentication yes/g' /target/etc/ssh/sshd_config
- echo '${build_username} ALL=(ALL) NOPASSWD:ALL' > /target/etc/sudoers.d/${build_username}
- curtin in-target --target=/target -- chmod 440 /etc/sudoers.d/${build_username}

View File

@@ -0,0 +1,45 @@
/*
DESCRIPTION:
Ubuntu Server 22.04 LTS variables used by the Packer Plugin for Proxmox (proxmox-iso).
*/
// Guest Operating System Metadata
vm_os_language = "en_US"
vm_os_keyboard = "us"
vm_os_timezone = "UTC"
vm_os_family = "linux"
vm_os_name = "ubuntu"
vm_os_version = "22.04-lts"
// Virtual Machine Guest Operating System Setting
vm_os_type = "l26"
// Virtual Machine Hardware Settings
vm_bios = "seabios"
vm_cpu_count = 1
vm_cpu_sockets = 1
vm_cpu_type = "kvm64"
vm_mem_size = 2048
vm_disk_type = "virtio"
vm_disk_size = "32G"
vm_disk_format = "raw"
vm_storage_pool = "vm-data"
vm_disk_controller_type = "virtio-scsi-pci"
vm_network_card_model = "virtio"
vm_bridge_interface = "vmbr0"
vm_vlan_tag = "102"
// Removable Media Settings
iso_path = "iso"
iso_file = "ubuntu-22.04-live-server-amd64.iso"
iso_checksum = "84aeaf7823c8c61baa0ae862d0a06b03409394800000b3235854a6b38eb4856f"
// Boot Settings
vm_boot = "order=virtio0;ide2;net0"
vm_boot_wait = "5s"
// EFI Settings
vm_firmware_path = "./OVMF.fd"
vm_efi_storage_pool = "vm-data"
vm_efi_pre_enrolled_keys = false
vm_efi_type = "4m"

View File

@@ -0,0 +1,198 @@
/*
DESCRIPTION:
Ubuntu Server 22.04 LTS template using the Packer Builder for VMware vSphere (vsphere-iso).
*/
// BLOCK: packer
// The Packer configuration.
packer {
required_version = ">= 1.9.1"
required_plugins {
ansible = {
source = "github.com/hashicorp/ansible"
version = "~> 1"
}
git = {
version = ">= 0.4.2"
source = "github.com/ethanmdavidson/git"
}
proxmox = {
version = ">= 1.0.6"
source = "github.com/hashicorp/proxmox"
}
}
}
// BLOCK: data
// Defines the data sources.
data "git-repository" "cwd" {}
// BLOCK: locals
// Defines the local variables.
locals {
build_by = "Built by: HashiCorp Packer ${packer.version}"
build_date = formatdate("DD-MM-YYYY hh:mm ZZZ", "${timestamp()}" )
build_version = data.git-repository.cwd.head
build_description = "Version: ${local.build_version}\nBuilt on: ${local.build_date}\n${local.build_by}\nCloud-Init: ${var.vm_cloud_init_enable}"
vm_disk_type = var.vm_disk_type == "virtio" ? "vda" : "sda"
manifest_date = formatdate("YYYY-MM-DD hh:mm:ss", timestamp())
manifest_path = "${path.cwd}/manifests/"
manifest_output = "${local.manifest_path}${local.manifest_date}.json"
data_source_content = {
"/meta-data" = file("${abspath(path.root)}/data/meta-data")
"/user-data" = templatefile("${abspath(path.root)}/data/user-data.pkrtpl.hcl", {
build_username = var.build_username
build_password = var.build_password
build_password_encrypted = var.build_password_encrypted
vm_disk_type = local.vm_disk_type
vm_os_language = var.vm_os_language
vm_os_keyboard = var.vm_os_keyboard
vm_os_timezone = var.vm_os_timezone
storage = templatefile("${abspath(path.root)}/data/storage.pkrtpl.hcl", {
device = var.vm_disk_device
swap = var.vm_disk_use_swap
partitions = var.vm_disk_partitions
lvm = var.vm_disk_lvm
vm_bios = var.vm_bios
})
})
}
data_source_command = var.common_data_source == "http" ? "ds=\"nocloud-net;seedfrom=http://{{.HTTPIP}}:{{.HTTPPort}}/\"" : "ds=\"nocloud\""
vm_name = "${var.vm_os_family}-${var.vm_os_name}-${var.vm_os_version}"
vm_bios = var.vm_bios == "ovmf" ? var.vm_firmware_path : null
}
// BLOCK: source
// Defines the builder configuration blocks.
source "proxmox-iso" "ubuntu" {
// Proxmox Connection Settings and Credentials
proxmox_url = "https://${var.proxmox_hostname}:8006/api2/json"
username = "${var.proxmox_api_token_id}"
token = "${var.proxmox_api_token_secret}"
insecure_skip_tls_verify = "${var.proxmox_insecure_connection}"
// Proxmox Settings
node = "${var.proxmox_node}"
// Virtual Machine Settings
vm_name = "${local.vm_name}"
bios = "${var.vm_bios}"
sockets = "${var.vm_cpu_sockets}"
cores = "${var.vm_cpu_count}"
cpu_type = "${var.vm_cpu_type}"
memory = "${var.vm_mem_size}"
os = "${var.vm_os_type}"
scsi_controller = "${var.vm_disk_controller_type}"
disks {
disk_size = "${var.vm_disk_size}"
type = "${var.vm_disk_type}"
storage_pool = "${var.vm_storage_pool}"
format = "${var.vm_disk_format}"
}
dynamic "efi_config" {
for_each = var.vm_bios == "ovmf" ? [1] : []
content {
efi_storage_pool = var.vm_bios == "ovmf" ? var.vm_efi_storage_pool : null
efi_type = var.vm_bios == "ovmf" ? var.vm_efi_type : null
pre_enrolled_keys = var.vm_bios == "ovmf" ? var.vm_efi_pre_enrolled_keys : null
}
}
unmount_iso = true
ssh_username = "${var.build_username}"
ssh_password = "${var.build_password}"
ssh_timeout = "${var.timeout}"
ssh_port = "22"
iso_file = "${var.common_iso_storage}:${var.iso_path}/${var.iso_file}"
iso_checksum = "${var.iso_checksum}"
qemu_agent = true
network_adapters {
bridge = "${var.vm_bridge_interface}"
model = "${var.vm_network_card_model}"
vlan_tag = "${var.vm_vlan_tag}"
}
// Removable Media Settings
http_content = "${var.common_data_source}" == "http" ? "${local.data_source_content}" : null
// Boot and Provisioning Settings
http_bind_address = var.common_data_source == "http" ? var.common_http_bind_address : null
http_port_min = var.common_data_source == "http" ? var.common_http_port_min : null
http_port_max = var.common_data_source == "http" ? var.common_http_port_max : null
boot = var.vm_boot
boot_wait = var.vm_boot_wait
boot_command = [
"c<wait5>",
"linux /casper/vmlinuz --- autoinstall ${local.data_source_command}",
"<enter><wait10>",
"initrd /casper/initrd",
"<enter><wait10>",
"boot",
"<enter>"
]
dynamic "additional_iso_files" {
for_each = var.common_data_source == "disk" ? [1] : []
content {
cd_files = var.common_data_source == "disk" ? local.data_source_content : null
cd_label = var.common_data_source == "disk" ? "cidata" : null
iso_storage_pool = var.common_data_source == "disk" ? "local" : null
}
}
template_name = "${local.vm_name}"
template_description = "${local.build_description}"
# VM Cloud Init Settings
cloud_init = var.vm_cloud_init_enable
cloud_init_storage_pool = var.vm_cloud_init_enable == true ? var.vm_storage_pool : null
}
# Build Definition to create the VM Template
build {
sources = ["source.proxmox-iso.ubuntu"]
provisioner "ansible" {
user = "${var.build_username}"
playbook_file = "${path.cwd}/ansible/main.yml"
roles_path = "${path.cwd}/ansible/roles"
ansible_env_vars = [
"ANSIBLE_CONFIG=${path.cwd}/ansible/ansible.cfg"
]
extra_arguments = [
"--extra-vars", "display_skipped_hosts=false",
"--extra-vars", "BUILD_USERNAME=${var.build_username}",
"--extra-vars", "BUILD_SECRET='${var.build_key}'",
"--extra-vars", "ANSIBLE_USERNAME=${var.ansible_username}",
"--extra-vars", "ANSIBLE_SECRET='${var.ansible_key}'",
"--extra-vars", "cloud_init='${var.vm_cloud_init_enable}'",
]
}
post-processor "manifest" {
output = local.manifest_output
strip_path = true
strip_time = true
custom_data = {
ansible_username = "${var.ansible_username}"
build_username = "${var.build_username}"
build_date = "${local.build_date}"
build_version = "${local.build_version}"
common_data_source = "${var.common_data_source}"
vm_cpu_sockets = "${var.vm_cpu_sockets}"
vm_cpu_count = "${var.vm_cpu_count}"
vm_disk_size = "${var.vm_disk_size}"
vm_bios = "${var.vm_bios}"
vm_os_type = "${var.vm_os_type}"
vm_mem_size = "${var.vm_mem_size}"
vm_network_card_model = "${var.vm_network_card_model}"
vm_cloud_init_enable = "${var.vm_cloud_init_enable}"
}
}
}

View File

@@ -0,0 +1,53 @@
/*
DESCRIPTION:
Ubuntu Server 22.04 LTS storage variables used by the Packer Plugin for VMware vSphere (vsphere-iso).
*/
// VM Storage Settings
variable "vm_disk_device" {
type = string
description = "The device for the virtual disk. (e.g. 'sda')"
}
variable "vm_disk_use_swap" {
type = bool
description = "Whether to use a swap partition."
}
variable "vm_disk_partitions" {
type = list(object({
name = string
size = number
format = object({
label = string
fstype = string
})
mount = object({
path = string
options = string
})
volume_group = string
}))
description = "The disk partitions for the virtual disk."
}
variable "vm_disk_lvm" {
type = list(object({
name = string
partitions = list(object({
name = string
size = number
format = object({
label = string
fstype = string
})
mount = object({
path = string
options = string
})
}))
}))
description = "The LVM configuration for the virtual disk."
default = []
}

View File

@@ -0,0 +1,297 @@
/*
DESCRIPTION:
Ubuntu Server 22.04 LTS variables using the Packer Builder for Proxmox (proxmox-iso).
*/
// BLOCK: variable
// Defines the input variables.
// Proxmox Credentials
variable "proxmox_hostname" {
type = string
description = "The FQDN or IP address of a Proxmox node. Only one node should be specified in a cluster."
}
variable "proxmox_api_token_id" {
type = string
description = "The token to login to the Proxmox node/cluster. The format is USER@REALM!TOKENID. (e.g. packer@pam!packer_pve_token)"
}
variable "proxmox_api_token_secret" {
type = string
description = "The secret for the API token used to login to the Proxmox API."
# sensitive = true
}
variable "proxmox_insecure_connection" {
description = "true/false to skip Proxmox TLS certificate checks."
type = bool
default = true
}
// Proxmox Settings
variable "proxmox_node" {
type = string
description = "The name of the Proxmox node that Packer will build templates on."
}
// Virtual Machine Settings
variable "vm_os_language" {
type = string
description = "The guest operating system language."
default = "en_US"
}
variable "vm_os_keyboard" {
type = string
description = "The guest operating system keyboard layout."
default = "us"
}
variable "vm_os_timezone" {
type = string
description = "The guest operating system timezone."
default = "UTC"
}
variable "vm_os_family" {
type = string
description = "The guest operating system family. Used for naming. (e.g. 'linux')"
}
variable "vm_os_name" {
type = string
description = "The guest operating system name. Used for naming. (e.g. 'ubuntu')"
}
variable "vm_os_version" {
type = string
description = "The guest operating system version. Used for naming. (e.g. '22-04-lts')"
}
variable "vm_os_type" {
type = string
description = "The guest operating system type. (e.g. 'l26')"
}
variable "vm_bios" {
type = string
description = "The firmware type. Allowed values 'ovmf' or 'seabios'"
default = "OVMF"
validation {
condition = contains(["ovmf", "seabios"], var.vm_bios)
error_message = "The vm_bios value must be 'ovmf' or 'seabios'."
}
}
variable "vm_firmware_path" {
type = string
description = "The firmware file to be used. Needed for EFI"
default = "/usr/share/ovmf/OVMF.fd"
}
variable "vm_efi_storage_pool" {
type = string
description = "Set the UEFI disk storage location. (e.g. 'local-lvm')"
}
variable "vm_efi_type" {
type = string
description = "Specifies the version of the OVMF firmware to be used. (e.g. '4m')"
}
variable "vm_efi_pre_enrolled_keys" {
type = bool
description = "Whether Microsoft Standard Secure Boot keys should be pre-loaded on the EFI disk. (e.g. false)"
}
variable "vm_cpu_count" {
type = number
description = "The number of virtual CPUs. (e.g. '2')"
}
variable "vm_cpu_sockets" {
type = number
description = "The number of virtual CPU sockets. (e.g. '1')"
}
variable "vm_cpu_type" {
type = string
description = "The CPU type to emulate. See the Proxmox API documentation for the complete list of accepted values. For best performance, set this to host. Defaults to kvm64."
}
variable "vm_mem_size" {
type = number
description = "The size for the virtual memory in MB. (e.g. '2048')"
}
variable "vm_disk_controller_type" {
type = string
description = "The SCSI controller model to emulate. (e.g. 'virtio-scsi-pci')"
}
variable "vm_disk_type" {
type = string
description = "The type of disk to emulate. (e.g. 'virtio')"
}
variable "vm_storage_pool" {
type = string
description = "The name of the Proxmox storage pool to store the VM template. (e.g. 'local-lvm')"
}
variable "vm_disk_size" {
type = string
description = "The size for the virtual disk in GB. (e.g. '32G')"
}
variable "vm_disk_format" {
type = string
description = "The format of the file backing the disk. (e.g. 'qcow2')"
}
variable "vm_network_card_model" {
type = string
description = "The model of the virtual network adapter to emulate. (e.g. 'virtio')"
}
variable "vm_bridge_interface" {
type = string
description = "The name of the Proxmox bridge to attach the adapter to."
}
variable "vm_vlan_tag" {
type = string
description = "If the adapter should tag packets, give the VLAN ID. (e.g. '102')"
}
// Cloud-Init Settings
variable "vm_cloud_init_enable" {
type = bool
description = "Enable or disable cloud-init drive in Proxmox. (e.g. false)"
default = false
}
// Removable Media Settings
variable "common_iso_storage" {
type = string
description = "The name of the source Proxmox storage location for ISO images. (e.g. 'local-lvm')"
}
variable "iso_path" {
type = string
description = "The path on the source Proxmox storage location for ISO images. (e.g. 'iso')"
}
variable "iso_file" {
type = string
description = "The file name of the ISO image used by the vendor. (e.g. 'ubuntu-<version>-live-server-amd64.iso')"
}
variable "iso_checksum" {
type = string
description = "The checksum value of the ISO image provided by the vendor."
}
// Boot Settings
variable "common_data_source" {
type = string
description = "The provisioning data source. (e.g. 'http' or 'disk')"
}
variable "common_http_bind_address" {
type = string
description = "Define an IP address on the host to use for the HTTP server."
default = null
}
variable "common_http_port_min" {
type = number
description = "The start of the HTTP port range."
}
variable "common_http_port_max" {
type = number
description = "The end of the HTTP port range."
}
variable "vm_boot" {
type = string
description = "The boot order for virtual machine devices. (e.g. 'order=virtio0;ide2;net0')"
}
variable "vm_boot_wait" {
type = string
description = "The time to wait after booting the initial VM before typing the boot_command (e.g '10s')"
}
variable "common_ip_wait_timeout" {
type = string
description = "Time to wait for guest operating system IP address response."
}
variable "common_shutdown_timeout" {
type = string
description = "Time to wait for guest operating system shutdown."
}
// Communicator Settings and Credentials
variable "build_username" {
type = string
description = "The username to login to the guest operating system. (e.g. 'ubuntu')"
# sensitive = true
}
variable "build_password" {
type = string
description = "The password to login to the guest operating system."
# sensitive = true
}
variable "build_password_encrypted" {
type = string
description = "The encrypted password to login to the guest operating system."
# sensitive = true
}
variable "build_key" {
type = string
description = "The SSH public key to login to the guest operating system."
# sensitive = true
}
variable "timeout" {
description = "not sure why I need so high a timeout but here we are"
default = "90m"
}
// Ansible Credentials
variable "ansible_username" {
type = string
description = "The username for Ansible to login to the guest operating system. (e.g. 'ansible')"
# sensitive = true
}
variable "ansible_key" {
type = string
description = "The public key for Ansible to login to the guest operating system."
# sensitive = true
}
// HCP Packer Settings
variable "common_hcp_packer_registry_enabled" {
type = bool
description = "Enable the HCP Packer registry."
default = false
}

View File

@@ -0,0 +1,14 @@
/*
DESCRIPTION:
Proxmox Virtual Environment variables used for all builds.
- Variables are use by the source blocks.
*/
// Proxmox Credentials
proxmox_api_url = "<FQDN or IP of proxmox server>"
proxmox_api_token_id = "name@realm!token"
proxmox_api_token_secret = "<token secret>"
proxmox_insecure_connection = false
// Proxmox Settings
proxmox_node = "<proxmox node name>"