Skip to content

Conversation

@zachary-bailey
Copy link
Contributor

@zachary-bailey zachary-bailey commented Jan 20, 2026

What this PR does / why we need it:

Migrates Packer template to HCL due to JSON deprecation and to make sure of additional Packer features

Which issue(s) this PR fixes:

JSON deprecation, reduces clutter and maintenance issues in the repo

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates Packer templates from JSON to HCL2 format to address JSON deprecation and leverage modern Packer features. The migration consolidates multiple distro-specific JSON templates into a unified HCL2 configuration with dynamic provisioners.

Changes:

  • Introduces new HCL2 configuration files (variables.pkr.hcl, source.pkr.hcl, build.pkr.hcl, packer-plugin.pkr.hcl) replacing multiple JSON templates
  • Updates build scripts to reference the new buildconfig directory structure
  • Refactors Makefile to use a single unified template path instead of multiple distro-specific paths

Reviewed changes

Copilot reviewed 9 out of 12 changed files in this pull request and generated 15 comments.

Show a summary per file
File Description
vhdbuilder/packer/buildconfig/variables.pkr.hcl Defines all Packer variables and local values with environment variable defaults
vhdbuilder/packer/buildconfig/source.pkr.hcl Configures the Azure ARM builder source with image and infrastructure settings
vhdbuilder/packer/buildconfig/build.pkr.hcl Defines the build process with dynamic provisioners for file uploads and shell scripts
vhdbuilder/packer/buildconfig/packer-plugin.pkr.hcl Specifies required Packer plugin versions
vhdbuilder/packer/buildconfig/produce-packer-settings.sh Script for generating Packer settings JSON from environment variables
vhdbuilder/packer/buildconfig/produce-packer-settings-functions.sh Helper functions for settings generation and Azure resource management
vhdbuilder/packer/buildconfig/dynamic-provisioners/*.json JSON files defining file upload/download mappings for different distros
packer.mk Updated Makefile to use unified HCL2 template path instead of multiple JSON templates

buildNumber = "${var.build_number}"
createdBy = "aks-vhd-pipeline"
image_sku = "${var.img_sku}"
now = "${var.create_time}"
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable create_time is referenced but never declared. This will cause a Packer error. You need to add a variable declaration for create_time.

Copilot uses AI. Check for mistakes.
Comment on lines 21 to 48
for_each = "${local.ubuntu_file_upload}"
content {
type = "file"
source = provisioner.value.source
destination = provisioner.value.destination
when = lower(var.os_sku) == "ubuntu"
}
}

// AzureLinux-specific file uploads
dynamic "provisioner" {
for_each = "${local.azlinux_file_upload}"
content {
type = "file"
source = provisioner.value.source
destination = provisioner.value.destination
when = lower(var.os_sku) == "cblmariner"
}
}

// Flatcar-specific file uploads
dynamic "provisioner" {
for_each = "${local.flatcar_file_upload}"
content {
type = "file"
source = provisioner.value.source
destination = provisioner.value.destination
when = lower(var.os_sku) == "flatcar"
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The when attribute is not valid for dynamic provisioners in Packer. The conditional logic should be implemented using a conditional expression in the for_each itself:

for_each = lower(var.os_sku) == "flatcar" ? local.flatcar_file_upload : []
Suggested change
for_each = "${local.ubuntu_file_upload}"
content {
type = "file"
source = provisioner.value.source
destination = provisioner.value.destination
when = lower(var.os_sku) == "ubuntu"
}
}
// AzureLinux-specific file uploads
dynamic "provisioner" {
for_each = "${local.azlinux_file_upload}"
content {
type = "file"
source = provisioner.value.source
destination = provisioner.value.destination
when = lower(var.os_sku) == "cblmariner"
}
}
// Flatcar-specific file uploads
dynamic "provisioner" {
for_each = "${local.flatcar_file_upload}"
content {
type = "file"
source = provisioner.value.source
destination = provisioner.value.destination
when = lower(var.os_sku) == "flatcar"
for_each = lower(var.os_sku) == "ubuntu" ? local.ubuntu_file_upload : []
content {
type = "file"
source = provisioner.value.source
destination = provisioner.value.destination
}
}
// AzureLinux-specific file uploads
dynamic "provisioner" {
for_each = lower(var.os_sku) == "cblmariner" ? local.azlinux_file_upload : []
content {
type = "file"
source = provisioner.value.source
destination = provisioner.value.destination
}
}
// Flatcar-specific file uploads
dynamic "provisioner" {
for_each = lower(var.os_sku) == "flatcar" ? local.flatcar_file_upload : []
content {
type = "file"
source = provisioner.value.source
destination = provisioner.value.destination

Copilot uses AI. Check for mistakes.

subscription_id = "${var.subscription_id}"
user_assigned_managed_identities = "${var.msi_resource_strings}"
use_azure_cli_auth = "true"
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use_azure_cli_auth is set to the string "true" but should be a boolean value true (without quotes) or reference the variable var.use_azure_cli_auth. As defined in variables.pkr.hcl line 125, this variable is of type bool, so it should be referenced as:

use_azure_cli_auth = var.use_azure_cli_auth
Suggested change
use_azure_cli_auth = "true"
use_azure_cli_auth = var.use_azure_cli_auth

Copilot uses AI. Check for mistakes.
Comment on lines 80 to 118
inline = "${local.reboot_command}"
pause_after = "60s"
skip_clean = true
}

provisioner "shell" {
inline = ["/bin/bash -ux /home/packer/install-dependencies.sh"]
environment_vars = [
FEATURE_FLAGS=${var.feature_flags},
BUILD_NUMBER=${var.build_number},
BUILD_ID=${var.build_id},
COMMIT=${var.commit},
HYPERV_GENERATION=${var.hyperv_generation},
CONTAINER_RUNTIME=${var.container_runtime},
TELEPORTD_PLUGIN_DOWNLOAD_URL=${var.teleportd_plugin_download_url},
ENABLE_FIPS=${var.enable_fips},
IMG_SKU=${var.img_sku},
PRIVATE_PACKAGES_URL=${var.private_packages_url},
VHD_BUILD_TIMESTAMP=${local.vhd_build_timestamp}
]
}

provisioner "shell" {
inline = ["sudo /bin/bash /home/packer/generate-disk-usage.sh"]
}

dynamic "provisioner" {
for_each = "${local.midway_file_downloads}"
content {
type = "file"
direction = "download"
source = provisioner.value.source
destination = provisioner.value.destination
}
}

provisioner "shell" {
expect_disconnect = true
inline = "${local.reboot_command}"
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary string interpolation. The expression "${local.reboot_command}" can be simplified to local.reboot_command since it's already a string value. The same simplification can be applied throughout this file where single values are wrapped in string interpolation without additional text.

Copilot uses AI. Check for mistakes.
image_version = "${var.captured_sig_version}"
replication_regions = ["${var.location}"]
resource_group = "${var.resource_group_name}"
subscription = "${local.gallery_subscription_id}"
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The local variable gallery_subscription_id is referenced but never defined. This will cause a Packer error. You need to add a local or variable definition for gallery_subscription_id.

Copilot uses AI. Check for mistakes.

variable "captured_sig_version" {
type = string
default = "${env("$${CAPTURED_SIG_VERSION")}"
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable default value contains a malformed environment variable reference. The syntax "${env("$${CAPTURED_SIG_VERSION")}" has an extra dollar sign and brace. This should be "${env("CAPTURED_SIG_VERSION")}" to correctly reference the environment variable.

Suggested change
default = "${env("$${CAPTURED_SIG_VERSION")}"
default = "${env("CAPTURED_SIG_VERSION")}"

Copilot uses AI. Check for mistakes.
ENABLE_FIPS=${var.enable_fips},
IMG_SKU=${var.img_sku},
UA_TOKEN=${var.ua_token},
VHD_BUILD_TIMESTAMP=${local.vhd_build_timestamp}
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The local variable vhd_build_timestamp is referenced but never defined in the variables.pkr.hcl file. This will cause a Packer error. You need to add a local or variable definition for vhd_build_timestamp.

Copilot uses AI. Check for mistakes.

variable "SkipLinuxAzSecPack" {
type = string
default = true
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default value is set to the boolean true, but the type is declared as string. This type mismatch will cause a Packer error. The default should be "true" (string) or the type should be changed to bool.

Suggested change
default = true
default = "true"

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,265 @@
locals {
// Managed Image settings - empty for ARM64 builds
managed_image_resource_group_name = lower("${var.architecture}") == "arm64" ? "" : "${var.resource_group_name}"
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable resource_group_name is referenced in line 3 but is never declared in this file. This will cause Packer to fail with an undefined variable error. You need to add a variable declaration for resource_group_name.

Copilot uses AI. Check for mistakes.
packer.mk Outdated

run-packer: az-login
@packer init ./vhdbuilder/packer/packer-plugin.pkr.hcl && packer version && ($(MAKE) -f packer.mk init-packer | tee packer-output) && ($(MAKE) -f packer.mk build-packer | tee -a packer-output)
@packer init ./vhdbuilder/packer/buildconfig/build.pkr.hcl && packer version && ($(MAKE) -f packer.mk init-packer | tee packer-output) && ($(MAKE) -f packer.mk build-packer | tee -a packer-output)
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The packer init command should target the directory containing all HCL files (buildconfig) rather than just build.pkr.hcl. The correct command should be:

packer init ./vhdbuilder/packer/buildconfig

This ensures all .pkr.hcl files in the directory are properly initialized.

Suggested change
@packer init ./vhdbuilder/packer/buildconfig/build.pkr.hcl && packer version && ($(MAKE) -f packer.mk init-packer | tee packer-output) && ($(MAKE) -f packer.mk build-packer | tee -a packer-output)
@packer init ./vhdbuilder/packer/buildconfig && packer version && ($(MAKE) -f packer.mk init-packer | tee packer-output) && ($(MAKE) -f packer.mk build-packer | tee -a packer-output)

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 12 changed files in this pull request and generated 20 comments.

Comment on lines +22 to +35
secure_boot_enabled = "${local.secure_boot_enabled}"
vtpm_enabled = "${local.vtpm_enabled}"
security_type = "${local.security_type}"
security_encryption_type = "${local.security_encryption_type}"

custom_data_file = "${local.custom_data_file}"

os_disk_size_gb = 30
os_type = "Linux"
polling_duration_timeout = "1h"
ssh_read_write_timeout = "5m"

shared_image_gallery_destination {
specialized = "${local.specialized_image}"
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In HCL2, boolean and string values in source blocks should not be wrapped in quotes when they're already boolean values. The values for 'secure_boot_enabled', 'vtpm_enabled', and 'specialized' are already booleans from the locals, so the string interpolation syntax "${local.X}" will convert them to strings. Remove the quotes or use direct reference like 'local.secure_boot_enabled' instead of '"${local.secure_boot_enabled}"'.

Copilot uses AI. Check for mistakes.
Comment on lines 141 to 143
SKU_NAME=${var.sku_name},
IMAGE_VERSION=${var.image_version},
CONTAINER_RUNTIME=${var.container_runtime}
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The environment variable assignments are missing quotes around the variable references. In HCL2 shell provisioners, environment_vars should be strings in the format "KEY=value". Change these lines to use proper quoting, for example: "SKU_NAME=${var.sku_name}" instead of SKU_NAME=${var.sku_name}.

Suggested change
SKU_NAME=${var.sku_name},
IMAGE_VERSION=${var.image_version},
CONTAINER_RUNTIME=${var.container_runtime}
"SKU_NAME=${var.sku_name}",
"IMAGE_VERSION=${var.image_version}",
"CONTAINER_RUNTIME=${var.container_runtime}"

Copilot uses AI. Check for mistakes.
type = string
default = "${env("OS_SKU")}"
}

Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable 'create_time' is referenced in source.pkr.hcl at line 53, but it is never defined in variables.pkr.hcl. This will cause Packer to fail with an undefined variable error. You need to add a variable declaration for 'create_time'.

Suggested change
variable "create_time" {
type = string
default = "${env("CREATE_TIME")}"
}

Copilot uses AI. Check for mistakes.

provisioner "shell" {
expect_disconnect = true
inline = "${local.reboot_command}"
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The inline command is using string interpolation for a list value. In HCL2, when 'inline' expects a list, you should use array syntax. Change this from 'inline = "${local.reboot_command}"' to 'inline = [local.reboot_command]' (without quotes and with square brackets).

Suggested change
inline = "${local.reboot_command}"
inline = [local.reboot_command]

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +28
locals {
// Managed Image settings - empty for ARM64 builds
managed_image_resource_group_name = lower("${var.architecture}") == "arm64" ? "" : "${var.resource_group_name}"
managed_image_name = lower("${var.architecture}") == "arm64" ? "" : "${var.sig_image_name}-${var.captured_sig_version}"

// Confidential VM settings, if enabled via feature flags
secure_boot_enabled = can(regex("cvm", lower(var.feature_flags))) ? true : false
vtpm_enabled = can(regex("cvm", lower(var.feature_flags))) ? true : false
security_type = can(regex("cvm", lower(var.feature_flags))) ? "ConfidentialVM" : ""
security_encryption_type = can(regex("cvm", lower(var.feature_flags))) ? "VMGuestStateOnly" : ""
specialized_image = can(regex("cvm", lower(var.feature_flags))) ? true : false
cvm_encryption_type = can(regex("cvm", lower(var.feature_flags))) ? "EncryptedVMGuestStateOnlyWithPmk" : ""

// File uploads for build process
custom_data_file = lower(var.os_version) == "flatcar" ? var.custom_data_file : ""
aks_node_controller = lower("${var.architecture}") == "x86_64" ? var.aksnode_controller_amd64 : var.aksnode_controller_arm64
common_file_upload = jsondecode(file(var.common_file_upload)).files
ubuntu_file_upload = jsondecode(file(var.ubuntu_file_upload)).files
azlinux_file_upload = jsondecode(file(var.azlinux_file_upload)).files
flatcar_file_upload = jsondecode(file(var.flatcar_file_upload)).files

// File downloads for artifact creation
midway_file_downloads = jsondecode(file(var.file_downloads)).midway
post_build_file_downloads = jsondecode(file(var.file_downloads)).post-build

// Reboot command based on distro
reboot_command = lower(var.os_version) == "flatcar" ? ": reboot" : "sudo reboot"
}
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The local variable 'vhd_build_timestamp' is referenced in build.pkr.hcl at lines 74 and 98, but it is never defined in the locals block of variables.pkr.hcl. This will cause Packer to fail with an undefined local variable error. You need to add a definition for 'vhd_build_timestamp' in the locals block.

Copilot uses AI. Check for mistakes.

// Ubuntu-specific file uploads
dynamic "provisioner" {
for_each = "${local.ubuntu_file_upload}"
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dynamic provisioner blocks use "${local.ubuntu_file_upload}" with unnecessary string interpolation. In HCL2, for_each expects a map or set directly, so this should be written as 'for_each = local.ubuntu_file_upload' without the quotes and interpolation markers.

Suggested change
for_each = "${local.ubuntu_file_upload}"
for_each = local.ubuntu_file_upload

Copilot uses AI. Check for mistakes.
Comment on lines +490 to +494
"source": "parts/linux/cloud-init/artifacts/pam-d-common-auth",
"destination": "/home/packer/pam-d-common-auth"
},
{
"type": "file",
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file 'parts/linux/cloud-init/artifacts/pam-d-common-auth' with destination '/home/packer/pam-d-common-auth' is listed twice in this file (lines 294-297 and 489-492). This duplication will cause the file to be uploaded twice, which is redundant and may cause issues during the build process. Remove one of these duplicate entries.

Suggested change
"source": "parts/linux/cloud-init/artifacts/pam-d-common-auth",
"destination": "/home/packer/pam-d-common-auth"
},
{
"type": "file",

Copilot uses AI. Check for mistakes.

// These files are common to all VHDs, and will be uploaded to the Packer VM regardless of distro
dynamic "provisioner" {
for_each = "${local.common_file_upload}"
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dynamic provisioner blocks use "${local.common_file_upload}" with unnecessary string interpolation. In HCL2, for_each expects a map or set directly, so this should be written as 'for_each = local.common_file_upload' without the quotes and interpolation markers.

Copilot uses AI. Check for mistakes.
}

dynamic "provisioner" {
for_each = "${local.midway_file_downloads}"
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dynamic provisioner blocks use "${local.midway_file_downloads}" with unnecessary string interpolation. In HCL2, for_each expects a map or set directly, so this should be written as 'for_each = local.midway_file_downloads' without the quotes and interpolation markers.

Suggested change
for_each = "${local.midway_file_downloads}"
for_each = local.midway_file_downloads

Copilot uses AI. Check for mistakes.
}

dynamic "provisioner" {
for_each = "${local.post_build_file_downloads}"
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dynamic provisioner blocks use "${local.post_build_file_downloads}" with unnecessary string interpolation. In HCL2, for_each expects a map or set directly, so this should be written as 'for_each = local.post_build_file_downloads' without the quotes and interpolation markers.

Suggested change
for_each = "${local.post_build_file_downloads}"
for_each = local.post_build_file_downloads

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 12 changed files in this pull request and generated 7 comments.

Comment on lines +490 to +494
"source": "parts/linux/cloud-init/artifacts/pam-d-common-auth",
"destination": "/home/packer/pam-d-common-auth"
},
{
"type": "file",
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file pam-d-common-auth is uploaded twice to the same destination /home/packer/pam-d-common-auth from the same source. This is a duplicate entry that should be removed to avoid confusion and unnecessary file transfer operations.

Suggested change
"source": "parts/linux/cloud-init/artifacts/pam-d-common-auth",
"destination": "/home/packer/pam-d-common-auth"
},
{
"type": "file",

Copilot uses AI. Check for mistakes.
Comment on lines +47 to +51
},
{
"type": "file",
"source": "parts/linux/cloud-init/artifacts/update_certs.service",
"destination": "/home/packer/update_certs.service"
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both file entries upload to the same destination /home/packer/update_certs.service, but from different sources. The second upload will overwrite the first one. This appears to be a duplicate or conflicting configuration. Verify which source file is the correct one to use for Azure Linux/Mariner builds.

Suggested change
},
{
"type": "file",
"source": "parts/linux/cloud-init/artifacts/update_certs.service",
"destination": "/home/packer/update_certs.service"

Copilot uses AI. Check for mistakes.

variable "captured_sig_version" {
type = string
default = "${env("$${CAPTURED_SIG_VERSION")}"
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This environment variable reference has incorrect syntax. The dollar sign escaping is malformed - it should be either ${env("CAPTURED_SIG_VERSION")} without the extra $${} wrapper, or if you're trying to reference a literal ${CAPTURED_SIG_VERSION} string, the syntax is incorrect. This will cause the variable to fail to read the environment variable properly.

Suggested change
default = "${env("$${CAPTURED_SIG_VERSION")}"
default = "${env("CAPTURED_SIG_VERSION")}"

Copilot uses AI. Check for mistakes.
Comment on lines 21 to 51
for_each = "${local.ubuntu_file_upload}"
content {
type = "file"
source = provisioner.value.source
destination = provisioner.value.destination
when = lower(var.os_sku) == "ubuntu"
}
}

// AzureLinux-specific file uploads
dynamic "provisioner" {
for_each = "${local.azlinux_file_upload}"
content {
type = "file"
source = provisioner.value.source
destination = provisioner.value.destination
when = lower(var.os_sku) == "cblmariner"
}
}

// Flatcar-specific file uploads
dynamic "provisioner" {
for_each = "${local.flatcar_file_upload}"
content {
type = "file"
source = provisioner.value.source
destination = provisioner.value.destination
when = lower(var.os_sku) == "flatcar"
}
}

Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conditional logic for the when attribute is incorrect. In HCL2, conditionals should use a boolean expression directly, but here lower(var.os_sku) == "ubuntu" returns a boolean, which should work. However, verify that the when attribute is supported in this context, as it's not a standard Packer provisioner attribute. The correct approach would be to wrap the entire dynamic block with a conditional or use only at the build level.

Suggested change
for_each = "${local.ubuntu_file_upload}"
content {
type = "file"
source = provisioner.value.source
destination = provisioner.value.destination
when = lower(var.os_sku) == "ubuntu"
}
}
// AzureLinux-specific file uploads
dynamic "provisioner" {
for_each = "${local.azlinux_file_upload}"
content {
type = "file"
source = provisioner.value.source
destination = provisioner.value.destination
when = lower(var.os_sku) == "cblmariner"
}
}
// Flatcar-specific file uploads
dynamic "provisioner" {
for_each = "${local.flatcar_file_upload}"
content {
type = "file"
source = provisioner.value.source
destination = provisioner.value.destination
when = lower(var.os_sku) == "flatcar"
}
}
for_each = lower(var.os_sku) == "ubuntu" ? local.ubuntu_file_upload : []
content {
type = "file"
source = provisioner.value.source
destination = provisioner.value.destination
}
}
// AzureLinux-specific file uploads
dynamic "provisioner" {
for_each = lower(var.os_sku) == "cblmariner" ? local.azlinux_file_upload : []
content {
type = "file"
source = provisioner.value.source
destination = provisioner.value.destination
}
}
// Flatcar-specific file uploads
dynamic "provisioner" {
for_each = lower(var.os_sku) == "flatcar" ? local.flatcar_file_upload : []
content {
type = "file"
source = provisioner.value.source
destination = provisioner.value.destination
}
}

Copilot uses AI. Check for mistakes.
Comment on lines +495 to +499
"source": "parts/linux/cloud-init/artifacts/pam-d-common-password",
"destination": "/home/packer/pam-d-common-password"
},
{
"type": "file",
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file pam-d-common-password is uploaded twice to the same destination /home/packer/pam-d-common-password from the same source. This is a duplicate entry that should be removed to avoid confusion and unnecessary file transfer operations.

Suggested change
"source": "parts/linux/cloud-init/artifacts/pam-d-common-password",
"destination": "/home/packer/pam-d-common-password"
},
{
"type": "file",

Copilot uses AI. Check for mistakes.
Comment on lines +500 to +504
"source": "parts/linux/cloud-init/artifacts/pam-d-su",
"destination": "/home/packer/pam-d-su"
},
{
"type": "file",
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file pam-d-su is uploaded twice to the same destination /home/packer/pam-d-su from the same source. This is a duplicate entry that should be removed to avoid confusion and unnecessary file transfer operations.

Suggested change
"source": "parts/linux/cloud-init/artifacts/pam-d-su",
"destination": "/home/packer/pam-d-su"
},
{
"type": "file",

Copilot uses AI. Check for mistakes.

variable "file_downloads" {
type = string
default = "vhdbuilder/packer/buildconfig/dynamic-provisioners/file-downloads.json"
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file path references file-downloads.json (with a hyphen), but the actual file in the directory is named file_downloads.json (with an underscore). This mismatch will cause a file not found error when Packer tries to load this JSON file. Either rename the actual file to use a hyphen, or update this path to use an underscore.

Suggested change
default = "vhdbuilder/packer/buildconfig/dynamic-provisioners/file-downloads.json"
default = "vhdbuilder/packer/buildconfig/dynamic-provisioners/file_downloads.json"

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 12 changed files in this pull request and generated 9 comments.

Comment on lines 58 to 59
destination = "${var.aks_node_controller}"
source = "/home/packer/aks-node-controller"
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorrect provisioner file configuration. The destination and source parameters are swapped. According to Packer documentation, for file provisioners, source should be the local path and destination should be the remote path. Here, var.aks_node_controller appears to be a local file path but is assigned to destination, while /home/packer/aks-node-controller should be the destination on the VM.

Suggested change
destination = "${var.aks_node_controller}"
source = "/home/packer/aks-node-controller"
source = "/home/packer/aks-node-controller"
destination = "${var.aks_node_controller}"

Copilot uses AI. Check for mistakes.
Comment on lines +3 to +27
image_offer = "${var.img_offer}"
image_publisher = "${var.img_publisher}"
image_sku = "${var.img_sku}"
image_version = "${var.img_version}"

subscription_id = "${var.subscription_id}"
user_assigned_managed_identities = "${var.msi_resource_strings}"
use_azure_cli_auth = "true"
location = "${var.location}"
vm_size = "${var.vm_size}"

managed_image_resource_group_name = "${local.managed_image_resource_group_name}"
managed_image_name = "${local.managed_image_name}"
managed_image_storage_account_type = "Premium_LRS"

virtual_network_resource_group_name = "${var.vnet_resource_group_name}"
virtual_network_name = "${var.vnet_name}"
virtual_network_subnet_name = "${var.subnet_name}"

secure_boot_enabled = "${local.secure_boot_enabled}"
vtpm_enabled = "${local.vtpm_enabled}"
security_type = "${local.security_type}"
security_encryption_type = "${local.security_encryption_type}"

custom_data_file = "${local.custom_data_file}"
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary string interpolation. In HCL2, when referencing a variable directly, you don't need the wrapping quotes and dollar sign. Change "${var.img_offer}" to var.img_offer for cleaner syntax. This applies to all variable references in this source block.

Copilot uses AI. Check for mistakes.
Comment on lines +22 to +36
secure_boot_enabled = "${local.secure_boot_enabled}"
vtpm_enabled = "${local.vtpm_enabled}"
security_type = "${local.security_type}"
security_encryption_type = "${local.security_encryption_type}"

custom_data_file = "${local.custom_data_file}"

os_disk_size_gb = 30
os_type = "Linux"
polling_duration_timeout = "1h"
ssh_read_write_timeout = "5m"

shared_image_gallery_destination {
specialized = "${local.specialized_image}"
confidential_vm_image_encryption_type = "${local.cvm_encryption_type}"
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary string interpolation. In HCL2, when referencing a local variable directly, you don't need the wrapping quotes and dollar sign. Change "${local.secure_boot_enabled}" to local.secure_boot_enabled for cleaner syntax. This applies to all local references in this source block.

Copilot uses AI. Check for mistakes.
Comment on lines +45 to +55
azure_tags = {
SkipLinuxAzSecPack = "true"
branch = "${var.branch}"
buildDefinitionName = "${var.build_definition_name}"
buildId = "${var.build_id}"
buildNumber = "${var.build_number}"
createdBy = "aks-vhd-pipeline"
image_sku = "${var.img_sku}"
now = "${var.create_time}"
os = "Linux"
}
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary string interpolation. In HCL2, when referencing a variable or local directly, you don't need the wrapping quotes and dollar sign. Change "${var.sig_gallery_name}" to var.sig_gallery_name for cleaner syntax. This applies to all references in this shared_image_gallery_destination block.

Copilot uses AI. Check for mistakes.
"ENABLE_FIPS=${var.enable_fips}",
"IMG_SKU=${var.img_sku}",
"PRIVATE_PACKAGES_URL=${var.private_packages_url}",
"VHD_BUILD_TIMESTAMP=${local.vhd_build_timestamp}"
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorrect variable reference. vhd_build_timestamp should be referenced as var.vhd_build_timestamp instead of local.vhd_build_timestamp. The value comes from the settings.json file as a variable, not a local value computed at runtime.

Suggested change
"VHD_BUILD_TIMESTAMP=${local.vhd_build_timestamp}"
"VHD_BUILD_TIMESTAMP=${var.vhd_build_timestamp}"

Copilot uses AI. Check for mistakes.
Comment on lines 10 to 153
dynamic "provisioner" {
for_each = "${local.common_file_upload}"
content {
labels = ["azure-arm.nodelifecycle-image-builder"]
type = "file"
source = provisioner.value.source
destination = provisioner.value.destination
}
}

// Ubuntu-specific file uploads
dynamic "provisioner" {
for_each = "${local.ubuntu_file_upload}"
content {
labels = ["azure-arm.nodelifecycle-image-builder"]
type = "file"
source = provisioner.value.source
destination = provisioner.value.destination
when = lower(var.os_sku) == "ubuntu"
}
}

// AzureLinux-specific file uploads
dynamic "provisioner" {
for_each = "${local.azlinux_file_upload}"
content {
labels = ["azure-arm.nodelifecycle-image-builder"]
type = "file"
source = provisioner.value.source
destination = provisioner.value.destination
when = lower(var.os_sku) == "cblmariner"
}
}

// Flatcar-specific file uploads
dynamic "provisioner" {
for_each = "${local.flatcar_file_upload}"
content {
labels = ["azure-arm.nodelifecycle-image-builder"]
type = "file"
source = provisioner.value.source
destination = provisioner.value.destination
when = lower(var.os_sku) == "flatcar"
}
}

// Architecture-specific aks-node-controller upload
provisioner "file" {
destination = "${var.aks_node_controller}"
source = "/home/packer/aks-node-controller"
}


// Build Process begins
// pre-install-dependencies.sh, install-dependencies.sh, post-install-dependencies.sh, and list-images.sh are run in order, typically with reboots and file downloads in between
provisioner "shell" {
inline = ["/bin/bash -ux /home/packer/pre-install-dependencies.sh"]
environment_vars = [
"FEATURE_FLAGS=${var.feature_flags}",
"BUILD_NUMBER=${var.build_number}",
"BUILD_ID=${var.build_id}",
"COMMIT=${var.commit}",
"HYPERV_GENERATION=${var.hyperv_generation}",
"CONTAINER_RUNTIME=${var.container_runtime}",
"TELEPORTD_PLUGIN_DOWNLOAD_URL=${var.teleportd_plugin_download_url}",
"ENABLE_FIPS=${var.enable_fips}",
"IMG_SKU=${var.img_sku}",
"UA_TOKEN=${var.ua_token}",
"VHD_BUILD_TIMESTAMP=${local.vhd_build_timestamp}"
]
}

provisioner "shell" {
expect_disconnect = true
inline = "${local.reboot_command}"
pause_after = "60s"
skip_clean = true
}

provisioner "shell" {
inline = ["/bin/bash -ux /home/packer/install-dependencies.sh"]
environment_vars = [
"FEATURE_FLAGS=${var.feature_flags}",
"BUILD_NUMBER=${var.build_number}",
"BUILD_ID=${var.build_id}",
"COMMIT=${var.commit}",
"HYPERV_GENERATION=${var.hyperv_generation}",
"CONTAINER_RUNTIME=${var.container_runtime}",
"TELEPORTD_PLUGIN_DOWNLOAD_URL=${var.teleportd_plugin_download_url}",
"ENABLE_FIPS=${var.enable_fips}",
"IMG_SKU=${var.img_sku}",
"PRIVATE_PACKAGES_URL=${var.private_packages_url}",
"VHD_BUILD_TIMESTAMP=${local.vhd_build_timestamp}"
]
}

provisioner "shell" {
inline = ["sudo /bin/bash /home/packer/generate-disk-usage.sh"]
}

dynamic "provisioner" {
for_each = "${local.midway_file_downloads}"
content {
labels = ["azure-arm.nodelifecycle-image-builder"]
type = "file"
direction = "download"
source = provisioner.value.source
destination = provisioner.value.destination
}
}

provisioner "shell" {
expect_disconnect = true
inline = "${local.reboot_command}"
pause_after = "60s"
skip_clean = true
}

provisioner "shell" {
inline = ["/bin/bash -ux /home/packer/post-install-dependencies.sh"]
environment_vars = [
"FEATURE_FLAGS=${var.feature_flags}",
"BUILD_NUMBER=${var.build_number}",
"BUILD_ID=${var.build_id}",
"COMMIT=${var.commit}",
"HYPERV_GENERATION=${var.hyperv_generation}",
"CONTAINER_RUNTIME=${var.container_runtime}",
"TELEPORTD_PLUGIN_DOWNLOAD_URL=${var.teleportd_plugin_download_url}",
"ENABLE_FIPS=${var.enable_fips}",
"IMG_SKU=${var.img_sku}"
]
}

provisioner "shell" {
inline = ["/bin/bash -ux /home/packer/list-images.sh"]
environment_vars = [
"SKU_NAME=${var.sku_name}",
"IMAGE_VERSION=${var.image_version}",
"CONTAINER_RUNTIME=${var.container_runtime}"
]
}

dynamic "provisioner" {
for_each = "${local.post_build_file_downloads}"
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary string interpolation in for_each expressions. In HCL2, when referencing a local variable directly, you don't need the wrapping quotes and dollar sign. Change for_each = "${local.common_file_upload}" to for_each = local.common_file_upload for cleaner syntax. This applies to all for_each expressions in this build block.

Copilot uses AI. Check for mistakes.

provisioner "shell" {
expect_disconnect = true
inline = "${local.reboot_command}"
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary string interpolation. Change inline = "${local.reboot_command}" to inline = [local.reboot_command] since inline expects a list of strings, not a single interpolated string.

Suggested change
inline = "${local.reboot_command}"
inline = [local.reboot_command]

Copilot uses AI. Check for mistakes.

provisioner "shell" {
expect_disconnect = true
inline = "${local.reboot_command}"
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary string interpolation. Change inline = "${local.reboot_command}" to inline = [local.reboot_command] since inline expects a list of strings, not a single interpolated string.

Copilot uses AI. Check for mistakes.
type = string
default = "${env("OS_SKU")}"
}

Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing required variable declarations. The variables resource_group_name, gallery_subscription_id, create_time, and vhd_build_timestamp are generated in the settings.json file (see produce-packer-settings.sh lines 224, 223, 228, and 232) but are not declared in this variables file. These variables need to be declared to receive values from the var-file. Add these variable declarations with appropriate types (all should be string type).

Suggested change
variable "resource_group_name" {
type = string
}
variable "gallery_subscription_id" {
type = string
}
variable "create_time" {
type = string
}
variable "vhd_build_timestamp" {
type = string
}

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 12 changed files in this pull request and generated 15 comments.


variable "captured_sig_version" {
type = string
default = "${env("$${CAPTURED_SIG_VERSION")}"
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's an invalid variable reference with incorrect escape sequence. The syntax "${env("$${CAPTURED_SIG_VERSION")}" includes an extra dollar sign and brace that should not be present. It should be "${env("CAPTURED_SIG_VERSION")}" to properly reference the environment variable.

Suggested change
default = "${env("$${CAPTURED_SIG_VERSION")}"
default = "${env("CAPTURED_SIG_VERSION")}"

Copilot uses AI. Check for mistakes.
image_version = "${var.captured_sig_version}"
replication_regions = ["${var.location}"]
resource_group = "${var.resource_group_name}"
subscription = "${local.gallery_subscription_id}"
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The local variable "gallery_subscription_id" is referenced here but is never defined in the locals block or anywhere in variables.pkr.hcl. This will cause a build failure. Based on the produce-packer-settings.sh script (line 223), this should likely reference a variable named "gallery_subscription_id" that needs to be added to the variables file.

Suggested change
subscription = "${local.gallery_subscription_id}"
subscription = "${var.gallery_subscription_id}"

Copilot uses AI. Check for mistakes.
Comment on lines +3 to +12
image_offer = "${var.img_offer}"
image_publisher = "${var.img_publisher}"
image_sku = "${var.img_sku}"
image_version = "${var.img_version}"

subscription_id = "${var.subscription_id}"
user_assigned_managed_identities = "${var.msi_resource_strings}"
use_azure_cli_auth = "true"
location = "${var.location}"
vm_size = "${var.vm_size}"
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary string interpolation. The syntax "${var.img_offer}" can be simplified to just var.img_offer since it's already a string variable. This applies to all similar cases in this file (lines 3-12, 18-27, etc.). While not strictly incorrect, removing the unnecessary interpolation makes the code cleaner and more idiomatic HCL2.

Copilot uses AI. Check for mistakes.
Comment on lines +21 to +23
dynamic "provisioner" {
for_each = "${local.ubuntu_file_upload}"
labels = ["azure-arm.nodelifecycle-image-builder"]
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The labels for dynamic provisioners should only contain the provisioner type, not include the source name. The labels should be ["file"] instead of ["azure-arm.nodelifecycle-image-builder"]. This pattern appears throughout the build block but is inconsistent with standard Packer HCL2 syntax for dynamic blocks.

Copilot uses AI. Check for mistakes.
Comment on lines +45 to +47
dynamic "provisioner" {
for_each = "${local.flatcar_file_upload}"
labels = ["azure-arm.nodelifecycle-image-builder"]
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The labels for dynamic provisioners should only contain the provisioner type, not include the source name. The labels should be ["file"] instead of ["azure-arm.nodelifecycle-image-builder"]. This pattern appears throughout the build block but is inconsistent with standard Packer HCL2 syntax for dynamic blocks.

Copilot uses AI. Check for mistakes.

provisioner "shell" {
expect_disconnect = true
inline = "${local.reboot_command}"
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The inline parameter expects an array but the value is incorrectly wrapped in string interpolation syntax. It should be inline = [local.reboot_command] instead of inline = "${local.reboot_command}" to properly pass an array of commands to the shell provisioner.

Copilot uses AI. Check for mistakes.
type = "file"
source = provisioner.value.source
destination = provisioner.value.destination
when = lower(var.os_sku) == "ubuntu"
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The when condition is checking "os_sku" but should be checking "os_version" to match the logic in the locals block (line 15 of variables.pkr.hcl) which uses os_version for Ubuntu detection. This mismatch will cause Ubuntu-specific files to not be uploaded when they should be.

Suggested change
when = lower(var.os_sku) == "ubuntu"
when = lower(var.os_version) == "ubuntu"

Copilot uses AI. Check for mistakes.
type = "file"
source = provisioner.value.source
destination = provisioner.value.destination
when = lower(var.os_sku) == "flatcar"
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The when condition is checking "os_sku" but should be checking "os_version" to match the logic in the locals block (line 15 of variables.pkr.hcl) which uses os_version for Flatcar detection. This mismatch will cause Flatcar-specific files to not be uploaded when they should be.

Suggested change
when = lower(var.os_sku) == "flatcar"
when = lower(var.os_version) == "flatcar"

Copilot uses AI. Check for mistakes.
Comment on lines +152 to +154
dynamic "provisioner" {
for_each = "${local.post_build_file_downloads}"
labels = ["azure-arm.nodelifecycle-image-builder"]
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The labels for dynamic provisioners should only contain the provisioner type, not include the source name. The labels should be ["file"] instead of ["azure-arm.nodelifecycle-image-builder"]. This pattern appears throughout the build block but is inconsistent with standard Packer HCL2 syntax for dynamic blocks.

Copilot uses AI. Check for mistakes.

variable "resource_group_name" {
type = string
default = "${env("AZURE_RESOURCE_GROUP_NAM")}"
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The environment variable name appears to be truncated. It should be "AZURE_RESOURCE_GROUP_NAME" but is currently "AZURE_RESOURCE_GROUP_NAM" (missing the final "E"). This will cause the variable to not be populated correctly from the environment.

Suggested change
default = "${env("AZURE_RESOURCE_GROUP_NAM")}"
default = "${env("AZURE_RESOURCE_GROUP_NAME")}"

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants