-
Notifications
You must be signed in to change notification settings - Fork 250
feat: install waagent via wireserver #7987
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
8eed1ac
59ea521
5549b6a
059b354
e95b8b1
b5b93f1
a8c8cf4
41543df
15b18b6
f1177c2
b52e152
ca22f1b
1e02dde
03f5267
cbfc811
71b7c9d
f13e689
4e48098
6696a63
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -296,6 +296,153 @@ downloadSecureTLSBootstrapClient() { | |
| echo "aks-secure-tls-bootstrap-client installed successfully" | ||
| } | ||
|
|
||
| # installWALinuxAgent queries the Azure wireserver to get the WALinuxAgent GAFamily | ||
| # version and manifest, downloads the zip for that version, and installs it under | ||
| # /var/lib/waagent/WALinuxAgent-<version>/. | ||
| # GAFamily is the exact version the waagent daemon targets during auto-update. | ||
| # Installing it during VHD build lets the daemon pick it up locally without | ||
| # downloading from the network at provisioning time. | ||
| installWALinuxAgent() { | ||
| local downloadDir=$1 | ||
| local wireserverURL=$2 | ||
|
|
||
| echo "Installing WALinuxAgent from wireserver GAFamily manifest..." | ||
|
|
||
| # Step 1: Get the goalstate to find the ExtensionsConfig URL | ||
| local goalstate | ||
| goalstate=$(retrycmd_if_failure 10 5 60 curl -sSf -H "x-ms-agent-name: WALinuxAgent" -H "x-ms-version: 2012-11-30" "${wireserverURL}/machine/?comp=goalstate") || { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. curl has its own retries mechanism, look at the repo and search for |
||
| echo "ERROR: Failed to fetch goalstate from wireserver" | ||
| return 1 | ||
| } | ||
|
|
||
| # Step 2: Extract and decode the ExtensionsConfig URL | ||
| local extensions_config_url | ||
| extensions_config_url=$(echo "${goalstate}" | python3 -c " | ||
| import sys, re | ||
| content = sys.stdin.read() | ||
| m = re.search(r'<ExtensionsConfig>([^<]+)</ExtensionsConfig>', content) | ||
| if m: | ||
| print(m.group(1)) | ||
| else: | ||
| sys.exit(1) | ||
| ") || { | ||
| echo "ERROR: Failed to extract ExtensionsConfig URL from goalstate" | ||
| return 1 | ||
| } | ||
| # URL-decode and fix XML-escaped ampersands | ||
| extensions_config_url=$(echo "${extensions_config_url}" | python3 -c "import sys, urllib.parse; print(urllib.parse.unquote(sys.stdin.read().strip()))" | sed 's/&/\&/g') | ||
|
|
||
| # Step 3: Fetch the extensions config to find the GAFamily version and manifest URI | ||
| local extensions_config | ||
| extensions_config=$(retrycmd_if_failure 10 5 60 curl -sSf -H "x-ms-agent-name: WALinuxAgent" -H "x-ms-version: 2012-11-30" "${extensions_config_url}") || { | ||
| echo "ERROR: Failed to fetch extensions config" | ||
| return 1 | ||
| } | ||
mxj220 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| # Step 4: Extract the GAFamily version and first manifest URI using python3 regex. | ||
| # We use python3 instead of grep because: | ||
| # - grep -A N is fragile when the number of <Uri> entries varies by region | ||
| # - grep -oP (PCRE \K) has portability issues across distros/configurations | ||
| # - The GAFamily block can span many lines; python3 re.DOTALL handles this cleanly | ||
| local ga_family_info | ||
| ga_family_info=$(echo "${extensions_config}" | python3 -c " | ||
| import sys, re | ||
| content = sys.stdin.read() | ||
| # Extract version from the GAFamily block | ||
| vm = re.search(r'<GAFamily>.*?<Version>([^<]+)</Version>', content, re.DOTALL) | ||
| if not vm: | ||
| print('ERROR: No GAFamily version found', file=sys.stderr) | ||
| sys.exit(1) | ||
| # Extract first URI from the GAFamily block | ||
| um = re.search(r'<GAFamily>.*?<Uri>([^<]+)</Uri>', content, re.DOTALL) | ||
| if not um: | ||
| print('ERROR: No GAFamily manifest URI found', file=sys.stderr) | ||
| sys.exit(1) | ||
| print(vm.group(1)) | ||
| print(um.group(1)) | ||
| ") || { | ||
| echo "ERROR: Failed to parse GAFamily from extensions config" | ||
| return 1 | ||
| } | ||
|
|
||
| local version | ||
| version=$(echo "${ga_family_info}" | head -n 1) | ||
| echo "GAFamily version: ${version}" | ||
|
|
||
| local manifest_url | ||
| manifest_url=$(echo "${ga_family_info}" | tail -n 1) | ||
| # Fix XML-escaped ampersands in SAS query parameters (same issue as extensions config URL) | ||
| manifest_url=$(echo "${manifest_url}" | sed 's/&/\&/g') | ||
|
|
||
| # Step 6: Fetch the manifest | ||
| # Use retrycmd_silent to avoid logging the full URL (contains SAS token). | ||
| local manifest | ||
| manifest=$(retrycmd_silent 10 5 60 curl -sSf "${manifest_url}") || { | ||
| echo "ERROR: Failed to fetch manifest from ${manifest_url%%\?*}" | ||
| return 1 | ||
| } | ||
|
|
||
| # Step 7: Find the zip URL for the GAFamily version by parsing the manifest XML | ||
| local zip_url | ||
| zip_url=$(echo "${manifest}" | python3 -c " | ||
| import sys | ||
| import xml.etree.ElementTree as ET | ||
| content = sys.stdin.read() | ||
| root = ET.fromstring(content) | ||
| target = '${version}' | ||
| for plugin in root.findall('.//Plugin'): | ||
| ver = plugin.find('Version') | ||
| if ver is not None and ver.text == target: | ||
| uri = plugin.find('.//Uri') | ||
| if uri is not None: | ||
| print(uri.text) | ||
| sys.exit(0) | ||
| sys.exit(1) | ||
| ") || { | ||
| echo "ERROR: Version ${version} not found in WALinuxAgent manifest" | ||
| return 1 | ||
| } | ||
|
|
||
| if [ -z "${zip_url}" ]; then | ||
| echo "ERROR: No download URL found for WALinuxAgent version ${version}" | ||
| return 1 | ||
| fi | ||
|
|
||
| # Log the URL without query parameters to avoid leaking SAS tokens in build logs | ||
| echo "Found WALinuxAgent ${version} zip at: ${zip_url%%\?*}" | ||
|
|
||
| # Step 8: Download the zip | ||
| # Use retrycmd_silent to avoid logging the full URL (contains SAS token). | ||
| local tmpDir | ||
| tmpDir=$(mktemp -d) | ||
| local zipFile="${tmpDir}/WALinuxAgent-${version}.zip" | ||
|
|
||
| retrycmd_silent 10 5 60 curl -sSf -o "${zipFile}" "${zip_url}" || { | ||
| echo "ERROR: Failed to download WALinuxAgent zip from ${zip_url%%\?*}" | ||
| rm -rf "${tmpDir}" | ||
| return 1 | ||
| } | ||
|
|
||
| # Step 9: Install the agent zip under /var/lib/waagent/WALinuxAgent-<version>/ | ||
| local installDir="/var/lib/waagent/WALinuxAgent-${version}" | ||
| mkdir -p "${installDir}" | ||
| # Use python3 zipfile module instead of unzip, which may not be installed on all build VMs | ||
| python3 -m zipfile -e "${zipFile}" "${installDir}" || { | ||
| echo "ERROR: Failed to extract WALinuxAgent zip to ${installDir}" | ||
| rm -rf "${tmpDir}" | ||
| return 1 | ||
| } | ||
|
|
||
| echo "WALinuxAgent ${version} installed successfully to ${installDir}" | ||
|
|
||
| # Store the zip in the download directory for provenance tracking | ||
| mkdir -p "${downloadDir}" | ||
| cp "${zipFile}" "${downloadDir}/" 2>/dev/null || true | ||
|
|
||
| # Clean up temporary files | ||
| rm -rf "${tmpDir}" | ||
| } | ||
|
|
||
| evalPackageDownloadURL() { | ||
| local url=${1:-} | ||
| if [ -n "$url" ]; then | ||
|
|
||
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,3 +13,63 @@ chmod 644 /etc/machine-id | |
| rm -f /opt/azure/disk-usage.txt | ||
| # Cleanup IMDS instance metadata cache file | ||
| rm -f /opt/azure/containers/imds_instance_metadata_cache.json | ||
|
|
||
| # Write post-deprovision WALinuxAgent install script. | ||
| # The deprovision step (waagent -force -deprovision+user) clears /var/lib/waagent/, | ||
| # so we install the latest agent AFTER deprovision. This script is called from the | ||
| # packer inline block after the deprovision command completes. | ||
| # Skip on Flatcar and AzureLinux OSGuard which use their OS-packaged version. | ||
| OS_ID=$(. /etc/os-release 2>/dev/null && echo "${ID:-}" | tr '[:lower:]' '[:upper:]') | ||
| OS_VARIANT_ID=$(. /etc/os-release 2>/dev/null && echo "${VARIANT_ID:-}" | tr '[:lower:]' '[:upper:]' | tr -d '"') | ||
| if [ "$OS_ID" != "FLATCAR" ] && [ "$OS_VARIANT_ID" != "OSGUARD" ]; then | ||
| WALINUXAGENT_DOWNLOAD_DIR="/opt/walinuxagent/downloads" | ||
| WALINUXAGENT_WIRESERVER_URL="http://168.63.129.16:80" | ||
| cat > /opt/azure/containers/post-deprovision-walinuxagent.sh << WALINUXAGENT_SCRIPT | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you create this file in the repo directly (check it in) instead of creating one on the fly |
||
| #!/bin/bash -eu | ||
| # Post-deprovision WALinuxAgent install script. | ||
| # NOTE: -x is intentionally omitted to avoid leaking SAS tokens from | ||
| # wireserver manifest/blob URLs in packer build logs. | ||
| # Sources the provisioning helpers and installs the latest agent from wireserver, | ||
| # then configures waagent.conf to use the pre-cached agent from disk. | ||
mxj220 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| # 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 | ||
mxj220 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| source /opt/azure/containers/provision_source.sh | ||
| source /opt/azure/containers/provision_installs.sh | ||
|
|
||
| # Install WALinuxAgent from wireserver GAFamily manifest | ||
| installWALinuxAgent ${WALINUXAGENT_DOWNLOAD_DIR} ${WALINUXAGENT_WIRESERVER_URL} | ||
|
|
||
mxj220 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| # 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" | ||
| WALINUXAGENT_SCRIPT | ||
| chmod 755 /opt/azure/containers/post-deprovision-walinuxagent.sh | ||
| echo "Wrote post-deprovision WALinuxAgent install script" | ||
| fi | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -784,7 +784,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 && if [ -f /opt/azure/containers/post-deprovision-walinuxagent.sh ]; then /bin/bash -eu /opt/azure/containers/post-deprovision-walinuxagent.sh && rm -f /opt/azure/containers/post-deprovision-walinuxagent.sh; fi' || exit 125" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. move the whole command into deprovision script for easier debugging |
||
| ] | ||
| } | ||
| ], | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i see lot of python used in this function. Why not move all the functionality into a python script and call it? Just makes it easier to read and maintain.