diff --git a/.github/workflows/ms.compute.disks.yml b/.github/workflows/ms.compute.disks.yml index 389bd0f063..69e09d3dbe 100644 --- a/.github/workflows/ms.compute.disks.yml +++ b/.github/workflows/ms.compute.disks.yml @@ -106,8 +106,7 @@ jobs: - name: 'Using test file [${{ matrix.moduleTestFilePaths }}]' uses: ./.github/actions/templates/validateModuleDeployment with: - templateFilePath: '${{ env.modulePath }}/deploy.bicep' - parameterFilePath: '${{ env.modulePath }}/${{ matrix.moduleTestFilePaths }}' + templateFilePath: '${{ env.modulePath }}/${{ matrix.moduleTestFilePaths }}' location: '${{ env.location }}' resourceGroupName: '${{ env.resourceGroupName }}' subscriptionId: '${{ secrets.ARM_SUBSCRIPTION_ID }}' diff --git a/modules/Microsoft.Compute/disks/.test/.scripts/Copy-VhdToStorageAccount.ps1 b/modules/Microsoft.Compute/disks/.test/.scripts/Copy-VhdToStorageAccount.ps1 new file mode 100644 index 0000000000..ff8568b0a9 --- /dev/null +++ b/modules/Microsoft.Compute/disks/.test/.scripts/Copy-VhdToStorageAccount.ps1 @@ -0,0 +1,124 @@ +<# + .SYNOPSIS + Copy a VHD baked from a given image template to a given destination storage account blob container + + .DESCRIPTION + Copy a VHD baked from a given image template to a given destination storage account blob container + + .PARAMETER ImageTemplateName + Mandatory. The name of the image template + + .PARAMETER ImageTemplateResourceGroup + Mandatory. The resource group name of the image template + + .PARAMETER DestinationStorageAccountName + Mandatory. The name of the destination storage account + + .PARAMETER DestinationContainerName + Optional. The name of the existing destination blob container + + .PARAMETER VhdName + Optional. Specify a different name for the destination VHD file + + .PARAMETER WaitForComplete + Optional. Run the command synchronously. Wait for the completion of the copy. + + .EXAMPLE + Copy-VhdToStorageAccount -ImageTemplateName 'vhd-img-template-001-2022-07-29-15-54-01' -ImageTemplateResourceGroup 'validation-rg' -DestinationStorageAccountName 'vhdstorage001' + + Copy a VHD created by image template 'vhd-img-template-001-2022-07-29-15-54-01' in resource group 'validation-rg' to destination storage account 'vhdstorage001' in blob container named 'vhds'. Save the VHD file as 'vhd-img-template-001-2022-07-29-15-54-01.vhd'. + + .EXAMPLE + Copy-VhdToStorageAccount -ImageTemplateName 'vhd-img-template-001-2022-07-29-15-54-01' -ImageTemplateResourceGroup 'validation-rg' -DestinationStorageAccountName 'vhdstorage001' -VhdName 'vhd-img-template-001' -WaitForComplete + + Copy a VHD baked by image template 'vhd-img-template-001-2022-07-29-15-54-01' in resource group 'validation-rg' to destination storage account 'vhdstorage001' in a blob container named 'vhds' and wait for the completion of the copy. Save the VHD file as 'vhd-img-template-001.vhd'. +#> + +[CmdletBinding(SupportsShouldProcess)] +param ( + [Parameter(Mandatory = $true)] + [string] $ImageTemplateName, + + [Parameter(Mandatory = $true)] + [string] $ImageTemplateResourceGroup, + + [Parameter(Mandatory = $true)] + [string] $DestinationStorageAccountName, + + [Parameter(Mandatory = $false)] + [string] $DestinationContainerName = 'vhds', + + [Parameter(Mandatory = $false)] + [string] $VhdName = $ImageTemplateName, + + [Parameter(Mandatory = $false)] + [switch] $WaitForComplete +) + +begin { + Write-Debug ('{0} entered' -f $MyInvocation.MyCommand) + + # Install required modules + $currentVerbosePreference = $VerbosePreference + $VerbosePreference = 'SilentlyContinue' + $requiredModules = @( + 'Az.ImageBuilder', + 'Az.Storage' + ) + foreach ($moduleName in $requiredModules) { + if (-not ($installedModule = Get-Module $moduleName -ListAvailable)) { + Install-Module $moduleName -Repository 'PSGallery' -Force -Scope 'CurrentUser' + if ($installed = Get-Module -Name $moduleName -ListAvailable) { + Write-Verbose ('Installed module [{0}] with version [{1}]' -f $installed.Name, $installed.Version) -Verbose + } + } else { + Write-Verbose ('Module [{0}] already installed in version [{1}]' -f $installedModule[0].Name, $installedModule[0].Version) -Verbose + } + } + $VerbosePreference = $currentVerbosePreference +} + +process { + # Retrieving and initializing parameters before the blob copy + Write-Verbose 'Initializing source storage account parameters before the blob copy' -Verbose + Write-Verbose ('Retrieving source storage account from image template [{0}] in resource group [{1}]' -f $imageTemplateName, $imageTemplateResourceGroup) -Verbose + Get-InstalledModule + $imgtRunOutput = Get-AzImageBuilderTemplateRunOutput -ImageTemplateName $imageTemplateName -ResourceGroupName $imageTemplateResourceGroup | Where-Object ArtifactUri -NE $null + $sourceUri = $imgtRunOutput.ArtifactUri + $sourceStorageAccountName = $sourceUri.Split('//')[1].Split('.')[0] + $storageAccountList = Get-AzStorageAccount + $sourceStorageAccount = $storageAccountList | Where-Object StorageAccountName -EQ $sourceStorageAccountName + $sourceStorageAccountContext = $sourceStorageAccount.Context + $sourceStorageAccountRGName = $sourceStorageAccount.ResourceGroupName + Write-Verbose ('Retrieving artifact uri [{0}] stored in resource group [{1}]' -f $sourceUri, $sourceStorageAccountRGName) -Verbose + + Write-Verbose 'Initializing destination storage account parameters before the blob copy' -Verbose + $destinationStorageAccount = $storageAccountList | Where-Object StorageAccountName -EQ $destinationStorageAccountName + $destinationStorageAccountContext = $destinationStorageAccount.Context + $destinationBlobName = "$vhdName.vhd" + Write-Verbose ('Planning for destination blob name [{0}] in container [{1}] and storage account [{2}]' -f $destinationBlobName, $destinationContainerName, $destinationStorageAccountName) -Verbose + + # Copying the VHD to a destination blob container + $resourceActionInputObject = @{ + AbsoluteUri = $sourceUri + Context = $sourceStorageAccountContext + DestContext = $destinationStorageAccountContext + DestBlob = $destinationBlobName + DestContainer = $destinationContainerName + Force = $true + } + + if ($PSCmdlet.ShouldProcess('Storage blob copy of VHD [{0}]' -f $destinationBlobName, 'Start')) { + $destBlob = Start-AzStorageBlobCopy @resourceActionInputObject + Write-Verbose ('Copied/initialized copy of VHD from URI [{0}] to container [{1}] in storage account [{2}]' -f $sourceUri, $destinationContainerName, $destinationStorageAccountName) -Verbose + } + + if ($WaitForComplete) { + $destBlob | Get-AzStorageBlobCopyState -WaitForComplete + } +} + +end { + Write-Debug ('{0} exited' -f $MyInvocation.MyCommand) +} + diff --git a/modules/Microsoft.Compute/disks/.test/.scripts/Start-ImageTemplate.ps1 b/modules/Microsoft.Compute/disks/.test/.scripts/Start-ImageTemplate.ps1 new file mode 100644 index 0000000000..9118832ea3 --- /dev/null +++ b/modules/Microsoft.Compute/disks/.test/.scripts/Start-ImageTemplate.ps1 @@ -0,0 +1,79 @@ +<# + .SYNOPSIS + Create image artifacts from a given image template + + .DESCRIPTION + Create image artifacts from a given image template + + .PARAMETER ImageTemplateName + Mandatory. The name of the image template + + .PARAMETER ImageTemplateResourceGroup + Mandatory. The resource group name of the image template + + .PARAMETER NoWait + Optional. Run the command asynchronously + + .EXAMPLE + Start-AzImageBuilderTemplate -ImageTemplateName 'vhd-img-template-001-2022-07-29-15-54-01' -ImageTemplateResourceGroup 'validation-rg' + + Create image artifacts from image template 'vhd-img-template-001-2022-07-29-15-54-01' in resource group 'validation-rg' and wait for their completion + + .EXAMPLE + Start-AzImageBuilderTemplate -ImageTemplateName 'vhd-img-template-001-2022-07-29-15-54-01' -ImageTemplateResourceGroup 'validation-rg' -NoWait + + Start the creation of artifacts from image template 'vhd-img-template-001-2022-07-29-15-54-01' in resource group 'validation-rg' and do not wait for their completion +#> + +[CmdletBinding(SupportsShouldProcess)] +param ( + [Parameter(Mandatory = $true)] + [string] $ImageTemplateName, + + [Parameter(Mandatory = $true)] + [string] $ImageTemplateResourceGroup, + + [Parameter(Mandatory = $false)] + [switch] $NoWait +) + +begin { + Write-Debug ('{0} entered' -f $MyInvocation.MyCommand) + + # Install required modules + $currentVerbosePreference = $VerbosePreference + $VerbosePreference = 'SilentlyContinue' + $requiredModules = @( + 'Az.ImageBuilder' + ) + foreach ($moduleName in $requiredModules) { + if (-not ($installedModule = Get-Module $moduleName -ListAvailable)) { + Install-Module $moduleName -Repository 'PSGallery' -Force -Scope 'CurrentUser' + if ($installed = Get-Module -Name $moduleName -ListAvailable) { + Write-Verbose ('Installed module [{0}] with version [{1}]' -f $installed.Name, $installed.Version) -Verbose + } + } else { + Write-Verbose ('Module [{0}] already installed in version [{1}]' -f $installedModule[0].Name, $installedModule[0].Version) -Verbose + } + } + $VerbosePreference = $currentVerbosePreference +} + +process { + # Create image artifacts from existing image template + $resourceActionInputObject = @{ + ImageTemplateName = $imageTemplateName + ResourceGroupName = $imageTemplateResourceGroup + } + if ($NoWait) { + $resourceActionInputObject['NoWait'] = $true + } + if ($PSCmdlet.ShouldProcess('Image template [{0}]' -f $imageTemplateName, 'Start')) { + $null = Start-AzImageBuilderTemplate @resourceActionInputObject + Write-Verbose ('Created/initialized creation of image artifacts from image template [{0}] in resource group [{1}]' -f $imageTemplateName, $imageTemplateResourceGroup) -Verbose + } +} + +end { + Write-Debug ('{0} exited' -f $MyInvocation.MyCommand) +} diff --git a/modules/Microsoft.Compute/disks/.test/common/dependencies.bicep b/modules/Microsoft.Compute/disks/.test/common/dependencies.bicep new file mode 100644 index 0000000000..13ea7a4d97 --- /dev/null +++ b/modules/Microsoft.Compute/disks/.test/common/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created managed identity') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/modules/Microsoft.Compute/disks/.test/common/deploy.test.bicep b/modules/Microsoft.Compute/disks/.test/common/deploy.test.bicep new file mode 100644 index 0000000000..b97a860f7a --- /dev/null +++ b/modules/Microsoft.Compute/disks/.test/common/deploy.test.bicep @@ -0,0 +1,61 @@ +targetScope = 'subscription' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for a testing purposes') +@maxLength(90) +param resourceGroupName string = 'ms.compute.images-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to') +param location string = deployment().location + +@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 = 'cdcom' + +// =========== // +// Deployments // +// =========== // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +module resourceGroupResources 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-paramNested' + params: { + managedIdentityName: 'dep-<>-msi-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // +module testDeployment '../../deploy.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}' + params: { + name: '<>-${serviceShort}001' + sku: 'UltraSSD_LRS' + diskIOPSReadWrite: 500 + diskMBpsReadWrite: 60 + diskSizeGB: 128 + lock: 'CanNotDelete' + logicalSectorSize: 512 + osType: 'Windows' + publicNetworkAccess: 'Enabled' + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalIds: [ + resourceGroupResources.outputs.managedIdentityPrincipalId + ] + } + ] + } +} diff --git a/modules/Microsoft.Compute/disks/.test/image.parameters.json b/modules/Microsoft.Compute/disks/.test/image.parameters.json deleted file mode 100644 index d6934ac643..0000000000 --- a/modules/Microsoft.Compute/disks/.test/image.parameters.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "name": { - "value": "<>-az-disk-image-001" - }, - "sku": { - "value": "Standard_LRS" - }, - "createOption": { - "value": "FromImage" - }, - "imageReferenceId": { - "value": "/Subscriptions/<>/Providers/Microsoft.Compute/Locations/westeurope/Publishers/MicrosoftWindowsServer/ArtifactTypes/VMImage/Offers/WindowsServer/Skus/2016-Datacenter/Versions/14393.4906.2112080838" - }, - "roleAssignments": { - "value": [ - { - "roleDefinitionIdOrName": "Reader", - "principalIds": [ - "<>" - ] - } - ] - } - } -} diff --git a/modules/Microsoft.Compute/disks/.test/image/dependencies.bicep b/modules/Microsoft.Compute/disks/.test/image/dependencies.bicep new file mode 100644 index 0000000000..13ea7a4d97 --- /dev/null +++ b/modules/Microsoft.Compute/disks/.test/image/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created managed identity') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/modules/Microsoft.Compute/disks/.test/image/deploy.test.bicep b/modules/Microsoft.Compute/disks/.test/image/deploy.test.bicep new file mode 100644 index 0000000000..0476e90e8a --- /dev/null +++ b/modules/Microsoft.Compute/disks/.test/image/deploy.test.bicep @@ -0,0 +1,56 @@ +targetScope = 'subscription' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for a testing purposes') +@maxLength(90) +param resourceGroupName string = 'ms.compute.images-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to') +param location string = deployment().location + +@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 = 'cdimg' + +// =========== // +// Deployments // +// =========== // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +module resourceGroupResources 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-paramNested' + params: { + managedIdentityName: 'dep-<>-msi-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // +module testDeployment '../../deploy.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}' + params: { + name: '<>-${serviceShort}001' + sku: 'Standard_LRS' + createOption: 'FromImage' + imageReferenceId: '${subscription().id}/Providers/Microsoft.Compute/Locations/westeurope/Publishers/MicrosoftWindowsServer/ArtifactTypes/VMImage/Offers/WindowsServer/Skus/2016-Datacenter/Versions/14393.4906.2112080838' + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalIds: [ + resourceGroupResources.outputs.managedIdentityPrincipalId + ] + } + ] + } +} diff --git a/modules/Microsoft.Compute/disks/.test/import.parameters.json b/modules/Microsoft.Compute/disks/.test/import.parameters.json deleted file mode 100644 index 808508ac65..0000000000 --- a/modules/Microsoft.Compute/disks/.test/import.parameters.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "name": { - "value": "<>-az-disk-import-001" - }, - "sku": { - "value": "Standard_LRS" - }, - "createOption": { - "value": "Import" - }, - "sourceUri": { - "value": "https://adp<>azsavhd001.blob.core.windows.net/vhds/adp-<>-az-imgt-vhd-001.vhd" - }, - "storageAccountId": { - "value": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Storage/storageAccounts/adp<>azsavhd001" - }, - "roleAssignments": { - "value": [ - { - "roleDefinitionIdOrName": "Reader", - "principalIds": [ - "<>" - ] - } - ] - } - } -} diff --git a/modules/Microsoft.Compute/disks/.test/import/dependencies.bicep b/modules/Microsoft.Compute/disks/.test/import/dependencies.bicep new file mode 100644 index 0000000000..dad8af70fe --- /dev/null +++ b/modules/Microsoft.Compute/disks/.test/import/dependencies.bicep @@ -0,0 +1,152 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Storage Account to create and to copy the VHD into.') +param storageAccountName string + +@description('Required. The name prefix of the Image Template to create.') +param imageTemplateNamePrefix string + +@description('Generated. Do not provide a value! This date value is used to generate a unique image template name.') +param baseTime string = utcNow('yyyy-MM-dd-HH-mm-ss') + +@description('Required. The name of the Deployment Script to create for triggering the image creation.') +param triggerImageDeploymentScriptName string + +@description('Required. The name of the Deployment Script to copy the VHD to a destination storage account.') +param copyVhdDeploymentScriptName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { + name: storageAccountName + location: location + kind: 'StorageV2' + sku: { + name: 'Standard_LRS' + } + properties: { + allowBlobPublicAccess: false + } + resource blobServices 'blobServices@2021-09-01' = { + name: 'default' + resource container 'containers@2021-09-01' = { + name: 'vhds' + properties: { + publicAccess: 'None' + } + } + } +} + +module roleAssignment 'dependencies_rbac.bicep' = { + name: '${deployment().name}-MSI-roleAssignment' + scope: subscription() + params: { + managedIdentityPrincipalId: managedIdentity.properties.principalId + managedIdentityResourceId: managedIdentity.id + } +} + +// Deploy image template +resource imageTemplate 'Microsoft.VirtualMachineImages/imageTemplates@2022-02-14' = { + name: '${imageTemplateNamePrefix}-${baseTime}' + location: location + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + buildTimeoutInMinutes: 0 + vmProfile: { + vmSize: 'Standard_D2s_v3' + osDiskSizeGB: 127 + } + source: { + type: 'PlatformImage' + publisher: 'MicrosoftWindowsDesktop' + offer: 'Windows-10' + sku: '19h2-evd' + version: 'latest' + } + distribute: [ + { + type: 'VHD' + runOutputName: '${imageTemplateNamePrefix}-VHD' + artifactTags: {} + } + ] + customize: [ + { + restartTimeout: '30m' + type: 'WindowsRestart' + } + ] + } +} + +// Trigger VHD creation +resource triggerImageDeploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: triggerImageDeploymentScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '8.0' + retentionInterval: 'P1D' + arguments: '-ImageTemplateName \\"${imageTemplate.name}\\" -ImageTemplateResourceGroup \\"${resourceGroup().name}\\"' + scriptContent: loadTextContent('../.scripts/Start-ImageTemplate.ps1') + cleanupPreference: 'OnSuccess' + forceUpdateTag: baseTime + } + dependsOn: [ + roleAssignment + ] +} + +// Copy VHD to destination storage account +resource copyVhdDeploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: copyVhdDeploymentScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '8.0' + retentionInterval: 'P1D' + arguments: '-ImageTemplateName \\"${imageTemplate.name}\\" -ImageTemplateResourceGroup \\"${resourceGroup().name}\\" -DestinationStorageAccountName \\"${storageAccount.name}\\" -VhdName \\"${imageTemplateNamePrefix}\\" -WaitForComplete' + scriptContent: loadTextContent('../.scripts/Copy-VhdToStorageAccount.ps1') + cleanupPreference: 'OnSuccess' + forceUpdateTag: baseTime + } + dependsOn: [ triggerImageDeploymentScript ] +} + +@description('The URI of the created VHD.') +output vhdUri string = 'https://${storageAccount.name}.blob.core.windows.net/vhds/${imageTemplateNamePrefix}.vhd' + +@description('The resource ID of the created Storage Account.') +output storageAccountResourceId string = storageAccount.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id diff --git a/modules/Microsoft.Compute/disks/.test/import/dependencies_rbac.bicep b/modules/Microsoft.Compute/disks/.test/import/dependencies_rbac.bicep new file mode 100644 index 0000000000..cdca1b63bd --- /dev/null +++ b/modules/Microsoft.Compute/disks/.test/import/dependencies_rbac.bicep @@ -0,0 +1,16 @@ +targetScope = 'subscription' + +@description('Required. The resource ID of the created Managed Identity.') +param managedIdentityResourceId string + +@description('Required. The principal ID of the created Managed Identity.') +param managedIdentityPrincipalId string + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(subscription().subscriptionId, 'Contributor', managedIdentityResourceId) + properties: { + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') // Contributor + principalId: managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } +} diff --git a/modules/Microsoft.Compute/disks/.test/import/deploy.test.bicep b/modules/Microsoft.Compute/disks/.test/import/deploy.test.bicep new file mode 100644 index 0000000000..d438d6a64c --- /dev/null +++ b/modules/Microsoft.Compute/disks/.test/import/deploy.test.bicep @@ -0,0 +1,61 @@ +targetScope = 'subscription' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for a testing purposes') +@maxLength(90) +param resourceGroupName string = 'ms.compute.images-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to') +param location string = deployment().location + +@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 = 'cdimp' + +// =========== // +// Deployments // +// =========== // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +module resourceGroupResources 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-paramNested' + params: { + managedIdentityName: 'dep-<>-msi-${serviceShort}' + storageAccountName: 'dep<>sa${serviceShort}01' + imageTemplateNamePrefix: 'dep-<>-imgt-${serviceShort}' + triggerImageDeploymentScriptName: 'dep-<>-ds-${serviceShort}-triggerImageTemplate' + copyVhdDeploymentScriptName: 'dep-<>-ds-${serviceShort}-copyVhdToStorage' + } +} + +// ============== // +// Test Execution // +// ============== // +module testDeployment '../../deploy.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}' + params: { + name: '<>-${serviceShort}001' + sku: 'Standard_LRS' + createOption: 'Import' + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalIds: [ + resourceGroupResources.outputs.managedIdentityPrincipalId + ] + } + ] + sourceUri: resourceGroupResources.outputs.vhdUri + storageAccountId: resourceGroupResources.outputs.storageAccountResourceId + } +} diff --git a/modules/Microsoft.Compute/disks/.test/min.parameters.json b/modules/Microsoft.Compute/disks/.test/min.parameters.json deleted file mode 100644 index d19f33a37d..0000000000 --- a/modules/Microsoft.Compute/disks/.test/min.parameters.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "name": { - "value": "<>-az-disk-min-001" - }, - "sku": { - "value": "Standard_LRS" - }, - "diskSizeGB": { - "value": 1 - }, - "roleAssignments": { - "value": [ - { - "roleDefinitionIdOrName": "Reader", - "principalIds": [ - "<>" - ] - } - ] - } - } -} diff --git a/modules/Microsoft.Compute/disks/.test/min/deploy.test.bicep b/modules/Microsoft.Compute/disks/.test/min/deploy.test.bicep new file mode 100644 index 0000000000..6fb986db71 --- /dev/null +++ b/modules/Microsoft.Compute/disks/.test/min/deploy.test.bicep @@ -0,0 +1,39 @@ +targetScope = 'subscription' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for a testing purposes') +@maxLength(90) +param resourceGroupName string = 'ms.compute.images-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to') +param location string = deployment().location + +@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 = 'cdmin' + +// =========== // +// Deployments // +// =========== // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +// ============== // +// Test Execution // +// ============== // +module testDeployment '../../deploy.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}' + params: { + name: '<>-${serviceShort}001' + sku: 'Standard_LRS' + diskSizeGB: 1 + } +} diff --git a/modules/Microsoft.Compute/disks/.test/parameters.json b/modules/Microsoft.Compute/disks/.test/parameters.json deleted file mode 100644 index 833336ee1e..0000000000 --- a/modules/Microsoft.Compute/disks/.test/parameters.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "name": { - "value": "<>-az-disk-x-001" - }, - "lock": { - "value": "CanNotDelete" - }, - "sku": { - "value": "UltraSSD_LRS" - }, - "diskSizeGB": { - "value": 128 - }, - "logicalSectorSize": { - "value": 512 - }, - "diskIOPSReadWrite": { - "value": 500 - }, - "diskMBpsReadWrite": { - "value": 60 - }, - "osType": { - "value": "Windows" - }, - "publicNetworkAccess": { - "value": "Enabled" - }, - "roleAssignments": { - "value": [ - { - "roleDefinitionIdOrName": "Reader", - "principalIds": [ - "<>" - ] - } - ] - } - } -} diff --git a/modules/Microsoft.Compute/disks/deploy.bicep b/modules/Microsoft.Compute/disks/deploy.bicep index b6d2a4216b..afd0d9fabf 100644 --- a/modules/Microsoft.Compute/disks/deploy.bicep +++ b/modules/Microsoft.Compute/disks/deploy.bicep @@ -51,13 +51,13 @@ param sourceResourceId string = '' @description('Optional. If create option is Import, this is the URI of a blob to be imported into a managed disk.') param sourceUri string = '' -@description('Optional. Required if create option is Import. The Azure Resource Manager identifier of the storage account containing the blob to import as a disk.') +@description('Conditional. The resource ID of the storage account containing the blob to import as a disk. Required if create option is Import.') param storageAccountId string = '' @description('Optional. If create option is Upload, this is the size of the contents of the upload including the VHD footer.') param uploadSizeBytes int = 20972032 -@description('Optional. If create option is empty, this field is mandatory and it indicates the size of the disk to create.') +@description('Conditional. The size of the disk to create. Required if create option is Empty.') param diskSizeGB int = 0 @description('Optional. The number of IOPS allowed for this disk; only settable for UltraSSD disks.') diff --git a/modules/Microsoft.Compute/disks/readme.md b/modules/Microsoft.Compute/disks/readme.md index 72dfd6d833..a83b0dd649 100644 --- a/modules/Microsoft.Compute/disks/readme.md +++ b/modules/Microsoft.Compute/disks/readme.md @@ -27,6 +27,13 @@ This template deploys a disk | `name` | string | | The name of the disk that is being created. | | `sku` | string | `[Premium_LRS, Premium_ZRS, Premium_ZRS, Standard_LRS, StandardSSD_LRS, UltraSSD_LRS]` | The disks sku name. Can be . | +**Conditional parameters** + +| Parameter Name | Type | Default Value | Description | +| :-- | :-- | :-- | :-- | +| `diskSizeGB` | int | `0` | The size of the disk to create. Required if create option is Empty. | +| `storageAccountId` | string | `''` | The resource ID of the storage account containing the blob to import as a disk. Required if create option is Import. | + **Optional parameters** | Parameter Name | Type | Default Value | Allowed Values | Description | @@ -37,7 +44,6 @@ This template deploys a disk | `createOption` | string | `'Empty'` | `[Attach, Copy, CopyStart, Empty, FromImage, Import, ImportSecure, Restore, Upload, UploadPreparedSecure]` | Sources of a disk creation. | | `diskIOPSReadWrite` | int | `0` | | The number of IOPS allowed for this disk; only settable for UltraSSD disks. | | `diskMBpsReadWrite` | int | `0` | | The bandwidth allowed for this disk; only settable for UltraSSD disks. | -| `diskSizeGB` | int | `0` | | If create option is empty, this field is mandatory and it indicates the size of the disk to create. | | `enableDefaultTelemetry` | bool | `True` | | Enable telemetry via the Customer Usage Attribution ID (GUID). | | `hyperVGeneration` | string | `'V2'` | `[V1, V2]` | The hypervisor generation of the Virtual Machine. Applicable to OS disks only. | | `imageReferenceId` | string | `''` | | A relative uri containing either a Platform Image Repository or user image reference. | @@ -52,7 +58,6 @@ This template deploys a disk | `securityDataUri` | string | `''` | | If create option is ImportSecure, this is the URI of a blob to be imported into VM guest state. | | `sourceResourceId` | string | `''` | | If create option is Copy, this is the ARM ID of the source snapshot or disk. | | `sourceUri` | string | `''` | | If create option is Import, this is the URI of a blob to be imported into a managed disk. | -| `storageAccountId` | string | `''` | | Required if create option is Import. The Azure Resource Manager identifier of the storage account containing the blob to import as a disk. | | `tags` | object | `{object}` | | Tags of the availability set resource. | | `uploadSizeBytes` | int | `20972032` | | If create option is Upload, this is the size of the contents of the upload including the VHD footer. | @@ -177,7 +182,7 @@ The following module usage examples are retrieved from the content of the files >**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. -

