Skip to content

Commit

Permalink
feat: Uplift Virtual Machine Images - Image Templates to the latest A…
Browse files Browse the repository at this point in the history
…PI `2024-02-01` (#4367)

## Description

Closes #4175 

Update to the latest API and expose new properties:

- `autoRunState`
- `managedResourceTags`
- `errorHandlingOnCustomizerError`
- `errorHandlingOnValidationError`

Worked with @AlexanderSehr to retire usage of the `union` function in
favor of `map` and `shallowMerge`.

## Pipeline Reference

<!-- Insert your Pipeline Status Badge below -->

| Pipeline |
| -------- |
|
[![avm.res.virtual-machine-images.image-template](https://github.com/ahmadabdalla/bicep-registry-modules/actions/workflows/avm.res.virtual-machine-images.image-template.yml/badge.svg?branch=users%2Fahmad%2F4175)](https://github.com/ahmadabdalla/bicep-registry-modules/actions/workflows/avm.res.virtual-machine-images.image-template.yml)
|

## Type of Change

<!-- Use the checkboxes [x] on the options that are relevant. -->

- [ ] Update to CI Environment or utilities (Non-module affecting
changes)
- [ ] Azure Verified Module updates:
- [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT
bumped the MAJOR or MINOR version in `version.json`:
- [ ] Someone has opened a bug report issue, and I have included "Closes
#{bug_report_issue_number}" in the PR description.
- [ ] The bug was found by the module author, and no one has opened an
issue to report it yet.
- [x] Feature update backwards compatible feature updates, and I have
bumped the MINOR version in `version.json`.
- [ ] Breaking changes and I have bumped the MAJOR version in
`version.json`.
  - [ ] Update to documentation

## Checklist

- [x] I'm sure there are no other open Pull Requests for the same
update/change
- [x] I have run `Set-AVMModule` locally to generate the supporting
module files.
- [x] My corresponding pipelines / checks run clean and green without
any errors or warnings

<!-- Please keep up to date with the contribution guide at
https://aka.ms/avm/contribute/bicep -->
  • Loading branch information
ahmadabdalla authored Feb 3, 2025
1 parent f323e8f commit 3ce4603
Show file tree
Hide file tree
Showing 6 changed files with 229 additions and 80 deletions.
95 changes: 93 additions & 2 deletions avm/res/virtual-machine-images/image-template/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ This module deploys a Virtual Machine Image Template that can be consumed by Azu
| :-- | :-- |
| `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) |
| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) |
| `Microsoft.VirtualMachineImages/imageTemplates` | [2023-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.VirtualMachineImages/2023-07-01/imageTemplates) |
| `Microsoft.VirtualMachineImages/imageTemplates` | [2024-02-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.VirtualMachineImages/2024-02-01/imageTemplates) |

## Usage examples

Expand Down Expand Up @@ -202,6 +202,7 @@ module imageTemplate 'br/public:avm/res/virtual-machine-images/image-template:<v
}
name: 'vmiitmax001'
// Non-required parameters
autoRunState: 'Enabled'
buildTimeoutInMinutes: 60
customizationSteps: [
{
Expand All @@ -223,11 +224,17 @@ module imageTemplate 'br/public:avm/res/virtual-machine-images/image-template:<v
type: 'Shell'
}
]
errorHandlingOnCustomizerError: 'cleanup'
errorHandlingOnValidationError: 'abort'
location: '<location>'
lock: {
kind: 'CanNotDelete'
name: 'myCustomLockName'
}
managedResourceTags: {
testKey1: 'testValue1'
testKey2: 'testValue2'
}
optimizeVmBoot: 'Enabled'
osDiskSizeGB: 127
roleAssignments: [
Expand Down Expand Up @@ -330,6 +337,9 @@ module imageTemplate 'br/public:avm/res/virtual-machine-images/image-template:<v
"value": "vmiitmax001"
},
// Non-required parameters
"autoRunState": {
"value": "Enabled"
},
"buildTimeoutInMinutes": {
"value": 60
},
Expand All @@ -355,6 +365,12 @@ module imageTemplate 'br/public:avm/res/virtual-machine-images/image-template:<v
}
]
},
"errorHandlingOnCustomizerError": {
"value": "cleanup"
},
"errorHandlingOnValidationError": {
"value": "abort"
},
"location": {
"value": "<location>"
},
Expand All @@ -364,6 +380,12 @@ module imageTemplate 'br/public:avm/res/virtual-machine-images/image-template:<v
"name": "myCustomLockName"
}
},
"managedResourceTags": {
"value": {
"testKey1": "testValue1",
"testKey2": "testValue2"
}
},
"optimizeVmBoot": {
"value": "Enabled"
},
Expand Down Expand Up @@ -474,6 +496,7 @@ param managedIdentities = {
}
param name = 'vmiitmax001'
// Non-required parameters
param autoRunState = 'Enabled'
param buildTimeoutInMinutes = 60
param customizationSteps = [
{
Expand All @@ -495,11 +518,17 @@ param customizationSteps = [
type: 'Shell'
}
]
param errorHandlingOnCustomizerError = 'cleanup'
param errorHandlingOnValidationError = 'abort'
param location = '<location>'
param lock = {
kind: 'CanNotDelete'
name: 'myCustomLockName'
}
param managedResourceTags = {
testKey1: 'testValue1'
testKey2: 'testValue2'
}
param optimizeVmBoot = 'Enabled'
param osDiskSizeGB = 127
param roleAssignments = [
Expand Down Expand Up @@ -731,11 +760,15 @@ param tags = {

| Parameter | Type | Description |
| :-- | :-- | :-- |
| [`autoRunState`](#parameter-autorunstate) | string | Indicates whether or not to automatically run the image template build on template creation or update. |
| [`buildTimeoutInMinutes`](#parameter-buildtimeoutinminutes) | int | The image build timeout in minutes. 0 means the default 240 minutes. |
| [`customizationSteps`](#parameter-customizationsteps) | array | Customization steps to be run when building the VM image. |
| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. |
| [`errorHandlingOnCustomizerError`](#parameter-errorhandlingoncustomizererror) | string | If there is a customizer error and this field is set to 'cleanup', the build VM and associated network resources will be cleaned up. This is the default behavior. If there is a customizer error and this field is set to 'abort', the build VM will be preserved. |
| [`errorHandlingOnValidationError`](#parameter-errorhandlingonvalidationerror) | string | If there is a validation error and this field is set to 'cleanup', the build VM and associated network resources will be cleaned up. If there is a validation error and this field is set to 'abort', the build VM will be preserved. This is the default behavior. |
| [`location`](#parameter-location) | string | Location for all resources. |
| [`lock`](#parameter-lock) | object | The lock settings of the service. |
| [`managedResourceTags`](#parameter-managedresourcetags) | object | Tags that will be applied to the resource group and/or resources created by the service. |
| [`optimizeVmBoot`](#parameter-optimizevmboot) | string | The optimize property can be enabled while creating a VM image and allows VM optimization to improve image creation time. |
| [`osDiskSizeGB`](#parameter-osdisksizegb) | int | Specifies the size of OS disk. |
| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. |
Expand Down Expand Up @@ -793,6 +826,21 @@ The name prefix of the Image Template to be built by the Azure Image Builder ser
- Required: Yes
- Type: string

### Parameter: `autoRunState`

Indicates whether or not to automatically run the image template build on template creation or update.

- Required: No
- Type: string
- Default: `'Disabled'`
- Allowed:
```Bicep
[
'Disabled'
'Enabled'
]
```

### Parameter: `buildTimeoutInMinutes`

The image build timeout in minutes. 0 means the default 240 minutes.
Expand Down Expand Up @@ -822,6 +870,40 @@ Enable/Disable usage telemetry for module.
- MinValue: 0
- MaxValue: 960

### Parameter: `errorHandlingOnCustomizerError`

If there is a customizer error and this field is set to 'cleanup', the build VM and associated network resources will be cleaned up. This is the default behavior. If there is a customizer error and this field is set to 'abort', the build VM will be preserved.

- Required: No
- Type: string
- Default: `'cleanup'`
- Allowed:
```Bicep
[
'abort'
'cleanup'
]
```
- MinValue: 0
- MaxValue: 960

### Parameter: `errorHandlingOnValidationError`

If there is a validation error and this field is set to 'cleanup', the build VM and associated network resources will be cleaned up. If there is a validation error and this field is set to 'abort', the build VM will be preserved. This is the default behavior.

- Required: No
- Type: string
- Default: `'cleanup'`
- Allowed:
```Bicep
[
'abort'
'cleanup'
]
```
- MinValue: 0
- MaxValue: 960

### Parameter: `location`

Location for all resources.
Expand Down Expand Up @@ -874,6 +956,15 @@ Specify the name of lock.
- MinValue: 0
- MaxValue: 960

### Parameter: `managedResourceTags`

Tags that will be applied to the resource group and/or resources created by the service.

- Required: No
- Type: object
- MinValue: 0
- MaxValue: 960

### Parameter: `optimizeVmBoot`

The optimize property can be enabled while creating a VM image and allows VM optimization to improve image creation time.
Expand Down Expand Up @@ -1257,7 +1348,7 @@ This section gives you an overview of all local-referenced module files (i.e., o

| Reference | Type |
| :-- | :-- |
| `br/public:avm/utl/types/avm-common-types:0.2.1` | Remote reference |
| `br/public:avm/utl/types/avm-common-types:0.5.1` | Remote reference |

## Notes

Expand Down
126 changes: 79 additions & 47 deletions avm/res/virtual-machine-images/image-template/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ param customizationSteps array?
@description('Optional. Resource ID of the staging resource group in the same subscription and location as the image template that will be used to build the image.</p>If this field is empty, a resource group with a random name will be created.</p>If the resource group specified in this field doesn\'t exist, it will be created with the same name.</p>If the resource group specified exists, it must be empty and in the same region as the image template.</p>The resource group created will be deleted during template deletion if this field is empty or the resource group specified doesn\'t exist,</p>but if the resource group specified exists the resources created in the resource group will be deleted during template deletion and the resource group itself will remain.')
param stagingResourceGroupResourceId string?

import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.2.1'
import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.5.1'
@description('Optional. The lock settings of the service.')
param lock lockType?

Expand All @@ -43,7 +43,7 @@ param baseTime string = utcNow('yyyy-MM-dd-HH-mm-ss')
@description('Optional. Enable/Disable usage telemetry for module.')
param enableTelemetry bool = true

import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.2.1'
import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1'
@description('Optional. Array of role assignments to create.')
param roleAssignments roleAssignmentType[]?

Expand All @@ -53,7 +53,7 @@ param distributions distributionType[]
@description('Optional. List of User-Assigned Identities associated to the Build VM for accessing Azure resources such as Key Vaults from your customizer scripts. Be aware, the user assigned identities specified in the \'managedIdentities\' parameter must have the \'Managed Identity Operator\' role assignment on all the user assigned identities specified in this parameter for Azure Image Builder to be able to associate them to the build VM.')
param vmUserAssignedIdentities array = []

import { managedIdentityOnlyUserAssignedType } from 'br/public:avm/utl/types/avm-common-types:0.2.1'
import { managedIdentityOnlyUserAssignedType } from 'br/public:avm/utl/types/avm-common-types:0.5.1'
@description('Required. The managed identity definition for this resource.')
param managedIdentities managedIdentityOnlyUserAssignedType

Expand All @@ -67,6 +67,30 @@ param validationProcess validationProcessType?
@description('Optional. The optimize property can be enabled while creating a VM image and allows VM optimization to improve image creation time.')
param optimizeVmBoot string?

@allowed([
'Enabled'
'Disabled'
])
@description('Optional. Indicates whether or not to automatically run the image template build on template creation or update.')
param autoRunState string = 'Disabled'

@allowed([
'cleanup'
'abort'
])
@description('Optional. If there is a customizer error and this field is set to \'cleanup\', the build VM and associated network resources will be cleaned up. This is the default behavior. If there is a customizer error and this field is set to \'abort\', the build VM will be preserved.')
param errorHandlingOnCustomizerError string = 'cleanup'

@allowed([
'cleanup'
'abort'
])
@description('Optional. If there is a validation error and this field is set to \'cleanup\', the build VM and associated network resources will be cleaned up. If there is a validation error and this field is set to \'abort\', the build VM will be preserved. This is the default behavior.')
param errorHandlingOnValidationError string = 'cleanup'

@description('Optional. Tags that will be applied to the resource group and/or resources created by the service.')
param managedResourceTags object?

var identity = {
type: 'UserAssigned'
userAssignedIdentities: reduce(
Expand Down Expand Up @@ -120,7 +144,7 @@ resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableT
}
}

resource imageTemplate 'Microsoft.VirtualMachineImages/imageTemplates@2023-07-01' = {
resource imageTemplate 'Microsoft.VirtualMachineImages/imageTemplates@2024-02-01' = {
#disable-next-line use-stable-resource-identifiers // Disabling as ImageTemplates are not idempotent and hence always must have new name
name: '${name}-${baseTime}'
location: location
Expand All @@ -139,51 +163,51 @@ resource imageTemplate 'Microsoft.VirtualMachineImages/imageTemplates@2023-07-01
: null
}
source: imageSource
customize: customizationSteps
...(!empty(customizationSteps)
? {
customize: customizationSteps
}
: {})
stagingResourceGroup: stagingResourceGroupResourceId
distribute: [
for distribution in distributions: union(
{
type: distribution.type
artifactTags: distribution.?artifactTags ?? {
sourceType: imageSource.type
sourcePublisher: imageSource.?publisher
sourceOffer: imageSource.?offer
sourceSku: imageSource.?sku
sourceVersion: imageSource.?version
sourceImageId: imageSource.?imageId
sourceImageVersionID: imageSource.?imageVersionID
creationTime: baseTime
distribute: map(distributions, distribution => {
type: distribution.type
artifactTags: distribution.?artifactTags ?? {
sourceType: imageSource.type
sourcePublisher: imageSource.?publisher
sourceOffer: imageSource.?offer
sourceSku: imageSource.?sku
sourceVersion: imageSource.?version
sourceImageId: imageSource.?imageId
sourceImageVersionID: imageSource.?imageVersionID
creationTime: baseTime
}
...(distribution.type == 'ManagedImage'
? {
runOutputName: distribution.?runOutputName ?? '${distribution.imageName}-${baseTime}-ManagedImage'
location: distribution.?location ?? location
#disable-next-line use-resource-id-functions // Disabling rule as this is an input parameter that is used inside an array.
imageId: distribution.?imageResourceId ?? '${subscription().id}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Compute/images/${distribution.imageName}-${baseTime}'
}
},
(distribution.type == 'ManagedImage'
? {
runOutputName: distribution.?runOutputName ?? '${distribution.imageName}-${baseTime}-ManagedImage'
location: distribution.?location ?? location
#disable-next-line use-resource-id-functions // Disabling rule as this is an input parameter that is used inside an array.
imageId: distribution.?imageResourceId ?? '${subscription().id}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Compute/images/${distribution.imageName}-${baseTime}'
}
: {}),
(distribution.type == 'SharedImage'
? {
runOutputName: distribution.?runOutputName ?? (!empty(distribution.?sharedImageGalleryImageDefinitionResourceId)
? '${last(split((distribution.sharedImageGalleryImageDefinitionResourceId ?? '/'), '/'))}-SharedImage'
: 'SharedImage')
galleryImageId: !empty(distribution.?sharedImageGalleryImageDefinitionTargetVersion)
? '${distribution.sharedImageGalleryImageDefinitionResourceId}/versions/${distribution.sharedImageGalleryImageDefinitionTargetVersion}'
: distribution.sharedImageGalleryImageDefinitionResourceId
excludeFromLatest: distribution.?excludeFromLatest ?? false
replicationRegions: distribution.?replicationRegions ?? [location]
storageAccountType: distribution.?storageAccountType ?? 'Standard_LRS'
}
: {}),
(distribution.type == 'VHD'
? {
runOutputName: distribution.?runOutputName ?? '${distribution.imageName}-VHD'
}
: {})
)
]
: {})
...(distribution.type == 'SharedImage'
? {
runOutputName: distribution.?runOutputName ?? (!empty(distribution.?sharedImageGalleryImageDefinitionResourceId)
? '${last(split((distribution.sharedImageGalleryImageDefinitionResourceId ?? '/'), '/'))}-SharedImage'
: 'SharedImage')
galleryImageId: !empty(distribution.?sharedImageGalleryImageDefinitionTargetVersion)
? '${distribution.sharedImageGalleryImageDefinitionResourceId}/versions/${distribution.sharedImageGalleryImageDefinitionTargetVersion}'
: distribution.sharedImageGalleryImageDefinitionResourceId
excludeFromLatest: distribution.?excludeFromLatest ?? false
replicationRegions: distribution.?replicationRegions ?? [location]
storageAccountType: distribution.?storageAccountType ?? 'Standard_LRS'
}
: {})
...(distribution.type == 'VHD'
? {
runOutputName: distribution.?runOutputName ?? '${distribution.imageName}-VHD'
}
: {})
})
#disable-next-line BCP225 // The discriminator property "type" value cannot be determined at compilation time. - which is fine
validate: validationProcess
optimize: optimizeVmBoot != null
Expand All @@ -193,6 +217,14 @@ resource imageTemplate 'Microsoft.VirtualMachineImages/imageTemplates@2023-07-01
}
}
: null
autoRun: {
state: autoRunState
}
errorHandling: {
onCustomizerError: errorHandlingOnCustomizerError
onValidationError: errorHandlingOnValidationError
}
managedResourceTags: managedResourceTags
}
}

Expand Down
Loading

0 comments on commit 3ce4603

Please sign in to comment.