Skip to content

Commit

Permalink
Add offline deployment
Browse files Browse the repository at this point in the history
  • Loading branch information
WillyMoselhy committed Nov 6, 2024
1 parent df7e718 commit 98172f5
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 4 deletions.
10 changes: 9 additions & 1 deletion Build/Build-Zip-File.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,21 @@ $filesToUpdate = @(
BannerPattern = '("uri": "https://github.com/Azure/AVDReplacementPlans/blob/)(.*)(/docs/Permissions.md")'
}
@{
Path = '.\deploy\bicep\modules\deployFunctionApp.bicep'
Path = '.\deploy\bicep\DeployAVDSessionHostReplacer.bicep'
BannerPattern = "(param FunctionAppZipUrl string = 'https://github.com/Azure/AVDSessionHostReplacer/releases/download/)(.*)(/FunctionApp.zip')"
}
@{
Path = '.\docs\CodeDeploy.md'
BannerPattern = "(TemplateUri = 'https://raw.githubusercontent.com/Azure/AVDSessionHostReplacer/)(.+)(/deploy/arm/DeployAVDSessionHostReplacer.json')"
}
@{
Path = '.\docs\CodeDeploy-offline.md'
BannerPattern = "(\* \[DeployAVDSessionHostReplacer.json\]\(https://github.com/Azure/AVDSessionHostReplacer/releases/download/)(.+)(/DeployAVDSessionHostReplacer.json\))"
}
@{
Path = '.\docs\CodeDeploy-offline.md'
BannerPattern = "(\* \[FunctionApp.zip\]\(https://github.com/Azure/AVDSessionHostReplacer/releases/download/)(.+)(/FunctionApp.zip\))"
}
)

