diff --git a/avm/res/cdn/profile/README.md b/avm/res/cdn/profile/README.md index 45ce097300..c789fbe1fd 100644 --- a/avm/res/cdn/profile/README.md +++ b/avm/res/cdn/profile/README.md @@ -849,11 +849,14 @@ Endpoint tags. | Output | Type | Description | | :-- | :-- | :-- | +| `endpointId` | string | The resource ID of the CDN profile endpoint. | +| `endpointName` | string | The name of the CDN profile endpoint. | | `location` | string | The location the resource was deployed into. | | `name` | string | The name of the CDN profile. | | `profileType` | string | The type of the CDN profile. | | `resourceGroupName` | string | The resource group where the CDN profile is deployed. | | `resourceId` | string | The resource ID of the CDN profile. | +| `uri` | string | The uri of the CDN profile endpoint. | ## Cross-referenced modules diff --git a/avm/res/cdn/profile/afdEndpoint/README.md b/avm/res/cdn/profile/afdEndpoint/README.md index 1824848d10..8534159c47 100644 --- a/avm/res/cdn/profile/afdEndpoint/README.md +++ b/avm/res/cdn/profile/afdEndpoint/README.md @@ -118,6 +118,7 @@ The tags of the AFD Endpoint. | `name` | string | The name of the AFD Endpoint. | | `resourceGroupName` | string | The name of the resource group the endpoint was created in. | | `resourceId` | string | The resource id of the AFD Endpoint. | +| `routes` | array | The list of routes assigned to the AFD endpoint. | ## Cross-referenced modules diff --git a/avm/res/cdn/profile/afdEndpoint/main.bicep b/avm/res/cdn/profile/afdEndpoint/main.bicep index f58b77ad8c..a280fcf07f 100644 --- a/avm/res/cdn/profile/afdEndpoint/main.bicep +++ b/avm/res/cdn/profile/afdEndpoint/main.bicep @@ -81,3 +81,6 @@ output resourceGroupName string = resourceGroup().name @description('The location the resource was deployed into.') output location string = afdEndpoint.location + +@description('The list of routes assigned to the AFD endpoint.') +output routes array = routes ?? [] diff --git a/avm/res/cdn/profile/afdEndpoint/main.json b/avm/res/cdn/profile/afdEndpoint/main.json index 925daf8da7..baf13ec542 100644 --- a/avm/res/cdn/profile/afdEndpoint/main.json +++ b/avm/res/cdn/profile/afdEndpoint/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "1139997023996590437" + "version": "0.28.1.47646", + "templateHash": "12134994933996412108" }, "name": "CDN Profiles AFD Endpoints", "description": "This module deploys a CDN Profile AFD Endpoint.", @@ -156,8 +156,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "5770374289363120600" + "version": "0.28.1.47646", + "templateHash": "4116565038484106851" }, "name": "CDN Profiles AFD Endpoint Route", "description": "This module deploys a CDN Profile AFD Endpoint route.", @@ -431,6 +431,13 @@ "description": "The location the resource was deployed into." }, "value": "[reference('afdEndpoint', '2023-05-01', 'full').location]" + }, + "routes": { + "type": "array", + "metadata": { + "description": "The list of routes assigned to the AFD endpoint." + }, + "value": "[coalesce(parameters('routes'), createArray())]" } } -} +} \ No newline at end of file diff --git a/avm/res/cdn/profile/afdEndpoint/route/main.json b/avm/res/cdn/profile/afdEndpoint/route/main.json index 5f6294f050..1febe02474 100644 --- a/avm/res/cdn/profile/afdEndpoint/route/main.json +++ b/avm/res/cdn/profile/afdEndpoint/route/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "5770374289363120600" + "version": "0.28.1.47646", + "templateHash": "4116565038484106851" }, "name": "CDN Profiles AFD Endpoint Route", "description": "This module deploys a CDN Profile AFD Endpoint route.", @@ -244,4 +244,4 @@ "value": "[resourceGroup().name]" } } -} +} \ No newline at end of file diff --git a/avm/res/cdn/profile/customdomain/main.json b/avm/res/cdn/profile/customdomain/main.json index 8966e5eb46..86709ccc54 100644 --- a/avm/res/cdn/profile/customdomain/main.json +++ b/avm/res/cdn/profile/customdomain/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "15721665305636481516" + "version": "0.28.1.47646", + "templateHash": "16920601274318465194" }, "name": "CDN Profiles Custom Domains", "description": "This module deploys a CDN Profile Custom Domains.", @@ -121,4 +121,4 @@ "value": "[resourceGroup().name]" } } -} +} \ No newline at end of file diff --git a/avm/res/cdn/profile/endpoint/README.md b/avm/res/cdn/profile/endpoint/README.md index ac8d86345a..1044e2e951 100644 --- a/avm/res/cdn/profile/endpoint/README.md +++ b/avm/res/cdn/profile/endpoint/README.md @@ -85,6 +85,7 @@ Endpoint tags. | `name` | string | The name of the endpoint. | | `resourceGroupName` | string | The name of the resource group the endpoint was created in. | | `resourceId` | string | The resource ID of the endpoint. | +| `uri` | string | The uri of the endpoint. | ## Cross-referenced modules diff --git a/avm/res/cdn/profile/endpoint/main.bicep b/avm/res/cdn/profile/endpoint/main.bicep index 2379bba4d0..6ce0fd6de9 100644 --- a/avm/res/cdn/profile/endpoint/main.bicep +++ b/avm/res/cdn/profile/endpoint/main.bicep @@ -64,3 +64,6 @@ output location string = endpoint.location @description('The properties of the endpoint.') output endpointProperties object = endpoint.properties + +@description('The uri of the endpoint.') +output uri string = 'https://${endpoint.properties.hostName}' diff --git a/avm/res/cdn/profile/endpoint/main.json b/avm/res/cdn/profile/endpoint/main.json index 51a7779ed9..2f982eb836 100644 --- a/avm/res/cdn/profile/endpoint/main.json +++ b/avm/res/cdn/profile/endpoint/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "2906172435071993445" + "version": "0.28.1.47646", + "templateHash": "265552218697992746" }, "name": "CDN Profiles Endpoints", "description": "This module deploys a CDN Profile Endpoint.", @@ -125,8 +125,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "3665403791951260301" + "version": "0.28.1.47646", + "templateHash": "3976201598135370414" }, "name": "CDN Profiles Endpoints Origins", "description": "This module deploys a CDN Profile Endpoint Origin.", @@ -321,6 +321,13 @@ "description": "The properties of the endpoint." }, "value": "[reference('endpoint')]" + }, + "uri": { + "type": "string", + "metadata": { + "description": "The uri of the endpoint." + }, + "value": "[format('https://{0}', reference('endpoint').hostName)]" } } -} +} \ No newline at end of file diff --git a/avm/res/cdn/profile/endpoint/origin/main.json b/avm/res/cdn/profile/endpoint/origin/main.json index 3d2af22841..8b2acd2d62 100644 --- a/avm/res/cdn/profile/endpoint/origin/main.json +++ b/avm/res/cdn/profile/endpoint/origin/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "3665403791951260301" + "version": "0.28.1.47646", + "templateHash": "3976201598135370414" }, "name": "CDN Profiles Endpoints Origins", "description": "This module deploys a CDN Profile Endpoint Origin.", @@ -158,4 +158,4 @@ "value": "[reference('endpoint', '2021-06-01', 'full').location]" } } -} +} \ No newline at end of file diff --git a/avm/res/cdn/profile/main.bicep b/avm/res/cdn/profile/main.bicep index 1e951d3c75..2750e6cb73 100644 --- a/avm/res/cdn/profile/main.bicep +++ b/avm/res/cdn/profile/main.bicep @@ -259,6 +259,15 @@ output profileType string = profile.type @description('The location the resource was deployed into.') output location string = profile.location +@description('The name of the CDN profile endpoint.') +output endpointName string = !empty(endpointProperties) ? profile_endpoint.outputs.name : '' + +@description('The resource ID of the CDN profile endpoint.') +output endpointId string = !empty(endpointProperties) ? profile_endpoint.outputs.resourceId : '' + +@description('The uri of the CDN profile endpoint.') +output uri string = !empty(endpointProperties) ? profile_endpoint.outputs.uri : '' + // =============== // // Definitions // // =============== // diff --git a/avm/res/cdn/profile/main.json b/avm/res/cdn/profile/main.json index 10d4e53686..f86d5e2680 100644 --- a/avm/res/cdn/profile/main.json +++ b/avm/res/cdn/profile/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.28.1.47646", - "templateHash": "1004296684432790978" + "templateHash": "10450324656254846829" }, "name": "CDN Profiles", "description": "This module deploys a CDN Profile.", @@ -337,7 +337,7 @@ "_generator": { "name": "bicep", "version": "0.28.1.47646", - "templateHash": "646975231992417020" + "templateHash": "265552218697992746" }, "name": "CDN Profiles Endpoints", "description": "This module deploys a CDN Profile Endpoint.", @@ -652,6 +652,13 @@ "description": "The properties of the endpoint." }, "value": "[reference('endpoint')]" + }, + "uri": { + "type": "string", + "metadata": { + "description": "The uri of the endpoint." + }, + "value": "[format('https://{0}', reference('endpoint').hostName)]" } } } @@ -1656,7 +1663,7 @@ "_generator": { "name": "bicep", "version": "0.28.1.47646", - "templateHash": "2563478312676565785" + "templateHash": "12134994933996412108" }, "name": "CDN Profiles AFD Endpoints", "description": "This module deploys a CDN Profile AFD Endpoint.", @@ -2081,6 +2088,13 @@ "description": "The location the resource was deployed into." }, "value": "[reference('afdEndpoint', '2023-05-01', 'full').location]" + }, + "routes": { + "type": "array", + "metadata": { + "description": "The list of routes assigned to the AFD endpoint." + }, + "value": "[coalesce(parameters('routes'), createArray())]" } } } @@ -2128,6 +2142,27 @@ "description": "The location the resource was deployed into." }, "value": "[reference('profile', '2023-05-01', 'full').location]" + }, + "endpointName": { + "type": "string", + "metadata": { + "description": "The name of the CDN profile endpoint." + }, + "value": "[if(not(empty(parameters('endpointProperties'))), reference('profile_endpoint').outputs.name.value, '')]" + }, + "endpointId": { + "type": "string", + "metadata": { + "description": "The resource ID of the CDN profile endpoint." + }, + "value": "[if(not(empty(parameters('endpointProperties'))), reference('profile_endpoint').outputs.resourceId.value, '')]" + }, + "uri": { + "type": "string", + "metadata": { + "description": "The uri of the CDN profile endpoint." + }, + "value": "[if(not(empty(parameters('endpointProperties'))), reference('profile_endpoint').outputs.uri.value, '')]" } } } \ No newline at end of file diff --git a/avm/res/cdn/profile/origingroup/main.json b/avm/res/cdn/profile/origingroup/main.json index 13a07fe56c..5240c3ee2b 100644 --- a/avm/res/cdn/profile/origingroup/main.json +++ b/avm/res/cdn/profile/origingroup/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "12438540618132459307" + "version": "0.28.1.47646", + "templateHash": "767830983281905975" }, "name": "CDN Profiles Origin Group", "description": "This module deploys a CDN Profile Origin Group.", @@ -142,8 +142,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "8566106020570825253" + "version": "0.28.1.47646", + "templateHash": "16416786424096977239" }, "name": "CDN Profiles Origin", "description": "This module deploys a CDN Profile Origin.", @@ -331,4 +331,4 @@ "value": "[reference('profile', '2023-05-01', 'full').location]" } } -} +} \ No newline at end of file diff --git a/avm/res/cdn/profile/origingroup/origin/main.json b/avm/res/cdn/profile/origingroup/origin/main.json index 6c1cdb4ebe..2e59867a78 100644 --- a/avm/res/cdn/profile/origingroup/origin/main.json +++ b/avm/res/cdn/profile/origingroup/origin/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "8566106020570825253" + "version": "0.28.1.47646", + "templateHash": "16416786424096977239" }, "name": "CDN Profiles Origin", "description": "This module deploys a CDN Profile Origin.", @@ -157,4 +157,4 @@ "value": "[resourceGroup().name]" } } -} +} \ No newline at end of file diff --git a/avm/res/cdn/profile/ruleset/main.json b/avm/res/cdn/profile/ruleset/main.json index 7bdf9944da..87d871e139 100644 --- a/avm/res/cdn/profile/ruleset/main.json +++ b/avm/res/cdn/profile/ruleset/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "5891069247146856543" + "version": "0.28.1.47646", + "templateHash": "6477030276001558789" }, "name": "CDN Profiles Rule Sets", "description": "This module deploys a CDN Profile rule set.", @@ -91,8 +91,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "4690708071413750601" + "version": "0.28.1.47646", + "templateHash": "13457744126513087238" }, "name": "CDN Profiles Rules", "description": "This module deploys a CDN Profile rule.", @@ -230,4 +230,4 @@ "value": "[resourceGroup().name]" } } -} +} \ No newline at end of file diff --git a/avm/res/cdn/profile/ruleset/rule/main.json b/avm/res/cdn/profile/ruleset/rule/main.json index 14828f7139..5e1613c351 100644 --- a/avm/res/cdn/profile/ruleset/rule/main.json +++ b/avm/res/cdn/profile/ruleset/rule/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "4690708071413750601" + "version": "0.28.1.47646", + "templateHash": "13457744126513087238" }, "name": "CDN Profiles Rules", "description": "This module deploys a CDN Profile rule.", @@ -117,4 +117,4 @@ "value": "[resourceGroup().name]" } } -} +} \ No newline at end of file diff --git a/avm/res/cdn/profile/secret/main.json b/avm/res/cdn/profile/secret/main.json index dd68ba9f77..dac212a39b 100644 --- a/avm/res/cdn/profile/secret/main.json +++ b/avm/res/cdn/profile/secret/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "364931243138434002" + "version": "0.28.1.47646", + "templateHash": "11180937853362920611" }, "name": "CDN Profiles Secret", "description": "This module deploys a CDN Profile Secret.", @@ -99,4 +99,4 @@ "value": "[resourceGroup().name]" } } -} +} \ No newline at end of file diff --git a/avm/res/compute/gallery/README.md b/avm/res/compute/gallery/README.md index cf8e00455a..6393269e82 100644 --- a/avm/res/compute/gallery/README.md +++ b/avm/res/compute/gallery/README.md @@ -17,9 +17,9 @@ This module deploys an Azure Compute Gallery (formerly known as Shared Image Gal | :-- | :-- | | `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.Compute/galleries` | [2022-03-03](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2022-03-03/galleries) | +| `Microsoft.Compute/galleries` | [2023-07-03](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2023-07-03/galleries) | | `Microsoft.Compute/galleries/applications` | [2022-03-03](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2022-03-03/galleries/applications) | -| `Microsoft.Compute/galleries/images` | [2022-03-03](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2022-03-03/galleries/images) | +| `Microsoft.Compute/galleries/images` | [2023-07-03](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2023-07-03/galleries/images) | ## Usage examples @@ -116,75 +116,151 @@ module gallery 'br/public:avm/res/compute/gallery:' = { ] images: [ { + architecture: 'x64' + description: 'testDescription' + endOfLife: '2033-01-01' + eula: 'test Eula' + excludedDiskTypes: [ + 'Standard_LRS' + ] hyperVGeneration: 'V1' + identifier: { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + } name: 'az-imgd-ws-001' - offer: 'WindowsServer' + osState: 'Generalized' osType: 'Windows' - publisher: 'MicrosoftWindowsServer' - roleAssignments: [ - { - principalId: '' - principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' - } - ] - sku: '2022-datacenter-azure-edition' + privacyStatementUri: 'https://testPrivacyStatementUri.com' + purchasePlan: { + name: 'testPlanName1' + product: 'testProduct1' + publisher: 'testPublisher1' + } + releaseNoteUri: 'https://testReleaseNoteUri.com' } { hyperVGeneration: 'V2' + identifier: { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition-hibernate' + } isAcceleratedNetworkSupported: false isHibernateSupported: true - maxRecommendedMemory: 16 - maxRecommendedvCPUs: 8 - minRecommendedMemory: 4 - minRecommendedvCPUs: 2 + memory: { + max: 16 + min: 4 + } name: 'az-imgd-ws-002' - offer: 'WindowsServer' osState: 'Generalized' osType: 'Windows' - publisher: 'MicrosoftWindowsServer' - roleAssignments: [ - { - principalId: '' - principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' - } - ] - sku: '2022-datacenter-azure-edition-hibernate' + vCPUs: { + max: 8 + min: 2 + } } { hyperVGeneration: 'V2' - maxRecommendedMemory: 16 - maxRecommendedvCPUs: 4 - minRecommendedMemory: 4 - minRecommendedvCPUs: 2 - name: 'az-imgd-wdtl-001' - offer: 'WindowsDesktop' + identifier: { + offer: 'WindowsDesktop' + publisher: 'MicrosoftWindowsDesktop' + sku: 'Win11-21H2' + } + memory: { + max: 16 + min: 4 + } + name: 'az-imgd-wdtl-003' osState: 'Generalized' osType: 'Windows' - publisher: 'MicrosoftWindowsDesktop' - roleAssignments: [ - { - principalId: '' - principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' - } - ] + purchasePlan: { + name: 'testPlanName' + product: 'testProduct' + publisher: 'testPublisher' + } securityType: 'TrustedLaunch' - sku: 'Win11-21H2' + vCPUs: { + max: 8 + min: 2 + } + } + { + hyperVGeneration: 'V2' + identifier: { + offer: '0001-com-ubuntu-minimal-focal' + publisher: 'canonical' + sku: '22_04-lts-gen2' + } + isAcceleratedNetworkSupported: false + memory: { + max: 32 + min: 4 + } + name: 'az-imgd-us-004' + osState: 'Generalized' + osType: 'Linux' + vCPUs: { + max: 4 + min: 1 + } } { hyperVGeneration: 'V2' - maxRecommendedMemory: 32 - maxRecommendedvCPUs: 4 - minRecommendedMemory: 4 - minRecommendedvCPUs: 1 - name: 'az-imgd-us-001' - offer: '0001-com-ubuntu-server-focal' + identifier: { + offer: '0001-com-ubuntu-minimal-focal' + publisher: 'canonical' + sku: '20_04-lts-gen2' + } + isAcceleratedNetworkSupported: true + memory: { + max: 32 + min: 4 + } + name: 'az-imgd-us-005' osState: 'Generalized' osType: 'Linux' - publisher: 'canonical' - sku: '20_04-lts-gen2' + vCPUs: { + max: 4 + min: 1 + } + } + { + architecture: 'x64' + description: 'testDescription' + endOfLife: '2033-01-01' + eula: 'test Eula' + excludedDiskTypes: [ + 'Standard_LRS' + ] + hyperVGeneration: 'V2' + identifier: { + offer: '0001-com-ubuntu-server-focal' + publisher: 'canonical' + sku: '20_04-lts-gen2' + } + isAcceleratedNetworkSupported: false + isHibernateSupported: true + memory: { + max: 32 + min: 4 + } + name: 'az-imgd-us-006' + osState: 'Generalized' + osType: 'Linux' + privacyStatementUri: 'https://testPrivacyStatementUri.com' + purchasePlan: { + name: 'testPlanName' + product: 'testProduct' + publisher: 'testPublisher' + } + releaseNoteUri: 'https://testReleaseNoteUri.com' + securityType: 'TrustedLaunch' + vCPUs: { + max: 4 + min: 1 + } } ] location: '' @@ -257,75 +333,151 @@ module gallery 'br/public:avm/res/compute/gallery:' = { "images": { "value": [ { + "architecture": "x64", + "description": "testDescription", + "endOfLife": "2033-01-01", + "eula": "test Eula", + "excludedDiskTypes": [ + "Standard_LRS" + ], "hyperVGeneration": "V1", + "identifier": { + "offer": "WindowsServer", + "publisher": "MicrosoftWindowsServer", + "sku": "2022-datacenter-azure-edition" + }, "name": "az-imgd-ws-001", - "offer": "WindowsServer", + "osState": "Generalized", "osType": "Windows", - "publisher": "MicrosoftWindowsServer", - "roleAssignments": [ - { - "principalId": "", - "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" - } - ], - "sku": "2022-datacenter-azure-edition" + "privacyStatementUri": "https://testPrivacyStatementUri.com", + "purchasePlan": { + "name": "testPlanName1", + "product": "testProduct1", + "publisher": "testPublisher1" + }, + "releaseNoteUri": "https://testReleaseNoteUri.com" }, { "hyperVGeneration": "V2", + "identifier": { + "offer": "WindowsServer", + "publisher": "MicrosoftWindowsServer", + "sku": "2022-datacenter-azure-edition-hibernate" + }, "isAcceleratedNetworkSupported": false, "isHibernateSupported": true, - "maxRecommendedMemory": 16, - "maxRecommendedvCPUs": 8, - "minRecommendedMemory": 4, - "minRecommendedvCPUs": 2, + "memory": { + "max": 16, + "min": 4 + }, "name": "az-imgd-ws-002", - "offer": "WindowsServer", "osState": "Generalized", "osType": "Windows", - "publisher": "MicrosoftWindowsServer", - "roleAssignments": [ - { - "principalId": "", - "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" - } - ], - "sku": "2022-datacenter-azure-edition-hibernate" + "vCPUs": { + "max": 8, + "min": 2 + } }, { "hyperVGeneration": "V2", - "maxRecommendedMemory": 16, - "maxRecommendedvCPUs": 4, - "minRecommendedMemory": 4, - "minRecommendedvCPUs": 2, - "name": "az-imgd-wdtl-001", - "offer": "WindowsDesktop", + "identifier": { + "offer": "WindowsDesktop", + "publisher": "MicrosoftWindowsDesktop", + "sku": "Win11-21H2" + }, + "memory": { + "max": 16, + "min": 4 + }, + "name": "az-imgd-wdtl-003", "osState": "Generalized", "osType": "Windows", - "publisher": "MicrosoftWindowsDesktop", - "roleAssignments": [ - { - "principalId": "", - "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" - } - ], + "purchasePlan": { + "name": "testPlanName", + "product": "testProduct", + "publisher": "testPublisher" + }, "securityType": "TrustedLaunch", - "sku": "Win11-21H2" + "vCPUs": { + "max": 8, + "min": 2 + } }, { "hyperVGeneration": "V2", - "maxRecommendedMemory": 32, - "maxRecommendedvCPUs": 4, - "minRecommendedMemory": 4, - "minRecommendedvCPUs": 1, - "name": "az-imgd-us-001", - "offer": "0001-com-ubuntu-server-focal", + "identifier": { + "offer": "0001-com-ubuntu-minimal-focal", + "publisher": "canonical", + "sku": "22_04-lts-gen2" + }, + "isAcceleratedNetworkSupported": false, + "memory": { + "max": 32, + "min": 4 + }, + "name": "az-imgd-us-004", "osState": "Generalized", "osType": "Linux", - "publisher": "canonical", - "sku": "20_04-lts-gen2" + "vCPUs": { + "max": 4, + "min": 1 + } + }, + { + "hyperVGeneration": "V2", + "identifier": { + "offer": "0001-com-ubuntu-minimal-focal", + "publisher": "canonical", + "sku": "20_04-lts-gen2" + }, + "isAcceleratedNetworkSupported": true, + "memory": { + "max": 32, + "min": 4 + }, + "name": "az-imgd-us-005", + "osState": "Generalized", + "osType": "Linux", + "vCPUs": { + "max": 4, + "min": 1 + } + }, + { + "architecture": "x64", + "description": "testDescription", + "endOfLife": "2033-01-01", + "eula": "test Eula", + "excludedDiskTypes": [ + "Standard_LRS" + ], + "hyperVGeneration": "V2", + "identifier": { + "offer": "0001-com-ubuntu-server-focal", + "publisher": "canonical", + "sku": "20_04-lts-gen2" + }, + "isAcceleratedNetworkSupported": false, + "isHibernateSupported": true, + "memory": { + "max": 32, + "min": 4 + }, + "name": "az-imgd-us-006", + "osState": "Generalized", + "osType": "Linux", + "privacyStatementUri": "https://testPrivacyStatementUri.com", + "purchasePlan": { + "name": "testPlanName", + "product": "testProduct", + "publisher": "testPublisher" + }, + "releaseNoteUri": "https://testReleaseNoteUri.com", + "securityType": "TrustedLaunch", + "vCPUs": { + "max": 4, + "min": 1 + } } ] }, @@ -395,11 +547,14 @@ module gallery 'br/public:avm/res/compute/gallery:' = { ] images: [ { + identifier: { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + } name: 'az-imgd-ws-001' - offer: 'WindowsServer' + osState: 'Generalized' osType: 'Windows' - publisher: 'MicrosoftWindowsServer' - sku: '2022-datacenter-azure-edition' } ] location: '' @@ -440,11 +595,14 @@ module gallery 'br/public:avm/res/compute/gallery:' = { "images": { "value": [ { + "identifier": { + "offer": "WindowsServer", + "publisher": "MicrosoftWindowsServer", + "sku": "2022-datacenter-azure-edition" + }, "name": "az-imgd-ws-001", - "offer": "WindowsServer", - "osType": "Windows", - "publisher": "MicrosoftWindowsServer", - "sku": "2022-datacenter-azure-edition" + "osState": "Generalized", + "osType": "Windows" } ] }, @@ -525,6 +683,297 @@ Images to create. - Required: No - Type: array +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`identifier`](#parameter-imagesidentifier) | object | This is the gallery image definition identifier. | +| [`name`](#parameter-imagesname) | string | Name of the image definition. | +| [`osState`](#parameter-imagesosstate) | string | This property allows the user to specify the state of the OS of the image. | +| [`osType`](#parameter-imagesostype) | string | This property allows you to specify the type of the OS that is included in the disk when creating a VM from a managed image. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`architecture`](#parameter-imagesarchitecture) | string | The architecture of the image. Applicable to OS disks only. | +| [`description`](#parameter-imagesdescription) | string | The description of this gallery image definition resource. This property is updatable. | +| [`endOfLife`](#parameter-imagesendoflife) | string | The end of life date of the gallery image definition. This property can be used for decommissioning purposes. This property is updatable. | +| [`eula`](#parameter-imageseula) | string | The Eula agreement for the gallery image definition. | +| [`excludedDiskTypes`](#parameter-imagesexcludeddisktypes) | array | Describes the disallowed disk types. | +| [`hyperVGeneration`](#parameter-imageshypervgeneration) | string | The hypervisor generation of the Virtual Machine. If this value is not specified, then it is determined by the securityType parameter. If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1. | +| [`isAcceleratedNetworkSupported`](#parameter-imagesisacceleratednetworksupported) | bool | Specify if the image supports accelerated networking. Defaults to true. | +| [`isHibernateSupported`](#parameter-imagesishibernatesupported) | bool | Specifiy if the image supports hibernation. | +| [`memory`](#parameter-imagesmemory) | object | Describes the resource range (1-4000 GB RAM). Defaults to min=4, max=16. | +| [`privacyStatementUri`](#parameter-imagesprivacystatementuri) | string | The privacy statement uri. | +| [`purchasePlan`](#parameter-imagespurchaseplan) | object | Describes the gallery image definition purchase plan. This is used by marketplace images. | +| [`releaseNoteUri`](#parameter-imagesreleasenoteuri) | string | The release note uri. Has to be a valid URL. | +| [`securityType`](#parameter-imagessecuritytype) | string | The security type of the image. Requires a hyperVGeneration V2. Defaults to `Standard`. | +| [`vCPUs`](#parameter-imagesvcpus) | object | Describes the resource range (1-128 CPU cores). Defaults to min=1, max=4. | + +### Parameter: `images.identifier` + +This is the gallery image definition identifier. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`offer`](#parameter-imagesidentifieroffer) | string | The name of the gallery image definition offer. | +| [`publisher`](#parameter-imagesidentifierpublisher) | string | The name of the gallery image definition publisher. | +| [`sku`](#parameter-imagesidentifiersku) | string | The name of the gallery image definition SKU. | + +### Parameter: `images.identifier.offer` + +The name of the gallery image definition offer. + +- Required: Yes +- Type: string + +### Parameter: `images.identifier.publisher` + +The name of the gallery image definition publisher. + +- Required: Yes +- Type: string + +### Parameter: `images.identifier.sku` + +The name of the gallery image definition SKU. + +- Required: Yes +- Type: string + +### Parameter: `images.name` + +Name of the image definition. + +- Required: Yes +- Type: string + +### Parameter: `images.osState` + +This property allows the user to specify the state of the OS of the image. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Generalized' + 'Specialized' + ] + ``` + +### Parameter: `images.osType` + +This property allows you to specify the type of the OS that is included in the disk when creating a VM from a managed image. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Linux' + 'Windows' + ] + ``` + +### Parameter: `images.architecture` + +The architecture of the image. Applicable to OS disks only. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Arm64' + 'x64' + ] + ``` + +### Parameter: `images.description` + +The description of this gallery image definition resource. This property is updatable. + +- Required: No +- Type: string + +### Parameter: `images.endOfLife` + +The end of life date of the gallery image definition. This property can be used for decommissioning purposes. This property is updatable. + +- Required: No +- Type: string + +### Parameter: `images.eula` + +The Eula agreement for the gallery image definition. + +- Required: No +- Type: string + +### Parameter: `images.excludedDiskTypes` + +Describes the disallowed disk types. + +- Required: No +- Type: array + +### Parameter: `images.hyperVGeneration` + +The hypervisor generation of the Virtual Machine. If this value is not specified, then it is determined by the securityType parameter. If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'V1' + 'V2' + ] + ``` + +### Parameter: `images.isAcceleratedNetworkSupported` + +Specify if the image supports accelerated networking. Defaults to true. + +- Required: No +- Type: bool + +### Parameter: `images.isHibernateSupported` + +Specifiy if the image supports hibernation. + +- Required: No +- Type: bool + +### Parameter: `images.memory` + +Describes the resource range (1-4000 GB RAM). Defaults to min=4, max=16. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`max`](#parameter-imagesmemorymax) | int | The minimum number of the resource. | +| [`min`](#parameter-imagesmemorymin) | int | The minimum number of the resource. | + +### Parameter: `images.memory.max` + +The minimum number of the resource. + +- Required: No +- Type: int + +### Parameter: `images.memory.min` + +The minimum number of the resource. + +- Required: No +- Type: int + +### Parameter: `images.privacyStatementUri` + +The privacy statement uri. + +- Required: No +- Type: string + +### Parameter: `images.purchasePlan` + +Describes the gallery image definition purchase plan. This is used by marketplace images. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-imagespurchaseplanname) | string | The plan ID. | +| [`product`](#parameter-imagespurchaseplanproduct) | string | The product ID. | +| [`publisher`](#parameter-imagespurchaseplanpublisher) | string | The publisher ID. | + +### Parameter: `images.purchasePlan.name` + +The plan ID. + +- Required: Yes +- Type: string + +### Parameter: `images.purchasePlan.product` + +The product ID. + +- Required: Yes +- Type: string + +### Parameter: `images.purchasePlan.publisher` + +The publisher ID. + +- Required: Yes +- Type: string + +### Parameter: `images.releaseNoteUri` + +The release note uri. Has to be a valid URL. + +- Required: No +- Type: string + +### Parameter: `images.securityType` + +The security type of the image. Requires a hyperVGeneration V2. Defaults to `Standard`. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'ConfidentialVM' + 'ConfidentialVMSupported' + 'Standard' + 'TrustedLaunch' + ] + ``` + +### Parameter: `images.vCPUs` + +Describes the resource range (1-128 CPU cores). Defaults to min=1, max=4. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`max`](#parameter-imagesvcpusmax) | int | The minimum number of the resource. | +| [`min`](#parameter-imagesvcpusmin) | int | The minimum number of the resource. | + +### Parameter: `images.vCPUs.max` + +The minimum number of the resource. + +- Required: No +- Type: int + +### Parameter: `images.vCPUs.min` + +The minimum number of the resource. + +- Required: No +- Type: int + ### Parameter: `location` Location for all resources. @@ -678,6 +1127,13 @@ Tags for all resources. - Required: No - Type: object +- Example: + ```Bicep + { + key1: 'value1' + key2: 'value2' + } + ``` ## Outputs diff --git a/avm/res/compute/gallery/application/main.json b/avm/res/compute/gallery/application/main.json index 91e65e1bb1..0e4a0f094e 100644 --- a/avm/res/compute/gallery/application/main.json +++ b/avm/res/compute/gallery/application/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "9175012718933553578" + "version": "0.28.1.47646", + "templateHash": "1567876913625134678" }, "name": "Compute Galleries Applications", "description": "This module deploys an Azure Compute Gallery Application.", diff --git a/avm/res/compute/gallery/image/README.md b/avm/res/compute/gallery/image/README.md index 1919e986ba..b02c5674df 100644 --- a/avm/res/compute/gallery/image/README.md +++ b/avm/res/compute/gallery/image/README.md @@ -15,7 +15,7 @@ This module deploys an Azure Compute Gallery Image Definition. | Resource Type | API Version | | :-- | :-- | | `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | -| `Microsoft.Compute/galleries/images` | [2022-03-03](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2022-03-03/galleries/images) | +| `Microsoft.Compute/galleries/images` | [2023-07-03](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2023-07-03/galleries/images) | ## Parameters @@ -23,11 +23,10 @@ This module deploys an Azure Compute Gallery Image Definition. | Parameter | Type | Description | | :-- | :-- | :-- | +| [`identifier`](#parameter-identifier) | object | This is the gallery image definition identifier. | | [`name`](#parameter-name) | string | Name of the image definition. | -| [`offer`](#parameter-offer) | string | The name of the gallery Image Definition offer. | -| [`osType`](#parameter-ostype) | string | OS type of the image to be created. | -| [`publisher`](#parameter-publisher) | string | The name of the gallery Image Definition publisher. | -| [`sku`](#parameter-sku) | string | The name of the gallery Image Definition SKU. | +| [`osState`](#parameter-osstate) | string | This property allows the user to specify the state of the OS of the image. | +| [`osType`](#parameter-ostype) | string | This property allows you to specify the type of the OS that is included in the disk when creating a VM from a managed image. | **Conditional parameters** @@ -39,27 +38,59 @@ This module deploys an Azure Compute Gallery Image Definition. | Parameter | Type | Description | | :-- | :-- | :-- | -| [`description`](#parameter-description) | string | The description of this gallery Image Definition resource. This property is updatable. | -| [`endOfLife`](#parameter-endoflife) | string | The end of life date of the gallery Image Definition. This property can be used for decommissioning purposes. This property is updatable. Allowed format: 2020-01-10T23:00:00.000Z. | -| [`eula`](#parameter-eula) | string | The Eula agreement for the gallery Image Definition. Has to be a valid URL. | -| [`excludedDiskTypes`](#parameter-excludeddisktypes) | array | List of the excluded disk types (e.g., Standard_LRS). | -| [`hyperVGeneration`](#parameter-hypervgeneration) | string | The hypervisor generation of the Virtual Machine.
  • If this value is not specified, then it is determined by the securityType parameter.
  • If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1.

    | -| [`isAcceleratedNetworkSupported`](#parameter-isacceleratednetworksupported) | bool | Specify if the image supports accelerated networking.

    Accelerated networking enables single root I/O virtualization (SR-IOV) to a VM, greatly improving its networking performance.

    This high-performance path bypasses the host from the data path, which reduces latency, jitter, and CPU utilization for the most demanding network workloads on supported VM types.

    | +| [`architecture`](#parameter-architecture) | string | The architecture of the image. Applicable to OS disks only. | +| [`description`](#parameter-description) | string | The description of this gallery image definition resource. This property is updatable. | +| [`disallowed`](#parameter-disallowed) | object | Describes the disallowed disk types. | +| [`endOfLifeDate`](#parameter-endoflifedate) | string | The end of life date of the gallery image definition. This property can be used for decommissioning purposes. This property is updatable. | +| [`eula`](#parameter-eula) | string | The Eula agreement for the gallery image definition. | +| [`hyperVGeneration`](#parameter-hypervgeneration) | string | The hypervisor generation of the Virtual Machine. If this value is not specified, then it is determined by the securityType parameter. If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1. | +| [`isAcceleratedNetworkSupported`](#parameter-isacceleratednetworksupported) | bool | Specify if the image supports accelerated networking. | | [`isHibernateSupported`](#parameter-ishibernatesupported) | bool | Specifiy if the image supports hibernation. | | [`location`](#parameter-location) | string | Location for all resources. | -| [`maxRecommendedMemory`](#parameter-maxrecommendedmemory) | int | The maximum amount of RAM in GB recommended for this image. | -| [`maxRecommendedvCPUs`](#parameter-maxrecommendedvcpus) | int | The maximum number of the CPU cores recommended for this image. | -| [`minRecommendedMemory`](#parameter-minrecommendedmemory) | int | The minimum amount of RAM in GB recommended for this image. | -| [`minRecommendedvCPUs`](#parameter-minrecommendedvcpus) | int | The minimum number of the CPU cores recommended for this image. | -| [`osState`](#parameter-osstate) | string | This property allows the user to specify whether the virtual machines created under this image are 'Generalized' or 'Specialized'. | -| [`planName`](#parameter-planname) | string | The plan ID. | -| [`planPublisherName`](#parameter-planpublishername) | string | The publisher ID. | -| [`privacyStatementUri`](#parameter-privacystatementuri) | string | The privacy statement uri. Has to be a valid URL. | -| [`productName`](#parameter-productname) | string | The product ID. | +| [`memory`](#parameter-memory) | object | Describes the resource range (1-4000 GB RAM). | +| [`privacyStatementUri`](#parameter-privacystatementuri) | string | The privacy statement uri. | +| [`purchasePlan`](#parameter-purchaseplan) | object | Describes the gallery image definition purchase plan. This is used by marketplace images. | | [`releaseNoteUri`](#parameter-releasenoteuri) | string | The release note uri. Has to be a valid URL. | | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`securityType`](#parameter-securitytype) | string | The security type of the image. Requires a hyperVGeneration V2. | -| [`tags`](#parameter-tags) | object | Tags for all resources. | +| [`tags`](#parameter-tags) | object | Tags for all the image. | +| [`vCPUs`](#parameter-vcpus) | object | Describes the resource range (1-128 CPU cores). | + +### Parameter: `identifier` + +This is the gallery image definition identifier. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`offer`](#parameter-identifieroffer) | string | The name of the gallery image definition offer. | +| [`publisher`](#parameter-identifierpublisher) | string | The name of the gallery image definition publisher. | +| [`sku`](#parameter-identifiersku) | string | The name of the gallery image definition SKU. | + +### Parameter: `identifier.offer` + +The name of the gallery image definition offer. + +- Required: Yes +- Type: string + +### Parameter: `identifier.publisher` + +The name of the gallery image definition publisher. + +- Required: Yes +- Type: string + +### Parameter: `identifier.sku` + +The name of the gallery image definition SKU. + +- Required: Yes +- Type: string ### Parameter: `name` @@ -68,16 +99,23 @@ Name of the image definition. - Required: Yes - Type: string -### Parameter: `offer` +### Parameter: `osState` -The name of the gallery Image Definition offer. +This property allows the user to specify the state of the OS of the image. - Required: Yes - Type: string +- Allowed: + ```Bicep + [ + 'Generalized' + 'Specialized' + ] + ``` ### Parameter: `osType` -OS type of the image to be created. +This property allows you to specify the type of the OS that is included in the disk when creating a VM from a managed image. - Required: Yes - Type: string @@ -89,60 +127,77 @@ OS type of the image to be created. ] ``` -### Parameter: `publisher` +### Parameter: `galleryName` -The name of the gallery Image Definition publisher. +The name of the parent Azure Shared Image Gallery. Required if the template is used in a standalone deployment. - Required: Yes - Type: string -### Parameter: `sku` +### Parameter: `architecture` -The name of the gallery Image Definition SKU. +The architecture of the image. Applicable to OS disks only. -- Required: Yes +- Required: No - Type: string +- Allowed: + ```Bicep + [ + 'Arm64' + 'x64' + ] + ``` -### Parameter: `galleryName` +### Parameter: `description` -The name of the parent Azure Shared Image Gallery. Required if the template is used in a standalone deployment. +The description of this gallery image definition resource. This property is updatable. -- Required: Yes +- Required: No - Type: string -### Parameter: `description` +### Parameter: `disallowed` -The description of this gallery Image Definition resource. This property is updatable. +Describes the disallowed disk types. - Required: No -- Type: string +- Type: object + +**Required parameters** -### Parameter: `endOfLife` +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`diskTypes`](#parameter-disalloweddisktypes) | array | A list of disk types. | -The end of life date of the gallery Image Definition. This property can be used for decommissioning purposes. This property is updatable. Allowed format: 2020-01-10T23:00:00.000Z. +### Parameter: `disallowed.diskTypes` -- Required: No -- Type: string -- Default: `''` +A list of disk types. -### Parameter: `eula` +- Required: Yes +- Type: array +- Example: + ```Bicep + [ + 'Standard_LRS' + ] + ``` -The Eula agreement for the gallery Image Definition. Has to be a valid URL. +### Parameter: `endOfLifeDate` + +The end of life date of the gallery image definition. This property can be used for decommissioning purposes. This property is updatable. - Required: No - Type: string -### Parameter: `excludedDiskTypes` +### Parameter: `eula` -List of the excluded disk types (e.g., Standard_LRS). +The Eula agreement for the gallery image definition. - Required: No -- Type: array -- Default: `[]` +- Type: string ### Parameter: `hyperVGeneration` -The hypervisor generation of the Virtual Machine.

  • If this value is not specified, then it is determined by the securityType parameter.
  • If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1.

    +The hypervisor generation of the Virtual Machine. If this value is not specified, then it is determined by the securityType parameter. If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1. - Required: No - Type: string @@ -156,7 +211,7 @@ The hypervisor generation of the Virtual Machine.

  • If this value is not specif ### Parameter: `isAcceleratedNetworkSupported` -Specify if the image supports accelerated networking.

    Accelerated networking enables single root I/O virtualization (SR-IOV) to a VM, greatly improving its networking performance.

    This high-performance path bypasses the host from the data path, which reduces latency, jitter, and CPU utilization for the most demanding network workloads on supported VM types.

    +Specify if the image supports accelerated networking. - Required: No - Type: bool @@ -168,7 +223,6 @@ Specifiy if the image supports hibernation. - Required: No - Type: bool -- Default: `False` ### Parameter: `location` @@ -178,79 +232,82 @@ Location for all resources. - Type: string - Default: `[resourceGroup().location]` -### Parameter: `maxRecommendedMemory` +### Parameter: `memory` -The maximum amount of RAM in GB recommended for this image. +Describes the resource range (1-4000 GB RAM). - Required: No -- Type: int -- Default: `16` - -### Parameter: `maxRecommendedvCPUs` +- Type: object +- Default: + ```Bicep + { + max: 16 + min: 4 + } + ``` -The maximum number of the CPU cores recommended for this image. +**Optional parameters** -- Required: No -- Type: int -- Default: `4` +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`max`](#parameter-memorymax) | int | The minimum number of the resource. | +| [`min`](#parameter-memorymin) | int | The minimum number of the resource. | -### Parameter: `minRecommendedMemory` +### Parameter: `memory.max` -The minimum amount of RAM in GB recommended for this image. +The minimum number of the resource. - Required: No - Type: int -- Default: `4` -### Parameter: `minRecommendedvCPUs` +### Parameter: `memory.min` -The minimum number of the CPU cores recommended for this image. +The minimum number of the resource. - Required: No - Type: int -- Default: `1` -### Parameter: `osState` +### Parameter: `privacyStatementUri` -This property allows the user to specify whether the virtual machines created under this image are 'Generalized' or 'Specialized'. +The privacy statement uri. - Required: No - Type: string -- Default: `'Generalized'` -- Allowed: - ```Bicep - [ - 'Generalized' - 'Specialized' - ] - ``` -### Parameter: `planName` +### Parameter: `purchasePlan` -The plan ID. +Describes the gallery image definition purchase plan. This is used by marketplace images. - Required: No -- Type: string +- Type: object + +**Required parameters** -### Parameter: `planPublisherName` +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-purchaseplanname) | string | The plan ID. | +| [`product`](#parameter-purchaseplanproduct) | string | The product ID. | +| [`publisher`](#parameter-purchaseplanpublisher) | string | The publisher ID. | -The publisher ID. +### Parameter: `purchasePlan.name` -- Required: No +The plan ID. + +- Required: Yes - Type: string -### Parameter: `privacyStatementUri` +### Parameter: `purchasePlan.product` -The privacy statement uri. Has to be a valid URL. +The product ID. -- Required: No +- Required: Yes - Type: string -### Parameter: `productName` +### Parameter: `purchasePlan.publisher` -The product ID. +The publisher ID. -- Required: No +- Required: Yes - Type: string ### Parameter: `releaseNoteUri` @@ -355,7 +412,6 @@ The security type of the image. Requires a hyperVGeneration V2. - Required: No - Type: string -- Default: `'Standard'` - Allowed: ```Bicep [ @@ -368,10 +424,52 @@ The security type of the image. Requires a hyperVGeneration V2. ### Parameter: `tags` -Tags for all resources. +Tags for all the image. - Required: No - Type: object +- Example: + ```Bicep + { + key1: 'value1' + key2: 'value2' + } + ``` + +### Parameter: `vCPUs` + +Describes the resource range (1-128 CPU cores). + +- Required: No +- Type: object +- Default: + ```Bicep + { + max: 4 + min: 1 + } + ``` + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`max`](#parameter-vcpusmax) | int | The minimum number of the resource. | +| [`min`](#parameter-vcpusmin) | int | The minimum number of the resource. | + +### Parameter: `vCPUs.max` + +The minimum number of the resource. + +- Required: No +- Type: int + +### Parameter: `vCPUs.min` + +The minimum number of the resource. + +- Required: No +- Type: int ## Outputs diff --git a/avm/res/compute/gallery/image/main.bicep b/avm/res/compute/gallery/image/main.bicep index 976535121b..b622a892ad 100644 --- a/avm/res/compute/gallery/image/main.bicep +++ b/avm/res/compute/gallery/image/main.bicep @@ -3,6 +3,8 @@ metadata description = 'This module deploys an Azure Compute Gallery Image Defin metadata owner = 'Azure/module-maintainers' @sys.description('Required. Name of the image definition.') +@minLength(1) +@maxLength(80) param name string @sys.description('Optional. Location for all resources.') @@ -12,108 +14,69 @@ param location string = resourceGroup().location @minLength(1) param galleryName string -@sys.description('Required. OS type of the image to be created.') -@allowed([ - 'Windows' - 'Linux' -]) -param osType string - -@sys.description('Optional. This property allows the user to specify whether the virtual machines created under this image are \'Generalized\' or \'Specialized\'.') -@allowed([ - 'Generalized' - 'Specialized' -]) -param osState string = 'Generalized' - -@sys.description('Required. The name of the gallery Image Definition publisher.') -param publisher string - -@sys.description('Required. The name of the gallery Image Definition offer.') -param offer string - -@sys.description('Required. The name of the gallery Image Definition SKU.') -param sku string - -@sys.description('Optional. The minimum number of the CPU cores recommended for this image.') -@minValue(1) -@maxValue(128) -param minRecommendedvCPUs int = 1 - -@sys.description('Optional. The maximum number of the CPU cores recommended for this image.') -@minValue(1) -@maxValue(128) -param maxRecommendedvCPUs int = 4 - -@sys.description('Optional. The minimum amount of RAM in GB recommended for this image.') -@minValue(1) -@maxValue(4000) -param minRecommendedMemory int = 4 - -@sys.description('Optional. The maximum amount of RAM in GB recommended for this image.') -@minValue(1) -@maxValue(4000) -param maxRecommendedMemory int = 16 - -@sys.description('''Optional. The hypervisor generation of the Virtual Machine. -- If this value is not specified, then it is determined by the securityType parameter. -- If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1. -''') -@allowed([ - 'V1' - 'V2' -]) -param hyperVGeneration string? +@sys.description('Required. This is the gallery image definition identifier.') +param identifier identifierType -@sys.description('Optional. The security type of the image. Requires a hyperVGeneration V2.') -@allowed([ - 'Standard' - 'TrustedLaunch' - 'ConfidentialVM' - 'ConfidentialVMSupported' -]) -param securityType string = 'Standard' +@sys.description('Required. This property allows the user to specify the state of the OS of the image.') +param osState ('Generalized' | 'Specialized') -@sys.description('Optional. Specifiy if the image supports hibernation.') -param isHibernateSupported bool = false +@sys.description('Required. This property allows you to specify the type of the OS that is included in the disk when creating a VM from a managed image.') +param osType ('Linux' | 'Windows') -@sys.description('''Optional. Specify if the image supports accelerated networking. -Accelerated networking enables single root I/O virtualization (SR-IOV) to a VM, greatly improving its networking performance. -This high-performance path bypasses the host from the data path, which reduces latency, jitter, and CPU utilization for the most demanding network workloads on supported VM types. -''') -param isAcceleratedNetworkSupported bool = true +@sys.description('Optional. The privacy statement uri.') +param privacyStatementUri string? -@sys.description('Optional. The description of this gallery Image Definition resource. This property is updatable.') -param description string? +@sys.description('Optional. Describes the gallery image definition purchase plan. This is used by marketplace images.') +param purchasePlan purchasePlanType? -@sys.description('Optional. The Eula agreement for the gallery Image Definition. Has to be a valid URL.') -param eula string? +@sys.description('Optional. Describes the resource range (1-128 CPU cores).') +param vCPUs resourceRangeType = { min: 1, max: 4 } -@sys.description('Optional. The privacy statement uri. Has to be a valid URL.') -param privacyStatementUri string? +@sys.description('Optional. Describes the resource range (1-4000 GB RAM).') +param memory resourceRangeType = { min: 4, max: 16 } @sys.description('Optional. The release note uri. Has to be a valid URL.') param releaseNoteUri string? -@sys.description('Optional. The product ID.') -param productName string? +@sys.description('Optional. The security type of the image. Requires a hyperVGeneration V2.') +param securityType ('Standard' | 'TrustedLaunch' | 'ConfidentialVM' | 'ConfidentialVMSupported')? + +@sys.description('Optional. Specify if the image supports accelerated networking.') +param isAcceleratedNetworkSupported bool = true + +@sys.description('Optional. Specifiy if the image supports hibernation.') +param isHibernateSupported bool? + +@sys.description('Optional. The architecture of the image. Applicable to OS disks only.') +param architecture ('x64' | 'Arm64')? + +@sys.description('Optional. The description of this gallery image definition resource. This property is updatable.') +param description string? -@sys.description('Optional. The plan ID.') -param planName string? +@sys.description('Optional. Describes the disallowed disk types.') +param disallowed disallowedType? -@sys.description('Optional. The publisher ID.') -param planPublisherName string? +@sys.description('Optional. The end of life date of the gallery image definition. This property can be used for decommissioning purposes. This property is updatable.') +param endOfLifeDate string? -@sys.description('Optional. The end of life date of the gallery Image Definition. This property can be used for decommissioning purposes. This property is updatable. Allowed format: 2020-01-10T23:00:00.000Z.') -param endOfLife string = '' +@sys.description('Optional. The Eula agreement for the gallery image definition.') +param eula string? -@sys.description('Optional. List of the excluded disk types (e.g., Standard_LRS).') -param excludedDiskTypes array = [] +@sys.description('Optional. The hypervisor generation of the Virtual Machine. If this value is not specified, then it is determined by the securityType parameter. If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1.') +param hyperVGeneration ('V1' | 'V2')? @sys.description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType -@sys.description('Optional. Tags for all resources.') +@sys.description('Optional. Tags for all the image.') +@metadata({ + example: ''' +{ + key1: 'value1' + key2: 'value2' +} +''' +}) param tags object? var builtInRoleNames = { @@ -134,67 +97,59 @@ var builtInRoleNames = { ) } -resource gallery 'Microsoft.Compute/galleries@2022-03-03' existing = { +resource gallery 'Microsoft.Compute/galleries@2023-07-03' existing = { name: galleryName } -resource image 'Microsoft.Compute/galleries/images@2022-03-03' = { +resource image 'Microsoft.Compute/galleries/images@2023-07-03' = { name: name parent: gallery location: location tags: tags properties: { - osType: osType - osState: osState - identifier: { - publisher: publisher - offer: offer - sku: sku - } - recommended: { - vCPUs: { - min: minRecommendedvCPUs - max: maxRecommendedvCPUs - } - memory: { - min: minRecommendedMemory - max: maxRecommendedMemory - } + architecture: architecture + description: description + disallowed: { + diskTypes: disallowed.?diskTypes ?? [] } - hyperVGeneration: hyperVGeneration ?? (!empty(securityType) ? 'V2' : 'V1') + endOfLifeDate: endOfLifeDate + eula: eula features: union( [ { name: 'IsAcceleratedNetworkSupported' value: '${isAcceleratedNetworkSupported}' } - { - name: 'IsHibernateSupported' - value: '${isHibernateSupported}' - } ], - (securityType != 'Standard' + (securityType != null ? [ { name: 'SecurityType' - value: securityType + value: '${securityType}' + } + ] + : []), + (isHibernateSupported != null + ? [ + { + name: 'IsHibernateSupported' + value: '${isHibernateSupported}' } ] : []) ) - description: description - eula: eula + hyperVGeneration: hyperVGeneration ?? (!empty(securityType ?? '') ? 'V2' : 'V1') + identifier: { + publisher: identifier.publisher + offer: identifier.offer + sku: identifier.sku + } + osState: osState + osType: osType privacyStatementUri: privacyStatementUri + purchasePlan: purchasePlan ?? null + recommended: { vCPUs: vCPUs, memory: memory } releaseNoteUri: releaseNoteUri - purchasePlan: { - product: productName - name: planName - publisher: planPublisherName - } - endOfLifeDate: endOfLife - disallowed: { - diskTypes: excludedDiskTypes - } } } @@ -256,3 +211,46 @@ type roleAssignmentType = { @sys.description('Optional. The Resource Id of the delegated managed identity resource.') delegatedManagedIdentityResourceId: string? }[]? + +@export() +type resourceRangeType = { + @sys.description('Optional. The minimum number of the resource.') + @minValue(1) + min: int? + + @sys.description('Optional. The minimum number of the resource.') + max: int? +} + +type disallowedType = { + @sys.description('Required. A list of disk types.') + @metadata({ example: ''' + [ + 'Standard_LRS' + ]''' }) + diskTypes: string[] +}? + +@export() +type identifierType = { + @sys.description('Required. The name of the gallery image definition publisher.') + publisher: string + + @sys.description('Required. The name of the gallery image definition offer.') + offer: string + + @sys.description('Required. The name of the gallery image definition SKU.') + sku: string +} + +@export() +type purchasePlanType = { + @sys.description('Required. The plan ID.') + name: string + + @sys.description('Required. The product ID.') + product: string + + @sys.description('Required. The publisher ID.') + publisher: string +}? diff --git a/avm/res/compute/gallery/image/main.json b/avm/res/compute/gallery/image/main.json index 11f350a32c..ee490554ab 100644 --- a/avm/res/compute/gallery/image/main.json +++ b/avm/res/compute/gallery/image/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "7059991596058545894" + "version": "0.28.1.47646", + "templateHash": "751325967553230167" }, "name": "Compute Galleries Image Definitions", "description": "This module deploys an Azure Compute Gallery Image Definition.", @@ -78,11 +78,105 @@ } }, "nullable": true + }, + "resourceRangeType": { + "type": "object", + "properties": { + "min": { + "type": "int", + "nullable": true, + "minValue": 1, + "metadata": { + "description": "Optional. The minimum number of the resource." + } + }, + "max": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The minimum number of the resource." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "disallowedType": { + "type": "object", + "properties": { + "diskTypes": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "example": " [\n 'Standard_LRS'\n ]", + "description": "Required. A list of disk types." + } + } + }, + "nullable": true + }, + "identifierType": { + "type": "object", + "properties": { + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the gallery image definition publisher." + } + }, + "offer": { + "type": "string", + "metadata": { + "description": "Required. The name of the gallery image definition offer." + } + }, + "sku": { + "type": "string", + "metadata": { + "description": "Required. The name of the gallery image definition SKU." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "purchasePlanType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The plan ID." + } + }, + "product": { + "type": "string", + "metadata": { + "description": "Required. The product ID." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The publisher ID." + } + } + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } } }, "parameters": { "name": { "type": "string", + "minLength": 1, + "maxLength": 80, "metadata": { "description": "Required. Name of the image definition." } @@ -101,180 +195,148 @@ "description": "Conditional. The name of the parent Azure Shared Image Gallery. Required if the template is used in a standalone deployment." } }, - "osType": { - "type": "string", - "allowedValues": [ - "Windows", - "Linux" - ], + "identifier": { + "$ref": "#/definitions/identifierType", "metadata": { - "description": "Required. OS type of the image to be created." + "description": "Required. This is the gallery image definition identifier." } }, "osState": { "type": "string", - "defaultValue": "Generalized", "allowedValues": [ "Generalized", "Specialized" ], "metadata": { - "description": "Optional. This property allows the user to specify whether the virtual machines created under this image are 'Generalized' or 'Specialized'." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the gallery Image Definition publisher." + "description": "Required. This property allows the user to specify the state of the OS of the image." } }, - "offer": { + "osType": { "type": "string", + "allowedValues": [ + "Linux", + "Windows" + ], "metadata": { - "description": "Required. The name of the gallery Image Definition offer." + "description": "Required. This property allows you to specify the type of the OS that is included in the disk when creating a VM from a managed image." } }, - "sku": { + "privacyStatementUri": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The name of the gallery Image Definition SKU." - } - }, - "minRecommendedvCPUs": { - "type": "int", - "defaultValue": 1, - "minValue": 1, - "maxValue": 128, - "metadata": { - "description": "Optional. The minimum number of the CPU cores recommended for this image." + "description": "Optional. The privacy statement uri." } }, - "maxRecommendedvCPUs": { - "type": "int", - "defaultValue": 4, - "minValue": 1, - "maxValue": 128, + "purchasePlan": { + "$ref": "#/definitions/purchasePlanType", + "nullable": true, "metadata": { - "description": "Optional. The maximum number of the CPU cores recommended for this image." + "description": "Optional. Describes the gallery image definition purchase plan. This is used by marketplace images." } }, - "minRecommendedMemory": { - "type": "int", - "defaultValue": 4, - "minValue": 1, - "maxValue": 4000, + "vCPUs": { + "$ref": "#/definitions/resourceRangeType", + "defaultValue": { + "min": 1, + "max": 4 + }, "metadata": { - "description": "Optional. The minimum amount of RAM in GB recommended for this image." + "description": "Optional. Describes the resource range (1-128 CPU cores)." } }, - "maxRecommendedMemory": { - "type": "int", - "defaultValue": 16, - "minValue": 1, - "maxValue": 4000, + "memory": { + "$ref": "#/definitions/resourceRangeType", + "defaultValue": { + "min": 4, + "max": 16 + }, "metadata": { - "description": "Optional. The maximum amount of RAM in GB recommended for this image." + "description": "Optional. Describes the resource range (1-4000 GB RAM)." } }, - "hyperVGeneration": { + "releaseNoteUri": { "type": "string", "nullable": true, - "allowedValues": [ - "V1", - "V2" - ], "metadata": { - "description": "Optional. The hypervisor generation of the Virtual Machine.\n- If this value is not specified, then it is determined by the securityType parameter.\n- If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1.\n" + "description": "Optional. The release note uri. Has to be a valid URL." } }, "securityType": { "type": "string", - "defaultValue": "Standard", "allowedValues": [ - "Standard", - "TrustedLaunch", "ConfidentialVM", - "ConfidentialVMSupported" + "ConfidentialVMSupported", + "Standard", + "TrustedLaunch" ], + "nullable": true, "metadata": { "description": "Optional. The security type of the image. Requires a hyperVGeneration V2." } }, - "isHibernateSupported": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifiy if the image supports hibernation." - } - }, "isAcceleratedNetworkSupported": { "type": "bool", "defaultValue": true, "metadata": { - "description": "Optional. Specify if the image supports accelerated networking.\nAccelerated networking enables single root I/O virtualization (SR-IOV) to a VM, greatly improving its networking performance.\nThis high-performance path bypasses the host from the data path, which reduces latency, jitter, and CPU utilization for the most demanding network workloads on supported VM types.\n" + "description": "Optional. Specify if the image supports accelerated networking." } }, - "description": { - "type": "string", + "isHibernateSupported": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The description of this gallery Image Definition resource. This property is updatable." + "description": "Optional. Specifiy if the image supports hibernation." } }, - "eula": { + "architecture": { "type": "string", + "allowedValues": [ + "Arm64", + "x64" + ], "nullable": true, "metadata": { - "description": "Optional. The Eula agreement for the gallery Image Definition. Has to be a valid URL." + "description": "Optional. The architecture of the image. Applicable to OS disks only." } }, - "privacyStatementUri": { + "description": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The privacy statement uri. Has to be a valid URL." + "description": "Optional. The description of this gallery image definition resource. This property is updatable." } }, - "releaseNoteUri": { - "type": "string", + "disallowed": { + "$ref": "#/definitions/disallowedType", "nullable": true, "metadata": { - "description": "Optional. The release note uri. Has to be a valid URL." + "description": "Optional. Describes the disallowed disk types." } }, - "productName": { + "endOfLifeDate": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The product ID." + "description": "Optional. The end of life date of the gallery image definition. This property can be used for decommissioning purposes. This property is updatable." } }, - "planName": { + "eula": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The plan ID." + "description": "Optional. The Eula agreement for the gallery image definition." } }, - "planPublisherName": { + "hyperVGeneration": { "type": "string", + "allowedValues": [ + "V1", + "V2" + ], "nullable": true, "metadata": { - "description": "Optional. The publisher ID." - } - }, - "endOfLife": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The end of life date of the gallery Image Definition. This property can be used for decommissioning purposes. This property is updatable. Allowed format: 2020-01-10T23:00:00.000Z." - } - }, - "excludedDiskTypes": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. List of the excluded disk types (e.g., Standard_LRS)." + "description": "Optional. The hypervisor generation of the Virtual Machine. If this value is not specified, then it is determined by the securityType parameter. If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1." } }, "roleAssignments": { @@ -287,7 +349,8 @@ "type": "object", "nullable": true, "metadata": { - "description": "Optional. Tags for all resources." + "example": "{\n key1: 'value1'\n key2: 'value2'\n}\n", + "description": "Optional. Tags for all the image." } } }, @@ -305,48 +368,39 @@ "gallery": { "existing": true, "type": "Microsoft.Compute/galleries", - "apiVersion": "2022-03-03", + "apiVersion": "2023-07-03", "name": "[parameters('galleryName')]" }, "image": { "type": "Microsoft.Compute/galleries/images", - "apiVersion": "2022-03-03", + "apiVersion": "2023-07-03", "name": "[format('{0}/{1}', parameters('galleryName'), parameters('name'))]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", "properties": { - "osType": "[parameters('osType')]", - "osState": "[parameters('osState')]", - "identifier": { - "publisher": "[parameters('publisher')]", - "offer": "[parameters('offer')]", - "sku": "[parameters('sku')]" - }, - "recommended": { - "vCPUs": { - "min": "[parameters('minRecommendedvCPUs')]", - "max": "[parameters('maxRecommendedvCPUs')]" - }, - "memory": { - "min": "[parameters('minRecommendedMemory')]", - "max": "[parameters('maxRecommendedMemory')]" - } - }, - "hyperVGeneration": "[coalesce(parameters('hyperVGeneration'), if(not(empty(parameters('securityType'))), 'V2', 'V1'))]", - "features": "[union(createArray(createObject('name', 'IsAcceleratedNetworkSupported', 'value', format('{0}', parameters('isAcceleratedNetworkSupported'))), createObject('name', 'IsHibernateSupported', 'value', format('{0}', parameters('isHibernateSupported')))), if(not(equals(parameters('securityType'), 'Standard')), createArray(createObject('name', 'SecurityType', 'value', parameters('securityType'))), createArray()))]", + "architecture": "[parameters('architecture')]", "description": "[parameters('description')]", + "disallowed": { + "diskTypes": "[coalesce(tryGet(parameters('disallowed'), 'diskTypes'), createArray())]" + }, + "endOfLifeDate": "[parameters('endOfLifeDate')]", "eula": "[parameters('eula')]", + "features": "[union(createArray(createObject('name', 'IsAcceleratedNetworkSupported', 'value', format('{0}', parameters('isAcceleratedNetworkSupported')))), if(not(equals(parameters('securityType'), null())), createArray(createObject('name', 'SecurityType', 'value', format('{0}', parameters('securityType')))), createArray()), if(not(equals(parameters('isHibernateSupported'), null())), createArray(createObject('name', 'IsHibernateSupported', 'value', format('{0}', parameters('isHibernateSupported')))), createArray()))]", + "hyperVGeneration": "[coalesce(parameters('hyperVGeneration'), if(not(empty(coalesce(parameters('securityType'), ''))), 'V2', 'V1'))]", + "identifier": { + "publisher": "[parameters('identifier').publisher]", + "offer": "[parameters('identifier').offer]", + "sku": "[parameters('identifier').sku]" + }, + "osState": "[parameters('osState')]", + "osType": "[parameters('osType')]", "privacyStatementUri": "[parameters('privacyStatementUri')]", - "releaseNoteUri": "[parameters('releaseNoteUri')]", - "purchasePlan": { - "product": "[parameters('productName')]", - "name": "[parameters('planName')]", - "publisher": "[parameters('planPublisherName')]" + "purchasePlan": "[coalesce(parameters('purchasePlan'), null())]", + "recommended": { + "vCPUs": "[parameters('vCPUs')]", + "memory": "[parameters('memory')]" }, - "endOfLifeDate": "[parameters('endOfLife')]", - "disallowed": { - "diskTypes": "[parameters('excludedDiskTypes')]" - } + "releaseNoteUri": "[parameters('releaseNoteUri')]" }, "dependsOn": [ "gallery" @@ -402,7 +456,7 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('image', '2022-03-03', 'full').location]" + "value": "[reference('image', '2023-07-03', 'full').location]" } } } \ No newline at end of file diff --git a/avm/res/compute/gallery/main.bicep b/avm/res/compute/gallery/main.bicep index a715aad8d0..13acf14e95 100644 --- a/avm/res/compute/gallery/main.bicep +++ b/avm/res/compute/gallery/main.bicep @@ -2,6 +2,10 @@ metadata name = 'Azure Compute Galleries' metadata description = 'This module deploys an Azure Compute Gallery (formerly known as Shared Image Gallery).' metadata owner = 'Azure/module-maintainers' +// ============ // +// Parameters // +// ============ // + @minLength(1) @sys.description('Required. Name of the Azure Compute Gallery.') param name string @@ -9,6 +13,9 @@ param name string @sys.description('Optional. Location for all resources.') param location string = resourceGroup().location +@sys.description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + @sys.description('Optional. Description of the Azure Shared Image Gallery.') param description string? @@ -16,20 +23,25 @@ param description string? param applications array? @sys.description('Optional. Images to create.') -param images array? +param images imageType[]? // use a UDT here to not overload the main module, as it has images and applications parameters @sys.description('Optional. The lock settings of the service.') -param lock lockType +param lock lockType? @sys.description('Optional. Array of role assignments to create.') -param roleAssignments roleAssignmentType +param roleAssignments roleAssignmentType? @sys.description('Optional. Tags for all resources.') +@metadata({ + example: ''' + { + key1: 'value1' + key2: 'value2' + } + ''' +}) param tags object? -@sys.description('Optional. Enable/Disable usage telemetry for module.') -param enableTelemetry bool = true - @sys.description('Optional. Profile for gallery sharing to subscription or tenant.') param sharingProfile object? @@ -54,6 +66,10 @@ var builtInRoleNames = { ) } +// ============== // +// Resources // +// ============== // + #disable-next-line no-deployments-resources resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { name: '46d3xbcp.res.compute-gallery.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' @@ -73,7 +89,7 @@ resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableT } } -resource gallery 'Microsoft.Compute/galleries@2022-03-03' = { +resource gallery 'Microsoft.Compute/galleries@2023-07-03' = { name: name location: location tags: tags @@ -140,36 +156,36 @@ module galleries_images 'image/main.bicep' = [ for (image, index) in (images ?? []): { name: '${uniqueString(deployment().name, location)}-Gallery-Image-${index}' params: { - location: location name: image.name + location: image.?location ?? location galleryName: gallery.name + description: image.?description osType: image.osType - osState: image.?osState - publisher: image.publisher - offer: image.offer - sku: image.sku - minRecommendedvCPUs: image.?minRecommendedvCPUs - maxRecommendedvCPUs: image.?maxRecommendedvCPUs - minRecommendedMemory: image.?minRecommendedMemory - maxRecommendedMemory: image.?maxRecommendedMemory + osState: image.osState + identifier: image.identifier + vCPUs: image.?vCPUs + memory: image.?memory hyperVGeneration: image.?hyperVGeneration securityType: image.?securityType isAcceleratedNetworkSupported: image.?isAcceleratedNetworkSupported - description: image.?description + isHibernateSupported: image.?isHibernateSupported + architecture: image.?architecture eula: image.?eula privacyStatementUri: image.?privacyStatementUri releaseNoteUri: image.?releaseNoteUri - productName: image.?productName - planName: image.?planName - planPublisherName: image.?planPublisherName - endOfLife: image.?endOfLife - excludedDiskTypes: image.?excludedDiskTypes + purchasePlan: image.?purchasePlan + endOfLifeDate: image.?endOfLife + disallowed: { diskTypes: image.?excludedDiskTypes ?? [] } roleAssignments: image.?roleAssignments tags: image.?tags ?? tags } } ] +// ============ // +// Outputs // +// ============ // + @sys.description('The resource ID of the deployed image gallery.') output resourceId string = gallery.id @@ -197,7 +213,7 @@ type lockType = { @sys.description('Optional. Specify the type of lock.') kind: ('CanNotDelete' | 'ReadOnly' | 'None')? -}? +} type roleAssignmentType = { @sys.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\'.') @@ -220,4 +236,63 @@ type roleAssignmentType = { @sys.description('Optional. The Resource Id of the delegated managed identity resource.') delegatedManagedIdentityResourceId: string? -}[]? +}[] + +import { identifierType, purchasePlanType, resourceRangeType } from './image/main.bicep' +type imageType = { + @sys.description('Required. Name of the image definition.') + @minLength(1) + @maxLength(80) + name: string + + @sys.description('Optional. The description of this gallery image definition resource. This property is updatable.') + description: string? + + @sys.description('Required. This property allows you to specify the type of the OS that is included in the disk when creating a VM from a managed image.') + osType: ('Linux' | 'Windows') + + @sys.description('Required. This property allows the user to specify the state of the OS of the image.') + osState: ('Generalized' | 'Specialized') + + @sys.description('Required. This is the gallery image definition identifier.') + identifier: identifierType + + @sys.description('Optional. Describes the resource range (1-128 CPU cores). Defaults to min=1, max=4.') + vCPUs: resourceRangeType? + + @sys.description('Optional. Describes the resource range (1-4000 GB RAM). Defaults to min=4, max=16.') + memory: resourceRangeType? + + @sys.description('Optional. The hypervisor generation of the Virtual Machine. If this value is not specified, then it is determined by the securityType parameter. If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1.') + hyperVGeneration: ('V1' | 'V2')? + + @sys.description('Optional. The security type of the image. Requires a hyperVGeneration V2. Defaults to `Standard`.') + securityType: ('Standard' | 'TrustedLaunch' | 'ConfidentialVM' | 'ConfidentialVMSupported')? + + @sys.description('Optional. Specify if the image supports accelerated networking. Defaults to true.') + isAcceleratedNetworkSupported: bool? + + @sys.description('Optional. Specifiy if the image supports hibernation.') + isHibernateSupported: bool? + + @sys.description('Optional. The architecture of the image. Applicable to OS disks only.') + architecture: ('x64' | 'Arm64')? + + @sys.description('Optional. The Eula agreement for the gallery image definition.') + eula: string? + + @sys.description('Optional. The privacy statement uri.') + privacyStatementUri: string? + + @sys.description('Optional. The release note uri. Has to be a valid URL.') + releaseNoteUri: string? + + @sys.description('Optional. Describes the gallery image definition purchase plan. This is used by marketplace images.') + purchasePlan: purchasePlanType? + + @sys.description('Optional. The end of life date of the gallery image definition. This property can be used for decommissioning purposes. This property is updatable.') + endOfLife: string? + + @sys.description('Optional. Describes the disallowed disk types.') + excludedDiskTypes: string[]? +} diff --git a/avm/res/compute/gallery/main.json b/avm/res/compute/gallery/main.json index 6b5790c1ed..e806011f6a 100644 --- a/avm/res/compute/gallery/main.json +++ b/avm/res/compute/gallery/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.28.1.47646", - "templateHash": "11213845722898410674" + "templateHash": "10621558710592844448" }, "name": "Azure Compute Galleries", "description": "This module deploys an Azure Compute Gallery (formerly known as Shared Image Gallery).", @@ -35,8 +35,7 @@ "description": "Optional. Specify the type of lock." } } - }, - "nullable": true + } }, "roleAssignmentType": { "type": "array", @@ -101,8 +100,243 @@ } } } + } + }, + "imageType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 80, + "metadata": { + "description": "Required. Name of the image definition." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of this gallery image definition resource. This property is updatable." + } + }, + "osType": { + "type": "string", + "allowedValues": [ + "Linux", + "Windows" + ], + "metadata": { + "description": "Required. This property allows you to specify the type of the OS that is included in the disk when creating a VM from a managed image." + } + }, + "osState": { + "type": "string", + "allowedValues": [ + "Generalized", + "Specialized" + ], + "metadata": { + "description": "Required. This property allows the user to specify the state of the OS of the image." + } + }, + "identifier": { + "$ref": "#/definitions/identifierType", + "metadata": { + "description": "Required. This is the gallery image definition identifier." + } + }, + "vCPUs": { + "$ref": "#/definitions/resourceRangeType", + "nullable": true, + "metadata": { + "description": "Optional. Describes the resource range (1-128 CPU cores). Defaults to min=1, max=4." + } + }, + "memory": { + "$ref": "#/definitions/resourceRangeType", + "nullable": true, + "metadata": { + "description": "Optional. Describes the resource range (1-4000 GB RAM). Defaults to min=4, max=16." + } + }, + "hyperVGeneration": { + "type": "string", + "allowedValues": [ + "V1", + "V2" + ], + "nullable": true, + "metadata": { + "description": "Optional. The hypervisor generation of the Virtual Machine. If this value is not specified, then it is determined by the securityType parameter. If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1." + } + }, + "securityType": { + "type": "string", + "allowedValues": [ + "ConfidentialVM", + "ConfidentialVMSupported", + "Standard", + "TrustedLaunch" + ], + "nullable": true, + "metadata": { + "description": "Optional. The security type of the image. Requires a hyperVGeneration V2. Defaults to `Standard`." + } + }, + "isAcceleratedNetworkSupported": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Specify if the image supports accelerated networking. Defaults to true." + } + }, + "isHibernateSupported": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Specifiy if the image supports hibernation." + } + }, + "architecture": { + "type": "string", + "allowedValues": [ + "Arm64", + "x64" + ], + "nullable": true, + "metadata": { + "description": "Optional. The architecture of the image. Applicable to OS disks only." + } + }, + "eula": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Eula agreement for the gallery image definition." + } + }, + "privacyStatementUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The privacy statement uri." + } + }, + "releaseNoteUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The release note uri. Has to be a valid URL." + } + }, + "purchasePlan": { + "$ref": "#/definitions/purchasePlanType", + "nullable": true, + "metadata": { + "description": "Optional. Describes the gallery image definition purchase plan. This is used by marketplace images." + } + }, + "endOfLife": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The end of life date of the gallery image definition. This property can be used for decommissioning purposes. This property is updatable." + } + }, + "excludedDiskTypes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Describes the disallowed disk types." + } + } + } + }, + "identifierType": { + "type": "object", + "properties": { + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the gallery image definition publisher." + } + }, + "offer": { + "type": "string", + "metadata": { + "description": "Required. The name of the gallery image definition offer." + } + }, + "sku": { + "type": "string", + "metadata": { + "description": "Required. The name of the gallery image definition SKU." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "image/main.bicep" + } + } + }, + "purchasePlanType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The plan ID." + } + }, + "product": { + "type": "string", + "metadata": { + "description": "Required. The product ID." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The publisher ID." + } + } + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "image/main.bicep" + } + } + }, + "resourceRangeType": { + "type": "object", + "properties": { + "min": { + "type": "int", + "nullable": true, + "minValue": 1, + "metadata": { + "description": "Optional. The minimum number of the resource." + } + }, + "max": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The minimum number of the resource." + } + } }, - "nullable": true + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "image/main.bicep" + } + } } }, "parameters": { @@ -120,6 +354,13 @@ "description": "Optional. Location for all resources." } }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, "description": { "type": "string", "nullable": true, @@ -136,6 +377,9 @@ }, "images": { "type": "array", + "items": { + "$ref": "#/definitions/imageType" + }, "nullable": true, "metadata": { "description": "Optional. Images to create." @@ -143,12 +387,14 @@ }, "lock": { "$ref": "#/definitions/lockType", + "nullable": true, "metadata": { "description": "Optional. The lock settings of the service." } }, "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", + "nullable": true, "metadata": { "description": "Optional. Array of role assignments to create." } @@ -157,16 +403,10 @@ "type": "object", "nullable": true, "metadata": { + "example": " {\n key1: 'value1'\n key2: 'value2'\n }\n ", "description": "Optional. Tags for all resources." } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, "sharingProfile": { "type": "object", "nullable": true, @@ -215,7 +455,7 @@ }, "gallery": { "type": "Microsoft.Compute/galleries", - "apiVersion": "2022-03-03", + "apiVersion": "2023-07-03", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", @@ -590,41 +830,32 @@ }, "mode": "Incremental", "parameters": { - "location": { - "value": "[parameters('location')]" - }, "name": { "value": "[coalesce(parameters('images'), createArray())[copyIndex()].name]" }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'location'), parameters('location'))]" + }, "galleryName": { "value": "[parameters('name')]" }, + "description": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'description')]" + }, "osType": { "value": "[coalesce(parameters('images'), createArray())[copyIndex()].osType]" }, "osState": { - "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'osState')]" - }, - "publisher": { - "value": "[coalesce(parameters('images'), createArray())[copyIndex()].publisher]" - }, - "offer": { - "value": "[coalesce(parameters('images'), createArray())[copyIndex()].offer]" - }, - "sku": { - "value": "[coalesce(parameters('images'), createArray())[copyIndex()].sku]" - }, - "minRecommendedvCPUs": { - "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'minRecommendedvCPUs')]" + "value": "[coalesce(parameters('images'), createArray())[copyIndex()].osState]" }, - "maxRecommendedvCPUs": { - "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'maxRecommendedvCPUs')]" + "identifier": { + "value": "[coalesce(parameters('images'), createArray())[copyIndex()].identifier]" }, - "minRecommendedMemory": { - "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'minRecommendedMemory')]" + "vCPUs": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'vCPUs')]" }, - "maxRecommendedMemory": { - "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'maxRecommendedMemory')]" + "memory": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'memory')]" }, "hyperVGeneration": { "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'hyperVGeneration')]" @@ -635,8 +866,11 @@ "isAcceleratedNetworkSupported": { "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'isAcceleratedNetworkSupported')]" }, - "description": { - "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'description')]" + "isHibernateSupported": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'isHibernateSupported')]" + }, + "architecture": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'architecture')]" }, "eula": { "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'eula')]" @@ -647,20 +881,16 @@ "releaseNoteUri": { "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'releaseNoteUri')]" }, - "productName": { - "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'productName')]" - }, - "planName": { - "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'planName')]" - }, - "planPublisherName": { - "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'planPublisherName')]" + "purchasePlan": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'purchasePlan')]" }, - "endOfLife": { + "endOfLifeDate": { "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'endOfLife')]" }, - "excludedDiskTypes": { - "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'excludedDiskTypes')]" + "disallowed": { + "value": { + "diskTypes": "[coalesce(tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'excludedDiskTypes'), createArray())]" + } }, "roleAssignments": { "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'roleAssignments')]" @@ -677,7 +907,7 @@ "_generator": { "name": "bicep", "version": "0.28.1.47646", - "templateHash": "5623163747199511447" + "templateHash": "751325967553230167" }, "name": "Compute Galleries Image Definitions", "description": "This module deploys an Azure Compute Gallery Image Definition.", @@ -749,11 +979,105 @@ } }, "nullable": true + }, + "resourceRangeType": { + "type": "object", + "properties": { + "min": { + "type": "int", + "nullable": true, + "minValue": 1, + "metadata": { + "description": "Optional. The minimum number of the resource." + } + }, + "max": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The minimum number of the resource." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "disallowedType": { + "type": "object", + "properties": { + "diskTypes": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "example": " [\n 'Standard_LRS'\n ]", + "description": "Required. A list of disk types." + } + } + }, + "nullable": true + }, + "identifierType": { + "type": "object", + "properties": { + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the gallery image definition publisher." + } + }, + "offer": { + "type": "string", + "metadata": { + "description": "Required. The name of the gallery image definition offer." + } + }, + "sku": { + "type": "string", + "metadata": { + "description": "Required. The name of the gallery image definition SKU." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "purchasePlanType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The plan ID." + } + }, + "product": { + "type": "string", + "metadata": { + "description": "Required. The product ID." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The publisher ID." + } + } + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } } }, "parameters": { "name": { "type": "string", + "minLength": 1, + "maxLength": 80, "metadata": { "description": "Required. Name of the image definition." } @@ -772,180 +1096,148 @@ "description": "Conditional. The name of the parent Azure Shared Image Gallery. Required if the template is used in a standalone deployment." } }, - "osType": { - "type": "string", - "allowedValues": [ - "Windows", - "Linux" - ], + "identifier": { + "$ref": "#/definitions/identifierType", "metadata": { - "description": "Required. OS type of the image to be created." + "description": "Required. This is the gallery image definition identifier." } }, "osState": { "type": "string", - "defaultValue": "Generalized", "allowedValues": [ "Generalized", "Specialized" ], "metadata": { - "description": "Optional. This property allows the user to specify whether the virtual machines created under this image are 'Generalized' or 'Specialized'." + "description": "Required. This property allows the user to specify the state of the OS of the image." } }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the gallery Image Definition publisher." - } - }, - "offer": { + "osType": { "type": "string", + "allowedValues": [ + "Linux", + "Windows" + ], "metadata": { - "description": "Required. The name of the gallery Image Definition offer." + "description": "Required. This property allows you to specify the type of the OS that is included in the disk when creating a VM from a managed image." } }, - "sku": { + "privacyStatementUri": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The name of the gallery Image Definition SKU." - } - }, - "minRecommendedvCPUs": { - "type": "int", - "defaultValue": 1, - "minValue": 1, - "maxValue": 128, - "metadata": { - "description": "Optional. The minimum number of the CPU cores recommended for this image." + "description": "Optional. The privacy statement uri." } }, - "maxRecommendedvCPUs": { - "type": "int", - "defaultValue": 4, - "minValue": 1, - "maxValue": 128, + "purchasePlan": { + "$ref": "#/definitions/purchasePlanType", + "nullable": true, "metadata": { - "description": "Optional. The maximum number of the CPU cores recommended for this image." + "description": "Optional. Describes the gallery image definition purchase plan. This is used by marketplace images." } }, - "minRecommendedMemory": { - "type": "int", - "defaultValue": 4, - "minValue": 1, - "maxValue": 4000, + "vCPUs": { + "$ref": "#/definitions/resourceRangeType", + "defaultValue": { + "min": 1, + "max": 4 + }, "metadata": { - "description": "Optional. The minimum amount of RAM in GB recommended for this image." + "description": "Optional. Describes the resource range (1-128 CPU cores)." } }, - "maxRecommendedMemory": { - "type": "int", - "defaultValue": 16, - "minValue": 1, - "maxValue": 4000, + "memory": { + "$ref": "#/definitions/resourceRangeType", + "defaultValue": { + "min": 4, + "max": 16 + }, "metadata": { - "description": "Optional. The maximum amount of RAM in GB recommended for this image." + "description": "Optional. Describes the resource range (1-4000 GB RAM)." } }, - "hyperVGeneration": { + "releaseNoteUri": { "type": "string", "nullable": true, - "allowedValues": [ - "V1", - "V2" - ], "metadata": { - "description": "Optional. The hypervisor generation of the Virtual Machine.\n- If this value is not specified, then it is determined by the securityType parameter.\n- If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1.\n" + "description": "Optional. The release note uri. Has to be a valid URL." } }, "securityType": { "type": "string", - "defaultValue": "Standard", "allowedValues": [ - "Standard", - "TrustedLaunch", "ConfidentialVM", - "ConfidentialVMSupported" + "ConfidentialVMSupported", + "Standard", + "TrustedLaunch" ], + "nullable": true, "metadata": { "description": "Optional. The security type of the image. Requires a hyperVGeneration V2." } }, - "isHibernateSupported": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifiy if the image supports hibernation." - } - }, "isAcceleratedNetworkSupported": { "type": "bool", "defaultValue": true, "metadata": { - "description": "Optional. Specify if the image supports accelerated networking.\nAccelerated networking enables single root I/O virtualization (SR-IOV) to a VM, greatly improving its networking performance.\nThis high-performance path bypasses the host from the data path, which reduces latency, jitter, and CPU utilization for the most demanding network workloads on supported VM types.\n" + "description": "Optional. Specify if the image supports accelerated networking." } }, - "description": { - "type": "string", + "isHibernateSupported": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The description of this gallery Image Definition resource. This property is updatable." + "description": "Optional. Specifiy if the image supports hibernation." } }, - "eula": { + "architecture": { "type": "string", + "allowedValues": [ + "Arm64", + "x64" + ], "nullable": true, "metadata": { - "description": "Optional. The Eula agreement for the gallery Image Definition. Has to be a valid URL." + "description": "Optional. The architecture of the image. Applicable to OS disks only." } }, - "privacyStatementUri": { + "description": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The privacy statement uri. Has to be a valid URL." + "description": "Optional. The description of this gallery image definition resource. This property is updatable." } }, - "releaseNoteUri": { - "type": "string", + "disallowed": { + "$ref": "#/definitions/disallowedType", "nullable": true, "metadata": { - "description": "Optional. The release note uri. Has to be a valid URL." + "description": "Optional. Describes the disallowed disk types." } }, - "productName": { + "endOfLifeDate": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The product ID." + "description": "Optional. The end of life date of the gallery image definition. This property can be used for decommissioning purposes. This property is updatable." } }, - "planName": { + "eula": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The plan ID." + "description": "Optional. The Eula agreement for the gallery image definition." } }, - "planPublisherName": { + "hyperVGeneration": { "type": "string", + "allowedValues": [ + "V1", + "V2" + ], "nullable": true, "metadata": { - "description": "Optional. The publisher ID." - } - }, - "endOfLife": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The end of life date of the gallery Image Definition. This property can be used for decommissioning purposes. This property is updatable. Allowed format: 2020-01-10T23:00:00.000Z." - } - }, - "excludedDiskTypes": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. List of the excluded disk types (e.g., Standard_LRS)." + "description": "Optional. The hypervisor generation of the Virtual Machine. If this value is not specified, then it is determined by the securityType parameter. If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1." } }, "roleAssignments": { @@ -958,7 +1250,8 @@ "type": "object", "nullable": true, "metadata": { - "description": "Optional. Tags for all resources." + "example": "{\n key1: 'value1'\n key2: 'value2'\n}\n", + "description": "Optional. Tags for all the image." } } }, @@ -976,48 +1269,39 @@ "gallery": { "existing": true, "type": "Microsoft.Compute/galleries", - "apiVersion": "2022-03-03", + "apiVersion": "2023-07-03", "name": "[parameters('galleryName')]" }, "image": { "type": "Microsoft.Compute/galleries/images", - "apiVersion": "2022-03-03", + "apiVersion": "2023-07-03", "name": "[format('{0}/{1}', parameters('galleryName'), parameters('name'))]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", "properties": { - "osType": "[parameters('osType')]", - "osState": "[parameters('osState')]", - "identifier": { - "publisher": "[parameters('publisher')]", - "offer": "[parameters('offer')]", - "sku": "[parameters('sku')]" - }, - "recommended": { - "vCPUs": { - "min": "[parameters('minRecommendedvCPUs')]", - "max": "[parameters('maxRecommendedvCPUs')]" - }, - "memory": { - "min": "[parameters('minRecommendedMemory')]", - "max": "[parameters('maxRecommendedMemory')]" - } - }, - "hyperVGeneration": "[coalesce(parameters('hyperVGeneration'), if(not(empty(parameters('securityType'))), 'V2', 'V1'))]", - "features": "[union(createArray(createObject('name', 'IsAcceleratedNetworkSupported', 'value', format('{0}', parameters('isAcceleratedNetworkSupported'))), createObject('name', 'IsHibernateSupported', 'value', format('{0}', parameters('isHibernateSupported')))), if(not(equals(parameters('securityType'), 'Standard')), createArray(createObject('name', 'SecurityType', 'value', parameters('securityType'))), createArray()))]", + "architecture": "[parameters('architecture')]", "description": "[parameters('description')]", + "disallowed": { + "diskTypes": "[coalesce(tryGet(parameters('disallowed'), 'diskTypes'), createArray())]" + }, + "endOfLifeDate": "[parameters('endOfLifeDate')]", "eula": "[parameters('eula')]", + "features": "[union(createArray(createObject('name', 'IsAcceleratedNetworkSupported', 'value', format('{0}', parameters('isAcceleratedNetworkSupported')))), if(not(equals(parameters('securityType'), null())), createArray(createObject('name', 'SecurityType', 'value', format('{0}', parameters('securityType')))), createArray()), if(not(equals(parameters('isHibernateSupported'), null())), createArray(createObject('name', 'IsHibernateSupported', 'value', format('{0}', parameters('isHibernateSupported')))), createArray()))]", + "hyperVGeneration": "[coalesce(parameters('hyperVGeneration'), if(not(empty(coalesce(parameters('securityType'), ''))), 'V2', 'V1'))]", + "identifier": { + "publisher": "[parameters('identifier').publisher]", + "offer": "[parameters('identifier').offer]", + "sku": "[parameters('identifier').sku]" + }, + "osState": "[parameters('osState')]", + "osType": "[parameters('osType')]", "privacyStatementUri": "[parameters('privacyStatementUri')]", - "releaseNoteUri": "[parameters('releaseNoteUri')]", - "purchasePlan": { - "product": "[parameters('productName')]", - "name": "[parameters('planName')]", - "publisher": "[parameters('planPublisherName')]" + "purchasePlan": "[coalesce(parameters('purchasePlan'), null())]", + "recommended": { + "vCPUs": "[parameters('vCPUs')]", + "memory": "[parameters('memory')]" }, - "endOfLifeDate": "[parameters('endOfLife')]", - "disallowed": { - "diskTypes": "[parameters('excludedDiskTypes')]" - } + "releaseNoteUri": "[parameters('releaseNoteUri')]" }, "dependsOn": [ "gallery" @@ -1073,7 +1357,7 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('image', '2022-03-03', 'full').location]" + "value": "[reference('image', '2023-07-03', 'full').location]" } } } @@ -1110,7 +1394,7 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('gallery', '2022-03-03', 'full').location]" + "value": "[reference('gallery', '2023-07-03', 'full').location]" }, "imageResourceIds": { "type": "array", diff --git a/avm/res/compute/gallery/tests/e2e/max/main.test.bicep b/avm/res/compute/gallery/tests/e2e/max/main.test.bicep index d00744b531..8d3bc53f81 100644 --- a/avm/res/compute/gallery/tests/e2e/max/main.test.bicep +++ b/avm/res/compute/gallery/tests/e2e/max/main.test.bicep @@ -75,75 +75,148 @@ module testDeployment '../../../main.bicep' = [ ] images: [ { - hyperVGeneration: 'V1' name: '${namePrefix}-az-imgd-ws-001' - offer: 'WindowsServer' + hyperVGeneration: 'V1' + identifier: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition' + } osType: 'Windows' - publisher: 'MicrosoftWindowsServer' - sku: '2022-datacenter-azure-edition' - roleAssignments: [ - { - roleDefinitionIdOrName: 'Reader' - principalId: nestedDependencies.outputs.managedIdentityPrincipalId - principalType: 'ServicePrincipal' - } - ] + osState: 'Generalized' + eula: 'test Eula' + architecture: 'x64' + description: 'testDescription' + privacyStatementUri: 'https://testPrivacyStatementUri.com' + excludedDiskTypes: ['Standard_LRS'] + purchasePlan: { + name: 'testPlanName1' + product: 'testProduct1' + publisher: 'testPublisher1' + } + endOfLife: '2033-01-01' + releaseNoteUri: 'https://testReleaseNoteUri.com' } { + name: '${namePrefix}-az-imgd-ws-002' hyperVGeneration: 'V2' + identifier: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition-hibernate' + } + osType: 'Windows' + vCPUs: { + min: 2 + max: 8 + } + memory: { + min: 4 + max: 16 + } + + osState: 'Generalized' isHibernateSupported: true isAcceleratedNetworkSupported: false - maxRecommendedMemory: 16 - maxRecommendedvCPUs: 8 - minRecommendedMemory: 4 - minRecommendedvCPUs: 2 - name: '${namePrefix}-az-imgd-ws-002' - offer: 'WindowsServer' - osState: 'Generalized' - osType: 'Windows' - publisher: 'MicrosoftWindowsServer' - roleAssignments: [ - { - roleDefinitionIdOrName: 'Reader' - principalId: nestedDependencies.outputs.managedIdentityPrincipalId - principalType: 'ServicePrincipal' - } - ] - sku: '2022-datacenter-azure-edition-hibernate' } { - hyperVGeneration: 'V2' + name: '${namePrefix}-az-imgd-wdtl-003' securityType: 'TrustedLaunch' - maxRecommendedMemory: 16 - maxRecommendedvCPUs: 4 - minRecommendedMemory: 4 - minRecommendedvCPUs: 2 - name: '${namePrefix}-az-imgd-wdtl-001' - offer: 'WindowsDesktop' - osState: 'Generalized' osType: 'Windows' - publisher: 'MicrosoftWindowsDesktop' - roleAssignments: [ - { - roleDefinitionIdOrName: 'Reader' - principalId: nestedDependencies.outputs.managedIdentityPrincipalId - principalType: 'ServicePrincipal' - } - ] - sku: 'Win11-21H2' + osState: 'Generalized' + hyperVGeneration: 'V2' + identifier: { + publisher: 'MicrosoftWindowsDesktop' + offer: 'WindowsDesktop' + sku: 'Win11-21H2' + } + memory: { + min: 4 + max: 16 + } + vCPUs: { + min: 2 + max: 8 + } + purchasePlan: { + name: 'testPlanName' + product: 'testProduct' + publisher: 'testPublisher' + } } { + name: '${namePrefix}-az-imgd-us-004' + osType: 'Linux' + osState: 'Generalized' hyperVGeneration: 'V2' - maxRecommendedMemory: 32 - maxRecommendedvCPUs: 4 - minRecommendedMemory: 4 - minRecommendedvCPUs: 1 - name: '${namePrefix}-az-imgd-us-001' - offer: '0001-com-ubuntu-server-focal' + identifier: { + publisher: 'canonical' + offer: '0001-com-ubuntu-minimal-focal' + sku: '22_04-lts-gen2' + } + memory: { + min: 4 + max: 32 + } + vCPUs: { + min: 1 + max: 4 + } + isAcceleratedNetworkSupported: false + } + { + name: '${namePrefix}-az-imgd-us-005' + osType: 'Linux' osState: 'Generalized' + hyperVGeneration: 'V2' + identifier: { + publisher: 'canonical' + offer: '0001-com-ubuntu-minimal-focal' + sku: '20_04-lts-gen2' + } + memory: { + min: 4 + max: 32 + } + vCPUs: { + min: 1 + max: 4 + } + isAcceleratedNetworkSupported: true + } + { + name: '${namePrefix}-az-imgd-us-006' + description: 'testDescription' osType: 'Linux' - publisher: 'canonical' - sku: '20_04-lts-gen2' + osState: 'Generalized' + hyperVGeneration: 'V2' + identifier: { + publisher: 'canonical' + offer: '0001-com-ubuntu-server-focal' + sku: '20_04-lts-gen2' + } + memory: { + min: 4 + max: 32 + } + vCPUs: { + min: 1 + max: 4 + } + securityType: 'TrustedLaunch' + architecture: 'x64' + endOfLife: '2033-01-01' + eula: 'test Eula' + excludedDiskTypes: ['Standard_LRS'] + isHibernateSupported: true + privacyStatementUri: 'https://testPrivacyStatementUri.com' + purchasePlan: { + name: 'testPlanName' + product: 'testProduct' + publisher: 'testPublisher' + } + releaseNoteUri: 'https://testReleaseNoteUri.com' + isAcceleratedNetworkSupported: false } ] roleAssignments: [ diff --git a/avm/res/compute/gallery/tests/e2e/waf-aligned/main.test.bicep b/avm/res/compute/gallery/tests/e2e/waf-aligned/main.test.bicep index ca7ee02323..6e757f64c3 100644 --- a/avm/res/compute/gallery/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/compute/gallery/tests/e2e/waf-aligned/main.test.bicep @@ -52,10 +52,13 @@ module testDeployment '../../../main.bicep' = [ images: [ { name: '${namePrefix}-az-imgd-ws-001' - offer: 'WindowsServer' + identifier: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition' + } osType: 'Windows' - publisher: 'MicrosoftWindowsServer' - sku: '2022-datacenter-azure-edition' + osState: 'Generalized' } ] tags: { diff --git a/avm/res/compute/gallery/version.json b/avm/res/compute/gallery/version.json index 13669e6601..41fc8c654f 100644 --- a/avm/res/compute/gallery/version.json +++ b/avm/res/compute/gallery/version.json @@ -1,7 +1,7 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.4", + "version": "0.5", "pathFilters": [ "./main.json" ] -} \ No newline at end of file +} diff --git a/avm/res/compute/virtual-machine-scale-set/README.md b/avm/res/compute/virtual-machine-scale-set/README.md index a6bb0e788f..b59cb73447 100644 --- a/avm/res/compute/virtual-machine-scale-set/README.md +++ b/avm/res/compute/virtual-machine-scale-set/README.md @@ -58,18 +58,6 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s version: 'latest' } name: 'cvmsslinmin001' - osDisk: { - createOption: 'fromImage' - diskSizeGB: '128' - managedDisk: { - storageAccountType: 'Premium_LRS' - } - } - osType: 'Linux' - skuName: 'Standard_B12ms' - // Non-required parameters - disablePasswordAuthentication: true - location: '' nicConfigurations: [ { ipConfigurations: [ @@ -88,6 +76,18 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s nicSuffix: '-nic01' } ] + osDisk: { + createOption: 'fromImage' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Linux' + skuName: 'Standard_B12ms' + // Non-required parameters + disablePasswordAuthentication: true + location: '' publicKeys: [ { keyData: '' @@ -125,6 +125,26 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s "name": { "value": "cvmsslinmin001" }, + "nicConfigurations": { + "value": [ + { + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "publicIPAddressConfiguration": { + "name": "pip-cvmsslinmin" + }, + "subnet": { + "id": "" + } + } + } + ], + "nicSuffix": "-nic01" + } + ] + }, "osDisk": { "value": { "createOption": "fromImage", @@ -147,26 +167,6 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s "location": { "value": "" }, - "nicConfigurations": { - "value": [ - { - "ipConfigurations": [ - { - "name": "ipconfig1", - "properties": { - "publicIPAddressConfiguration": { - "name": "pip-cvmsslinmin" - }, - "subnet": { - "id": "" - } - } - } - ], - "nicSuffix": "-nic01" - } - ] - }, "publicKeys": { "value": [ { @@ -204,6 +204,24 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s version: 'latest' } name: 'cvmsslinmax001' + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsslinmax' + } + subnet: { + id: '' + } + } + } + ] + nicSuffix: '-nic01' + } + ] osDisk: { createOption: 'fromImage' diskSizeGB: '128' @@ -297,24 +315,6 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s '' ] } - nicConfigurations: [ - { - ipConfigurations: [ - { - name: 'ipconfig1' - properties: { - publicIPAddressConfiguration: { - name: 'pip-cvmsslinmax' - } - subnet: { - id: '' - } - } - } - ] - nicSuffix: '-nic01' - } - ] publicKeys: [ { keyData: '' @@ -369,6 +369,26 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s "name": { "value": "cvmsslinmax001" }, + "nicConfigurations": { + "value": [ + { + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "publicIPAddressConfiguration": { + "name": "pip-cvmsslinmax" + }, + "subnet": { + "id": "" + } + } + } + ], + "nicSuffix": "-nic01" + } + ] + }, "osDisk": { "value": { "createOption": "fromImage", @@ -496,26 +516,6 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s ] } }, - "nicConfigurations": { - "value": [ - { - "ipConfigurations": [ - { - "name": "ipconfig1", - "properties": { - "publicIPAddressConfiguration": { - "name": "pip-cvmsslinmax" - }, - "subnet": { - "id": "" - } - } - } - ], - "nicSuffix": "-nic01" - } - ] - }, "publicKeys": { "value": [ { @@ -584,6 +584,24 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s version: 'latest' } name: 'cvmsslcmk001' + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsslcmk' + } + subnet: { + id: '' + } + } + } + ] + nicSuffix: '-nic01' + } + ] osDisk: { createOption: 'fromImage' diskSizeGB: '128' @@ -615,24 +633,6 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s enabled: true } location: '' - nicConfigurations: [ - { - ipConfigurations: [ - { - name: 'ipconfig1' - properties: { - publicIPAddressConfiguration: { - name: 'pip-cvmsslcmk' - } - subnet: { - id: '' - } - } - } - ] - nicSuffix: '-nic01' - } - ] publicKeys: [ { keyData: '' @@ -670,6 +670,26 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s "name": { "value": "cvmsslcmk001" }, + "nicConfigurations": { + "value": [ + { + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "publicIPAddressConfiguration": { + "name": "pip-cvmsslcmk" + }, + "subnet": { + "id": "" + } + } + } + ], + "nicSuffix": "-nic01" + } + ] + }, "osDisk": { "value": { "createOption": "fromImage", @@ -715,26 +735,6 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s "location": { "value": "" }, - "nicConfigurations": { - "value": [ - { - "ipConfigurations": [ - { - "name": "ipconfig1", - "properties": { - "publicIPAddressConfiguration": { - "name": "pip-cvmsslcmk" - }, - "subnet": { - "id": "" - } - } - } - ], - "nicSuffix": "-nic01" - } - ] - }, "publicKeys": { "value": [ { @@ -772,18 +772,6 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s version: 'latest' } name: 'cvmsswinmin001' - osDisk: { - createOption: 'fromImage' - diskSizeGB: '128' - managedDisk: { - storageAccountType: 'Premium_LRS' - } - } - osType: 'Windows' - skuName: 'Standard_B12ms' - // Non-required parameters - adminPassword: '' - location: '' nicConfigurations: [ { ipConfigurations: [ @@ -802,6 +790,18 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s nicSuffix: '-nic01' } ] + osDisk: { + createOption: 'fromImage' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Windows' + skuName: 'Standard_B12ms' + // Non-required parameters + adminPassword: '' + location: '' } } ``` @@ -833,6 +833,26 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s "name": { "value": "cvmsswinmin001" }, + "nicConfigurations": { + "value": [ + { + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "publicIPAddressConfiguration": { + "name": "pip-cvmsswinmin" + }, + "subnet": { + "id": "" + } + } + } + ], + "nicSuffix": "-nic01" + } + ] + }, "osDisk": { "value": { "createOption": "fromImage", @@ -854,26 +874,6 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s }, "location": { "value": "" - }, - "nicConfigurations": { - "value": [ - { - "ipConfigurations": [ - { - "name": "ipconfig1", - "properties": { - "publicIPAddressConfiguration": { - "name": "pip-cvmsswinmin" - }, - "subnet": { - "id": "" - } - } - } - ], - "nicSuffix": "-nic01" - } - ] } } } @@ -904,6 +904,24 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s version: 'latest' } name: 'cvmsswinmax001' + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsswinmax' + } + subnet: { + id: '' + } + } + } + ] + nicSuffix: '-nic01' + } + ] osDisk: { createOption: 'fromImage' diskSizeGB: '128' @@ -979,6 +997,14 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s extensionDSCConfig: { enabled: true } + extensionHealthConfig: { + enabled: true + settings: { + port: 80 + protocol: 'http' + requestPath: '/' + } + } extensionMonitoringAgentConfig: { enabled: true } @@ -996,24 +1022,6 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s '' ] } - nicConfigurations: [ - { - ipConfigurations: [ - { - name: 'ipconfig1' - properties: { - publicIPAddressConfiguration: { - name: 'pip-cvmsswinmax' - } - subnet: { - id: '' - } - } - } - ] - nicSuffix: '-nic01' - } - ] roleAssignments: [ { principalId: '' @@ -1061,6 +1069,26 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s "name": { "value": "cvmsswinmax001" }, + "nicConfigurations": { + "value": [ + { + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "publicIPAddressConfiguration": { + "name": "pip-cvmsswinmax" + }, + "subnet": { + "id": "" + } + } + } + ], + "nicSuffix": "-nic01" + } + ] + }, "osDisk": { "value": { "createOption": "fromImage", @@ -1158,6 +1186,16 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s "enabled": true } }, + "extensionHealthConfig": { + "value": { + "enabled": true, + "settings": { + "port": 80, + "protocol": "http", + "requestPath": "/" + } + } + }, "extensionMonitoringAgentConfig": { "value": { "enabled": true @@ -1185,26 +1223,6 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s ] } }, - "nicConfigurations": { - "value": [ - { - "ipConfigurations": [ - { - "name": "ipconfig1", - "properties": { - "publicIPAddressConfiguration": { - "name": "pip-cvmsswinmax" - }, - "subnet": { - "id": "" - } - } - } - ], - "nicSuffix": "-nic01" - } - ] - }, "roleAssignments": { "value": [ { @@ -1262,6 +1280,24 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s version: 'latest' } name: 'cvmsswinwaf001' + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsswinwaf' + } + subnet: { + id: '' + } + } + } + ] + nicSuffix: '-nic01' + } + ] osDisk: { createOption: 'fromImage' diskSizeGB: '128' @@ -1350,24 +1386,6 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s '' ] } - nicConfigurations: [ - { - ipConfigurations: [ - { - name: 'ipconfig1' - properties: { - publicIPAddressConfiguration: { - name: 'pip-cvmsswinwaf' - } - subnet: { - id: '' - } - } - } - ] - nicSuffix: '-nic01' - } - ] skuCapacity: 1 tags: { Environment: 'Non-Prod' @@ -1408,6 +1426,26 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s "name": { "value": "cvmsswinwaf001" }, + "nicConfigurations": { + "value": [ + { + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "publicIPAddressConfiguration": { + "name": "pip-cvmsswinwaf" + }, + "subnet": { + "id": "" + } + } + } + ], + "nicSuffix": "-nic01" + } + ] + }, "osDisk": { "value": { "createOption": "fromImage", @@ -1526,26 +1564,6 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s ] } }, - "nicConfigurations": { - "value": [ - { - "ipConfigurations": [ - { - "name": "ipconfig1", - "properties": { - "publicIPAddressConfiguration": { - "name": "pip-cvmsswinwaf" - }, - "subnet": { - "id": "" - } - } - } - ], - "nicSuffix": "-nic01" - } - ] - }, "skuCapacity": { "value": 1 }, @@ -1597,6 +1615,7 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s | [`availabilityZones`](#parameter-availabilityzones) | array | The virtual machine scale set zones. NOTE: Availability zones can only be set when you create the scale set. | | [`bootDiagnosticStorageAccountName`](#parameter-bootdiagnosticstorageaccountname) | string | Storage account used to store boot diagnostic information. Boot diagnostics will be disabled if no value is provided. | | [`bootDiagnosticStorageAccountUri`](#parameter-bootdiagnosticstorageaccounturi) | string | Storage account boot diagnostic base URI. | +| [`bypassPlatformSafetyChecksOnUserSchedule`](#parameter-bypassplatformsafetychecksonuserschedule) | bool | Enables customer to schedule patching without accidental upgrades. | | [`customData`](#parameter-customdata) | string | Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format. | | [`dataDisks`](#parameter-datadisks) | array | Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VM Scale sets. | | [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | @@ -1613,9 +1632,10 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s | [`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. | | [`extensionCustomScriptConfig`](#parameter-extensioncustomscriptconfig) | object | The configuration for the [Custom Script] extension. Must at least contain the ["enabled": true] property to be executed. | | [`extensionDependencyAgentConfig`](#parameter-extensiondependencyagentconfig) | object | The configuration for the [Dependency Agent] extension. Must at least contain the ["enabled": true] property to be executed. | -| [`extensionDomainJoinConfig`](#parameter-extensiondomainjoinconfig) | object | The configuration for the [Domain Join] extension. Must at least contain the ["enabled": true] property to be executed. | +| [`extensionDomainJoinConfig`](#parameter-extensiondomainjoinconfig) | secureObject | The configuration for the [Domain Join] extension. Must at least contain the ["enabled": true] property to be executed. | | [`extensionDomainJoinPassword`](#parameter-extensiondomainjoinpassword) | securestring | Required if name is specified. Password of the user specified in user parameter. | | [`extensionDSCConfig`](#parameter-extensiondscconfig) | object | The configuration for the [Desired State Configuration] extension. Must at least contain the ["enabled": true] property to be executed. | +| [`extensionHealthConfig`](#parameter-extensionhealthconfig) | object | Turned on by default. The configuration for the [Application Health Monitoring] extension. Must at least contain the ["enabled": true] property to be executed. | | [`extensionMonitoringAgentConfig`](#parameter-extensionmonitoringagentconfig) | object | The configuration for the [Monitoring Agent] extension. Must at least contain the ["enabled": true] property to be executed. | | [`extensionNetworkWatcherAgentConfig`](#parameter-extensionnetworkwatcheragentconfig) | object | The configuration for the [Network Watcher Agent] extension. Must at least contain the ["enabled": true] property to be executed. | | [`gracePeriod`](#parameter-graceperiod) | string | The amount of time for which automatic repairs are suspended due to a state change on VM. The grace time starts after the state change has completed. This helps avoid premature or accidental repairs. The time duration should be specified in ISO 8601 format. The minimum allowed grace period is 30 minutes (PT30M). The maximum allowed grace period is 90 minutes (PT90M). | @@ -1631,12 +1651,15 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s | [`monitoringWorkspaceResourceId`](#parameter-monitoringworkspaceresourceid) | string | Resource ID of the monitoring log analytics workspace. | | [`orchestrationMode`](#parameter-orchestrationmode) | string | Specifies the orchestration mode for the virtual machine scale set. | | [`overprovision`](#parameter-overprovision) | bool | Specifies whether the Virtual Machine Scale Set should be overprovisioned. | +| [`patchAssessmentMode`](#parameter-patchassessmentmode) | string | VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours. | +| [`patchMode`](#parameter-patchmode) | string | VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'. | | [`pauseTimeBetweenBatches`](#parameter-pausetimebetweenbatches) | string | The wait time between completing the update for all virtual machines in one batch and starting the next batch. The time duration should be specified in ISO 8601 format. | | [`plan`](#parameter-plan) | object | Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use. | | [`prioritizeUnhealthyInstances`](#parameter-prioritizeunhealthyinstances) | bool | Upgrade all unhealthy instances in a scale set before any healthy instances. | | [`provisionVMAgent`](#parameter-provisionvmagent) | bool | Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later. | | [`proximityPlacementGroupResourceId`](#parameter-proximityplacementgroupresourceid) | string | Resource ID of a proximity placement group. | | [`publicKeys`](#parameter-publickeys) | array | The list of SSH public keys used to authenticate with linux based VMs. | +| [`rebootSetting`](#parameter-rebootsetting) | string | Specifies the reboot setting for all AutomaticByPlatform patch installation operations. | | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`rollbackFailedInstancesOnPolicyBreach`](#parameter-rollbackfailedinstancesonpolicybreach) | bool | Rollback failed instances to previous model if the Rolling Upgrade policy is violated. | | [`sasTokenValidityLength`](#parameter-sastokenvaliditylength) | string | SAS token validity length to use to download files from storage accounts. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours. | @@ -1689,9 +1712,8 @@ Name of the VMSS. Configures NICs and PIPs. -- Required: No +- Required: Yes - Type: array -- Default: `[]` ### Parameter: `osDisk` @@ -1743,7 +1765,7 @@ Specifies whether automatic repairs should be enabled on the virtual machine sca - Required: No - Type: bool -- Default: `False` +- Default: `True` ### Parameter: `availabilityZones` @@ -1776,6 +1798,14 @@ Storage account boot diagnostic base URI. - Type: string - Default: `[format('.blob.{0}/', environment().suffixes.storage)]` +### Parameter: `bypassPlatformSafetyChecksOnUserSchedule` + +Enables customer to schedule patching without accidental upgrades. + +- Required: No +- Type: bool +- Default: `True` + ### Parameter: `customData` Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format. @@ -2031,7 +2061,7 @@ The configuration for the [Dependency Agent] extension. Must at least contain th The configuration for the [Domain Join] extension. Must at least contain the ["enabled": true] property to be executed. - Required: No -- Type: object +- Type: secureObject - Default: ```Bicep { @@ -2060,6 +2090,24 @@ The configuration for the [Desired State Configuration] extension. Must at least } ``` +### Parameter: `extensionHealthConfig` + +Turned on by default. The configuration for the [Application Health Monitoring] extension. Must at least contain the ["enabled": true] property to be executed. + +- Required: No +- Type: object +- Default: + ```Bicep + { + enabled: true + settings: { + port: 80 + protocol: 'http' + requestPath: '/' + } + } + ``` + ### Parameter: `extensionMonitoringAgentConfig` The configuration for the [Monitoring Agent] extension. Must at least contain the ["enabled": true] property to be executed. @@ -2252,6 +2300,39 @@ Specifies whether the Virtual Machine Scale Set should be overprovisioned. - Type: bool - Default: `False` +### Parameter: `patchAssessmentMode` + +VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours. + +- Required: No +- Type: string +- Default: `'ImageDefault'` +- Allowed: + ```Bicep + [ + 'AutomaticByPlatform' + 'ImageDefault' + ] + ``` + +### Parameter: `patchMode` + +VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'. + +- Required: No +- Type: string +- Default: `'AutomaticByPlatform'` +- Allowed: + ```Bicep + [ + '' + 'AutomaticByOS' + 'AutomaticByPlatform' + 'ImageDefault' + 'Manual' + ] + ``` + ### Parameter: `pauseTimeBetweenBatches` The wait time between completing the update for all virtual machines in one batch and starting the next batch. The time duration should be specified in ISO 8601 format. @@ -2300,6 +2381,23 @@ The list of SSH public keys used to authenticate with linux based VMs. - Type: array - Default: `[]` +### Parameter: `rebootSetting` + +Specifies the reboot setting for all AutomaticByPlatform patch installation operations. + +- Required: No +- Type: string +- Default: `'IfRequired'` +- Allowed: + ```Bicep + [ + 'Always' + 'IfRequired' + 'Never' + 'Unknown' + ] + ``` + ### Parameter: `roleAssignments` Array of role assignments to create. diff --git a/avm/res/compute/virtual-machine-scale-set/main.bicep b/avm/res/compute/virtual-machine-scale-set/main.bicep index 40f0918867..f64de8a695 100644 --- a/avm/res/compute/virtual-machine-scale-set/main.bicep +++ b/avm/res/compute/virtual-machine-scale-set/main.bicep @@ -56,7 +56,7 @@ param scaleSetFaultDomain int = 1 param proximityPlacementGroupResourceId string = '' @description('Required. Configures NICs and PIPs.') -param nicConfigurations array = [] +param nicConfigurations array @description('Optional. Specifies the priority for the virtual machine.') @allowed([ @@ -85,6 +85,8 @@ param licenseType string = '' param extensionDomainJoinPassword string = '' @description('Optional. The configuration for the [Domain Join] extension. Must at least contain the ["enabled": true] property to be executed.') +@secure() +#disable-next-line secure-parameter-default param extensionDomainJoinConfig object = { enabled: false } @@ -117,6 +119,16 @@ param extensionAzureDiskEncryptionConfig object = { enabled: false } +@description('Optional. Turned on by default. The configuration for the [Application Health Monitoring] extension. Must at least contain the ["enabled": true] property to be executed.') +param extensionHealthConfig object = { + enabled: true + settings: { + protocol: 'http' + port: 80 + requestPath: '/' + } +} + @description('Optional. The configuration for the [Desired State Configuration] extension. Must at least contain the ["enabled": true] property to be executed.') param extensionDSCConfig object = { enabled: false @@ -179,7 +191,7 @@ param enableAutomaticOSUpgrade bool = false param disableAutomaticRollback bool = false @description('Optional. Specifies whether automatic repairs should be enabled on the virtual machine scale set.') -param automaticRepairsPolicyEnabled bool = false +param automaticRepairsPolicyEnabled bool = true @description('Optional. The amount of time for which automatic repairs are suspended due to a state change on VM. The grace time starts after the state change has completed. This helps avoid premature or accidental repairs. The time duration should be specified in ISO 8601 format. The minimum allowed grace period is 30 minutes (PT30M). The maximum allowed grace period is 90 minutes (PT90M).') param gracePeriod string = 'PT30M' @@ -202,6 +214,35 @@ param provisionVMAgent bool = true @description('Optional. Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning.') param enableAutomaticUpdates bool = true +@description('Optional. VM guest patching orchestration mode. \'AutomaticByOS\' & \'Manual\' are for Windows only, \'ImageDefault\' for Linux only. Refer to \'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching\'.') +@allowed([ + 'AutomaticByPlatform' + 'AutomaticByOS' + 'Manual' + 'ImageDefault' + '' +]) +param patchMode string = 'AutomaticByPlatform' + +@description('Optional. Enables customer to schedule patching without accidental upgrades.') +param bypassPlatformSafetyChecksOnUserSchedule bool = true + +@description('Optional. Specifies the reboot setting for all AutomaticByPlatform patch installation operations.') +@allowed([ + 'Always' + 'IfRequired' + 'Never' + 'Unknown' +]) +param rebootSetting string = 'IfRequired' + +@description('Optional. VM guest patching assessment mode. Set it to \'AutomaticByPlatform\' to enable automatically check for updates every 24 hours.') +@allowed([ + 'AutomaticByPlatform' + 'ImageDefault' +]) +param patchAssessmentMode string = 'ImageDefault' + @description('Optional. Specifies the time zone of the virtual machine. e.g. \'Pacific Standard Time\'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`.') param timeZone string = '' @@ -288,11 +329,35 @@ var linuxConfiguration = { publicKeys: publicKeysFormatted } provisionVMAgent: provisionVMAgent + patchSettings: (provisionVMAgent && (patchMode =~ 'AutomaticByPlatform' || patchMode =~ 'ImageDefault')) + ? { + patchMode: patchMode + assessmentMode: patchAssessmentMode + automaticByPlatformSettings: (patchMode =~ 'AutomaticByPlatform') + ? { + bypassPlatformSafetyChecksOnUserSchedule: bypassPlatformSafetyChecksOnUserSchedule + rebootSetting: rebootSetting + } + : null + } + : null } var windowsConfiguration = { provisionVMAgent: provisionVMAgent enableAutomaticUpdates: enableAutomaticUpdates + patchSettings: (provisionVMAgent && (patchMode =~ 'AutomaticByPlatform' || patchMode =~ 'AutomaticByOS' || patchMode =~ 'Manual')) + ? { + patchMode: patchMode + assessmentMode: patchAssessmentMode + automaticByPlatformSettings: (patchMode =~ 'AutomaticByPlatform') + ? { + bypassPlatformSafetyChecksOnUserSchedule: bypassPlatformSafetyChecksOnUserSchedule + rebootSetting: rebootSetting + } + : null + } + : null timeZone: empty(timeZone) ? null : timeZone additionalUnattendContent: empty(additionalUnattendContent) ? null : additionalUnattendContent winRM: !empty(winRM) @@ -534,6 +599,26 @@ resource vmss 'Microsoft.Compute/virtualMachineScaleSets@2023-09-01' = { : null } } + extensionProfile: extensionHealthConfig.enabled + ? { + extensions: [ + { + name: 'HealthExtension' + properties: { + publisher: 'Microsoft.ManagedServices' + type: (osType == 'Windows' ? 'ApplicationHealthWindows' : 'ApplicationHealthLinux') + typeHandlerVersion: extensionHealthConfig.?typeHandlerVersion?? '1.0' + autoUpgradeMinorVersion: extensionHealthConfig.?autoUpgradeMinorVersion ?? false + settings: { + protocol: extensionHealthConfig.?protocol ?? 'http' + port: extensionHealthConfig.?port ?? '80' + requestPath: extensionHealthConfig.?requestPath ?? '/' + } + } + } + ] + } + : null licenseType: empty(licenseType) ? null : licenseType priority: vmPriority evictionPolicy: enableEvictionPolicy ? 'Deallocate' : null diff --git a/avm/res/compute/virtual-machine-scale-set/main.json b/avm/res/compute/virtual-machine-scale-set/main.json index 02551b6e2d..d466ab4db7 100644 --- a/avm/res/compute/virtual-machine-scale-set/main.json +++ b/avm/res/compute/virtual-machine-scale-set/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.28.1.47646", - "templateHash": "16376458652852426905" + "templateHash": "10261643860679294572" }, "name": "Virtual Machine Scale Sets", "description": "This module deploys a Virtual Machine Scale Set.", @@ -332,7 +332,6 @@ }, "nicConfigurations": { "type": "array", - "defaultValue": [], "metadata": { "description": "Required. Configures NICs and PIPs." } @@ -383,7 +382,7 @@ } }, "extensionDomainJoinConfig": { - "type": "object", + "type": "secureObject", "defaultValue": { "enabled": false }, @@ -443,6 +442,20 @@ "description": "Optional. 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." } }, + "extensionHealthConfig": { + "type": "object", + "defaultValue": { + "enabled": true, + "settings": { + "protocol": "http", + "port": 80, + "requestPath": "/" + } + }, + "metadata": { + "description": "Optional. Turned on by default. The configuration for the [Application Health Monitoring] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, "extensionDSCConfig": { "type": "object", "defaultValue": { @@ -572,7 +585,7 @@ }, "automaticRepairsPolicyEnabled": { "type": "bool", - "defaultValue": false, + "defaultValue": true, "metadata": { "description": "Optional. Specifies whether automatic repairs should be enabled on the virtual machine scale set." } @@ -618,6 +631,51 @@ "description": "Optional. Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning." } }, + "patchMode": { + "type": "string", + "defaultValue": "AutomaticByPlatform", + "allowedValues": [ + "AutomaticByPlatform", + "AutomaticByOS", + "Manual", + "ImageDefault", + "" + ], + "metadata": { + "description": "Optional. VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'." + } + }, + "bypassPlatformSafetyChecksOnUserSchedule": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enables customer to schedule patching without accidental upgrades." + } + }, + "rebootSetting": { + "type": "string", + "defaultValue": "IfRequired", + "allowedValues": [ + "Always", + "IfRequired", + "Never", + "Unknown" + ], + "metadata": { + "description": "Optional. Specifies the reboot setting for all AutomaticByPlatform patch installation operations." + } + }, + "patchAssessmentMode": { + "type": "string", + "defaultValue": "ImageDefault", + "allowedValues": [ + "AutomaticByPlatform", + "ImageDefault" + ], + "metadata": { + "description": "Optional. VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours." + } + }, "timeZone": { "type": "string", "defaultValue": "", @@ -791,11 +849,13 @@ "ssh": { "publicKeys": "[variables('publicKeysFormatted')]" }, - "provisionVMAgent": "[parameters('provisionVMAgent')]" + "provisionVMAgent": "[parameters('provisionVMAgent')]", + "patchSettings": "[if(and(parameters('provisionVMAgent'), or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('ImageDefault')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]" }, "windowsConfiguration": { "provisionVMAgent": "[parameters('provisionVMAgent')]", "enableAutomaticUpdates": "[parameters('enableAutomaticUpdates')]", + "patchSettings": "[if(and(parameters('provisionVMAgent'), or(or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('AutomaticByOS'))), equals(toLower(parameters('patchMode')), toLower('Manual')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]", "timeZone": "[if(empty(parameters('timeZone')), null(), parameters('timeZone'))]", "additionalUnattendContent": "[if(empty(parameters('additionalUnattendContent')), null(), parameters('additionalUnattendContent'))]", "winRM": "[if(not(empty(parameters('winRM'))), createObject('listeners', parameters('winRM')), null())]" @@ -949,6 +1009,7 @@ "storageUri": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), format('https://{0}{1}', parameters('bootDiagnosticStorageAccountName'), parameters('bootDiagnosticStorageAccountUri')), null())]" } }, + "extensionProfile": "[if(parameters('extensionHealthConfig').enabled, createObject('extensions', createArray(createObject('name', 'HealthExtension', 'properties', createObject('publisher', 'Microsoft.ManagedServices', 'type', if(equals(parameters('osType'), 'Windows'), 'ApplicationHealthWindows', 'ApplicationHealthLinux'), 'typeHandlerVersion', coalesce(tryGet(parameters('extensionHealthConfig'), 'typeHandlerVersion'), '1.0'), 'autoUpgradeMinorVersion', coalesce(tryGet(parameters('extensionHealthConfig'), 'autoUpgradeMinorVersion'), false()), 'settings', createObject('protocol', coalesce(tryGet(parameters('extensionHealthConfig'), 'protocol'), 'http'), 'port', coalesce(tryGet(parameters('extensionHealthConfig'), 'port'), '80'), 'requestPath', coalesce(tryGet(parameters('extensionHealthConfig'), 'requestPath'), '/')))))), null())]", "licenseType": "[if(empty(parameters('licenseType')), null(), parameters('licenseType'))]", "priority": "[parameters('vmPriority')]", "evictionPolicy": "[if(parameters('enableEvictionPolicy'), 'Deallocate', null())]", diff --git a/avm/res/compute/virtual-machine-scale-set/tests/e2e/windows.max/main.test.bicep b/avm/res/compute/virtual-machine-scale-set/tests/e2e/windows.max/main.test.bicep index ae46d40a0c..80d34f455c 100644 --- a/avm/res/compute/virtual-machine-scale-set/tests/e2e/windows.max/main.test.bicep +++ b/avm/res/compute/virtual-machine-scale-set/tests/e2e/windows.max/main.test.bicep @@ -161,6 +161,14 @@ module testDeployment '../../../main.bicep' = [ extensionNetworkWatcherAgentConfig: { enabled: true } + extensionHealthConfig: { + enabled: true + settings: { + protocol: 'http' + port: 80 + requestPath: '/' + } + } lock: { kind: 'CanNotDelete' name: 'myCustomLockName' diff --git a/avm/res/network/private-endpoint/README.md b/avm/res/network/private-endpoint/README.md index b5db7c46ce..87321bbb59 100644 --- a/avm/res/network/private-endpoint/README.md +++ b/avm/res/network/private-endpoint/README.md @@ -17,8 +17,8 @@ This module deploys a Private Endpoint. | :-- | :-- | | `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.Network/privateEndpoints` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints) | -| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints/privateDnsZoneGroups) | +| `Microsoft.Network/privateEndpoints` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints) | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints/privateDnsZoneGroups) | ## Usage examples @@ -30,7 +30,8 @@ The following section provides usage examples for the module, which were used to - [Using only defaults](#example-1-using-only-defaults) - [Using large parameter set](#example-2-using-large-parameter-set) -- [WAF-aligned](#example-3-waf-aligned) +- [Using private link service](#example-3-using-private-link-service) +- [WAF-aligned](#example-4-waf-aligned) ### Example 1: _Using only defaults_ @@ -49,15 +50,7 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = name: 'npemin001' subnetResourceId: '' // Non-required parameters - applicationSecurityGroupResourceIds: [] - customDnsConfigs: [] - customNetworkInterfaceName: '' - ipConfigurations: [] location: '' - lock: {} - manualPrivateLinkServiceConnections: [] - privateDnsZoneGroupName: '' - privateDnsZoneResourceIds: [] privateLinkServiceConnections: [ { name: 'npemin001' @@ -69,8 +62,6 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = } } ] - roleAssignments: [] - tags: {} } } ``` @@ -95,33 +86,9 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = "value": "" }, // Non-required parameters - "applicationSecurityGroupResourceIds": { - "value": [] - }, - "customDnsConfigs": { - "value": [] - }, - "customNetworkInterfaceName": { - "value": "" - }, - "ipConfigurations": { - "value": [] - }, "location": { "value": "" }, - "lock": { - "value": {} - }, - "manualPrivateLinkServiceConnections": { - "value": [] - }, - "privateDnsZoneGroupName": { - "value": "" - }, - "privateDnsZoneResourceIds": { - "value": [] - }, "privateLinkServiceConnections": { "value": [ { @@ -134,12 +101,6 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = } } ] - }, - "roleAssignments": { - "value": [] - }, - "tags": { - "value": {} } } } @@ -192,7 +153,6 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = kind: 'CanNotDelete' name: 'myCustomLockName' } - manualPrivateLinkServiceConnections: [] privateDnsZoneGroupName: 'default' privateDnsZoneResourceIds: [ '' @@ -294,9 +254,6 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = "name": "myCustomLockName" } }, - "manualPrivateLinkServiceConnections": { - "value": [] - }, "privateDnsZoneGroupName": { "value": "default" }, @@ -352,7 +309,101 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' =

    -### Example 3: _WAF-aligned_ +### Example 3: _Using private link service_ + +This instance deploys the module with a private link service to test the application of an empty list of string for `groupIds`. + + +

    + +via Bicep module + +```bicep +module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = { + name: 'privateEndpointDeployment' + params: { + // Required parameters + name: 'npepls001' + subnetResourceId: '' + // Non-required parameters + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: '' + memberName: '' + privateIPAddress: '10.0.0.10' + } + } + ] + location: '' + privateLinkServiceConnections: [ + { + name: 'npepls001' + properties: { + groupIds: [] + privateLinkServiceId: '' + } + } + ] + } +} +``` + +
    +

    + +

    + +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "npepls001" + }, + "subnetResourceId": { + "value": "" + }, + // Non-required parameters + "ipConfigurations": { + "value": [ + { + "name": "myIPconfig", + "properties": { + "groupId": "", + "memberName": "", + "privateIPAddress": "10.0.0.10" + } + } + ] + }, + "location": { + "value": "" + }, + "privateLinkServiceConnections": { + "value": [ + { + "name": "npepls001", + "properties": { + "groupIds": [], + "privateLinkServiceId": "" + } + } + ] + } + } +} +``` + +
    +

    + +### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. @@ -372,7 +423,6 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = applicationSecurityGroupResourceIds: [ '' ] - customDnsConfigs: [] customNetworkInterfaceName: 'npewaf001nic' ipConfigurations: [ { @@ -389,8 +439,6 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = kind: 'CanNotDelete' name: 'myCustomLockName' } - manualPrivateLinkServiceConnections: [] - privateDnsZoneGroupName: 'default' privateDnsZoneResourceIds: [ '' ] @@ -439,9 +487,6 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = "" ] }, - "customDnsConfigs": { - "value": [] - }, "customNetworkInterfaceName": { "value": "npewaf001nic" }, @@ -466,12 +511,6 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = "name": "myCustomLockName" } }, - "manualPrivateLinkServiceConnections": { - "value": [] - }, - "privateDnsZoneGroupName": { - "value": "default" - }, "privateDnsZoneResourceIds": { "value": [ "" @@ -628,20 +667,20 @@ Properties of private endpoint IP configurations. | Parameter | Type | Description | | :-- | :-- | :-- | -| [`groupId`](#parameter-ipconfigurationspropertiesgroupid) | string | The ID of a group obtained from the remote resource that this private endpoint should connect to. | -| [`memberName`](#parameter-ipconfigurationspropertiesmembername) | string | The member name of a group obtained from the remote resource that this private endpoint should connect to. | +| [`groupId`](#parameter-ipconfigurationspropertiesgroupid) | string | The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string. | +| [`memberName`](#parameter-ipconfigurationspropertiesmembername) | string | The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string. | | [`privateIPAddress`](#parameter-ipconfigurationspropertiesprivateipaddress) | string | A private IP address obtained from the private endpoint's subnet. | ### Parameter: `ipConfigurations.properties.groupId` -The ID of a group obtained from the remote resource that this private endpoint should connect to. +The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string. - Required: Yes - Type: string ### Parameter: `ipConfigurations.properties.memberName` -The member name of a group obtained from the remote resource that this private endpoint should connect to. +The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string. - Required: Yes - Type: string @@ -729,7 +768,7 @@ Properties of private link service connection. | Parameter | Type | Description | | :-- | :-- | :-- | -| [`groupIds`](#parameter-manualprivatelinkserviceconnectionspropertiesgroupids) | array | The ID of a group obtained from the remote resource that this private endpoint should connect to. | +| [`groupIds`](#parameter-manualprivatelinkserviceconnectionspropertiesgroupids) | array | The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`. | | [`privateLinkServiceId`](#parameter-manualprivatelinkserviceconnectionspropertiesprivatelinkserviceid) | string | The resource id of private link service. | **Optional parameters** @@ -740,7 +779,7 @@ Properties of private link service connection. ### Parameter: `manualPrivateLinkServiceConnections.properties.groupIds` -The ID of a group obtained from the remote resource that this private endpoint should connect to. +The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`. - Required: Yes - Type: array @@ -805,7 +844,7 @@ Properties of private link service connection. | Parameter | Type | Description | | :-- | :-- | :-- | -| [`groupIds`](#parameter-privatelinkserviceconnectionspropertiesgroupids) | array | The ID of a group obtained from the remote resource that this private endpoint should connect to. | +| [`groupIds`](#parameter-privatelinkserviceconnectionspropertiesgroupids) | array | The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`. | | [`privateLinkServiceId`](#parameter-privatelinkserviceconnectionspropertiesprivatelinkserviceid) | string | The resource id of private link service. | **Optional parameters** @@ -816,7 +855,7 @@ Properties of private link service connection. ### Parameter: `privateLinkServiceConnections.properties.groupIds` -The ID of a group obtained from the remote resource that this private endpoint should connect to. +The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`. - Required: Yes - Type: array diff --git a/avm/res/network/private-endpoint/main.bicep b/avm/res/network/private-endpoint/main.bicep index 12d0d99e34..f893474088 100644 --- a/avm/res/network/private-endpoint/main.bicep +++ b/avm/res/network/private-endpoint/main.bicep @@ -100,7 +100,7 @@ resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableT } } -resource privateEndpoint 'Microsoft.Network/privateEndpoints@2023-04-01' = { +resource privateEndpoint 'Microsoft.Network/privateEndpoints@2023-11-01' = { name: name location: location tags: tags @@ -174,9 +174,11 @@ output name string = privateEndpoint.name output location string = privateEndpoint.location @description('The group Id for the private endpoint Group.') -output groupId string = !empty(privateEndpoint.properties.manualPrivateLinkServiceConnections) - ? privateEndpoint.properties.manualPrivateLinkServiceConnections[0].properties.groupIds[0] - : privateEndpoint.properties.privateLinkServiceConnections[0].properties.groupIds[0] +output groupId string = !empty(privateEndpoint.properties.manualPrivateLinkServiceConnections) && length(privateEndpoint.properties.manualPrivateLinkServiceConnections[0].properties.?groupIds) > 0 + ? privateEndpoint.properties.manualPrivateLinkServiceConnections[0].properties.?groupIds[0] ?? '' + : !empty(privateEndpoint.properties.privateLinkServiceConnections) && length(privateEndpoint.properties.privateLinkServiceConnections[0].properties.?groupIds) > 0 + ? privateEndpoint.properties.privateLinkServiceConnections[0].properties.?groupIds[0] ?? '' + : '' // ================ // // Definitions // @@ -219,10 +221,10 @@ type ipConfigurationsType = { @description('Required. Properties of private endpoint IP configurations.') properties: { - @description('Required. The ID of a group obtained from the remote resource that this private endpoint should connect to.') + @description('Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string.') groupId: string - @description('Required. The member name of a group obtained from the remote resource that this private endpoint should connect to.') + @description('Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string.') memberName: string @description('Required. A private IP address obtained from the private endpoint\'s subnet.') @@ -236,8 +238,8 @@ type manualPrivateLinkServiceConnectionsType = { @description('Required. Properties of private link service connection.') properties: { - @description('Required. The ID of a group obtained from the remote resource that this private endpoint should connect to.') - groupIds: array + @description('Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`.') + groupIds: string[] @description('Required. The resource id of private link service.') privateLinkServiceId: string @@ -253,8 +255,8 @@ type privateLinkServiceConnectionsType = { @description('Required. Properties of private link service connection.') properties: { - @description('Required. The ID of a group obtained from the remote resource that this private endpoint should connect to.') - groupIds: array + @description('Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`.') + groupIds: string[] @description('Required. The resource id of private link service.') privateLinkServiceId: string diff --git a/avm/res/network/private-endpoint/main.json b/avm/res/network/private-endpoint/main.json index b354ae284d..a76b7fb3e3 100644 --- a/avm/res/network/private-endpoint/main.json +++ b/avm/res/network/private-endpoint/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.28.1.47646", - "templateHash": "6936556431546043466" + "templateHash": "12384550528617388749" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint.", @@ -121,13 +121,13 @@ "groupId": { "type": "string", "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." } }, "memberName": { "type": "string", "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." } }, "privateIPAddress": { @@ -161,8 +161,11 @@ "properties": { "groupIds": { "type": "array", + "items": { + "type": "string" + }, "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." } }, "privateLinkServiceId": { @@ -202,8 +205,11 @@ "properties": { "groupIds": { "type": "array", + "items": { + "type": "string" + }, "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." } }, "privateLinkServiceId": { @@ -389,7 +395,7 @@ }, "privateEndpoint": { "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2023-04-01", + "apiVersion": "2023-11-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", @@ -477,7 +483,7 @@ "_generator": { "name": "bicep", "version": "0.28.1.47646", - "templateHash": "8661907155223407544" + "templateHash": "18351493760118120087" }, "name": "Private Endpoint Private DNS Zone Groups", "description": "This module deploys a Private Endpoint Private DNS Zone Group.", @@ -523,7 +529,7 @@ "resources": [ { "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2023-04-01", + "apiVersion": "2023-11-01", "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", "properties": { "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" @@ -587,14 +593,14 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + "value": "[reference('privateEndpoint', '2023-11-01', 'full').location]" }, "groupId": { "type": "string", "metadata": { "description": "The group Id for the private endpoint Group." }, - "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" + "value": "[if(and(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), greater(length(tryGet(reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties, 'groupIds')), 0)), coalesce(tryGet(reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties, 'groupIds', 0), ''), if(and(not(empty(reference('privateEndpoint').privateLinkServiceConnections)), greater(length(tryGet(reference('privateEndpoint').privateLinkServiceConnections[0].properties, 'groupIds')), 0)), coalesce(tryGet(reference('privateEndpoint').privateLinkServiceConnections[0].properties, 'groupIds', 0), ''), ''))]" } } } \ No newline at end of file diff --git a/avm/res/network/private-endpoint/private-dns-zone-group/README.md b/avm/res/network/private-endpoint/private-dns-zone-group/README.md index e5cd06ad3d..9cafeb7cf3 100644 --- a/avm/res/network/private-endpoint/private-dns-zone-group/README.md +++ b/avm/res/network/private-endpoint/private-dns-zone-group/README.md @@ -14,7 +14,7 @@ This module deploys a Private Endpoint Private DNS Zone Group. | Resource Type | API Version | | :-- | :-- | -| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints/privateDnsZoneGroups) | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints/privateDnsZoneGroups) | ## Parameters diff --git a/avm/res/network/private-endpoint/private-dns-zone-group/main.bicep b/avm/res/network/private-endpoint/private-dns-zone-group/main.bicep index 701f48a69c..a2e7023024 100644 --- a/avm/res/network/private-endpoint/private-dns-zone-group/main.bicep +++ b/avm/res/network/private-endpoint/private-dns-zone-group/main.bicep @@ -22,11 +22,11 @@ var privateDnsZoneConfigs = [ } ] -resource privateEndpoint 'Microsoft.Network/privateEndpoints@2023-04-01' existing = { +resource privateEndpoint 'Microsoft.Network/privateEndpoints@2023-11-01' existing = { name: privateEndpointName } -resource privateDnsZoneGroup 'Microsoft.Network/privateEndpoints/privateDnsZoneGroups@2023-04-01' = { +resource privateDnsZoneGroup 'Microsoft.Network/privateEndpoints/privateDnsZoneGroups@2023-11-01' = { name: name parent: privateEndpoint properties: { diff --git a/avm/res/network/private-endpoint/private-dns-zone-group/main.json b/avm/res/network/private-endpoint/private-dns-zone-group/main.json index 3be73efbf6..8661ce0a3d 100644 --- a/avm/res/network/private-endpoint/private-dns-zone-group/main.json +++ b/avm/res/network/private-endpoint/private-dns-zone-group/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "13696906123248879101" + "version": "0.28.1.47646", + "templateHash": "18351493760118120087" }, "name": "Private Endpoint Private DNS Zone Groups", "description": "This module deploys a Private Endpoint Private DNS Zone Group.", @@ -51,7 +51,7 @@ "resources": [ { "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2023-04-01", + "apiVersion": "2023-11-01", "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", "properties": { "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" diff --git a/avm/res/network/private-endpoint/tests/e2e/defaults/main.test.bicep b/avm/res/network/private-endpoint/tests/e2e/defaults/main.test.bicep index fb69ae8935..7d3610ac50 100644 --- a/avm/res/network/private-endpoint/tests/e2e/defaults/main.test.bicep +++ b/avm/res/network/private-endpoint/tests/e2e/defaults/main.test.bicep @@ -57,16 +57,6 @@ module testDeployment '../../../main.bicep' = [ name: '${namePrefix}${serviceShort}001' location: resourceLocation subnetResourceId: nestedDependencies.outputs.subnetResourceId - // Workaround for PSRule - lock: {} - roleAssignments: [] - applicationSecurityGroupResourceIds: [] - customNetworkInterfaceName: '' - privateDnsZoneGroupName: '' - ipConfigurations: [] - customDnsConfigs: [] - privateDnsZoneResourceIds: [] - manualPrivateLinkServiceConnections: [] privateLinkServiceConnections: [ { name: '${namePrefix}${serviceShort}001' @@ -78,7 +68,6 @@ module testDeployment '../../../main.bicep' = [ } } ] - tags: {} } } ] diff --git a/avm/res/network/private-endpoint/tests/e2e/max/main.test.bicep b/avm/res/network/private-endpoint/tests/e2e/max/main.test.bicep index 22845ca801..7d708bd173 100644 --- a/avm/res/network/private-endpoint/tests/e2e/max/main.test.bicep +++ b/avm/res/network/private-endpoint/tests/e2e/max/main.test.bicep @@ -113,9 +113,7 @@ module testDeployment '../../../main.bicep' = [ Environment: 'Non-Prod' Role: 'DeploymentValidation' } - // Workaround for PSRule privateDnsZoneGroupName: 'default' - manualPrivateLinkServiceConnections: [] privateLinkServiceConnections: [ { name: '${namePrefix}${serviceShort}001' diff --git a/avm/res/network/private-endpoint/tests/e2e/private-link/dependencies.bicep b/avm/res/network/private-endpoint/tests/e2e/private-link/dependencies.bicep new file mode 100644 index 0000000000..5014b766b6 --- /dev/null +++ b/avm/res/network/private-endpoint/tests/e2e/private-link/dependencies.bicep @@ -0,0 +1,147 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Key Vault to create.') +param privateLinkServiceName string + +@description('Required. The name of the Load Balancer to create.') +param loadbalancerName string + +var addressPrefix = '10.0.0.0/16' +var backendPoolName = 'backEndPool' +var loadBalancerFrontEndIpConfigurationName = 'myFrontEnd' +var healthProbeName = 'healthProbe' + + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'frontendSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 24, 0) + privateLinkServiceNetworkPolicies: 'Disabled' + } + } + { + name: 'backendSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 24, 1) + } + } + ] + } +} + +resource loadbalancer 'Microsoft.Network/loadBalancers@2023-11-01' = { + name: loadbalancerName + location: location + sku: { + name: 'Standard' + } + properties: { + frontendIPConfigurations: [ + { + name: loadBalancerFrontEndIpConfigurationName + properties: { + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: virtualNetwork.properties.subnets[0].id // frontendSubnet + } + } + } + ] + backendAddressPools: [ + { + name: backendPoolName + } + ] + inboundNatRules: [ + { + name: 'RDP' + properties: { + frontendIPConfiguration: { + id: resourceId('Microsoft.Network/loadBalancers/frontendIpConfigurations', loadbalancerName, loadBalancerFrontEndIpConfigurationName) + } + protocol: 'Tcp' + frontendPort: 3389 + backendPort: 3389 + enableFloatingIP: false + } + } + ] + loadBalancingRules: [ + { + name: 'myHTTPRule' + properties: { + frontendIPConfiguration: { + id: resourceId('Microsoft.Network/loadBalancers/frontendIpConfigurations', loadbalancerName, loadBalancerFrontEndIpConfigurationName) + } + backendAddressPool: { + id: resourceId('Microsoft.Network/loadBalancers/backendAddressPools', loadbalancerName, backendPoolName) + } + probe: { + id: resourceId('Microsoft.Network/loadBalancers/probes', loadbalancerName, healthProbeName) + } + protocol: 'Tcp' + frontendPort: 80 + backendPort: 80 + idleTimeoutInMinutes: 15 + } + } + ] + probes: [ + { + properties: { + protocol: 'Tcp' + port: 80 + intervalInSeconds: 15 + numberOfProbes: 2 + } + name: healthProbeName + } + ] + } +} + +resource privateLinkService 'Microsoft.Network/privateLinkServices@2023-11-01' = { + name: privateLinkServiceName + location: location + properties: { + enableProxyProtocol: false + loadBalancerFrontendIpConfigurations: [ + { + id: loadbalancer.properties.frontendIPConfigurations[0].id + } + ] + ipConfigurations: [ + { + name: 'snet-provider-default-1' + properties: { + privateIPAllocationMethod: 'Dynamic' + privateIPAddressVersion: 'IPv4' + subnet: { + id: loadbalancer.properties.frontendIPConfigurations[0].properties.subnet.id + } + primary: false + } + } + ] + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created Private Link Service.') +output privateLinkServiceResourceId string = privateLinkService.id diff --git a/avm/res/network/private-endpoint/tests/e2e/private-link/main.test.bicep b/avm/res/network/private-endpoint/tests/e2e/private-link/main.test.bicep new file mode 100644 index 0000000000..1ad85ff5bb --- /dev/null +++ b/avm/res/network/private-endpoint/tests/e2e/private-link/main.test.bicep @@ -0,0 +1,79 @@ +targetScope = 'subscription' + +metadata name = 'Using private link service' +metadata description = 'This instance deploys the module with a private link service to test the application of an empty list of string for `groupIds`.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.privateendpoints-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation 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 = 'npepls' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + privateLinkServiceName: 'dep-${namePrefix}-pls-${serviceShort}' + loadbalancerName: 'dep-${namePrefix}-lb-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + subnetResourceId: nestedDependencies.outputs.subnetResourceId + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: '' + memberName: '' + privateIPAddress: '10.0.0.10' + } + } + ] + privateLinkServiceConnections: [ + { + name: '${namePrefix}${serviceShort}001' + properties: { + privateLinkServiceId: nestedDependencies.outputs.privateLinkServiceResourceId + groupIds: [] + } + } + ] + } + } +] diff --git a/avm/res/network/private-endpoint/tests/e2e/waf-aligned/main.test.bicep b/avm/res/network/private-endpoint/tests/e2e/waf-aligned/main.test.bicep index f90eb6358f..1687c147bd 100644 --- a/avm/res/network/private-endpoint/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/network/private-endpoint/tests/e2e/waf-aligned/main.test.bicep @@ -85,10 +85,6 @@ module testDeployment '../../../main.bicep' = [ Environment: 'Non-Prod' Role: 'DeploymentValidation' } - // Workaround for PSRule - privateDnsZoneGroupName: 'default' - customDnsConfigs: [] - manualPrivateLinkServiceConnections: [] privateLinkServiceConnections: [ { name: '${namePrefix}${serviceShort}001' diff --git a/avm/utilities/tools/Invoke-WorkflowsForBranch.ps1 b/avm/utilities/tools/Invoke-WorkflowsForBranch.ps1 index cde84fa56b..dbb34084d9 100644 --- a/avm/utilities/tools/Invoke-WorkflowsForBranch.ps1 +++ b/avm/utilities/tools/Invoke-WorkflowsForBranch.ps1 @@ -8,7 +8,7 @@ Invoke a given GitHub workflow Invoke a given GitHub workflow .PARAMETER PersonalAccessToken -Mandatory. The GitHub PAT to leverage when interacting with the GitHub API. +Optional. The PAT to use to interact with either GitHub / Azure DevOps. If not provided, the script will use the GitHub CLI to authenticate. .PARAMETER RepositoryOwner Mandatory. The repository's organization. @@ -34,7 +34,7 @@ function Invoke-GitHubWorkflow { [CmdletBinding(SupportsShouldProcess)] param ( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $false)] [string] $PersonalAccessToken, [Parameter(Mandatory = $true)] @@ -53,23 +53,49 @@ function Invoke-GitHubWorkflow { [string] $TargetBranch = 'main' ) - $requestInputObject = @{ - Method = 'POST' - Uri = "https://api.github.com/repos/$RepositoryOwner/$RepositoryName/actions/workflows/$WorkflowFileName/dispatches" - Headers = @{ - Authorization = "Bearer $PersonalAccessToken" + $triggerUrl = "/repos/$RepositoryOwner/$RepositoryName/actions/workflows/$WorkflowFileName/dispatches" + if ($PersonalAccessToken) { + # Using PAT + $requestInputObject = @{ + Method = 'POST' + Uri = "https://api.github.com$triggerUrl" + Headers = @{ + Authorization = "Bearer $PersonalAccessToken" + } + Body = @{ + ref = $TargetBranch + inputs = $WorkflowInputs + } | ConvertTo-Json } - Body = @{ - ref = $TargetBranch - inputs = $WorkflowInputs - } | ConvertTo-Json - } - if ($PSCmdlet.ShouldProcess("GitHub workflow [$WorkflowFileName] for branch [$TargetBranch]", 'Invoke')) { - try { - $response = Invoke-RestMethod @requestInputObject -Verbose:$false - } catch { - Write-Error ("Request failed for [$WorkflowFileName]. Response: [{0}]" -f $_.ErrorDetails) - return $false + if ($PSCmdlet.ShouldProcess("GitHub workflow [$WorkflowFileName] for branch [$TargetBranch]", 'Invoke')) { + try { + $response = Invoke-RestMethod @requestInputObject -Verbose:$false + } catch { + Write-Error ("Request failed for [$WorkflowFileName]. Response: [{0}]" -f $_.ErrorDetails) + return $false + } + if ($response) { + Write-Error "Request failed. Response: [$response]" + return $false + } + } + } else { + # Using GH API instead o + $requestInputObject = @( + '--method', 'POST', + '-H', 'Accept: application/vnd.github+json', + '-H', 'X-GitHub-Api-Version: 2022-11-28', + '-f', "ref=$TargetBranch", + $triggerUrl + ) + # Adding inputs + foreach ($key in $WorkflowInputs.Keys) { + $requestInputObject += @( + '-f', ('inputs[{0}]={1}' -f $key, $WorkflowInputs[$key]) + ) + } + if ($PSCmdlet.ShouldProcess("GitHub workflow [$WorkflowFileName] for branch [$TargetBranch]", 'Invoke')) { + $response = (gh api @requestInputObject | ConvertFrom-Json) } if ($response) { Write-Error "Request failed. Response: [$response]" @@ -88,7 +114,7 @@ Get a list of all GitHub module workflows Get a list of all GitHub module workflows. Does not return all properties but only the relevant ones. .PARAMETER PersonalAccessToken -Mandatory. The GitHub PAT to leverage when interacting with the GitHub API. +Optional. The PAT to use to interact with either GitHub / Azure DevOps. If not provided, the script will use the GitHub CLI to authenticate. .PARAMETER RepositoryOwner Mandatory. The repository's organization. @@ -96,8 +122,11 @@ Mandatory. The repository's organization. .PARAMETER RepositoryName Mandatory. The name of the repository to fetch the workflows from. +.PARAMETER IncludeDisabled +Optional. Set if you want to also include disabled workflows in the result. + .PARAMETER Filter -Optional. A filter to apply when fetching the workflows. By default we fetch all module workflows (avm.res.*). +Optional. A regex filter to apply when fetching the workflows. By default we fetch all module workflows. .EXAMPLE Get-GitHubModuleWorkflowList -PersonalAccessToken '' -RepositoryOwner 'Azure' -RepositoryName 'bicep-registry-modules' @@ -108,7 +137,7 @@ function Get-GitHubModuleWorkflowList { [CmdletBinding()] param ( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $false)] [string] $PersonalAccessToken, [Parameter(Mandatory = $true)] @@ -118,26 +147,46 @@ function Get-GitHubModuleWorkflowList { [string] $RepositoryName, [Parameter(Mandatory = $false)] - [string] $Filter = 'avm.res.*' + [switch] $IncludeDisabled, + + [Parameter(Mandatory = $false)] + [string] $Filter = 'avm\.(?:res|ptn|utl)' ) $allWorkflows = @() + $page = 1 do { - $requestInputObject = @{ - Method = 'GET' - Uri = "https://api.github.com/repos/$RepositoryOwner/$RepositoryName/actions/workflows?per_page=100&page=$page" - Headers = @{ - Authorization = "Bearer $PersonalAccessToken" + + $queryUrl = "/repos/$RepositoryOwner/$RepositoryName/actions/workflows?per_page=100&page=$page" + if ($PersonalAccessToken) { + # Using PAT + $requestInputObject = @{ + Method = 'GET' + Uri = "https://api.github.com$queryUrl" + Headers = @{ + Authorization = "Bearer $PersonalAccessToken" + } } + $response = Invoke-RestMethod @requestInputObject + } else { + # Using GH API instead of 'gh workflow list' to get all results instead of just the first few + $requestInputObject = @( + '-H', 'Accept: application/vnd.github+json', + '-H', 'X-GitHub-Api-Version: 2022-11-28', + $queryUrl + ) + $response = (gh api @requestInputObject | ConvertFrom-Json) } - $response = Invoke-RestMethod @requestInputObject if (-not $response.workflows) { Write-Error "Request failed. Reponse: [$response]" } - $allWorkflows += $response.workflows | Select-Object -Property @('id', 'name', 'path', 'badge_url') | Where-Object { (Split-Path $_.path -Leaf) -like $Filter } + $allWorkflows += $response.workflows | Select-Object -Property @('id', 'name', 'path', 'badge_url', 'state') | Where-Object { + $_.name -match $Filter -and + ($IncludeDisabled ? $true : $_.state -eq 'active') + } $expectedPages = [math]::ceiling($response.total_count / 100) $page++ @@ -155,13 +204,13 @@ Trigger all pipelines for GitHub Trigger all workflows for the given GitHub repository. By default, pipelines are filtered to AVM module pipelines. .PARAMETER PersonalAccessToken -Mandatory. The PAT to use to interact with either GitHub / Azure DevOps. +Optional. The PAT to use to interact with either GitHub / Azure DevOps. If not provided, the script will use the GitHub CLI to authenticate. .PARAMETER TargetBranch Optional. The branch to run the pipelines for (e.g. `main`). Defaults to currently checked-out branch. .PARAMETER PipelineFilter -Optional. The pipeline files to filter down to. By default only files with a name that starts with 'avm.res.*' are considered. E.g. 'avm.res.*'. +Optional. The pipeline files to filter down to (regex). .PARAMETER SkipPipelineBadges Optional. Specify to disable the output of generated pipeline status badges for the given pipeline configuration. @@ -179,32 +228,37 @@ Optional. The inputs to pass into the workflows. Defaults to only run static val Optional. Trigger workflows only for those who's module files have changed (based on diff of branch to main) .EXAMPLE -Invoke-WorkflowsForBranch -PersonalAccessToken '' -TargetBranch 'feature/branch' -PipelineFilter 'avm.res.*' -WorkflowInputs @{ staticValidation = 'true'; deploymentValidation = 'true'; removeDeployment = 'true' } +Invoke-WorkflowsForBranch -PersonalAccessToken '' -TargetBranch 'feature/branch' -PipelineFilter 'avm\.(?:res|ptn|utl)' -WorkflowInputs @{ staticValidation = 'true'; deploymentValidation = 'true'; removeDeployment = 'true' } -Run all GitHub workflows that start with'avm.res.*' using branch 'feature/branch'. Also returns all GitHub status badges. +Run all GitHub workflows that match 'avm\.(?:res|ptn|utl)' using branch 'feature/branch'. Also returns all GitHub status badges. .EXAMPLE -Invoke-WorkflowsForBranch -PersonalAccessToken '' -TargetBranch 'feature/branch' -PipelineFilter 'avm.res.*' -WorkflowInputs @{ staticValidation = 'true'; deploymentValidation = 'true'; removeDeployment = 'true' } -WhatIf +Invoke-WorkflowsForBranch -PersonalAccessToken '' -TargetBranch 'feature/branch' -PipelineFilter 'avm\.(?:res|ptn|utl)' -WorkflowInputs @{ staticValidation = 'true'; deploymentValidation = 'true'; removeDeployment = 'true' } -WhatIf -Only simulate the triggering of all GitHub workflows that start with'avm.res.*' using branch 'feature/branch'. Hence ONLY returns all GitHub status badges. +Only simulate the triggering of all GitHub workflows that match 'avm\.(?:res|ptn|utl)' using branch 'feature/branch'. Hence ONLY returns all GitHub status badges. .EXAMPLE Invoke-WorkflowsForBranch -PersonalAccessToken '' -RepositoryOwner 'MyFork' -Only simulate the triggering of all GitHub workflows of project [MyFork/bicep-registry-modules] that start with'avm.res.*', using the current locally checked out branch. Also returns all GitHub status badges. +Only simulate the triggering of all GitHub workflows of project [MyFork/bicep-registry-modules] that start with'avm.res.res|ptn|utl', using the current locally checked out branch. Also returns all GitHub status badges. + +.EXAMPLE +Invoke-WorkflowsForBranch -RepositoryOwner 'MyFork' + +Only simulate the triggering of all GitHub workflows of project [MyFork/bicep-registry-modules] that start with'avm.res|ptn|utl.', using the current locally checked out branch and the GitHub CLI. Also returns all GitHub status badges. #> function Invoke-WorkflowsForBranch { [CmdletBinding(SupportsShouldProcess)] param ( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $false)] [string] $PersonalAccessToken, [Parameter(Mandatory = $false)] [string] $TargetBranch = (git branch --show-current), [Parameter(Mandatory = $false)] - [string] $PipelineFilter = 'avm.res.*', + [string] $PipelineFilter = 'avm\.(?:res|ptn|utl)', [Parameter(Mandatory = $false)] [switch] $InvokeForDiff, @@ -230,9 +284,13 @@ function Invoke-WorkflowsForBranch { ) $baseInputObject = @{ - PersonalAccessToken = $PersonalAccessToken - RepositoryOwner = $RepositoryOwner - RepositoryName = $RepositoryName + RepositoryOwner = $RepositoryOwner + RepositoryName = $RepositoryName + } + if ($PersonalAccessToken) { + $baseInputObject['PersonalAccessToken'] = @{ + PersonalAccessToken = $PersonalAccessToken + } } Write-Verbose 'Fetching current GitHub workflows' -Verbose