From 95c373c0e9c7712656e785bb69a61e973c0265b0 Mon Sep 17 00:00:00 2001 From: David Jurgens Date: Tue, 17 Dec 2024 12:48:08 -0600 Subject: [PATCH 1/9] initial commit --- avm/res/compute/virtual-machine/README.md | 81 ++- avm/res/compute/virtual-machine/main.bicep | 156 ++--- avm/res/compute/virtual-machine/main.json | 619 +++++++++--------- .../tests/e2e/spot/dependencies.bicep | 89 +++ .../tests/e2e/spot/main.test.bicep | 113 ++++ 5 files changed, 666 insertions(+), 392 deletions(-) create mode 100644 avm/res/compute/virtual-machine/tests/e2e/spot/dependencies.bicep create mode 100644 avm/res/compute/virtual-machine/tests/e2e/spot/main.test.bicep diff --git a/avm/res/compute/virtual-machine/README.md b/avm/res/compute/virtual-machine/README.md index 3fd239938e..1500949893 100644 --- a/avm/res/compute/virtual-machine/README.md +++ b/avm/res/compute/virtual-machine/README.md @@ -18,7 +18,7 @@ This module deploys a Virtual Machine with one or multiple NICs and optionally o | :-- | :-- | | `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.Automanage/configurationProfileAssignments` | [2022-05-04](https://learn.microsoft.com/en-us/azure/templates) | +| `Microsoft.Automanage/configurationProfileAssignments` | [2022-05-04](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Automanage/2022-05-04/configurationProfileAssignments) | | `Microsoft.Compute/disks` | [2024-03-02](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2024-03-02/disks) | | `Microsoft.Compute/virtualMachines` | [2024-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2024-07-01/virtualMachines) | | `Microsoft.Compute/virtualMachines/extensions` | [2022-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2022-11-01/virtualMachines/extensions) | @@ -4775,10 +4775,10 @@ param virtualMachineScaleSetResourceId = '' | [`dedicatedHostId`](#parameter-dedicatedhostid) | string | Specifies resource ID about the dedicated host that the virtual machine resides in. | | [`disablePasswordAuthentication`](#parameter-disablepasswordauthentication) | bool | Specifies whether password authentication should be disabled. | | [`enableAutomaticUpdates`](#parameter-enableautomaticupdates) | bool | Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. When patchMode is set to Manual, this parameter must be set to false. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning. | -| [`enableEvictionPolicy`](#parameter-enableevictionpolicy) | bool | Specifies the eviction policy for the low priority virtual machine. Will result in 'Deallocate' eviction policy. | | [`enableHotpatching`](#parameter-enablehotpatching) | bool | Enables customers to patch their Azure VMs without requiring a reboot. For enableHotpatching, the 'provisionVMAgent' must be set to true and 'patchMode' must be set to 'AutomaticByPlatform'. | | [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | | [`encryptionAtHost`](#parameter-encryptionathost) | bool | This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs. | +| [`evictionPolicy`](#parameter-evictionpolicy) | string | Specifies the eviction policy for the low priority virtual machine. | | [`extensionAadJoinConfig`](#parameter-extensionaadjoinconfig) | object | The configuration for the [AAD Join] extension. Must at least contain the ["enabled": true] property to be executed. To enroll in Intune, add the setting mdmId: "0000000a-0000-0000-c000-000000000000". | | [`extensionAntiMalwareConfig`](#parameter-extensionantimalwareconfig) | object | The configuration for the [Anti Malware] extension. Must at least contain the ["enabled": true] property to be executed. | | [`extensionAzureDiskEncryptionConfig`](#parameter-extensionazurediskencryptionconfig) | object | The configuration for the [Azure Disk Encryption] extension. Must at least contain the ["enabled": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys. | @@ -4876,6 +4876,7 @@ Specifies the OS disk. For security reasons, it is recommended to specify DiskEn | [`caching`](#parameter-osdiskcaching) | string | Specifies the caching requirements. | | [`createOption`](#parameter-osdiskcreateoption) | string | Specifies how the virtual machine should be created. | | [`deleteOption`](#parameter-osdiskdeleteoption) | string | Specifies whether data disk should be deleted or detached upon VM deletion. | +| [`diffDiskSettings`](#parameter-osdiskdiffdisksettings) | object | Specifies the ephemeral Disk Settings for the operating system disk. | | [`diskSizeGB`](#parameter-osdiskdisksizegb) | int | Specifies the size of an empty data disk in gigabytes. | | [`name`](#parameter-osdiskname) | string | The disk name. | @@ -4963,6 +4964,34 @@ Specifies whether data disk should be deleted or detached upon VM deletion. ] ``` +### Parameter: `osDisk.diffDiskSettings` + +Specifies the ephemeral Disk Settings for the operating system disk. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`placement`](#parameter-osdiskdiffdisksettingsplacement) | string | Specifies the ephemeral disk placement for the operating system disk. | + +### Parameter: `osDisk.diffDiskSettings.placement` + +Specifies the ephemeral disk placement for the operating system disk. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'CacheDisk' + 'NvmeDisk' + 'ResourceDisk' + ] + ``` + ### Parameter: `osDisk.diskSizeGB` Specifies the size of an empty data disk in gigabytes. @@ -5324,14 +5353,6 @@ Indicates whether Automatic Updates is enabled for the Windows virtual machine. - Type: bool - Default: `True` -### Parameter: `enableEvictionPolicy` - -Specifies the eviction policy for the low priority virtual machine. Will result in 'Deallocate' eviction policy. - -- Required: No -- Type: bool -- Default: `False` - ### Parameter: `enableHotpatching` Enables customers to patch their Azure VMs without requiring a reboot. For enableHotpatching, the 'provisionVMAgent' must be set to true and 'patchMode' must be set to 'AutomaticByPlatform'. @@ -5356,6 +5377,21 @@ This property can be used by user in the request to enable or disable the Host E - Type: bool - Default: `True` +### Parameter: `evictionPolicy` + +Specifies the eviction policy for the low priority virtual machine. + +- Required: No +- Type: string +- Default: `'Deallocate'` +- Allowed: + ```Bicep + [ + 'Deallocate' + 'Delete' + ] + ``` + ### Parameter: `extensionAadJoinConfig` The configuration for the [AAD Join] extension. Must at least contain the ["enabled": true] property to be executed. To enroll in Intune, add the setting mdmId: "0000000a-0000-0000-c000-000000000000". @@ -5631,7 +5667,7 @@ The managed identity definition for this resource. The system-assigned managed i | Parameter | Type | Description | | :-- | :-- | :-- | | [`systemAssigned`](#parameter-managedidentitiessystemassigned) | bool | Enables system assigned managed identity on the resource. | -| [`userAssignedResourceIds`](#parameter-managedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. | +| [`userAssignedResourceIds`](#parameter-managedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption. | ### Parameter: `managedIdentities.systemAssigned` @@ -5642,7 +5678,7 @@ Enables system assigned managed identity on the resource. ### Parameter: `managedIdentities.userAssignedResourceIds` -The resource ID(s) to assign to the resource. +The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption. - Required: No - Type: array @@ -5736,6 +5772,27 @@ The list of SSH public keys used to authenticate with linux based VMs. - Type: array - Default: `[]` +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`keyData`](#parameter-publickeyskeydata) | string | Specifies the SSH public key data used to authenticate through ssh. | +| [`path`](#parameter-publickeyspath) | string | Specifies the full path on the created VM where ssh public key is stored. If the file already exists, the specified key is appended to the file. | + +### Parameter: `publicKeys.keyData` + +Specifies the SSH public key data used to authenticate through ssh. + +- Required: Yes +- Type: string + +### Parameter: `publicKeys.path` + +Specifies the full path on the created VM where ssh public key is stored. If the file already exists, the specified key is appended to the file. + +- Required: Yes +- Type: string + ### Parameter: `rebootSetting` Specifies the reboot setting for all AutomaticByPlatform patch installation operations. diff --git a/avm/res/compute/virtual-machine/main.bicep b/avm/res/compute/virtual-machine/main.bicep index 27c7365be7..f9a91f6b40 100644 --- a/avm/res/compute/virtual-machine/main.bicep +++ b/avm/res/compute/virtual-machine/main.bicep @@ -2,6 +2,12 @@ metadata name = 'Virtual Machines' metadata description = 'This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs.' metadata owner = 'Azure/module-maintainers' +import { + lockType + managedIdentityAllType + roleAssignmentType +} from 'br/public:avm/utl/types/avm-common-types:0.4.0' + @description('Required. The name of the virtual machine to be created. You should use a unique prefix to reduce name collisions in Active Directory.') param name string @@ -68,8 +74,12 @@ param certificatesToBeInstalled array = [] ]) param priority string = 'Regular' -@description('Optional. Specifies the eviction policy for the low priority virtual machine. Will result in \'Deallocate\' eviction policy.') -param enableEvictionPolicy bool = false +@description('Optional. Specifies the eviction policy for the low priority virtual machine.') +@allowed([ + 'Deallocate' + 'Delete' +]) +param evictionPolicy string = 'Deallocate' @description('Optional. Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars.') param maxPriceForLowPriorityVm string = '' @@ -88,10 +98,10 @@ param dedicatedHostId string = '' param licenseType string = '' @description('Optional. The list of SSH public keys used to authenticate with linux based VMs.') -param publicKeys array = [] +param publicKeys publicKeyType[] = [] @description('Optional. The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = "True".') -param managedIdentities managedIdentitiesType +param managedIdentities managedIdentityAllType? @description('Optional. Whether boot diagnostics should be enabled on the Virtual Machine. Boot diagnostics will be enabled with a managed storage account if no bootDiagnosticsStorageAccountName value is provided. If bootDiagnostics and bootDiagnosticsStorageAccountName values are not provided, boot diagnostics will be disabled.') param bootDiagnostics bool = false @@ -227,10 +237,10 @@ param extensionGuestConfigurationExtensionProtectedSettings object = {} param location string = resourceGroup().location @description('Optional. The lock settings of the service.') -param lock lockType +param lock lockType? @description('Optional. Array of role assignments to create.') -param roleAssignments roleAssignmentType +param roleAssignments roleAssignmentType[]? @description('Optional. Tags of the resource.') param tags object? @@ -543,17 +553,23 @@ resource vm 'Microsoft.Compute/virtualMachines@2024-07-01' = { storageProfile: { imageReference: imageReference osDisk: { - name: osDisk.?name ?? '${name}-disk-os-01' + caching: osDisk.?caching ?? 'ReadOnly' createOption: osDisk.?createOption ?? 'FromImage' deleteOption: osDisk.?deleteOption ?? 'Delete' + diffDiskSettings: empty(osDisk.?diffDiskSettings ?? {}) + ? null + : { + option: 'Local' + placement: osDisk.diffDiskSettings!.placement + } diskSizeGB: osDisk.diskSizeGB - caching: osDisk.?caching ?? 'ReadOnly' managedDisk: { - storageAccountType: osDisk.managedDisk.storageAccountType diskEncryptionSet: { id: osDisk.managedDisk.?diskEncryptionSetResourceId } + storageAccountType: osDisk.managedDisk.storageAccountType } + name: osDisk.?name ?? '${name}-disk-os-01' } dataDisks: [ for (dataDisk, index) in dataDisks ?? []: { @@ -630,7 +646,7 @@ resource vm 'Microsoft.Compute/virtualMachines@2024-07-01' = { } : null priority: priority - evictionPolicy: enableEvictionPolicy ? 'Deallocate' : null + evictionPolicy: 'Regular' != priority ? evictionPolicy : null #disable-next-line BCP036 billingProfile: !empty(priority) && !empty(maxPriceForLowPriorityVm) ? { @@ -1037,54 +1053,15 @@ output location string = vm.location // Definitions // // =============== // -type managedIdentitiesType = { - @description('Optional. Enables system assigned managed identity on the resource.') - systemAssigned: bool? - - @description('Optional. The resource ID(s) to assign to the resource.') - userAssignedResourceIds: string[]? -}? - -type lockType = { - @description('Optional. Specify the name of lock.') - name: string? - - @description('Optional. Specify the type of lock.') - kind: ('CanNotDelete' | 'ReadOnly' | 'None')? -}? - -type roleAssignmentType = { - @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') - name: string? - - @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') - roleDefinitionIdOrName: string - - @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') - principalId: string - - @description('Optional. The principal type of the assigned principal ID.') - principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? - - @description('Optional. The description of the role assignment.') - description: string? - - @description('Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container".') - condition: string? - - @description('Optional. Version of the condition.') - conditionVersion: '2.0'? - - @description('Optional. The Resource Id of the delegated managed identity resource.') - delegatedManagedIdentityResourceId: string? -}[]? - -type osDiskType = { +type dataDisksType = { @description('Optional. The disk name.') name: string? - @description('Optional. Specifies the size of an empty data disk in gigabytes.') - diskSizeGB: int? + @description('Optional. Specifies the logical unit number of the data disk.') + lun: int? + + @description('Required. Specifies the size of an empty data disk in gigabytes.') + diskSizeGB: int @description('Optional. Specifies how the virtual machine should be created.') createOption: 'Attach' | 'Empty' | 'FromImage'? @@ -1095,9 +1072,15 @@ type osDiskType = { @description('Optional. Specifies the caching requirements.') caching: 'None' | 'ReadOnly' | 'ReadWrite'? + @description('Optional. The number of IOPS allowed for this disk; only settable for UltraSSD disks. One operation can transfer between 4k and 256k bytes.') + diskIOPSReadWrite: int? + + @description('Optional. The bandwidth allowed for this disk; only settable for UltraSSD disks. MBps means millions of bytes per second - MB here uses the ISO notation, of powers of 10.') + diskMBpsReadWrite: int? + @description('Required. The managed disk parameters.') managedDisk: { - @description('Optional. Specifies the storage account type for the managed disk.') + @description('Required. Specifies the storage account type for the managed disk.') storageAccountType: | 'PremiumV2_LRS' | 'Premium_LRS' @@ -1105,41 +1088,41 @@ type osDiskType = { | 'StandardSSD_LRS' | 'StandardSSD_ZRS' | 'Standard_LRS' - | 'UltraSSD_LRS'? + | 'UltraSSD_LRS' @description('Optional. Specifies the customer managed disk encryption set resource id for the managed disk.') diskEncryptionSetResourceId: string? - } -} -type dataDisksType = { - @description('Optional. The disk name.') - name: string? - - @description('Optional. Specifies the logical unit number of the data disk.') - lun: int? + @description('Optional. Specifies the customer managed disk id for the managed disk.') + id: string? + } +}[]? - @description('Required. Specifies the size of an empty data disk in gigabytes.') - diskSizeGB: int +type osDiskType = { + @description('Optional. Specifies the caching requirements.') + caching: 'None' | 'ReadOnly' | 'ReadWrite'? @description('Optional. Specifies how the virtual machine should be created.') createOption: 'Attach' | 'Empty' | 'FromImage'? - @description('Optional. Specifies whether data disk should be deleted or detached upon VM deletion.') - deleteOption: 'Delete' | 'Detach'? + @description('Optional. Specifies the ephemeral Disk Settings for the operating system disk.') + diffDiskSettings: { + @description('Required. Specifies the ephemeral disk placement for the operating system disk.') + placement: ('CacheDisk' | 'NvmeDisk' | 'ResourceDisk') + }? - @description('Optional. Specifies the caching requirements.') - caching: 'None' | 'ReadOnly' | 'ReadWrite'? - - @description('Optional. The number of IOPS allowed for this disk; only settable for UltraSSD disks. One operation can transfer between 4k and 256k bytes.') - diskIOPSReadWrite: int? + @description('Optional. Specifies the size of an empty data disk in gigabytes.') + diskSizeGB: int? - @description('Optional. The bandwidth allowed for this disk; only settable for UltraSSD disks. MBps means millions of bytes per second - MB here uses the ISO notation, of powers of 10.') - diskMBpsReadWrite: int? + @description('Optional. Specifies whether data disk should be deleted or detached upon VM deletion.') + deleteOption: 'Delete' | 'Detach'? @description('Required. The managed disk parameters.') managedDisk: { - @description('Required. Specifies the storage account type for the managed disk.') + @description('Optional. Specifies the customer managed disk encryption set resource id for the managed disk.') + diskEncryptionSetResourceId: string? + + @description('Optional. Specifies the storage account type for the managed disk.') storageAccountType: | 'PremiumV2_LRS' | 'Premium_LRS' @@ -1147,12 +1130,17 @@ type dataDisksType = { | 'StandardSSD_LRS' | 'StandardSSD_ZRS' | 'Standard_LRS' - | 'UltraSSD_LRS' + | 'UltraSSD_LRS'? + } - @description('Optional. Specifies the customer managed disk encryption set resource id for the managed disk.') - diskEncryptionSetResourceId: string? + @description('Optional. The disk name.') + name: string? +} - @description('Optional. Specifies the customer managed disk id for the managed disk.') - id: string? - } -}[]? +type publicKeyType = { + @description('Required. Specifies the SSH public key data used to authenticate through ssh.') + keyData: string + + @description('Required. Specifies the full path on the created VM where ssh public key is stored. If the file already exists, the specified key is appended to the file.') + path: string +} diff --git a/avm/res/compute/virtual-machine/main.json b/avm/res/compute/virtual-machine/main.json index d46beb111b..30735b1902 100644 --- a/avm/res/compute/virtual-machine/main.json +++ b/avm/res/compute/virtual-machine/main.json @@ -5,220 +5,14 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "8928644602939334563" + "version": "0.32.4.45862", + "templateHash": "2725845996002425667" }, "name": "Virtual Machines", "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs.", "owner": "Azure/module-maintainers" }, "definitions": { - "managedIdentitiesType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource." - } - } - }, - "nullable": true - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "nullable": true - }, - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - }, - "osDiskType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The disk name." - } - }, - "diskSizeGB": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the size of an empty data disk in gigabytes." - } - }, - "createOption": { - "type": "string", - "allowedValues": [ - "Attach", - "Empty", - "FromImage" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies how the virtual machine should be created." - } - }, - "deleteOption": { - "type": "string", - "allowedValues": [ - "Delete", - "Detach" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." - } - }, - "caching": { - "type": "string", - "allowedValues": [ - "None", - "ReadOnly", - "ReadWrite" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the caching requirements." - } - }, - "managedDisk": { - "type": "object", - "properties": { - "storageAccountType": { - "type": "string", - "allowedValues": [ - "PremiumV2_LRS", - "Premium_LRS", - "Premium_ZRS", - "StandardSSD_LRS", - "StandardSSD_ZRS", - "Standard_LRS", - "UltraSSD_LRS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the storage account type for the managed disk." - } - }, - "diskEncryptionSetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." - } - } - }, - "metadata": { - "description": "Required. The managed disk parameters." - } - } - } - }, "dataDisksType": { "type": "array", "items": { @@ -333,6 +127,261 @@ } }, "nullable": true + }, + "osDiskType": { + "type": "object", + "properties": { + "caching": { + "type": "string", + "allowedValues": [ + "None", + "ReadOnly", + "ReadWrite" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the caching requirements." + } + }, + "createOption": { + "type": "string", + "allowedValues": [ + "Attach", + "Empty", + "FromImage" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies how the virtual machine should be created." + } + }, + "diffDiskSettings": { + "type": "object", + "properties": { + "placement": { + "type": "string", + "allowedValues": [ + "CacheDisk", + "NvmeDisk", + "ResourceDisk" + ], + "metadata": { + "description": "Required. Specifies the ephemeral disk placement for the operating system disk." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the ephemeral Disk Settings for the operating system disk." + } + }, + "diskSizeGB": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the size of an empty data disk in gigabytes." + } + }, + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." + } + }, + "managedDisk": { + "type": "object", + "properties": { + "diskEncryptionSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." + } + }, + "storageAccountType": { + "type": "string", + "allowedValues": [ + "PremiumV2_LRS", + "Premium_LRS", + "Premium_ZRS", + "StandardSSD_LRS", + "StandardSSD_ZRS", + "Standard_LRS", + "UltraSSD_LRS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the storage account type for the managed disk." + } + } + }, + "metadata": { + "description": "Required. The managed disk parameters." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The disk name." + } + } + } + }, + "publicKeyType": { + "type": "object", + "properties": { + "keyData": { + "type": "string", + "metadata": { + "description": "Required. Specifies the SSH public key data used to authenticate through ssh." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Specifies the full path on the created VM where ssh public key is stored. If the file already exists, the specified key is appended to the file." + } + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } } }, "parameters": { @@ -466,11 +515,15 @@ "description": "Optional. Specifies the priority for the virtual machine." } }, - "enableEvictionPolicy": { - "type": "bool", - "defaultValue": false, + "evictionPolicy": { + "type": "string", + "defaultValue": "Deallocate", + "allowedValues": [ + "Deallocate", + "Delete" + ], "metadata": { - "description": "Optional. Specifies the eviction policy for the low priority virtual machine. Will result in 'Deallocate' eviction policy." + "description": "Optional. Specifies the eviction policy for the low priority virtual machine." } }, "maxPriceForLowPriorityVm": { @@ -503,13 +556,17 @@ }, "publicKeys": { "type": "array", + "items": { + "$ref": "#/definitions/publicKeyType" + }, "defaultValue": [], "metadata": { "description": "Optional. The list of SSH public keys used to authenticate with linux based VMs." } }, "managedIdentities": { - "$ref": "#/definitions/managedIdentitiesType", + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, "metadata": { "description": "Optional. The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = \"True\"." } @@ -768,12 +825,17 @@ }, "lock": { "$ref": "#/definitions/lockType", + "nullable": true, "metadata": { "description": "Optional. The lock settings of the service." } }, "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, "metadata": { "description": "Optional. Array of role assignments to create." } @@ -1065,17 +1127,18 @@ ], "imageReference": "[parameters('imageReference')]", "osDisk": { - "name": "[coalesce(tryGet(parameters('osDisk'), 'name'), format('{0}-disk-os-01', parameters('name')))]", + "caching": "[coalesce(tryGet(parameters('osDisk'), 'caching'), 'ReadOnly')]", "createOption": "[coalesce(tryGet(parameters('osDisk'), 'createOption'), 'FromImage')]", "deleteOption": "[coalesce(tryGet(parameters('osDisk'), 'deleteOption'), 'Delete')]", + "diffDiskSettings": "[if(empty(coalesce(tryGet(parameters('osDisk'), 'diffDiskSettings'), createObject())), null(), createObject('option', 'Local', 'placement', parameters('osDisk').diffDiskSettings.placement))]", "diskSizeGB": "[parameters('osDisk').diskSizeGB]", - "caching": "[coalesce(tryGet(parameters('osDisk'), 'caching'), 'ReadOnly')]", "managedDisk": { - "storageAccountType": "[parameters('osDisk').managedDisk.storageAccountType]", "diskEncryptionSet": { "id": "[tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId')]" - } - } + }, + "storageAccountType": "[parameters('osDisk').managedDisk.storageAccountType]" + }, + "name": "[coalesce(tryGet(parameters('osDisk'), 'name'), format('{0}-disk-os-01', parameters('name')))]" } }, "additionalCapabilities": { @@ -1117,7 +1180,7 @@ "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]", "virtualMachineScaleSet": "[if(not(empty(parameters('virtualMachineScaleSetResourceId'))), createObject('id', parameters('virtualMachineScaleSetResourceId')), null())]", "priority": "[parameters('priority')]", - "evictionPolicy": "[if(parameters('enableEvictionPolicy'), 'Deallocate', null())]", + "evictionPolicy": "[if(not(equals('Regular', parameters('priority'))), parameters('evictionPolicy'), null())]", "billingProfile": "[if(and(not(empty(parameters('priority'))), not(empty(parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', json(parameters('maxPriceForLowPriorityVm'))), null())]", "host": "[if(not(empty(parameters('dedicatedHostId'))), createObject('id', parameters('dedicatedHostId')), null())]", "licenseType": "[if(not(empty(parameters('licenseType'))), parameters('licenseType'), null())]", @@ -1304,8 +1367,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "5147048658891642308" + "version": "0.32.4.45862", + "templateHash": "4332293246640728460" } }, "definitions": { @@ -2908,8 +2971,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "688718350646227538" + "version": "0.32.4.45862", + "templateHash": "12912200857967286939" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -3024,10 +3087,7 @@ "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", "suppressFailures": "[parameters('supressFailures')]" - }, - "dependsOn": [ - "virtualMachine" - ] + } } }, "outputs": { @@ -3123,8 +3183,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "688718350646227538" + "version": "0.32.4.45862", + "templateHash": "12912200857967286939" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -3239,10 +3299,7 @@ "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", "suppressFailures": "[parameters('supressFailures')]" - }, - "dependsOn": [ - "virtualMachine" - ] + } } }, "outputs": { @@ -3334,8 +3391,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "688718350646227538" + "version": "0.32.4.45862", + "templateHash": "12912200857967286939" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -3450,10 +3507,7 @@ "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", "suppressFailures": "[parameters('supressFailures')]" - }, - "dependsOn": [ - "virtualMachine" - ] + } } }, "outputs": { @@ -3540,8 +3594,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "688718350646227538" + "version": "0.32.4.45862", + "templateHash": "12912200857967286939" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -3656,10 +3710,7 @@ "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", "suppressFailures": "[parameters('supressFailures')]" - }, - "dependsOn": [ - "virtualMachine" - ] + } } }, "outputs": { @@ -3751,8 +3802,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "688718350646227538" + "version": "0.32.4.45862", + "templateHash": "12912200857967286939" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -3867,10 +3918,7 @@ "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", "suppressFailures": "[parameters('supressFailures')]" - }, - "dependsOn": [ - "virtualMachine" - ] + } } }, "outputs": { @@ -3957,8 +4005,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "688718350646227538" + "version": "0.32.4.45862", + "templateHash": "12912200857967286939" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -4073,10 +4121,7 @@ "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", "suppressFailures": "[parameters('supressFailures')]" - }, - "dependsOn": [ - "virtualMachine" - ] + } } }, "outputs": { @@ -4171,8 +4216,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "688718350646227538" + "version": "0.32.4.45862", + "templateHash": "12912200857967286939" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -4287,10 +4332,7 @@ "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", "suppressFailures": "[parameters('supressFailures')]" - }, - "dependsOn": [ - "virtualMachine" - ] + } } }, "outputs": { @@ -4389,8 +4431,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "688718350646227538" + "version": "0.32.4.45862", + "templateHash": "12912200857967286939" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -4505,10 +4547,7 @@ "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", "suppressFailures": "[parameters('supressFailures')]" - }, - "dependsOn": [ - "virtualMachine" - ] + } } }, "outputs": { @@ -4601,8 +4640,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "688718350646227538" + "version": "0.32.4.45862", + "templateHash": "12912200857967286939" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -4717,10 +4756,7 @@ "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", "suppressFailures": "[parameters('supressFailures')]" - }, - "dependsOn": [ - "virtualMachine" - ] + } } }, "outputs": { @@ -4809,8 +4845,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "688718350646227538" + "version": "0.32.4.45862", + "templateHash": "12912200857967286939" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -4925,10 +4961,7 @@ "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", "suppressFailures": "[parameters('supressFailures')]" - }, - "dependsOn": [ - "virtualMachine" - ] + } } }, "outputs": { @@ -5026,8 +5059,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "688718350646227538" + "version": "0.32.4.45862", + "templateHash": "12912200857967286939" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -5142,10 +5175,7 @@ "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", "suppressFailures": "[parameters('supressFailures')]" - }, - "dependsOn": [ - "virtualMachine" - ] + } } }, "outputs": { @@ -5239,8 +5269,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "688718350646227538" + "version": "0.32.4.45862", + "templateHash": "12912200857967286939" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -5355,10 +5385,7 @@ "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", "suppressFailures": "[parameters('supressFailures')]" - }, - "dependsOn": [ - "virtualMachine" - ] + } } }, "outputs": { @@ -5438,8 +5465,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "17378339479808033328" + "version": "0.32.4.45862", + "templateHash": "8409556960090427141" }, "name": "Recovery Service Vaults Protection Container Protected Item", "description": "This module deploys a Recovery Services Vault Protection Container Protected Item.", diff --git a/avm/res/compute/virtual-machine/tests/e2e/spot/dependencies.bicep b/avm/res/compute/virtual-machine/tests/e2e/spot/dependencies.bicep new file mode 100644 index 0000000000..c9a69d0b56 --- /dev/null +++ b/avm/res/compute/virtual-machine/tests/e2e/spot/dependencies.bicep @@ -0,0 +1,89 @@ +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Deployment Script to create for the SSH Key generation.') +param sshDeploymentScriptName string + +@description('Required. The name of the SSH Key to create.') +param sshKeyName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource msiRGContrRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(resourceGroup().id, 'Contributor', managedIdentity.id) + scope: resourceGroup() + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b24988ac-6180-42a0-ab88-20f7382dd24c' + ) // Contributor + principalType: 'ServicePrincipal' + } +} + +resource sshDeploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: sshDeploymentScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '9.0' + retentionInterval: 'P1D' + arguments: '-SSHKeyName "${sshKeyName}" -ResourceGroupName "${resourceGroup().name}"' + scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/New-SSHKey.ps1') + } + dependsOn: [ + msiRGContrRoleAssignment + ] +} + +resource sshKey 'Microsoft.Compute/sshPublicKeys@2022-03-01' = { + name: sshKeyName + location: location + properties: { + publicKey: sshDeploymentScript.properties.outputs.publicKey + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The Public Key of the created SSH Key.') +output SSHKeyPublicKey string = sshKey.properties.publicKey diff --git a/avm/res/compute/virtual-machine/tests/e2e/spot/main.test.bicep b/avm/res/compute/virtual-machine/tests/e2e/spot/main.test.bicep new file mode 100644 index 0000000000..aedb1271d8 --- /dev/null +++ b/avm/res/compute/virtual-machine/tests/e2e/spot/main.test.bicep @@ -0,0 +1,113 @@ +targetScope = 'subscription' + +metadata name = 'Using spot priority for the VM' +metadata description = 'This instance deploys the module with spot priority and an ephemeral OS disk.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' + +// Capacity constraints for VM type +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cvmlinspot' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' + params: { + location: enforcedLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + sshDeploymentScriptName: 'dep-${namePrefix}-ds-${serviceShort}' + sshKeyName: 'dep-${namePrefix}-ssh-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +// resource sshKey 'Microsoft.Compute/sshPublicKeys@2022-03-01' existing = { +// name: sshKeyName +// scope: resourceGroup +// } + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' + params: { + adminUsername: 'localAdminUser' + disablePasswordAuthentication: true + evictionPolicy: 'Delete' + imageReference: { + offer: 'debian-12' + publisher: 'debian' + sku: '12-arm64' + version: 'latest' + } + location: enforcedLocation + name: '${namePrefix}${serviceShort}' + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + pipConfiguration: { + name: 'pip-01' + } + } + ] + nicSuffix: '-nic-01' + } + ] + osDisk: { + caching: 'ReadOnly' + deleteOption: 'Delete' + diffDiskSettings: { + placement: 'NvmeDisk' + } + diskSizeGB: 75 + managedDisk: { + storageAccountType: 'Standard_LRS' + } + } + osType: 'Linux' + priority: 'Spot' + publicKeys: [ + { + keyData: nestedDependencies.outputs.SSHKeyPublicKey + path: '/home/localAdminUser/.ssh/authorized_keys' + } + ] + vmSize: 'Standard_D2plds_v6' + zone: 0 + } + dependsOn: [ + nestedDependencies // Required to leverage `existing` SSH key reference + ] + } +] From 7ff903611eaf309afbbd3ae5a0fe786276da2a4d Mon Sep 17 00:00:00 2001 From: David Jurgens Date: Tue, 17 Dec 2024 12:54:09 -0600 Subject: [PATCH 2/9] removed e2e test --- .../tests/e2e/spot/dependencies.bicep | 89 -------------- .../tests/e2e/spot/main.test.bicep | 113 ------------------ 2 files changed, 202 deletions(-) delete mode 100644 avm/res/compute/virtual-machine/tests/e2e/spot/dependencies.bicep delete mode 100644 avm/res/compute/virtual-machine/tests/e2e/spot/main.test.bicep diff --git a/avm/res/compute/virtual-machine/tests/e2e/spot/dependencies.bicep b/avm/res/compute/virtual-machine/tests/e2e/spot/dependencies.bicep deleted file mode 100644 index c9a69d0b56..0000000000 --- a/avm/res/compute/virtual-machine/tests/e2e/spot/dependencies.bicep +++ /dev/null @@ -1,89 +0,0 @@ -@description('Required. The name of the Virtual Network to create.') -param virtualNetworkName string - -@description('Required. The name of the Managed Identity to create.') -param managedIdentityName string - -@description('Required. The name of the Deployment Script to create for the SSH Key generation.') -param sshDeploymentScriptName string - -@description('Required. The name of the SSH Key to create.') -param sshKeyName string - -@description('Optional. The location to deploy resources to.') -param location string = resourceGroup().location - -var addressPrefix = '10.0.0.0/16' - -resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { - name: virtualNetworkName - location: location - properties: { - addressSpace: { - addressPrefixes: [ - addressPrefix - ] - } - subnets: [ - { - name: 'defaultSubnet' - properties: { - addressPrefix: cidrSubnet(addressPrefix, 16, 0) - } - } - ] - } -} - -resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { - name: managedIdentityName - location: location -} - -resource msiRGContrRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid(resourceGroup().id, 'Contributor', managedIdentity.id) - scope: resourceGroup() - properties: { - principalId: managedIdentity.properties.principalId - roleDefinitionId: subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'b24988ac-6180-42a0-ab88-20f7382dd24c' - ) // Contributor - principalType: 'ServicePrincipal' - } -} - -resource sshDeploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { - name: sshDeploymentScriptName - location: location - kind: 'AzurePowerShell' - identity: { - type: 'UserAssigned' - userAssignedIdentities: { - '${managedIdentity.id}': {} - } - } - properties: { - azPowerShellVersion: '9.0' - retentionInterval: 'P1D' - arguments: '-SSHKeyName "${sshKeyName}" -ResourceGroupName "${resourceGroup().name}"' - scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/New-SSHKey.ps1') - } - dependsOn: [ - msiRGContrRoleAssignment - ] -} - -resource sshKey 'Microsoft.Compute/sshPublicKeys@2022-03-01' = { - name: sshKeyName - location: location - properties: { - publicKey: sshDeploymentScript.properties.outputs.publicKey - } -} - -@description('The resource ID of the created Virtual Network Subnet.') -output subnetResourceId string = virtualNetwork.properties.subnets[0].id - -@description('The Public Key of the created SSH Key.') -output SSHKeyPublicKey string = sshKey.properties.publicKey diff --git a/avm/res/compute/virtual-machine/tests/e2e/spot/main.test.bicep b/avm/res/compute/virtual-machine/tests/e2e/spot/main.test.bicep deleted file mode 100644 index aedb1271d8..0000000000 --- a/avm/res/compute/virtual-machine/tests/e2e/spot/main.test.bicep +++ /dev/null @@ -1,113 +0,0 @@ -targetScope = 'subscription' - -metadata name = 'Using spot priority for the VM' -metadata description = 'This instance deploys the module with spot priority and an ephemeral OS disk.' - -// ========== // -// Parameters // -// ========== // - -@description('Optional. The name of the resource group to deploy for testing purposes.') -@maxLength(90) -param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' - -// Capacity constraints for VM type -#disable-next-line no-hardcoded-location -var enforcedLocation = 'uksouth' - -@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') -param serviceShort string = 'cvmlinspot' - -@description('Optional. A token to inject into the name of each resource.') -param namePrefix string = '#_namePrefix_#' - -// ============ // -// Dependencies // -// ============ // - -// General resources -// ================= -resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { - name: resourceGroupName - location: enforcedLocation -} - -module nestedDependencies 'dependencies.bicep' = { - scope: resourceGroup - name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' - params: { - location: enforcedLocation - virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' - managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' - sshDeploymentScriptName: 'dep-${namePrefix}-ds-${serviceShort}' - sshKeyName: 'dep-${namePrefix}-ssh-${serviceShort}' - } -} - -// ============== // -// Test Execution // -// ============== // - -// resource sshKey 'Microsoft.Compute/sshPublicKeys@2022-03-01' existing = { -// name: sshKeyName -// scope: resourceGroup -// } - -@batchSize(1) -module testDeployment '../../../main.bicep' = [ - for iteration in ['init', 'idem']: { - scope: resourceGroup - name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' - params: { - adminUsername: 'localAdminUser' - disablePasswordAuthentication: true - evictionPolicy: 'Delete' - imageReference: { - offer: 'debian-12' - publisher: 'debian' - sku: '12-arm64' - version: 'latest' - } - location: enforcedLocation - name: '${namePrefix}${serviceShort}' - nicConfigurations: [ - { - ipConfigurations: [ - { - name: 'ipconfig01' - subnetResourceId: nestedDependencies.outputs.subnetResourceId - pipConfiguration: { - name: 'pip-01' - } - } - ] - nicSuffix: '-nic-01' - } - ] - osDisk: { - caching: 'ReadOnly' - deleteOption: 'Delete' - diffDiskSettings: { - placement: 'NvmeDisk' - } - diskSizeGB: 75 - managedDisk: { - storageAccountType: 'Standard_LRS' - } - } - osType: 'Linux' - priority: 'Spot' - publicKeys: [ - { - keyData: nestedDependencies.outputs.SSHKeyPublicKey - path: '/home/localAdminUser/.ssh/authorized_keys' - } - ] - vmSize: 'Standard_D2plds_v6' - zone: 0 - } - dependsOn: [ - nestedDependencies // Required to leverage `existing` SSH key reference - ] - } -] From 3917aed5320f95289ddbf02d9b22658180ca7e19 Mon Sep 17 00:00:00 2001 From: David Jurgens Date: Tue, 17 Dec 2024 12:57:49 -0600 Subject: [PATCH 3/9] bumped major version --- avm/res/compute/virtual-machine/version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/avm/res/compute/virtual-machine/version.json b/avm/res/compute/virtual-machine/version.json index a830c3d961..91ffa760bf 100644 --- a/avm/res/compute/virtual-machine/version.json +++ b/avm/res/compute/virtual-machine/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.10", + "version": "0.11", "pathFilters": [ "./main.json" ] From 619c541df476e7ee02cf5d8f23df8e528e9e82f6 Mon Sep 17 00:00:00 2001 From: David Jurgens Date: Tue, 17 Dec 2024 13:00:47 -0600 Subject: [PATCH 4/9] generated dependent module --- avm/res/compute/virtual-machine/extension/main.json | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/avm/res/compute/virtual-machine/extension/main.json b/avm/res/compute/virtual-machine/extension/main.json index 2f5a0ec441..7d1084914e 100644 --- a/avm/res/compute/virtual-machine/extension/main.json +++ b/avm/res/compute/virtual-machine/extension/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "688718350646227538" + "version": "0.32.4.45862", + "templateHash": "12912200857967286939" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -121,10 +121,7 @@ "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", "suppressFailures": "[parameters('supressFailures')]" - }, - "dependsOn": [ - "virtualMachine" - ] + } } }, "outputs": { From e318ce35782f52621cf839df234c17d894c29f69 Mon Sep 17 00:00:00 2001 From: David Jurgens Date: Tue, 17 Dec 2024 13:39:16 -0600 Subject: [PATCH 5/9] added support for oidc auth --- .../actions/templates/avm-validateModuleDeployment/action.yml | 3 +++ .github/workflows/avm.template.module.yml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/.github/actions/templates/avm-validateModuleDeployment/action.yml b/.github/actions/templates/avm-validateModuleDeployment/action.yml index 391cc1bdd7..ad9d0edd99 100644 --- a/.github/actions/templates/avm-validateModuleDeployment/action.yml +++ b/.github/actions/templates/avm-validateModuleDeployment/action.yml @@ -62,8 +62,11 @@ runs: - name: Azure Login uses: azure/login@v2 with: + client-id: ${{ env.AZURE_CLIENT_ID }} creds: ${{ env.AZURE_CREDENTIALS }} enable-AzPSSession: true + subscription-id: ${{ env.AZURE_SUBSCRIPTION_ID }} + tenant-id: ${{ env.AZURE_TENANT_ID }} # [Set Deployment Location] task(s) # --------------------------- diff --git a/.github/workflows/avm.template.module.yml b/.github/workflows/avm.template.module.yml index 6bcdc747a3..7364599a26 100644 --- a/.github/workflows/avm.template.module.yml +++ b/.github/workflows/avm.template.module.yml @@ -178,7 +178,10 @@ jobs: removeDeployment: "${{ fromJson(inputs.workflowInput).removeDeployment }}" customLocation: "${{ fromJson(inputs.workflowInput).customLocation }}" env: + AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} + AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} ################## # Publishing # From bdddc172d0dadf5a2d1e6177de88e7221cfcdd61 Mon Sep 17 00:00:00 2001 From: David Jurgens Date: Tue, 17 Dec 2024 13:55:36 -0600 Subject: [PATCH 6/9] testing federated auth --- .../templates/avm-validateModuleDeployment/action.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/actions/templates/avm-validateModuleDeployment/action.yml b/.github/actions/templates/avm-validateModuleDeployment/action.yml index ad9d0edd99..67ebdfa8ed 100644 --- a/.github/actions/templates/avm-validateModuleDeployment/action.yml +++ b/.github/actions/templates/avm-validateModuleDeployment/action.yml @@ -61,10 +61,17 @@ runs: steps: - name: Azure Login uses: azure/login@v2 + if: {{ '' == env.AZURE_CLIENT_ID && '' == env.AZURE_SUBSCRIPTION_ID && '' == env.AZURE_TENANT_ID }} with: - client-id: ${{ env.AZURE_CLIENT_ID }} creds: ${{ env.AZURE_CREDENTIALS }} enable-AzPSSession: true + - name: Azure Login + if: {{ '' != env.AZURE_CLIENT_ID || '' != env.AZURE_SUBSCRIPTION_ID || '' != env.AZURE_TENANT_ID }} + uses: azure/login@v2 + with: + auth-type: 'IDENTITY' + client-id: ${{ env.AZURE_CLIENT_ID }} + enable-AzPSSession: true subscription-id: ${{ env.AZURE_SUBSCRIPTION_ID }} tenant-id: ${{ env.AZURE_TENANT_ID }} From d73429e450d7b8a4957350b2990e304c0b5a21ec Mon Sep 17 00:00:00 2001 From: David Jurgens Date: Tue, 17 Dec 2024 14:02:54 -0600 Subject: [PATCH 7/9] fixed syntax errors --- .../actions/templates/avm-validateModuleDeployment/action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/templates/avm-validateModuleDeployment/action.yml b/.github/actions/templates/avm-validateModuleDeployment/action.yml index 67ebdfa8ed..f45ca45afa 100644 --- a/.github/actions/templates/avm-validateModuleDeployment/action.yml +++ b/.github/actions/templates/avm-validateModuleDeployment/action.yml @@ -61,12 +61,12 @@ runs: steps: - name: Azure Login uses: azure/login@v2 - if: {{ '' == env.AZURE_CLIENT_ID && '' == env.AZURE_SUBSCRIPTION_ID && '' == env.AZURE_TENANT_ID }} + if: ${{ '' == env.AZURE_CLIENT_ID && '' == env.AZURE_SUBSCRIPTION_ID && '' == env.AZURE_TENANT_ID }} with: creds: ${{ env.AZURE_CREDENTIALS }} enable-AzPSSession: true - name: Azure Login - if: {{ '' != env.AZURE_CLIENT_ID || '' != env.AZURE_SUBSCRIPTION_ID || '' != env.AZURE_TENANT_ID }} + if: ${{ '' != env.AZURE_CLIENT_ID || '' != env.AZURE_SUBSCRIPTION_ID || '' != env.AZURE_TENANT_ID }} uses: azure/login@v2 with: auth-type: 'IDENTITY' From cb88257493c2f7eb42ede6500392521867da4a1d Mon Sep 17 00:00:00 2001 From: David Jurgens Date: Tue, 17 Dec 2024 14:14:23 -0600 Subject: [PATCH 8/9] removed unnecessary conditional step --- .../templates/avm-validateModuleDeployment/action.yml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/.github/actions/templates/avm-validateModuleDeployment/action.yml b/.github/actions/templates/avm-validateModuleDeployment/action.yml index f45ca45afa..ad9d0edd99 100644 --- a/.github/actions/templates/avm-validateModuleDeployment/action.yml +++ b/.github/actions/templates/avm-validateModuleDeployment/action.yml @@ -61,16 +61,9 @@ runs: steps: - name: Azure Login uses: azure/login@v2 - if: ${{ '' == env.AZURE_CLIENT_ID && '' == env.AZURE_SUBSCRIPTION_ID && '' == env.AZURE_TENANT_ID }} with: - creds: ${{ env.AZURE_CREDENTIALS }} - enable-AzPSSession: true - - name: Azure Login - if: ${{ '' != env.AZURE_CLIENT_ID || '' != env.AZURE_SUBSCRIPTION_ID || '' != env.AZURE_TENANT_ID }} - uses: azure/login@v2 - with: - auth-type: 'IDENTITY' client-id: ${{ env.AZURE_CLIENT_ID }} + creds: ${{ env.AZURE_CREDENTIALS }} enable-AzPSSession: true subscription-id: ${{ env.AZURE_SUBSCRIPTION_ID }} tenant-id: ${{ env.AZURE_TENANT_ID }} From f8cdec95b522575e0dddd1e7116d39df280656e7 Mon Sep 17 00:00:00 2001 From: David Jurgens Date: Sun, 22 Dec 2024 16:17:30 -0600 Subject: [PATCH 9/9] resolves comments --- .../actions/templates/avm-validateModuleDeployment/action.yml | 3 --- .github/workflows/avm.template.module.yml | 3 --- avm/res/compute/virtual-machine/version.json | 2 +- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/actions/templates/avm-validateModuleDeployment/action.yml b/.github/actions/templates/avm-validateModuleDeployment/action.yml index ad9d0edd99..391cc1bdd7 100644 --- a/.github/actions/templates/avm-validateModuleDeployment/action.yml +++ b/.github/actions/templates/avm-validateModuleDeployment/action.yml @@ -62,11 +62,8 @@ runs: - name: Azure Login uses: azure/login@v2 with: - client-id: ${{ env.AZURE_CLIENT_ID }} creds: ${{ env.AZURE_CREDENTIALS }} enable-AzPSSession: true - subscription-id: ${{ env.AZURE_SUBSCRIPTION_ID }} - tenant-id: ${{ env.AZURE_TENANT_ID }} # [Set Deployment Location] task(s) # --------------------------- diff --git a/.github/workflows/avm.template.module.yml b/.github/workflows/avm.template.module.yml index 7364599a26..6bcdc747a3 100644 --- a/.github/workflows/avm.template.module.yml +++ b/.github/workflows/avm.template.module.yml @@ -178,10 +178,7 @@ jobs: removeDeployment: "${{ fromJson(inputs.workflowInput).removeDeployment }}" customLocation: "${{ fromJson(inputs.workflowInput).customLocation }}" env: - AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} - AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} ################## # Publishing # diff --git a/avm/res/compute/virtual-machine/version.json b/avm/res/compute/virtual-machine/version.json index 91ffa760bf..23f3815885 100644 --- a/avm/res/compute/virtual-machine/version.json +++ b/avm/res/compute/virtual-machine/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.11", + "version": "0.12", "pathFilters": [ "./main.json" ]