foreach($file in $filesToUpdate){
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ the AVD Session Host Replacer helps you manage the task of replacing old session
| :------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Azure Portal UI | [![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAVDSessionHostReplacer%2Fv0.3.0%2Fdeploy%2Farm%2FDeployAVDSessionHostReplacer.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAVDSessionHostReplacer%2Fv0.3.0%2Fdeploy%2Fportal-ui%2Fportal-ui.json) [![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAVDSessionHostReplacer%2Fv0.3.0%2Fdeploy%2Farm%2FDeployAVDSessionHostReplacer.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAVDSessionHostReplacer%2Fv0.3.0%2Fdeploy%2Fportal-ui%2Fportal-ui.json) [![Deploy to Azure China](https://aka.ms/deploytoazurechinabutton)](https://portal.azure.cn/#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAVDSessionHostReplacer%2Fv0.3.0%2Fdeploy%2Farm%2FDeployAVDSessionHostReplacer.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAVDSessionHostReplacer%2Fv0.3.0%2Fdeploy%2Fportal-ui%2Fportal-ui.json) |
| Command line (Bicep/ARM) | [![Powershell/Azure CLI](./docs/icons/powershell.png)](./docs/CodeDeploy.md)
| Offline Deployment | [![Offline Deployment](./docs/icons/powershell.png)](./docs/CodeDeploy-offline.md) |

## Pre-requisites
The Session Host Replacer requires permissions to manage resources in Azure and, if the session hosts are Entra joined, permissions in Entra. The recommended approach is to create a User Managed Identity, assign the necessary permissions to it, and use it for all instances of the Session Host Replacer.
Expand Down
12 changes: 12 additions & 0 deletions deploy/bicep/DeployAVDSessionHostReplacer.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@
@description('Required: No | Region of the Function App. This does not need to be the same as the location of the Azure Virtual Desktop Host Pool. | Default: Location of the resource group.')
param Location string = resourceGroup().location

// FunctionApp
@description('Required: No | Boolean to enable offline deployment of the Function App. | Default: false')
param OfflineDeploy bool = false

@description('Required: No | URL of the FunctionApp.zip file. This is the zip file containing the Function App code. Must be provided when OfflineDeploy is set to false | Default: The latest release of the Function App code.')
param FunctionAppZipUrl string = 'https://github.com/Azure/AVDSessionHostReplacer/releases/download/v0.3.0/FunctionApp.zip'

//Monitoring
param EnableMonitoring bool = true
param UseExistingLAW bool = false
Expand Down Expand Up @@ -447,6 +454,8 @@ module deployFunctionApp 'modules/deployFunctionApp.bicep' = {
name: 'deployFunctionApp'
params: {
Location: Location
OfflineDeploy: OfflineDeploy
FunctionAppZipUrl: FunctionAppZipUrl
FunctionAppName: varFunctionAppName
EnableMonitoring: EnableMonitoring
UseExistingLAW: UseExistingLAW
Expand Down Expand Up @@ -491,3 +500,6 @@ module RBACTemplateSpec 'modules/RBACRoleAssignment.bicep' = if (!UseUserAssigne
Scope: deployStandardSessionHostTemplate.outputs.TemplateSpecResourceId
}
}

//---- Outputs ----//
output functionAppName string = varFunctionAppName
9 changes: 6 additions & 3 deletions deploy/bicep/modules/deployFunctionApp.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@ param LogAnalyticsWorkspaceId string = 'none'
@description('Required: Yes | Name of the Function App.')
param FunctionAppName string

@description('Required: No | URL of the FunctionApp.zip file. This is the zip file containing the Function App code. | Default: The latest release of the Function App code.')
param FunctionAppZipUrl string = 'https://github.com/Azure/AVDSessionHostReplacer/releases/download/v0.3.0/FunctionApp.zip'
@description('Required: No | Boolean to enable offline deployment of the Function App. | Default: false')
param OfflineDeploy bool = false

@description('Required: No | URL of the FunctionApp.zip file. This is the zip file containing the Function App code. Must be provided when OfflineDeploy is set to false | Default: Empty')
param FunctionAppZipUrl string = ''

@description('Required: No | App Service Plan Name | Default: Y1 for consumption based plan')
param AppPlanName string = 'Y1'
Expand Down Expand Up @@ -182,7 +185,7 @@ resource functionApp 'Microsoft.Web/sites@2023-01-01' = {
}
}
}
resource deployFromZip 'extensions@2023-01-01' = {
resource deployFromZip 'extensions@2023-12-01' = if (!OfflineDeploy) {
name: 'MSDeploy'
properties: {
packageUri: FunctionAppZipUrl
Expand Down
93 changes: 93 additions & 0 deletions docs/CodeDeploy-offline.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Code Deployment
## AVD Session Host Replacer with all parameters
This code deploys the AVD Session Host Replacer without dependency on GitHub. Remember to assign the [needed permissions](Permissions.md).

Required Files:
* [DeployAVDSessionHostReplacer.json](https://github.com/Azure/AVDSessionHostReplacer/releases/download/v0.3.0/DeployAVDSessionHostReplacer.json)
* [FunctionApp.zip](https://github.com/Azure/AVDSessionHostReplacer/releases/download/v0.3.0/FunctionApp.zip)

### PowerShell
```PowerShell
$ResourceGroupName = '<Target Resource Group Name>' # Same as the Host Pool RG
$TemplateParameters = @{
OfflineDeploy = $true
EnableMonitoring = $true
UseExistingLAW = $false
# LogAnalyticsWorkspaceId = '' # Only required if UseExistingLAW is $true. Use ResourceID
## Required Parameters ##
HostPoolName = '<Target Host Pool Name>'
HostPoolResourceGroupName = $ResourceGroupName
SessionHostNamePrefix = 'avdshr' # Will be appended by '-XX'
TargetSessionHostCount = 10 # How many session hosts to maintain in the Host Pool
TargetSessionHostBuffer = 5 # The maximum number of session hosts to add during a replacement process
IncludePreExistingSessionHosts = $false # Include existing session hosts in automation
# Identity
# Using a User Managed Identity is recommended. You can assign the same identity to different instances of session host replacer instances. The identity should have the proper permissions in Azure and Entra.
# The identity can be in a different Azure Subscription. If not used, a system assigned identity will be created and assigned permissions against the current subscription.
UseUserAssignedManagedIdentity = $true
UserAssignedManagedIdentityResourceId = '<Resource Id of the User Assigned Managed Identity>'
## Session Host Template Parameters ##
SessionHostsRegion = 'NorthEurope' # Does not have to be the same as Host Pool
AvailabilityZones = @("1", "3") # Set to empty array if not using AZs
SessionHostSize = 'Standard_D4ds_v5' # Make sure its available in the region / AZs
AcceleratedNetworking = $true # Make sure the size supports it
SessionHostDiskType = 'Premium_LRS' # STandard_LRS, StandardSSD_LRS, or Premium_LRS
MarketPlaceOrCustomImage = 'Marketplace' # MarketPlace or Gallery
MarketPlaceImage = 'win11-23h2-avd-m365'
# If the Compute Gallery is in a different subscription assign the function app "Desktop Virtualization Virtual Machine Contributor" after deployment
# GalleryImageId = '' # Only required for 'CustomImage'. Use ResourceId of an Image Definition.
SecurityType = 'TrustedLaunch' # Standard, TrustedLaunch, or ConfidentialVM
SecureBootEnabled = $true
TpmEnabled = $true
SubnetId = '<Resource Id, make sure it ends with /subnets/<subnetName>>'
IdentityServiceProvider = 'EntraID' # EntraID / ActiveDirectory / EntraDS
IntuneEnrollment = $false # This is only used when IdentityServiceProvider is EntraID
# Only used when IdentityServiceProvider is ActiveDirectory or EntraDS
#ADDomainName = 'contoso.com'
#ADDomainJoinUserName = 'DomainJoin'
#ADJoinUserPassword = 'P@ssw0rd' # We will store this password in a key vault
#ADOUPath = '' # OU DN where the session hosts will be joined
LocalAdminUserName = 'AVDAdmin' # The password is randomly generated. Please use LAPS or reset from Azure Portal.
## Optional Parameters ##
TagIncludeInAutomation = 'IncludeInAutoReplace'
TagDeployTimestamp = 'AutoReplaceDeployTimestamp'
TagPendingDrainTimestamp = 'AutoReplacePendingDrainTimestamp'
TagScalingPlanExclusionTag = 'ScalingPlanExclusion' # This is used to disable scaling plan on session hosts pending delete.
TargetVMAgeDays = 45 # Set this to 0 to never consider hosts to be old. Not recommended as you may use it to force replace.
DrainGracePeriodHours = 24
FixSessionHostTags = $true
SHRDeploymentPrefix = 'AVDSessionHostReplacer'
SessionHostInstanceNumberPadding = 2 # this controls the name, 2=> -01 or 3=> -001
ReplaceSessionHostOnNewImageVersion = $true #Set this to false when you only want to replace when the hosts are old (see TargetVMAgeDays)
ReplaceSessionHostOnNewImageVersionDelayDays = 0
VMNamesTemplateParameterName = 'VMNames' # Do not change this unless using a custom Template to deploy
SessionHostResourceGroupName = '' # Leave empty if same as HostPoolResourceGroupName
}
$paramNewAzResourceGroupDeployment = @{
Name = 'AVDSessionHostReplacer'
ResourceGroupName = $ResourceGroupName
TemplateFile = '<Path_TO_DeployAVDSessionHostReplacer.json>'
TemplateParameterObject = $TemplateParameters
}
$deploy = New-AzResourceGroupDeployment @paramNewAzResourceGroupDeployment
$null = Publish-AzWebapp -ResourceGroupName $ResourceGroupName -Name $deploy.Outputs.functionAppName.Value -ArchivePath "<PATH_TO_FunctionApp.zip>" -Force
```

0 comments on commit 98172f5

Please sign in to comment.