From 16903de38430777796edbf3c4b334b125be74cf6 Mon Sep 17 00:00:00 2001 From: Colby Williams Date: Tue, 18 Oct 2022 13:53:26 -0500 Subject: [PATCH] use winget settings.json --- README.md | 2 +- bake/HISTORY.rst | 5 ++ bake/azext_bake/_constants.py | 104 ++++++++++++++++++++++++++-------- bake/azext_bake/_packer.py | 79 +++++++------------------- bake/azext_bake/_utils.py | 2 +- bake/setup.py | 2 +- builder/Dockerfile | 2 +- schema/image.schema.json | 22 ++++++- 8 files changed, 131 insertions(+), 87 deletions(-) diff --git a/README.md b/README.md index 8d8597f..edfb394 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Microsoft Azure CLI Custom Image Helper 'az' Extension adds useful "utilities" f To install the Azure CLI Custom Image Helper extension, simply run the following command: ```sh -az extension add --source https://github.com/colbylwilliams/az-bake/releases/latest/download/bake-0.0.25-py3-none-any.whl -y +az extension add --source https://github.com/colbylwilliams/az-bake/releases/latest/download/bake-0.0.26-py3-none-any.whl -y ``` ### Update diff --git a/bake/HISTORY.rst b/bake/HISTORY.rst index 6329828..efb9c56 100644 --- a/bake/HISTORY.rst +++ b/bake/HISTORY.rst @@ -3,6 +3,11 @@ Release History =============== +0.0.26 +++++++ ++ Use winget settings.json +* Allow use of moniker name or id + 0.0.25 ++++++ + Add file logging for builder diff --git a/bake/azext_bake/_constants.py b/bake/azext_bake/_constants.py index 6ec28c3..cb03ff2 100644 --- a/bake/azext_bake/_constants.py +++ b/bake/azext_bake/_constants.py @@ -16,7 +16,6 @@ PKR_BUILD_FILE = 'build.pkr.hcl' PKR_VARS_FILE = 'variable.pkr.hcl' PKR_AUTO_VARS_FILE = 'vars.auto.pkrvars.json' -PKR_PACKAGES_CONFIG_FILE = 'packages.config' TAG_PREFIX = 'hidden-bake:' @@ -100,24 +99,6 @@ KEY_ALLOWED: IMAGE_ALLOWED_PROPERTIES } - -# PKR_DEFAULT_VARS = [ -# 'subscription', -# 'name', -# 'location', -# 'version', -# 'tempResourceGroup', -# 'buildResourceGroup', -# 'gallery', -# 'replicaLocations', -# 'keyVault', -# 'virtualNetwork', -# 'virtualNetworkSubnet', -# 'virtualNetworkResourceGroup', -# 'branch', -# 'commit' -# ] - PKR_DEFAULT_VARS = { 'image': [ 'name', @@ -151,10 +132,6 @@ def tag_key(key): return f'{TAG_PREFIX}{key}' -# def tag_key(key): -# return f'{TAG_PREFIX}{key}' - - DEFAULT_TAGS = { tag_key('cli-version'), tag_key('sandbox-version'), @@ -170,3 +147,84 @@ def tag_key(key): tag_key('subnetId'), tag_key('identityId'), } + +CHOCO_PACKAGES_CONFIG_FILE = 'packages.config' + +PKR_PROVISIONER_CHOCO = f''' + # Injected by az bake + provisioner "powershell" {{ + environment_vars = ["chocolateyUseWindowsCompression=false"] + inline = [ + "(new-object net.webclient).DownloadFile('https://chocolatey.org/install.ps1', 'C:/Windows/Temp/chocolatey.ps1')", + "& C:/Windows/Temp/chocolatey.ps1" + ] + }} + + # Injected by az bake + provisioner "file" {{ + source = "${{path.root}}/{CHOCO_PACKAGES_CONFIG_FILE}" + destination = "C:/Windows/Temp/{CHOCO_PACKAGES_CONFIG_FILE}" + }} + + # Injected by az bake + provisioner "powershell" {{ + elevated_user = build.User + elevated_password = build.Password + inline = [ + "choco install C:/Windows/Temp/{CHOCO_PACKAGES_CONFIG_FILE} --yes --no-progress" + ] + }} + {BAKE_PLACEHOLDER}''' + +WINGET_SETTINGS_FILE = 'settings.json' + +WINGET_INSTALLER_SRC = 'https://github.com/microsoft/winget-cli/releases/latest/download/Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle' +WINGET_INSTALLER_DEST = 'C:/Windows/Temp/Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle' +WINGET_SOURCE_SRC = 'https://winget.azureedge.net/cache/source.msix' +WINGET_SOURCE_DEST = 'C:/Windows/Temp/source.msix' + +WINGET_SETTINGS_PATH = 'C:/Users/packer/AppData/Local/Packages/Microsoft.DesktopAppInstaller_8wekyb3d8bbwe/LocalState/settings.json' + +WINGET_SETTINGS_JSON = f''' +{{ + "$schema": "https://aka.ms/winget-settings.schema.json", + "installBehavior": {{ + "preferences": {{ + "scope": "machine" + }} + }} +}} +''' + +PKR_PROVISIONER_WINGET_INSTALL = f''' + # Injected by az bake + provisioner "powershell" {{ + elevated_user = build.User + elevated_password = build.Password + inline = [ + "Write-Host '>>> Downloading package: {WINGET_INSTALLER_SRC} to {WINGET_INSTALLER_DEST}'", + "(new-object net.webclient).DownloadFile('{WINGET_INSTALLER_SRC}', '{WINGET_INSTALLER_DEST}')", + "Write-Host '>>> Installing package: {WINGET_INSTALLER_DEST}'", + "Add-AppxPackage -InstallAllResources -ForceTargetApplicationShutdown -ForceUpdateFromAnyVersion -Path '{WINGET_INSTALLER_DEST}'", + # "Add-AppxProvisionedPackage -Online -SkipLicense -PackagePath '{WINGET_INSTALLER_DEST}'", + + "Write-Host '>>> Downloading package: {WINGET_SOURCE_SRC} to {WINGET_SOURCE_DEST}'", + "(new-object net.webclient).DownloadFile('{WINGET_SOURCE_SRC}', '{WINGET_SOURCE_DEST}')", + "Write-Host '>>> Installing package: {WINGET_SOURCE_DEST}'", + "Add-AppxPackage -ForceTargetApplicationShutdown -ForceUpdateFromAnyVersion -Path '{WINGET_SOURCE_DEST}'", + # "Add-AppxProvisionedPackage -Online -SkipLicense -PackagePath '{WINGET_SOURCE_DEST}'", + + "winget --info", + + "Write-Host '>>> Resetting winget source'", + "winget source reset --force", + "winget source list" + ] + }} + + # Injected by az bake + provisioner "file" {{ + source = "${{path.root}}/{WINGET_SETTINGS_FILE}" + destination = "{WINGET_SETTINGS_PATH}" + }} +''' diff --git a/bake/azext_bake/_packer.py b/bake/azext_bake/_packer.py index 62c95b2..0195291 100644 --- a/bake/azext_bake/_packer.py +++ b/bake/azext_bake/_packer.py @@ -12,9 +12,11 @@ from azure.cli.core.azclierror import ValidationError -from ._constants import (BAKE_PLACEHOLDER, PKR_AUTO_VARS_FILE, PKR_BUILD_FILE, - PKR_DEFAULT_VARS, PKR_PACKAGES_CONFIG_FILE, - PKR_VARS_FILE) +from ._constants import (BAKE_PLACEHOLDER, CHOCO_PACKAGES_CONFIG_FILE, + PKR_AUTO_VARS_FILE, PKR_BUILD_FILE, PKR_DEFAULT_VARS, + PKR_PROVISIONER_CHOCO, PKR_PROVISIONER_WINGET_INSTALL, + PKR_VARS_FILE, WINGET_SETTINGS_FILE, + WINGET_SETTINGS_JSON) from ._utils import get_logger, get_templates_path logger = get_logger(__name__) @@ -149,36 +151,10 @@ def copy_packer_files(image_dir): def inject_choco_provisioners(image_dir, config_xml): '''Injects the chocolatey provisioners into the packer build file''' # create the choco packages config file - logger.info(f'Creating file: {image_dir / PKR_PACKAGES_CONFIG_FILE}') - with open(image_dir / PKR_PACKAGES_CONFIG_FILE, 'w') as f: + logger.info(f'Creating file: {image_dir / CHOCO_PACKAGES_CONFIG_FILE}') + with open(image_dir / CHOCO_PACKAGES_CONFIG_FILE, 'w') as f: f.write(config_xml) - choco_install = f''' - # Injected by az bake - provisioner "powershell" {{ - environment_vars = ["chocolateyUseWindowsCompression=false"] - inline = [ - "(new-object net.webclient).DownloadFile('https://chocolatey.org/install.ps1', 'C:/Windows/Temp/chocolatey.ps1')", - "& C:/Windows/Temp/chocolatey.ps1" - ] - }} - - # Injected by az bake - provisioner "file" {{ - source = "${{path.root}}/{PKR_PACKAGES_CONFIG_FILE}" - destination = "C:/Windows/Temp/{PKR_PACKAGES_CONFIG_FILE}" - }} - - # Injected by az bake - provisioner "powershell" {{ - elevated_user = build.User - elevated_password = build.Password - inline = [ - "choco install C:/Windows/Temp/{PKR_PACKAGES_CONFIG_FILE} --yes --no-progress" - ] - }} - {BAKE_PLACEHOLDER}''' - build_file_path = image_dir / PKR_BUILD_FILE if not build_file_path.exists(): @@ -195,7 +171,7 @@ def inject_choco_provisioners(image_dir, config_xml): if BAKE_PLACEHOLDER not in pkr_build: raise ValidationError(f'Could not find {BAKE_PLACEHOLDER} in {PKR_BUILD_FILE} at {build_file_path}') - pkr_build = pkr_build.replace(BAKE_PLACEHOLDER, choco_install) + pkr_build = pkr_build.replace(BAKE_PLACEHOLDER, PKR_PROVISIONER_CHOCO) with open(build_file_path, 'w') as f: f.write(pkr_build) @@ -204,41 +180,26 @@ def inject_choco_provisioners(image_dir, config_xml): def inject_winget_provisioners(image_dir, winget_packages): '''Injects the winget provisioners into the packer build file''' + logger.info(f'Creating file: {image_dir / WINGET_SETTINGS_FILE}') + with open(image_dir / WINGET_SETTINGS_FILE, 'w') as f: + f.write(WINGET_SETTINGS_JSON) + winget_install = f''' - # Injected by az bake - provisioner "powershell" {{ - elevated_user = build.User - elevated_password = build.Password - inline = [ - "Write-Host '>>> Downloading package: https://github.com/microsoft/winget-cli/releases/latest/download/Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle'", - "(new-object net.webclient).DownloadFile('https://github.com/microsoft/winget-cli/releases/latest/download/Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle', 'C:/Windows/Temp/appinstaller.msixbundle')", - "Write-Host '>>> Installing package: C:/Windows/Temp/appinstaller.msixbundle'", - "Add-AppxPackage -InstallAllResources -ForceTargetApplicationShutdown -ForceUpdateFromAnyVersion -Path 'C:/Windows/Temp/appinstaller.msixbundle'", - # "Add-AppxProvisionedPackage -Online -SkipLicense -PackagePath 'C:/Windows/Temp/appinstaller.msixbundle'", - - "Write-Host '>>> Downloading package: https://winget.azureedge.net/cache/source.msix'", - "(new-object net.webclient).DownloadFile('https://winget.azureedge.net/cache/source.msix', 'C:/Windows/Temp/source.msix')", - "Write-Host '>>> Installing package: C:/Windows/Temp/source.msix'", - "Add-AppxPackage -ForceTargetApplicationShutdown -ForceUpdateFromAnyVersion -Path 'C:/Windows/Temp/source.msix'", - # "Add-AppxProvisionedPackage -Online -SkipLicense -PackagePath 'C:/Windows/Temp/source.msix'", - - "Write-Host '>>> Resetting winget source'", - "winget source reset --force", - "winget source list" - ] - }} +{PKR_PROVISIONER_WINGET_INSTALL} # Injected by az bake provisioner "powershell" {{ inline = [ ''' - for i, p in enumerate(winget_packages): winget_cmd = f'winget install ' - for a in ['id', 'name', 'moniker', 'version', 'source']: - if a in p: - winget_cmd += f'--{a} {p[a]} ' - winget_cmd += '--scope machine --accept-package-agreements --accept-source-agreements' + if 'ANY' in p: + winget_cmd += f'{p["ANY"]} ' + else: + for a in ['id', 'name', 'moniker', 'version', 'source']: + if a in p: + winget_cmd += f'--{a} {p[a]} ' + winget_cmd += '--accept-package-agreements --accept-source-agreements' winget_install += f' "Write-Host \'>>> Running command: {winget_cmd}\'",\n' winget_install += f' "{winget_cmd}"' diff --git a/bake/azext_bake/_utils.py b/bake/azext_bake/_utils.py index 2f14f69..2e5152b 100644 --- a/bake/azext_bake/_utils.py +++ b/bake/azext_bake/_utils.py @@ -179,7 +179,7 @@ def get_install_winget(image): logger.info(f'Getting winget config for {c} type {type(c)}') if isinstance(c, str): # if only the id was givin, check the index for the rest of the config - winget_node = winget_index[c] if c in winget_index else {'moniker': c} + winget_node = winget_index[c] if c in winget_index else {'ANY': c} elif isinstance(c, dict): # if the full config was given, use it winget_node = c diff --git a/bake/setup.py b/bake/setup.py index 2cc2729..5d2f4cf 100644 --- a/bake/setup.py +++ b/bake/setup.py @@ -17,7 +17,7 @@ logger.warn("Wheel is not available, disabling bdist_wheel hook") # Must match a HISTORY.rst entry. -VERSION = '0.0.25' +VERSION = '0.0.26' # The full list of classifiers is available at # https://pypi.python.org/pypi?%3Aaction=list_classifiers diff --git a/builder/Dockerfile b/builder/Dockerfile index 5af5148..0d4c1e1 100644 --- a/builder/Dockerfile +++ b/builder/Dockerfile @@ -38,7 +38,7 @@ LABEL maintainer="Microsoft" \ RUN apk add --no-cache packer --repository=http://dl-cdn.alpinelinux.org/alpine/edge/community # install az-bake -RUN az extension add --source https://github.com/colbylwilliams/az-bake/releases/latest/download/bake-0.0.25-py3-none-any.whl -y +RUN az extension add --source https://github.com/colbylwilliams/az-bake/releases/latest/download/bake-0.0.26-py3-none-any.whl -y # Terminate container on stop STOPSIGNAL SIGTERM diff --git a/schema/image.schema.json b/schema/image.schema.json index 429c1df..13090a1 100644 --- a/schema/image.schema.json +++ b/schema/image.schema.json @@ -148,7 +148,7 @@ "oneOf": [ { "type": "string", - "description": "The moniker of the package to install" + "description": "The moniker, id, or name of the package to install" }, { "type": "object", @@ -189,6 +189,26 @@ "required": [ "name" ] + }, + { + "type": "object", + "properties": { + "moniker": { + "type": "string", + "description": "Limits the install to the moniker of the application." + }, + "version": { + "type": "string", + "description": "Enables you to specify an exact version to install. If not specified, latest will install the highest versioned application." + }, + "source": { + "type": "string", + "description": "Restricts the search to the source name provided. Must be followed by the source name." + } + }, + "required": [ + "moniker" + ] } ] }