Родитель
9f9b5ea492
Коммит
5095d47322
|
@ -39,6 +39,9 @@ What's changed since pre-release v1.38.0-B0011:
|
|||
- Azure Kubernetes Service:
|
||||
- Added check to automatically upgrade AKS cluster node image by @sharmilamusunuru.
|
||||
[#2445](https://github.com/Azure/PSRule.Rules.Azure/issues/2445)
|
||||
- Azure Virtual Desktop:
|
||||
- Added check for scheduled agent updates on host pools by @BernieWhite.
|
||||
[#2946](https://github.com/Azure/PSRule.Rules.Azure/issues/2946)
|
||||
- Engineering:
|
||||
- Quality updates to rule documentation by @BernieWhite.
|
||||
[#2570](https://github.com/Azure/PSRule.Rules.Azure/issues/2570)
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
---
|
||||
reviewed: 2024-06-18
|
||||
severity: Important
|
||||
pillar: Reliability
|
||||
category: RE:04 Target metrics
|
||||
resource: Azure Virtual Desktop
|
||||
online version: https://azure.github.io/PSRule.Rules.Azure/en/rules/Azure.AVD.ScheduleAgentUpdate/
|
||||
---
|
||||
|
||||
# Schedule agent updates for host pools
|
||||
|
||||
## SYNOPSIS
|
||||
|
||||
Define a windows for agent updates to minimize disruptions to users.
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
Azure Virtual Desktop (AVD) regularly provide updates to the agent software that runs on host pools.
|
||||
The agent software is responsible for managing user sessions and providing access to resources.
|
||||
These updates provide new functionality and fixes.
|
||||
While the update process is designed to minimize disruptions, updates should be applied outside of peak load times.
|
||||
|
||||
By default, agent updates are applied automatically when they become available.
|
||||
If you have configured a maintenance window, updates are only applied during the maintenance window that you specify.
|
||||
Each host pool can configure up to two maintenance windows per week.
|
||||
|
||||
## RECOMMENDATION
|
||||
|
||||
Consider defining a maintenance window for agent updates to minimize disruptions to users on AVD host pools.
|
||||
|
||||
## EXAMPLES
|
||||
|
||||
### Configure with Azure template
|
||||
|
||||
To deploy host pools that pass this rule:
|
||||
|
||||
- Set the `properties.agentUpdate.type` property to `Scheduled`. _AND_
|
||||
- Configure one or more maintenance windows in the `properties.agentUpdate.maintenanceWindows` property.
|
||||
|
||||
For example:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "Microsoft.DesktopVirtualization/hostPools",
|
||||
"apiVersion": "2024-04-03",
|
||||
"name": "[parameters('name')]",
|
||||
"location": "[parameters('location')]",
|
||||
"identity": {
|
||||
"type": "SystemAssigned"
|
||||
},
|
||||
"properties": {
|
||||
"hostPoolType": "Pooled",
|
||||
"loadBalancerType": "DepthFirst",
|
||||
"preferredAppGroupType": "Desktop",
|
||||
"maxSessionLimit": 10,
|
||||
"agentUpdate": {
|
||||
"type": "Scheduled",
|
||||
"maintenanceWindowTimeZone": "AUS Eastern Standard Time",
|
||||
"maintenanceWindows": [
|
||||
{
|
||||
"dayOfWeek": "Sunday",
|
||||
"hour": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Configure with Bicep
|
||||
|
||||
To deploy host pools that pass this rule:
|
||||
|
||||
- Set the `properties.agentUpdate.type` property to `Scheduled`. _AND_
|
||||
- Configure one or more maintenance windows in the `properties.agentUpdate.maintenanceWindows` property.
|
||||
|
||||
For example:
|
||||
|
||||
```bicep
|
||||
resource pool 'Microsoft.DesktopVirtualization/hostPools@2024-04-03' = {
|
||||
name: name
|
||||
location: location
|
||||
identity: {
|
||||
type: 'SystemAssigned'
|
||||
}
|
||||
properties: {
|
||||
hostPoolType: 'Pooled'
|
||||
loadBalancerType: 'DepthFirst'
|
||||
preferredAppGroupType: 'Desktop'
|
||||
maxSessionLimit: 10
|
||||
agentUpdate: {
|
||||
type: 'Scheduled'
|
||||
maintenanceWindowTimeZone: 'AUS Eastern Standard Time'
|
||||
maintenanceWindows: [
|
||||
{
|
||||
dayOfWeek: 'Sunday'
|
||||
hour: 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<!-- external:avm avm/res/desktop-virtualization/host-pool agentUpdate -->
|
||||
|
||||
## LINKS
|
||||
|
||||
- [RE:04 Target metrics](https://learn.microsoft.com/azure/well-architected/reliability/metrics)
|
||||
- [Get started with the Azure Virtual Desktop Agent](https://learn.microsoft.com/azure/virtual-desktop/agent-overview#agent-update-process)
|
||||
- [Scheduled Agent Updates for Azure Virtual Desktop host pools](https://learn.microsoft.com/azure/virtual-desktop/scheduled-agent-updates)
|
||||
- [What's new in the Azure Virtual Desktop Agent?](https://learn.microsoft.com/azure/virtual-desktop/whats-new-agent)
|
||||
- [Azure deployment reference](https://learn.microsoft.com/azure/templates/microsoft.desktopvirtualization/hostpools)
|
|
@ -0,0 +1,89 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
@description('The name of the resource.')
|
||||
param name string
|
||||
|
||||
@description('The location resources will be deployed.')
|
||||
param location string = resourceGroup().location
|
||||
|
||||
// An example pooled desktop host pool using depth first load balancing.
|
||||
resource pool 'Microsoft.DesktopVirtualization/hostPools@2024-04-03' = {
|
||||
name: name
|
||||
location: location
|
||||
identity: {
|
||||
type: 'SystemAssigned'
|
||||
}
|
||||
properties: {
|
||||
hostPoolType: 'Pooled'
|
||||
loadBalancerType: 'DepthFirst'
|
||||
preferredAppGroupType: 'Desktop'
|
||||
maxSessionLimit: 10
|
||||
agentUpdate: {
|
||||
type: 'Scheduled'
|
||||
maintenanceWindowTimeZone: 'AUS Eastern Standard Time'
|
||||
maintenanceWindows: [
|
||||
{
|
||||
dayOfWeek: 'Sunday'
|
||||
hour: 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// An example scaling plan for a host pool.
|
||||
resource scaling 'Microsoft.DesktopVirtualization/scalingPlans@2024-04-03' = {
|
||||
name: name
|
||||
location: location
|
||||
properties: {
|
||||
timeZone: 'E. Australia Standard Time'
|
||||
hostPoolType: 'Pooled'
|
||||
hostPoolReferences: [
|
||||
{
|
||||
hostPoolArmPath: pool.id
|
||||
scalingPlanEnabled: true
|
||||
}
|
||||
]
|
||||
schedules: [
|
||||
{
|
||||
rampUpStartTime: {
|
||||
hour: 8
|
||||
minute: 0
|
||||
}
|
||||
peakStartTime: {
|
||||
hour: 9
|
||||
minute: 0
|
||||
}
|
||||
rampDownStartTime: {
|
||||
hour: 18
|
||||
minute: 0
|
||||
}
|
||||
offPeakStartTime: {
|
||||
hour: 22
|
||||
minute: 0
|
||||
}
|
||||
name: 'weekdays_schedule'
|
||||
daysOfWeek: [
|
||||
'Monday'
|
||||
'Tuesday'
|
||||
'Wednesday'
|
||||
'Thursday'
|
||||
'Friday'
|
||||
]
|
||||
rampUpLoadBalancingAlgorithm: 'BreadthFirst'
|
||||
rampUpMinimumHostsPct: 20
|
||||
rampUpCapacityThresholdPct: 60
|
||||
peakLoadBalancingAlgorithm: 'DepthFirst'
|
||||
rampDownLoadBalancingAlgorithm: 'DepthFirst'
|
||||
rampDownMinimumHostsPct: 10
|
||||
rampDownCapacityThresholdPct: 90
|
||||
rampDownForceLogoffUsers: true
|
||||
rampDownWaitTimeMinutes: 30
|
||||
rampDownNotificationMessage: 'You will be logged off in 30 min. Make sure to save your work.'
|
||||
rampDownStopHostsWhen: 'ZeroSessions'
|
||||
offPeakLoadBalancingAlgorithm: 'DepthFirst'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
{
|
||||
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"metadata": {
|
||||
"_generator": {
|
||||
"name": "bicep",
|
||||
"version": "0.28.1.47646",
|
||||
"templateHash": "18117889941546285249"
|
||||
}
|
||||
},
|
||||
"parameters": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "The name of the resource."
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"type": "string",
|
||||
"defaultValue": "[resourceGroup().location]",
|
||||
"metadata": {
|
||||
"description": "The location resources will be deployed."
|
||||
}
|
||||
}
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"type": "Microsoft.DesktopVirtualization/hostPools",
|
||||
"apiVersion": "2024-04-03",
|
||||
"name": "[parameters('name')]",
|
||||
"location": "[parameters('location')]",
|
||||
"identity": {
|
||||
"type": "SystemAssigned"
|
||||
},
|
||||
"properties": {
|
||||
"hostPoolType": "Pooled",
|
||||
"loadBalancerType": "DepthFirst",
|
||||
"preferredAppGroupType": "Desktop",
|
||||
"maxSessionLimit": 10,
|
||||
"agentUpdate": {
|
||||
"type": "Scheduled",
|
||||
"maintenanceWindowTimeZone": "AUS Eastern Standard Time",
|
||||
"maintenanceWindows": [
|
||||
{
|
||||
"dayOfWeek": "Sunday",
|
||||
"hour": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.DesktopVirtualization/scalingPlans",
|
||||
"apiVersion": "2024-04-03",
|
||||
"name": "[parameters('name')]",
|
||||
"location": "[parameters('location')]",
|
||||
"properties": {
|
||||
"timeZone": "E. Australia Standard Time",
|
||||
"hostPoolType": "Pooled",
|
||||
"hostPoolReferences": [
|
||||
{
|
||||
"hostPoolArmPath": "[resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('name'))]",
|
||||
"scalingPlanEnabled": true
|
||||
}
|
||||
],
|
||||
"schedules": [
|
||||
{
|
||||
"rampUpStartTime": {
|
||||
"hour": 8,
|
||||
"minute": 0
|
||||
},
|
||||
"peakStartTime": {
|
||||
"hour": 9,
|
||||
"minute": 0
|
||||
},
|
||||
"rampDownStartTime": {
|
||||
"hour": 18,
|
||||
"minute": 0
|
||||
},
|
||||
"offPeakStartTime": {
|
||||
"hour": 22,
|
||||
"minute": 0
|
||||
},
|
||||
"name": "weekdays_schedule",
|
||||
"daysOfWeek": [
|
||||
"Monday",
|
||||
"Tuesday",
|
||||
"Wednesday",
|
||||
"Thursday",
|
||||
"Friday"
|
||||
],
|
||||
"rampUpLoadBalancingAlgorithm": "BreadthFirst",
|
||||
"rampUpMinimumHostsPct": 20,
|
||||
"rampUpCapacityThresholdPct": 60,
|
||||
"peakLoadBalancingAlgorithm": "DepthFirst",
|
||||
"rampDownLoadBalancingAlgorithm": "DepthFirst",
|
||||
"rampDownMinimumHostsPct": 10,
|
||||
"rampDownCapacityThresholdPct": 90,
|
||||
"rampDownForceLogoffUsers": true,
|
||||
"rampDownWaitTimeMinutes": 30,
|
||||
"rampDownNotificationMessage": "You will be logged off in 30 min. Make sure to save your work.",
|
||||
"rampDownStopHostsWhen": "ZeroSessions",
|
||||
"offPeakLoadBalancingAlgorithm": "DepthFirst"
|
||||
}
|
||||
]
|
||||
},
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('name'))]"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -345,6 +345,7 @@ task Rules Dependencies, {
|
|||
As = 'Summary'
|
||||
Outcome = 'Problem'
|
||||
}
|
||||
Import-Module PSRule -RequiredVersion 2.9.0;
|
||||
Import-Module (Join-Path -Path $PWD -ChildPath out/modules/PSRule.Rules.Azure) -Force;
|
||||
Assert-PSRule @assertParams -InputPath $PWD -Module PSRule.Rules.MSFT.OSS -Format File -OutputPath reports/ps-rule-file.xml;
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# Licensed under the MIT License.
|
||||
|
||||
#
|
||||
# Validation rules for Azure Virtual Desktop
|
||||
#
|
||||
|
||||
#region Rules
|
||||
|
||||
---
|
||||
# Synopsis: Define a windows for agent updates to minimize disruptions to users.
|
||||
apiVersion: github.com/microsoft/PSRule/v1
|
||||
kind: Rule
|
||||
metadata:
|
||||
name: Azure.AVD.ScheduleAgentUpdate
|
||||
ref: AZR-000437
|
||||
tags:
|
||||
release: GA
|
||||
ruleSet: 2024_06
|
||||
Azure.WAF/pillar: Reliability
|
||||
spec:
|
||||
type:
|
||||
- Microsoft.DesktopVirtualization/hostPools
|
||||
condition:
|
||||
allOf:
|
||||
- field: properties.agentUpdate.type
|
||||
equals: Scheduled
|
||||
|
||||
- field: properties.agentUpdate.maintenanceWindows
|
||||
greaterOrEquals: 1
|
||||
|
||||
#endregion Rules
|
|
@ -0,0 +1,58 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# Licensed under the MIT License.
|
||||
|
||||
#
|
||||
# Unit tests for Azure Virtual Desktop (AVD) rules
|
||||
#
|
||||
|
||||
[CmdletBinding()]
|
||||
param ()
|
||||
|
||||
BeforeAll {
|
||||
# Setup error handling
|
||||
$ErrorActionPreference = 'Stop';
|
||||
Set-StrictMode -Version latest;
|
||||
|
||||
if ($Env:SYSTEM_DEBUG -eq 'true') {
|
||||
$VerbosePreference = 'Continue';
|
||||
}
|
||||
|
||||
# Setup tests paths
|
||||
$rootPath = $PWD;
|
||||
Import-Module (Join-Path -Path $rootPath -ChildPath out/modules/PSRule.Rules.Azure) -Force;
|
||||
$here = (Resolve-Path $PSScriptRoot).Path;
|
||||
}
|
||||
|
||||
Describe 'Azure.AVD' -Tag 'AVD' {
|
||||
Context 'Conditions' {
|
||||
BeforeAll {
|
||||
$invokeParams = @{
|
||||
Baseline = 'Azure.All'
|
||||
Module = 'PSRule.Rules.Azure'
|
||||
WarningAction = 'Ignore'
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$dataPath = Join-Path -Path $here -ChildPath 'Resources.AVD.json';
|
||||
$result = Invoke-PSRule @invokeParams -InputPath $dataPath;
|
||||
}
|
||||
|
||||
It 'Azure.AVD.ScheduleAgentUpdate' {
|
||||
$filteredResult = $result | Where-Object { $_.RuleName -eq 'Azure.AVD.ScheduleAgentUpdate' };
|
||||
|
||||
# Fail
|
||||
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Fail' });
|
||||
$ruleResult | Should -Not -BeNullOrEmpty;
|
||||
$ruleResult.Length | Should -Be 2;
|
||||
$ruleResult.TargetName | Should -BeIn 'pool-A', 'pool-C';
|
||||
|
||||
$ruleResult[0].Reason | Should -BeExactly "Path properties.agentUpdate.type: The field 'properties.agentUpdate.type' does not exist.";
|
||||
$ruleResult[1].Reason | Should -BeExactly "Path properties.agentUpdate.type: Is set to 'Default'.";
|
||||
|
||||
# Pass
|
||||
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' });
|
||||
$ruleResult | Should -Not -BeNullOrEmpty;
|
||||
$ruleResult.Length | Should -Be 1;
|
||||
$ruleResult.TargetName | Should -BeIn 'pool-B';
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
[
|
||||
{
|
||||
"name": "pool-A",
|
||||
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/rg-test/providers/Microsoft.DesktopVirtualization/hostpools/pool-A",
|
||||
"type": "Microsoft.DesktopVirtualization/hostpools",
|
||||
"location": "region",
|
||||
"properties": {
|
||||
"managedPrivateUDP": "Default",
|
||||
"directUDP": "Default",
|
||||
"publicUDP": "Default",
|
||||
"relayUDP": "Default",
|
||||
"managementType": "Standard",
|
||||
"appAttachPackageReferences": [],
|
||||
"agentUpdate": null,
|
||||
"friendlyName": null,
|
||||
"description": "Created through the Azure Virtual Desktop extension",
|
||||
"hostPoolType": "Pooled",
|
||||
"personalDesktopAssignmentType": null,
|
||||
"applicationGroupReferences": [
|
||||
"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/rg-test/providers/Microsoft.DesktopVirtualization/applicationgroups/pool-A-DAG"
|
||||
],
|
||||
"customRdpProperty": "drivestoredirect:s:*;audiomode:i:0;videoplaybackmode:i:1;redirectclipboard:i:1;redirectprinters:i:1;devicestoredirect:s:*;redirectcomports:i:1;redirectsmartcards:i:1;usbdevicestoredirect:s:*;enablecredsspsupport:i:1;redirectwebauthn:i:1;use multimon:i:1;",
|
||||
"maxSessionLimit": 10,
|
||||
"loadBalancerType": "BreadthFirst",
|
||||
"validationEnvironment": false,
|
||||
"preferredAppGroupType": "Desktop"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "pool-B",
|
||||
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/rg-test/providers/Microsoft.DesktopVirtualization/hostpools/pool-B",
|
||||
"type": "Microsoft.DesktopVirtualization/hostpools",
|
||||
"location": "region",
|
||||
"properties": {
|
||||
"managedPrivateUDP": "Default",
|
||||
"directUDP": "Default",
|
||||
"publicUDP": "Default",
|
||||
"relayUDP": "Default",
|
||||
"managementType": "Standard",
|
||||
"appAttachPackageReferences": [],
|
||||
"agentUpdate": {
|
||||
"type": "Scheduled",
|
||||
"useSessionHostLocalTime": false,
|
||||
"maintenanceWindowTimeZone": "E. Australia Standard Time",
|
||||
"maintenanceWindows": [
|
||||
{
|
||||
"hour": 1,
|
||||
"dayOfWeek": "Sunday"
|
||||
}
|
||||
]
|
||||
},
|
||||
"friendlyName": null,
|
||||
"description": "Created through the Azure Virtual Desktop extension",
|
||||
"hostPoolType": "Pooled",
|
||||
"personalDesktopAssignmentType": null,
|
||||
"applicationGroupReferences": [
|
||||
"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/rg-test/providers/Microsoft.DesktopVirtualization/applicationgroups/pool-B-DAG"
|
||||
],
|
||||
"customRdpProperty": "drivestoredirect:s:*;audiomode:i:0;videoplaybackmode:i:1;redirectclipboard:i:1;redirectprinters:i:1;devicestoredirect:s:*;redirectcomports:i:1;redirectsmartcards:i:1;usbdevicestoredirect:s:*;enablecredsspsupport:i:1;redirectwebauthn:i:1;use multimon:i:1;",
|
||||
"maxSessionLimit": 10,
|
||||
"loadBalancerType": "BreadthFirst",
|
||||
"validationEnvironment": false,
|
||||
"preferredAppGroupType": "Desktop"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "pool-C",
|
||||
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/rg-test/providers/Microsoft.DesktopVirtualization/hostpools/pool-C",
|
||||
"type": "Microsoft.DesktopVirtualization/hostpools",
|
||||
"location": "region",
|
||||
"properties": {
|
||||
"managedPrivateUDP": "Default",
|
||||
"directUDP": "Default",
|
||||
"publicUDP": "Default",
|
||||
"relayUDP": "Default",
|
||||
"managementType": "Standard",
|
||||
"appAttachPackageReferences": [],
|
||||
"agentUpdate": {
|
||||
"type": "Default",
|
||||
"useSessionHostLocalTime": false,
|
||||
"maintenanceWindowTimeZone": "E. Australia Standard Time",
|
||||
"maintenanceWindows": [
|
||||
{
|
||||
"hour": 1,
|
||||
"dayOfWeek": "Sunday"
|
||||
}
|
||||
]
|
||||
},
|
||||
"friendlyName": null,
|
||||
"description": "Created through the Azure Virtual Desktop extension",
|
||||
"hostPoolType": "Pooled",
|
||||
"personalDesktopAssignmentType": null,
|
||||
"applicationGroupReferences": [
|
||||
"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/rg-test/providers/Microsoft.DesktopVirtualization/applicationgroups/pool-C-DAG"
|
||||
],
|
||||
"customRdpProperty": "drivestoredirect:s:*;audiomode:i:0;videoplaybackmode:i:1;redirectclipboard:i:1;redirectprinters:i:1;devicestoredirect:s:*;redirectcomports:i:1;redirectsmartcards:i:1;usbdevicestoredirect:s:*;enablecredsspsupport:i:1;redirectwebauthn:i:1;use multimon:i:1;",
|
||||
"maxSessionLimit": 10,
|
||||
"loadBalancerType": "BreadthFirst",
|
||||
"validationEnvironment": false,
|
||||
"preferredAppGroupType": "Desktop"
|
||||
}
|
||||
}
|
||||
]
|
Загрузка…
Ссылка в новой задаче