diff --git a/.github/workflows/validate-components.yml b/.github/workflows/validate-components.yml index 7a6ca8414b4..5a6be9dc683 100644 --- a/.github/workflows/validate-components.yml +++ b/.github/workflows/validate-components.yml @@ -16,7 +16,7 @@ jobs: GOPATH="$(go env | grep GOPATH | cut -d= -f2 | tr -d '"')" export PATH="$PATH:$GOPATH/bin" pushd /tmp - GO111MODULE=on go install cuelang.org/go/cmd/cue@latest + GO111MODULE=on go install cuelang.org/go/cmd/cue@v0.15.4 popd - name: Validate components.json conforms to cue schema diff --git a/.pipelines/templates/.builder-release-template.yaml b/.pipelines/templates/.builder-release-template.yaml index 24c9249f093..9246570fd00 100644 --- a/.pipelines/templates/.builder-release-template.yaml +++ b/.pipelines/templates/.builder-release-template.yaml @@ -68,7 +68,7 @@ steps: echo "GOPATH is currently set to $GOPATH" export PATH="$PATH:$GOPATH/bin" pushd /tmp - GO111MODULE=on go install cuelang.org/go/cmd/cue@latest + GO111MODULE=on go install cuelang.org/go/cmd/cue@v0.15.4 popd cue export ./schemas/manifest.cue > ./parts/linux/cloud-init/artifacts/manifest.json displayName: Setup Cue diff --git a/e2e/vmss.go b/e2e/vmss.go index 7bd589e854b..be1edede789 100644 --- a/e2e/vmss.go +++ b/e2e/vmss.go @@ -570,6 +570,7 @@ func extractLogsFromVMLinux(ctx context.Context, s *Scenario, vm *ScenarioVM) er "aks-log-collector.log": "sudo journalctl -u aks-log-collector", "cluster-provision-cse-output.log": "sudo cat /var/log/azure/cluster-provision-cse-output.log", "sysctl-out.log": "sudo sysctl -a", + "waagent.log": "sudo cat /var/log/waagent.log", "aks-node-controller.log": "sudo cat /var/log/azure/aks-node-controller.log", "aks-node-controller-config.json": "sudo cat /opt/azure/containers/aks-node-controller-config.json", // Only available in Scriptless. diff --git a/vhdbuilder/packer/install_walinuxagent.py b/vhdbuilder/packer/install_walinuxagent.py new file mode 100644 index 00000000000..6de451cd233 --- /dev/null +++ b/vhdbuilder/packer/install_walinuxagent.py @@ -0,0 +1,251 @@ +#!/usr/bin/env python3 +"""Install WALinuxAgent from the Azure wireserver GAFamily manifest. + +Queries the wireserver to discover the target GAFamily version of WALinuxAgent, +downloads the matching zip from the manifest, and installs it under +/var/lib/waagent/WALinuxAgent-/. + +This lets the waagent daemon pick up the correct version locally without +downloading from the network at provisioning time. + +Usage: + python3 install_walinuxagent.py + +Arguments: + download_dir Directory to store the downloaded zip for provenance tracking. + wireserver_url Base URL of the Azure wireserver (e.g. http://168.63.129.16:80). + +Exit codes: + 0 Success + 1 Fatal error (logged to stderr) + +Note: SAS tokens in manifest/blob URLs are never logged. Only the base URL +(before the '?' query string) is printed on error. +""" + +import os +import re +import shutil +import sys +import tempfile +import time +import urllib.parse +import urllib.request +import xml.etree.ElementTree as ET +import zipfile +from html import unescape as html_unescape + +# Retry configuration for wireserver requests +MAX_RETRIES = 10 +RETRY_WAIT_SECONDS = 5 +REQUEST_TIMEOUT_SECONDS = 60 + +# Wireserver request headers (mimic WALinuxAgent) +WIRESERVER_HEADERS = { + "x-ms-agent-name": "WALinuxAgent", + "x-ms-version": "2012-11-30", +} + + +def strip_sas_token(url: str) -> str: + """Return the URL without query parameters to avoid leaking SAS tokens.""" + return url.split("?")[0] + + +def fetch_url(url: str, headers: dict | None = None, silent: bool = False) -> str: + """Fetch a URL with retry logic. Returns the response body as a string. + + Args: + url: The URL to fetch. + headers: Optional HTTP headers to include. + silent: If True, suppress URL from error messages (for SAS token safety). + + Raises: + RuntimeError: If all retries are exhausted. + """ + safe_url = strip_sas_token(url) if silent else url + req = urllib.request.Request(url, headers=headers or {}) + + last_error = None + for attempt in range(1, MAX_RETRIES + 1): + try: + with urllib.request.urlopen(req, timeout=REQUEST_TIMEOUT_SECONDS) as resp: + return resp.read().decode("utf-8") + except Exception as exc: + last_error = exc + if attempt < MAX_RETRIES: + time.sleep(RETRY_WAIT_SECONDS) + + raise RuntimeError(f"Failed to fetch {safe_url} after {MAX_RETRIES} attempts: {last_error}") + + +def download_file(url: str, dest_path: str, silent: bool = False) -> None: + """Download a URL to a local file with retry logic. + + Args: + url: The URL to download. + dest_path: Local file path to write to. + silent: If True, suppress URL from error messages (for SAS token safety). + + Raises: + RuntimeError: If all retries are exhausted. + """ + safe_url = strip_sas_token(url) if silent else url + req = urllib.request.Request(url) + + last_error = None + for attempt in range(1, MAX_RETRIES + 1): + try: + with urllib.request.urlopen(req, timeout=REQUEST_TIMEOUT_SECONDS) as resp: + with open(dest_path, "wb") as f: + shutil.copyfileobj(resp, f) + return + except Exception as exc: + last_error = exc + if attempt < MAX_RETRIES: + time.sleep(RETRY_WAIT_SECONDS) + + raise RuntimeError(f"Failed to download {safe_url} after {MAX_RETRIES} attempts: {last_error}") + + +def extract_extensions_config_url(goalstate_xml: str) -> str: + """Extract and decode the ExtensionsConfig URL from the goalstate XML. + + The URL may be URL-encoded and contain XML-escaped ampersands (&). + Both are handled here. + """ + match = re.search(r"([^<]+)", goalstate_xml) + if not match: + raise RuntimeError("No element found in goalstate") + + url = match.group(1).strip() + url = urllib.parse.unquote(url) + url = html_unescape(url) + return url + + +def extract_ga_family_info(extensions_config_xml: str) -> tuple[str, str]: + """Extract the GAFamily version and first manifest URI from extensions config. + + Returns: + A tuple of (version, manifest_uri). + """ + # Use regex with DOTALL since the GAFamily block spans multiple lines + version_match = re.search( + r".*?([^<]+)", + extensions_config_xml, + re.DOTALL, + ) + if not version_match: + raise RuntimeError("No GAFamily version found in extensions config") + + uri_match = re.search( + r".*?([^<]+)", + extensions_config_xml, + re.DOTALL, + ) + if not uri_match: + raise RuntimeError("No GAFamily manifest URI found in extensions config") + + version = version_match.group(1).strip() + manifest_uri = html_unescape(uri_match.group(1).strip()) + return version, manifest_uri + + +def find_zip_url_in_manifest(manifest_xml: str, target_version: str) -> str: + """Parse the manifest XML and find the download URI for the target version.""" + root = ET.fromstring(manifest_xml) + + for plugin in root.findall(".//Plugin"): + ver_elem = plugin.find("Version") + if ver_elem is not None and ver_elem.text == target_version: + uri_elem = plugin.find(".//Uri") + if uri_elem is not None and uri_elem.text: + return uri_elem.text + + raise RuntimeError(f"Version {target_version} not found in WALinuxAgent manifest") + + +def install_walinuxagent(download_dir: str, wireserver_url: str) -> None: + """Main installation logic. + + 1. Fetch goalstate from wireserver + 2. Extract ExtensionsConfig URL from goalstate + 3. Fetch extensions config + 4. Extract GAFamily version and manifest URI + 5. Fetch the manifest + 6. Find the zip URL for the target version + 7. Download the zip + 8. Extract to /var/lib/waagent/WALinuxAgent-/ + 9. Copy zip to download_dir for provenance tracking + """ + print("Installing WALinuxAgent from wireserver GAFamily manifest...") + + # Step 1: Fetch goalstate + goalstate_url = f"{wireserver_url}/machine/?comp=goalstate" + print(f"Fetching goalstate from {goalstate_url}") + goalstate = fetch_url(goalstate_url, headers=WIRESERVER_HEADERS) + + # Step 2: Extract ExtensionsConfig URL + extensions_config_url = extract_extensions_config_url(goalstate) + + # Step 3: Fetch extensions config + print("Fetching extensions config...") + extensions_config = fetch_url(extensions_config_url, headers=WIRESERVER_HEADERS) + + # Step 4: Extract GAFamily version and manifest URI + version, manifest_url = extract_ga_family_info(extensions_config) + print(f"GAFamily version: {version}") + + # Step 5: Fetch the manifest (silent to avoid logging SAS token) + print(f"Fetching manifest from {strip_sas_token(manifest_url)}") + manifest = fetch_url(manifest_url, silent=True) + + # Step 6: Find the zip URL + zip_url = find_zip_url_in_manifest(manifest, version) + print(f"Found WALinuxAgent {version} zip at: {strip_sas_token(zip_url)}") + + # Step 7: Download the zip to a temp directory + tmp_dir = tempfile.mkdtemp() + try: + zip_path = os.path.join(tmp_dir, f"WALinuxAgent-{version}.zip") + print(f"Downloading WALinuxAgent {version}...") + download_file(zip_url, zip_path, silent=True) + + # Step 8: Extract to /var/lib/waagent/WALinuxAgent-/ + install_dir = f"/var/lib/waagent/WALinuxAgent-{version}" + os.makedirs(install_dir, exist_ok=True) + + with zipfile.ZipFile(zip_path, "r") as zf: + zf.extractall(install_dir) + + print(f"WALinuxAgent {version} installed successfully to {install_dir}") + + # Step 9: Store zip for provenance tracking + os.makedirs(download_dir, exist_ok=True) + dest_zip = os.path.join(download_dir, f"WALinuxAgent-{version}.zip") + shutil.copy2(zip_path, dest_zip) + + finally: + shutil.rmtree(tmp_dir, ignore_errors=True) + + +def main() -> int: + if len(sys.argv) != 3: + print(f"Usage: {sys.argv[0]} ", file=sys.stderr) + return 1 + + download_dir = sys.argv[1] + wireserver_url = sys.argv[2] + + try: + install_walinuxagent(download_dir, wireserver_url) + except Exception as exc: + print(f"ERROR: {exc}", file=sys.stderr) + return 1 + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/vhdbuilder/packer/packer_source.sh b/vhdbuilder/packer/packer_source.sh index 8482cd3504c..4940a69f1c4 100644 --- a/vhdbuilder/packer/packer_source.sh +++ b/vhdbuilder/packer/packer_source.sh @@ -141,6 +141,10 @@ copyPackerFiles() { SNAPSHOT_UPDATE_TIMER_DEST=/etc/systemd/system/snapshot-update.timer VHD_CLEANUP_SCRIPT_SRC=/home/packer/cleanup-vhd.sh VHD_CLEANUP_SCRIPT_DEST=/opt/azure/containers/cleanup-vhd.sh + POST_DEPROVISION_WALINUXAGENT_SRC=/home/packer/post-deprovision-walinuxagent.sh + POST_DEPROVISION_WALINUXAGENT_DEST=/opt/azure/containers/post-deprovision-walinuxagent.sh + INSTALL_WALINUXAGENT_PY_SRC=/home/packer/install_walinuxagent.py + INSTALL_WALINUXAGENT_PY_DEST=/opt/azure/containers/install_walinuxagent.py CONTAINER_IMAGE_PREFETCH_SCRIPT_SRC=/home/packer/prefetch.sh CONTAINER_IMAGE_PREFETCH_SCRIPT_DEST=/opt/azure/containers/prefetch.sh @@ -442,6 +446,10 @@ copyPackerFiles() { # to disk so we can run it again if needed in subsequent builds/releases (prefetch during SIG release) cpAndMode $VHD_CLEANUP_SCRIPT_SRC $VHD_CLEANUP_SCRIPT_DEST 644 + # Copy the post-deprovision WALinuxAgent install script and its Python helper + cpAndMode $POST_DEPROVISION_WALINUXAGENT_SRC $POST_DEPROVISION_WALINUXAGENT_DEST 644 + cpAndMode $INSTALL_WALINUXAGENT_PY_SRC $INSTALL_WALINUXAGENT_PY_DEST 644 + # Copy the generated CNI prefetch script to the appropriate location so AIB can invoke it later cpAndMode $CONTAINER_IMAGE_PREFETCH_SCRIPT_SRC $CONTAINER_IMAGE_PREFETCH_SCRIPT_DEST 644 } diff --git a/vhdbuilder/packer/post-deprovision-walinuxagent.sh b/vhdbuilder/packer/post-deprovision-walinuxagent.sh new file mode 100755 index 00000000000..372cec7a4cc --- /dev/null +++ b/vhdbuilder/packer/post-deprovision-walinuxagent.sh @@ -0,0 +1,62 @@ +#!/bin/bash -eu +# Post-deprovision WALinuxAgent install script. +# Called by packer inline block AFTER 'waagent -force -deprovision+user', +# which clears /var/lib/waagent/. This script re-installs the latest +# WALinuxAgent from the wireserver GAFamily manifest so the agent daemon +# can pick it up locally without downloading at provisioning time. +# +# NOTE: -x is intentionally omitted to avoid leaking SAS tokens from +# wireserver manifest/blob URLs in packer build logs. + +# Skip on AzureLinux OSGuard which uses its OS-packaged waagent version. +# Flatcar is excluded at the packer config level (its JSON does not call this). +OS_VARIANT_ID=$(. /etc/os-release 2>/dev/null && echo "${VARIANT_ID:-}" | tr '[:lower:]' '[:upper:]' | tr -d '"') +if [ "$OS_VARIANT_ID" = "OSGUARD" ]; then + echo "Skipping WALinuxAgent manifest install on AzureLinux OSGuard" + exit 0 +fi + +# Configuration +WALINUXAGENT_DOWNLOAD_DIR="/opt/walinuxagent/downloads" +WALINUXAGENT_WIRESERVER_URL="http://168.63.129.16:80" + +# DNS will be broken on AzLinux after deprovision because +# 'waagent -deprovision' clears /etc/resolv.conf. +# Temporarily restore Azure DNS for manifest download +# and then remove before the VHD is finalized to keep the image clean. +RESOLV_CONF_BAK="" +if [ ! -s /etc/resolv.conf ] || ! grep -q nameserver /etc/resolv.conf; then + cp /etc/resolv.conf /etc/resolv.conf.bak 2>/dev/null || true + RESOLV_CONF_BAK="/etc/resolv.conf.bak" + echo "nameserver 168.63.129.16" > /etc/resolv.conf + echo "Temporarily set DNS to Azure DNS for manifest download" +fi + +# Install WALinuxAgent from wireserver GAFamily manifest. +# Uses a standalone Python script (stdlib only) for wireserver HTTP, XML parsing, +# and zip extraction — replacing inline python3 one-liners that were in bash. +python3 /opt/azure/containers/install_walinuxagent.py "${WALINUXAGENT_DOWNLOAD_DIR}" "${WALINUXAGENT_WIRESERVER_URL}" + +# Configure waagent.conf to pick up the pre-cached agent from disk: +# - AutoUpdate.Enabled=y tells the daemon to look for newer agent versions on disk +# - AutoUpdate.UpdateToLatestVersion=n prevents downloading updates from the network +sed -i 's/AutoUpdate.Enabled=n/AutoUpdate.Enabled=y/g' /etc/waagent.conf +if ! grep -q '^AutoUpdate.Enabled=' /etc/waagent.conf; then + echo 'AutoUpdate.Enabled=y' >> /etc/waagent.conf +fi +sed -i 's/AutoUpdate.UpdateToLatestVersion=y/AutoUpdate.UpdateToLatestVersion=n/g' /etc/waagent.conf +if ! grep -q '^AutoUpdate.UpdateToLatestVersion=' /etc/waagent.conf; then + echo 'AutoUpdate.UpdateToLatestVersion=n' >> /etc/waagent.conf +fi + +# Restore resolv.conf to its post-deprovision state so the VHD ships clean +if [ -n "${RESOLV_CONF_BAK}" ] && [ -f "${RESOLV_CONF_BAK}" ]; then + mv "${RESOLV_CONF_BAK}" /etc/resolv.conf + echo "Restored /etc/resolv.conf to post-deprovision state" +fi + +echo "WALinuxAgent installed and waagent.conf configured post-deprovision" + +# Self-delete: these scripts are only needed during VHD build +rm -f /opt/azure/containers/install_walinuxagent.py +rm -f "${BASH_SOURCE[0]}" diff --git a/vhdbuilder/packer/test/linux-vhd-content-test.sh b/vhdbuilder/packer/test/linux-vhd-content-test.sh index dc1a5f06412..65102b91133 100644 --- a/vhdbuilder/packer/test/linux-vhd-content-test.sh +++ b/vhdbuilder/packer/test/linux-vhd-content-test.sh @@ -1502,6 +1502,63 @@ testBccTools () { return 0 } +# testWALinuxAgentInstalled verifies that the WALinuxAgent GAFamily version was +# installed post-deprovision and that waagent.conf is configured to use it. +# The test runs on a VM booted from the captured VHD image, so the post-deprovision +# script has already executed and self-deleted. We verify its *results*: +# 1. At least one WALinuxAgent-* directory exists under /var/lib/waagent/ +# 2. The directory contains the expected artifacts (bin/, HandlerManifest.json, manifest.xml) +# 3. waagent.conf has AutoUpdate.Enabled=y and AutoUpdate.UpdateToLatestVersion=n +testWALinuxAgentInstalled() { + local test="testWALinuxAgentInstalled" + echo "$test:Start" + + # Check that at least one WALinuxAgent-* directory was installed + local -a dirs + mapfile -t dirs < <(find /var/lib/waagent -maxdepth 1 -type d -name "WALinuxAgent-*" 2>/dev/null | sort -V) + local dirCount=${#dirs[@]} + if [ "$dirCount" -lt 1 ]; then + err "$test" "Expected at least 1 WALinuxAgent directory under /var/lib/waagent/, found ${dirCount}" + return 1 + fi + echo "$test: Found ${dirCount} WALinuxAgent directories: ${dirs[*]}" + + # Validate the newest directory (highest version) has expected artifacts + local installDir="${dirs[-1]}" + echo "$test: Validating pre-cached agent directory ${installDir}" + + local expectedFiles=("HandlerManifest.json" "manifest.xml") + for f in "${expectedFiles[@]}"; do + if [ ! -f "${installDir}/${f}" ]; then + err "$test" "Expected file ${f} not found in ${installDir}, contents: $(ls -al "${installDir}")" + return 1 + fi + echo "$test: Found expected file ${installDir}/${f}" + done + + if [ ! -d "${installDir}/bin" ]; then + err "$test" "bin/ directory not found in ${installDir}, contents: $(ls -al "${installDir}")" + return 1 + fi + echo "$test: Found bin/ directory in ${installDir}" + + # Verify waagent.conf has the expected AutoUpdate settings + if grep -q '^AutoUpdate.Enabled=y' /etc/waagent.conf; then + echo "$test: waagent.conf has AutoUpdate.Enabled=y" + else + err "$test" "waagent.conf missing AutoUpdate.Enabled=y" + return 1 + fi + if grep -q '^AutoUpdate.UpdateToLatestVersion=n' /etc/waagent.conf; then + echo "$test: waagent.conf has AutoUpdate.UpdateToLatestVersion=n" + else + err "$test" "waagent.conf missing AutoUpdate.UpdateToLatestVersion=n" + return 1 + fi + + echo "$test:Finish" +} + testAKSNodeControllerBinary () { local test="testAKSNodeControllerBinary" local go_binary_path="/opt/azure/containers/aks-node-controller" @@ -1908,6 +1965,11 @@ testBccTools $OS_SKU testVHDBuildLogsExist testCriticalTools testPackagesInstalled +# WALinuxAgent is installed post-deprovision (not via components.json), +# so test it separately. Skip on Flatcar and AzureLinuxOSGuard which use OS-packaged version. +if [ "$OS_SKU" != "Flatcar" ] && [ "$OS_SKU" != "AzureLinuxOSGuard" ]; then + testWALinuxAgentInstalled +fi testImagesPulled "$(cat $COMPONENTS_FILEPATH)" testImagesCompleted testPodSandboxImagePinned diff --git a/vhdbuilder/packer/vhd-image-builder-arm64-gen2.json b/vhdbuilder/packer/vhd-image-builder-arm64-gen2.json index 7e2c40f156a..d139810288d 100644 --- a/vhdbuilder/packer/vhd-image-builder-arm64-gen2.json +++ b/vhdbuilder/packer/vhd-image-builder-arm64-gen2.json @@ -118,6 +118,16 @@ "source": "vhdbuilder/packer/cleanup-vhd.sh", "destination": "/home/packer/cleanup-vhd.sh" }, + { + "type": "file", + "source": "vhdbuilder/packer/post-deprovision-walinuxagent.sh", + "destination": "/home/packer/post-deprovision-walinuxagent.sh" + }, + { + "type": "file", + "source": "vhdbuilder/packer/install_walinuxagent.py", + "destination": "/home/packer/install_walinuxagent.py" + }, { "type": "file", "source": "vhdbuilder/packer/packer_source.sh", @@ -786,7 +796,7 @@ "inline": [ "sudo /bin/bash -eux /home/packer/cis.sh", "sudo /bin/bash -eux /opt/azure/containers/cleanup-vhd.sh", - "sudo /usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0 && sync || exit 125" + "sudo /bin/bash -c '/usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0 && sync && /bin/bash -eu /opt/azure/containers/post-deprovision-walinuxagent.sh' || exit 125" ] } ], diff --git a/vhdbuilder/packer/vhd-image-builder-base.json b/vhdbuilder/packer/vhd-image-builder-base.json index ffca1d2c020..542036aa5ca 100644 --- a/vhdbuilder/packer/vhd-image-builder-base.json +++ b/vhdbuilder/packer/vhd-image-builder-base.json @@ -121,6 +121,16 @@ "source": "vhdbuilder/packer/cleanup-vhd.sh", "destination": "/home/packer/cleanup-vhd.sh" }, + { + "type": "file", + "source": "vhdbuilder/packer/post-deprovision-walinuxagent.sh", + "destination": "/home/packer/post-deprovision-walinuxagent.sh" + }, + { + "type": "file", + "source": "vhdbuilder/packer/install_walinuxagent.py", + "destination": "/home/packer/install_walinuxagent.py" + }, { "type": "file", "source": "vhdbuilder/packer/packer_source.sh", @@ -784,7 +794,7 @@ "inline": [ "sudo /bin/bash -eux /home/packer/cis.sh", "sudo /bin/bash -eux /opt/azure/containers/cleanup-vhd.sh", - "sudo /usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0 && sync || exit 125" + "sudo /bin/bash -c '/usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0 && sync && /bin/bash -eu /opt/azure/containers/post-deprovision-walinuxagent.sh' || exit 125" ] } ], diff --git a/vhdbuilder/packer/vhd-image-builder-cvm.json b/vhdbuilder/packer/vhd-image-builder-cvm.json index 0ef59882d26..093f86ade4b 100644 --- a/vhdbuilder/packer/vhd-image-builder-cvm.json +++ b/vhdbuilder/packer/vhd-image-builder-cvm.json @@ -125,6 +125,16 @@ "source": "vhdbuilder/packer/cleanup-vhd.sh", "destination": "/home/packer/cleanup-vhd.sh" }, + { + "type": "file", + "source": "vhdbuilder/packer/post-deprovision-walinuxagent.sh", + "destination": "/home/packer/post-deprovision-walinuxagent.sh" + }, + { + "type": "file", + "source": "vhdbuilder/packer/install_walinuxagent.py", + "destination": "/home/packer/install_walinuxagent.py" + }, { "type": "file", "source": "vhdbuilder/packer/packer_source.sh", @@ -788,7 +798,7 @@ "inline": [ "sudo /bin/bash -eux /home/packer/cis.sh", "sudo /bin/bash -eux /opt/azure/containers/cleanup-vhd.sh", - "sudo /usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0 && sync || exit 125" + "sudo /bin/bash -c '/usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0 && sync && /bin/bash -eu /opt/azure/containers/post-deprovision-walinuxagent.sh' || exit 125" ] } ], diff --git a/vhdbuilder/packer/vhd-image-builder-mariner-arm64.json b/vhdbuilder/packer/vhd-image-builder-mariner-arm64.json index f3041e30f8a..2715077f930 100644 --- a/vhdbuilder/packer/vhd-image-builder-mariner-arm64.json +++ b/vhdbuilder/packer/vhd-image-builder-mariner-arm64.json @@ -117,6 +117,16 @@ "source": "vhdbuilder/packer/cleanup-vhd.sh", "destination": "/home/packer/cleanup-vhd.sh" }, + { + "type": "file", + "source": "vhdbuilder/packer/post-deprovision-walinuxagent.sh", + "destination": "/home/packer/post-deprovision-walinuxagent.sh" + }, + { + "type": "file", + "source": "vhdbuilder/packer/install_walinuxagent.py", + "destination": "/home/packer/install_walinuxagent.py" + }, { "type": "file", "source": "vhdbuilder/packer/packer_source.sh", @@ -750,7 +760,7 @@ "inline": [ "sudo /bin/bash -eux /home/packer/cis.sh", "sudo /bin/bash -eux /opt/azure/containers/cleanup-vhd.sh", - "sudo waagent -force -deprovision+user && export HISTSIZE=0 && sync || exit 125" + "sudo /bin/bash -c 'waagent -force -deprovision+user && export HISTSIZE=0 && sync && /bin/bash -eu /opt/azure/containers/post-deprovision-walinuxagent.sh' || exit 125" ] } ], diff --git a/vhdbuilder/packer/vhd-image-builder-mariner-cvm.json b/vhdbuilder/packer/vhd-image-builder-mariner-cvm.json index add318e16df..669a3ce9ff4 100644 --- a/vhdbuilder/packer/vhd-image-builder-mariner-cvm.json +++ b/vhdbuilder/packer/vhd-image-builder-mariner-cvm.json @@ -123,6 +123,16 @@ "source": "vhdbuilder/packer/cleanup-vhd.sh", "destination": "/home/packer/cleanup-vhd.sh" }, + { + "type": "file", + "source": "vhdbuilder/packer/post-deprovision-walinuxagent.sh", + "destination": "/home/packer/post-deprovision-walinuxagent.sh" + }, + { + "type": "file", + "source": "vhdbuilder/packer/install_walinuxagent.py", + "destination": "/home/packer/install_walinuxagent.py" + }, { "type": "file", "source": "vhdbuilder/packer/packer_source.sh", @@ -751,7 +761,7 @@ "inline": [ "sudo /bin/bash -eux /home/packer/cis.sh", "sudo /bin/bash -eux /opt/azure/containers/cleanup-vhd.sh", - "sudo waagent -force -deprovision+user && export HISTSIZE=0 && sync || exit 125" + "sudo /bin/bash -c 'waagent -force -deprovision+user && export HISTSIZE=0 && sync && /bin/bash -eu /opt/azure/containers/post-deprovision-walinuxagent.sh' || exit 125" ] } ], diff --git a/vhdbuilder/packer/vhd-image-builder-mariner.json b/vhdbuilder/packer/vhd-image-builder-mariner.json index af2c6dfe856..19fd6c80ed9 100644 --- a/vhdbuilder/packer/vhd-image-builder-mariner.json +++ b/vhdbuilder/packer/vhd-image-builder-mariner.json @@ -119,6 +119,16 @@ "source": "vhdbuilder/packer/cleanup-vhd.sh", "destination": "/home/packer/cleanup-vhd.sh" }, + { + "type": "file", + "source": "vhdbuilder/packer/post-deprovision-walinuxagent.sh", + "destination": "/home/packer/post-deprovision-walinuxagent.sh" + }, + { + "type": "file", + "source": "vhdbuilder/packer/install_walinuxagent.py", + "destination": "/home/packer/install_walinuxagent.py" + }, { "type": "file", "source": "vhdbuilder/packer/packer_source.sh", @@ -752,7 +762,7 @@ "inline": [ "sudo /bin/bash -eux /home/packer/cis.sh", "sudo /bin/bash -eux /opt/azure/containers/cleanup-vhd.sh", - "sudo waagent -force -deprovision+user && export HISTSIZE=0 && sync || exit 125" + "sudo /bin/bash -c 'waagent -force -deprovision+user && export HISTSIZE=0 && sync && /bin/bash -eu /opt/azure/containers/post-deprovision-walinuxagent.sh' || exit 125" ] } ],