|
| 1 | +#!/bin/bash |
| 2 | + |
| 3 | +# Copyright (c) 2024-2025 The Flatcar Maintainers. |
| 4 | +# Use of this source code is governed by the Apache 2.0 license. |
| 5 | + |
| 6 | +# Script to publish Flatcar images to Azure Shared Galley Images |
| 7 | + |
| 8 | +# Set defaults for environment variables (allow override via --env or directly in script) |
| 9 | +AZURE_SUBSCRIPTION_ID="${AZURE_SUBSCRIPTION_ID:-3be1ff13-7eef-458c-b1ef-97a01af1b2f4}" |
| 10 | +IMAGE_PUBLISHER_NAME="${IMAGE_PUBLISHER_NAME:-flatcar}" |
| 11 | +AZURE_LOCATION="${AZURE_LOCATION:-westeurope}" |
| 12 | +SIG_RESOURCE_GROUP="${STAGING_SIG_RESOURCE_GROUP:-sayan-flatcar-image-gallery-staging}" |
| 13 | + |
| 14 | +FLATCAR_GALLERY_NAME="${FLATCAR_STAGING_GALLERY_NAME:-sayan_flatcar_staging}" |
| 15 | +FLATCAR_IMAGE_NAME="${FLATCAR_IMAGE_NAME:-"flatcar-${FLATCAR_CHANNEL}-${FLATCAR_ARCH}"}" |
| 16 | +FLATCAR_CHANNEL="${FLATCAR_CHANNEL:-developer}" |
| 17 | +FLATCAR_VERSION="${FLATCAR_VERSION:-3374.2.1}" |
| 18 | +FLATCAR_ARCH="${FLATCAR_ARCH:-amd64}" |
| 19 | +FLATCAR_LOCAL_FILE_NAME="${FLATCAR_LOCAL_FILE_NAME:-flatcar_production_azure_image.vhd}" |
| 20 | +FLATCAR_LOCAL_FILE_URL="${FLATCAR_LOCAL_FILE_URL:-}" |
| 21 | +FLATCAR_IMAGE_OFFER="${FLATCAR_IMAGE_OFFER:-${FLATCAR_CHANNEL}}" |
| 22 | + |
| 23 | +FLATCAR_GALLERY_IMAGE_NAME="${FLATCAR_GALLERY_IMAGE_NAME:-"flatcar-${FLATCAR_CHANNEL}-${FLATCAR_ARCH}"}" |
| 24 | +FLATCAR_GALLERY_VERSION="${FLATCAR_GALLERY_VERSION:-3374.2.9999}" |
| 25 | + |
| 26 | +VHD_STORAGE_ACCOUNT_NAME="${VHD_STORAGE_ACCOUNT_NAME:-flatcar}" |
| 27 | +VHD_STORAGE_RESOURCE_GROUP_NAME="${VHD_STORAGE_RESOURCE_GROUP_NAME:-flatcar}" |
| 28 | +VHD_STORAGE_CONTAINER_NAME="${VHD_STORAGE_CONTAINER_NAME:-developer}" |
| 29 | +BLACKLISTED_TARGET_REGIONS="${BLACKLISTED_TARGET_REGIONS:-polandcentral australiacentral2 brazilsoutheast centraluseuap eastus2euap eastusstg francesouth germanynorth jioindiacentral norwaywest southafricawest switzerlandwest uaecentral brazilus southcentralusstg}" |
| 30 | +TARGET_REGIONS="${TARGET_REGIONS:-}" |
| 31 | + |
| 32 | +function publish-flatcar-sig-image-version-from-vhd() { |
| 33 | + login |
| 34 | + |
| 35 | + get-target-regions |
| 36 | + ensure-vhd-uri-exists |
| 37 | + ensure-resource-group |
| 38 | + ensure-sig |
| 39 | + IMAGE_OFFER="${FLATCAR_IMAGE_OFFER}" IMAGE_PUBLISHER="${IMAGE_PUBLISHER_NAME}" ensure-image-definition |
| 40 | + |
| 41 | + STORAGE_ACCOUNT_ID="/subscriptions/${AZURE_SUBSCRIPTION_ID}/resourceGroups/${VHD_STORAGE_RESOURCE_GROUP_NAME}/providers/Microsoft.Storage/storageAccounts/${VHD_STORAGE_ACCOUNT_NAME}" |
| 42 | + VHD_URI="https://${VHD_STORAGE_ACCOUNT_NAME}.blob.core.windows.net/${VHD_STORAGE_CONTAINER_NAME}/flatcar-linux-${FLATCAR_GALLERY_VERSION}-${FLATCAR_CHANNEL}-${FLATCAR_ARCH}.vhd" |
| 43 | + |
| 44 | + if ! sig-image-version-exists; then |
| 45 | + echo "Creating SIG image version ${FLATCAR_GALLERY_VERSION}" |
| 46 | + az sig image-version create \ |
| 47 | + --resource-group "${SIG_RESOURCE_GROUP}" \ |
| 48 | + --gallery-name "${FLATCAR_GALLERY_NAME}" \ |
| 49 | + --gallery-image-definition "${FLATCAR_GALLERY_IMAGE_NAME}" \ |
| 50 | + --gallery-image-version "${FLATCAR_GALLERY_VERSION}" \ |
| 51 | + --os-vhd-storage-account "${STORAGE_ACCOUNT_ID}" \ |
| 52 | + --os-vhd-uri "${VHD_URI}" |
| 53 | + else |
| 54 | + echo "SIG image version ${FLATCAR_GALLERY_VERSION} already exists, skipping creation" |
| 55 | + fi |
| 56 | + |
| 57 | + sig-image-version-update-regions |
| 58 | +} |
| 59 | + |
| 60 | +function get-target-regions() { |
| 61 | + if [[ -n "${TARGET_REGIONS:-}" ]]; then |
| 62 | + return 0 |
| 63 | + fi |
| 64 | + |
| 65 | + echo "Fetching target regions" |
| 66 | + TARGET_REGIONS=$(az account list-locations -o json | jq -r '.[] | select( .metadata.regionType != "Logical" ) | .name' | sort | grep -v -E "(${BLACKLISTED_TARGET_REGIONS// /|})" | tr '\n' ' ') |
| 67 | +} |
| 68 | + |
| 69 | +function ensure-vhd-uri-exists() { |
| 70 | + EXISTS=$(az storage blob exists \ |
| 71 | + --account-name "${VHD_STORAGE_ACCOUNT_NAME}" \ |
| 72 | + --container-name "${VHD_STORAGE_CONTAINER_NAME}" \ |
| 73 | + --auth-mode login \ |
| 74 | + --name "flatcar-linux-${FLATCAR_GALLERY_VERSION}-${FLATCAR_CHANNEL}-${FLATCAR_ARCH}.vhd" \ |
| 75 | + --query "exists" -o tsv) |
| 76 | + |
| 77 | + if [[ "${EXISTS}" = "true" ]]; then |
| 78 | + echo "flatcar-linux-${FLATCAR_GALLERY_VERSION}-${FLATCAR_CHANNEL}-${FLATCAR_ARCH} Blob already exists. Skipping upload." |
| 79 | + return 0 |
| 80 | + fi |
| 81 | + |
| 82 | + if [[ -z "${FLATCAR_LOCAL_FILE_URL:-}" ]]; then |
| 83 | + echo "FLATCAR_LOCAL_FILE_URL variable is empty. Please set." |
| 84 | + exit 1 |
| 85 | + fi |
| 86 | + |
| 87 | + echo "Blob doesn't exist. Downloading flatcar-linux-${FLATCAR_GALLERY_VERSION}-${FLATCAR_CHANNEL}-${FLATCAR_ARCH}" |
| 88 | + # Download the VHD file (only if blob doesn't exist) |
| 89 | + echo "Downloading ${FLATCAR_LOCAL_FILE_URL}..." |
| 90 | + if ! curl -L -o "/data/${FLATCAR_LOCAL_FILE_NAME}.bz2" "${FLATCAR_LOCAL_FILE_URL}"; then |
| 91 | + echo "ERROR: Download failed. Exiting" |
| 92 | + exit 1 |
| 93 | + fi |
| 94 | + |
| 95 | + # Decompress the file |
| 96 | + echo "Decompressing ${FLATCAR_LOCAL_FILE_NAME}.bz2" |
| 97 | + if ! bzip2 -d "/data/${FLATCAR_LOCAL_FILE_NAME}.bz2"; then |
| 98 | + echo "ERROR: Decompression failed. Exiting" |
| 99 | + exit 1 |
| 100 | + fi |
| 101 | + |
| 102 | + echo "Uploading blob - flatcar-linux-${FLATCAR_GALLERY_VERSION}-${FLATCAR_CHANNEL}-${FLATCAR_ARCH}" |
| 103 | + if ! az storage blob upload \ |
| 104 | + --account-name "${VHD_STORAGE_ACCOUNT_NAME}" \ |
| 105 | + --auth-mode login \ |
| 106 | + --container "${VHD_STORAGE_CONTAINER_NAME}" \ |
| 107 | + --name "flatcar-linux-${FLATCAR_GALLERY_VERSION}-${FLATCAR_CHANNEL}-${FLATCAR_ARCH}.vhd" \ |
| 108 | + --file "/data/${FLATCAR_LOCAL_FILE_NAME}"; then |
| 109 | + echo "ERROR: Blob upload failed. Exiting" |
| 110 | + exit 1 |
| 111 | + fi |
| 112 | +} |
| 113 | + |
| 114 | +function sig-image-version-exists() { |
| 115 | + if ! az sig image-version show \ |
| 116 | + --gallery-image-definition "${FLATCAR_GALLERY_IMAGE_NAME}" \ |
| 117 | + --gallery-image-version "${FLATCAR_GALLERY_VERSION}" \ |
| 118 | + --gallery-name "${FLATCAR_GALLERY_NAME}" \ |
| 119 | + --resource-group "${SIG_RESOURCE_GROUP}" \ |
| 120 | + --output none \ |
| 121 | + --only-show-errors; then |
| 122 | + echo "SIG image ${SIG_RESOURCE_GROUP}/${FLATCAR_GALLERY_NAME}/${FLATCAR_GALLERY_VERSION}/${FLATCAR_GALLERY_IMAGE_NAME} does not exist" |
| 123 | + return 1 |
| 124 | + fi |
| 125 | + |
| 126 | + echo "SIG image ${SIG_RESOURCE_GROUP}/${FLATCAR_GALLERY_NAME}/${FLATCAR_GALLERY_VERSION}/${FLATCAR_GALLERY_IMAGE_NAME} already exists" |
| 127 | + return 0 |
| 128 | +} |
| 129 | + |
| 130 | +function sig-image-version-update-regions() { |
| 131 | + echo "DEBUG: Source location: ${AZURE_LOCATION}" |
| 132 | + echo "DEBUG: Target regions: ${TARGET_REGIONS}" |
| 133 | + az sig image-version update \ |
| 134 | + --resource-group "${SIG_RESOURCE_GROUP}" \ |
| 135 | + --gallery-name "${FLATCAR_GALLERY_NAME}" \ |
| 136 | + --gallery-image-definition "${FLATCAR_GALLERY_IMAGE_NAME}" \ |
| 137 | + --gallery-image-version "${FLATCAR_GALLERY_VERSION}" \ |
| 138 | + --target-regions ${TARGET_REGIONS} |
| 139 | +} |
| 140 | + |
| 141 | +function ensure-image-definition() { |
| 142 | + local architecture |
| 143 | + case "${FLATCAR_ARCH}" in |
| 144 | + amd64) architecture=x64 ;; |
| 145 | + arm64) architecture=Arm64 ;; |
| 146 | + *) echo "Unsupported architecture: '${FLATCAR_ARCH}'"; exit 1 ;; |
| 147 | + esac |
| 148 | + |
| 149 | + az sig image-definition create \ |
| 150 | + --gallery-image-definition "${FLATCAR_GALLERY_IMAGE_NAME}" \ |
| 151 | + --gallery-name "${FLATCAR_GALLERY_NAME}" \ |
| 152 | + --offer "${FLATCAR_IMAGE_OFFER}" \ |
| 153 | + --os-type Linux \ |
| 154 | + --publisher "${IMAGE_PUBLISHER_NAME}" \ |
| 155 | + --resource-group "${SIG_RESOURCE_GROUP}" \ |
| 156 | + --sku "${FLATCAR_GALLERY_IMAGE_NAME}" \ |
| 157 | + --architecture "${architecture}" \ |
| 158 | + --hyper-v-generation V2 |
| 159 | +} |
| 160 | + |
| 161 | +function ensure-sig() { |
| 162 | + az sig create \ |
| 163 | + --gallery-name "${FLATCAR_GALLERY_NAME}" \ |
| 164 | + --resource-group "${SIG_RESOURCE_GROUP}" |
| 165 | +} |
| 166 | + |
| 167 | +function ensure-resource-group() { |
| 168 | + if ! az group show -n "${SIG_RESOURCE_GROUP}" -o none 2>/dev/null; then |
| 169 | + az group create -n "${SIG_RESOURCE_GROUP}" -l "${AZURE_LOCATION}" |
| 170 | + fi |
| 171 | +} |
| 172 | + |
| 173 | +function login() { |
| 174 | + echo "Authenticating to Azure using managed identity" |
| 175 | + AZURE_LOGIN_ERR_FILE=$(mktemp) |
| 176 | + trap 'rm -f "$AZURE_LOGIN_ERR_FILE"' EXIT |
| 177 | + |
| 178 | + if ! az login --identity >/dev/null 2>"$AZURE_LOGIN_ERR_FILE"; then |
| 179 | + echo "Azure login failed. Error:" >&2 |
| 180 | + cat "$AZURE_LOGIN_ERR_FILE" >&2 |
| 181 | + exit 1 |
| 182 | + fi |
| 183 | + |
| 184 | + echo "Azure login successful." |
| 185 | + echo "Setting active subscription to ${AZURE_SUBSCRIPTION_ID}" |
| 186 | + if ! az account set -s "${AZURE_SUBSCRIPTION_ID}" >/dev/null 2>&1; then |
| 187 | + echo "Failed to set Azure subscription." |
| 188 | + exit 1 |
| 189 | + fi |
| 190 | + echo "Subscription set." |
| 191 | +} |
| 192 | + |
| 193 | +# Entrypoint |
| 194 | +publish-flatcar-sig-image-version-from-vhd |
0 commit comments