Example 1: Image

+

Example 1: Common

@@ -185,18 +190,23 @@ The following module usage examples are retrieved from the content of the files ```bicep module disks './Microsoft.Compute/disks/deploy.bicep' = { - name: '${uniqueString(deployment().name)}-Disks' + name: '${uniqueString(deployment().name, location)}-test-cdcom' params: { // Required parameters - name: '<>-az-disk-image-001' - sku: 'Standard_LRS' + name: '<>-cdcom001' + sku: 'UltraSSD_LRS' // Non-required parameters - createOption: 'FromImage' - imageReferenceId: '/Subscriptions/<>/Providers/Microsoft.Compute/Locations/westeurope/Publishers/MicrosoftWindowsServer/ArtifactTypes/VMImage/Offers/WindowsServer/Skus/2016-Datacenter/Versions/14393.4906.2112080838' + diskIOPSReadWrite: 500 + diskMBpsReadWrite: 60 + diskSizeGB: 128 + lock: 'CanNotDelete' + logicalSectorSize: 512 + osType: 'Windows' + publicNetworkAccess: 'Enabled' roleAssignments: [ { principalIds: [ - '<>' + '' ] roleDefinitionIdOrName: 'Reader' } @@ -219,23 +229,38 @@ module disks './Microsoft.Compute/disks/deploy.bicep' = { "parameters": { // Required parameters "name": { - "value": "<>-az-disk-image-001" + "value": "<>-cdcom001" }, "sku": { - "value": "Standard_LRS" + "value": "UltraSSD_LRS" }, // Non-required parameters - "createOption": { - "value": "FromImage" + "diskIOPSReadWrite": { + "value": 500 }, - "imageReferenceId": { - "value": "/Subscriptions/<>/Providers/Microsoft.Compute/Locations/westeurope/Publishers/MicrosoftWindowsServer/ArtifactTypes/VMImage/Offers/WindowsServer/Skus/2016-Datacenter/Versions/14393.4906.2112080838" + "diskMBpsReadWrite": { + "value": 60 + }, + "diskSizeGB": { + "value": 128 + }, + "lock": { + "value": "CanNotDelete" + }, + "logicalSectorSize": { + "value": 512 + }, + "osType": { + "value": "Windows" + }, + "publicNetworkAccess": { + "value": "Enabled" }, "roleAssignments": { "value": [ { "principalIds": [ - "<>" + "" ], "roleDefinitionIdOrName": "Reader" } @@ -248,7 +273,7 @@ module disks './Microsoft.Compute/disks/deploy.bicep' = {

-

Example 2: Import

+

Example 2: Image

@@ -256,23 +281,22 @@ module disks './Microsoft.Compute/disks/deploy.bicep' = { ```bicep module disks './Microsoft.Compute/disks/deploy.bicep' = { - name: '${uniqueString(deployment().name)}-Disks' + name: '${uniqueString(deployment().name, location)}-test-cdimg' params: { // Required parameters - name: '<>-az-disk-import-001' + name: '<>-cdimg001' sku: 'Standard_LRS' // Non-required parameters - createOption: 'Import' + createOption: 'FromImage' + imageReferenceId: '${subscription().id}/Providers/Microsoft.Compute/Locations/westeurope/Publishers/MicrosoftWindowsServer/ArtifactTypes/VMImage/Offers/WindowsServer/Skus/2016-Datacenter/Versions/14393.4906.2112080838' roleAssignments: [ { principalIds: [ - '<>' + '' ] roleDefinitionIdOrName: 'Reader' } ] - sourceUri: 'https://adp<>azsavhd001.blob.core.windows.net/vhds/adp-<>-az-imgt-vhd-001.vhd' - storageAccountId: '/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Storage/storageAccounts/adp<>azsavhd001' } } ``` @@ -291,30 +315,27 @@ module disks './Microsoft.Compute/disks/deploy.bicep' = { "parameters": { // Required parameters "name": { - "value": "<>-az-disk-import-001" + "value": "<>-cdimg001" }, "sku": { "value": "Standard_LRS" }, // Non-required parameters "createOption": { - "value": "Import" + "value": "FromImage" + }, + "imageReferenceId": { + "value": "${subscription().id}/Providers/Microsoft.Compute/Locations/westeurope/Publishers/MicrosoftWindowsServer/ArtifactTypes/VMImage/Offers/WindowsServer/Skus/2016-Datacenter/Versions/14393.4906.2112080838" }, "roleAssignments": { "value": [ { "principalIds": [ - "<>" + "" ], "roleDefinitionIdOrName": "Reader" } ] - }, - "sourceUri": { - "value": "https://adp<>azsavhd001.blob.core.windows.net/vhds/adp-<>-az-imgt-vhd-001.vhd" - }, - "storageAccountId": { - "value": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Storage/storageAccounts/adp<>azsavhd001" } } } @@ -323,7 +344,7 @@ module disks './Microsoft.Compute/disks/deploy.bicep' = {

-

Example 3: Min

+

Example 3: Import

@@ -331,21 +352,23 @@ module disks './Microsoft.Compute/disks/deploy.bicep' = { ```bicep module disks './Microsoft.Compute/disks/deploy.bicep' = { - name: '${uniqueString(deployment().name)}-Disks' + name: '${uniqueString(deployment().name, location)}-test-cdimp' params: { // Required parameters - name: '<>-az-disk-min-001' + name: '<>-cdimp001' sku: 'Standard_LRS' // Non-required parameters - diskSizeGB: 1 + createOption: 'Import' roleAssignments: [ { principalIds: [ - '<>' + '' ] roleDefinitionIdOrName: 'Reader' } ] + sourceUri: '' + storageAccountId: '' } } ``` @@ -364,24 +387,30 @@ module disks './Microsoft.Compute/disks/deploy.bicep' = { "parameters": { // Required parameters "name": { - "value": "<>-az-disk-min-001" + "value": "<>-cdimp001" }, "sku": { "value": "Standard_LRS" }, // Non-required parameters - "diskSizeGB": { - "value": 1 + "createOption": { + "value": "Import" }, "roleAssignments": { "value": [ { "principalIds": [ - "<>" + "" ], "roleDefinitionIdOrName": "Reader" } ] + }, + "sourceUri": { + "value": "" + }, + "storageAccountId": { + "value": "" } } } @@ -390,7 +419,7 @@ module disks './Microsoft.Compute/disks/deploy.bicep' = {

-

Example 4: Parameters

+

Example 4: Min

@@ -398,27 +427,13 @@ module disks './Microsoft.Compute/disks/deploy.bicep' = { ```bicep module disks './Microsoft.Compute/disks/deploy.bicep' = { - name: '${uniqueString(deployment().name)}-Disks' + name: '${uniqueString(deployment().name, location)}-test-cdmin' params: { // Required parameters - name: '<>-az-disk-x-001' - sku: 'UltraSSD_LRS' + name: '<>-cdmin001' + sku: 'Standard_LRS' // Non-required parameters - diskIOPSReadWrite: 500 - diskMBpsReadWrite: 60 - diskSizeGB: 128 - lock: 'CanNotDelete' - logicalSectorSize: 512 - osType: 'Windows' - publicNetworkAccess: 'Enabled' - roleAssignments: [ - { - principalIds: [ - '<>' - ] - roleDefinitionIdOrName: 'Reader' - } - ] + diskSizeGB: 1 } } ``` @@ -437,42 +452,14 @@ module disks './Microsoft.Compute/disks/deploy.bicep' = { "parameters": { // Required parameters "name": { - "value": "<>-az-disk-x-001" + "value": "<>-cdmin001" }, "sku": { - "value": "UltraSSD_LRS" + "value": "Standard_LRS" }, // Non-required parameters - "diskIOPSReadWrite": { - "value": 500 - }, - "diskMBpsReadWrite": { - "value": 60 - }, "diskSizeGB": { - "value": 128 - }, - "lock": { - "value": "CanNotDelete" - }, - "logicalSectorSize": { - "value": 512 - }, - "osType": { - "value": "Windows" - }, - "publicNetworkAccess": { - "value": "Enabled" - }, - "roleAssignments": { - "value": [ - { - "principalIds": [ - "<>" - ], - "roleDefinitionIdOrName": "Reader" - } - ] + "value": 1 } } }