-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add Amazon DCV Windows module (#345)
- Loading branch information
Showing
5 changed files
with
305 additions
and
0 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
--- | ||
display_name: Amazon DCV Windows | ||
description: Amazon DCV Server and Web Client for Windows | ||
icon: ../.icons/dcv.svg | ||
maintainer_github: coder | ||
verified: true | ||
tags: [windows, amazon, dcv, web, desktop] | ||
--- | ||
|
||
# Amazon DCV Windows | ||
|
||
Amazon DCV is high performance remote display protocol that provides a secure way to deliver remote desktop and application streaming from any cloud or data center to any device, over varying network conditions. | ||
|
||
![Amazon DCV on a Windows workspace](../.images/amazon-dcv-windows.png) | ||
|
||
Enable DCV Server and Web Client on Windows workspaces. | ||
|
||
```tf | ||
module "dcv" { | ||
count = data.coder_workspace.me.start_count | ||
source = "registry.coder.com/modules/amazon-dcv-windows/coder" | ||
version = "1.0.24" | ||
agent_id = resource.coder_agent.main.id | ||
} | ||
resource "coder_metadata" "dcv" { | ||
count = data.coder_workspace.me.start_count | ||
resource_id = aws_instance.dev.id # id of the instance resource | ||
item { | ||
key = "DCV client instructions" | ||
value = "Run `coder port-forward ${data.coder_workspace.me.name} -p ${module.dcv[count.index].port}` and connect to **localhost:${module.dcv[count.index].port}${module.dcv[count.index].web_url_path}**" | ||
} | ||
item { | ||
key = "username" | ||
value = module.dcv[count.index].username | ||
} | ||
item { | ||
key = "password" | ||
value = module.dcv[count.index].password | ||
sensitive = true | ||
} | ||
} | ||
``` | ||
|
||
## License | ||
|
||
Amazon DCV is free to use on AWS EC2 instances but requires a license for other cloud providers. Please see the instructions [here](https://docs.aws.amazon.com/dcv/latest/adminguide/setting-up-license.html#setting-up-license-ec2) for more information. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
# Terraform variables | ||
$adminPassword = "${admin_password}" | ||
$port = "${port}" | ||
$webURLPath = "${web_url_path}" | ||
|
||
function Set-LocalAdminUser { | ||
Write-Output "[INFO] Starting Set-LocalAdminUser function" | ||
$securePassword = ConvertTo-SecureString $adminPassword -AsPlainText -Force | ||
Write-Output "[DEBUG] Secure password created" | ||
Get-LocalUser -Name Administrator | Set-LocalUser -Password $securePassword | ||
Write-Output "[INFO] Administrator password set" | ||
Get-LocalUser -Name Administrator | Enable-LocalUser | ||
Write-Output "[INFO] User Administrator enabled successfully" | ||
Read-Host "[DEBUG] Press Enter to proceed to the next step" | ||
} | ||
|
||
function Get-VirtualDisplayDriverRequired { | ||
Write-Output "[INFO] Starting Get-VirtualDisplayDriverRequired function" | ||
$token = Invoke-RestMethod -Headers @{'X-aws-ec2-metadata-token-ttl-seconds' = '21600'} -Method PUT -Uri http://169.254.169.254/latest/api/token | ||
Write-Output "[DEBUG] Token acquired: $token" | ||
$instanceType = Invoke-RestMethod -Headers @{'X-aws-ec2-metadata-token' = $token} -Method GET -Uri http://169.254.169.254/latest/meta-data/instance-type | ||
Write-Output "[DEBUG] Instance type: $instanceType" | ||
$OSVersion = ((Get-ItemProperty -Path "Microsoft.PowerShell.Core\Registry::\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name ProductName).ProductName) -replace "[^0-9]", '' | ||
Write-Output "[DEBUG] OS version: $OSVersion" | ||
|
||
# Force boolean result | ||
$result = (($OSVersion -ne "2019") -and ($OSVersion -ne "2022") -and ($OSVersion -ne "2025")) -and (($instanceType[0] -ne 'g') -and ($instanceType[0] -ne 'p')) | ||
Write-Output "[INFO] VirtualDisplayDriverRequired result: $result" | ||
Read-Host "[DEBUG] Press Enter to proceed to the next step" | ||
return [bool]$result | ||
} | ||
|
||
function Download-DCV { | ||
param ( | ||
[bool]$VirtualDisplayDriverRequired | ||
) | ||
Write-Output "[INFO] Starting Download-DCV function" | ||
|
||
$downloads = @( | ||
@{ | ||
Name = "DCV Display Driver" | ||
Required = $VirtualDisplayDriverRequired | ||
Path = "C:\Windows\Temp\DCVDisplayDriver.msi" | ||
Uri = "https://d1uj6qtbmh3dt5.cloudfront.net/nice-dcv-virtual-display-x64-Release.msi" | ||
}, | ||
@{ | ||
Name = "DCV Server" | ||
Required = $true | ||
Path = "C:\Windows\Temp\DCVServer.msi" | ||
Uri = "https://d1uj6qtbmh3dt5.cloudfront.net/nice-dcv-server-x64-Release.msi" | ||
} | ||
) | ||
|
||
foreach ($download in $downloads) { | ||
if ($download.Required -and -not (Test-Path $download.Path)) { | ||
try { | ||
Write-Output "[INFO] Downloading $($download.Name)" | ||
|
||
# Display progress manually (no events) | ||
$progressActivity = "Downloading $($download.Name)" | ||
$progressStatus = "Starting download..." | ||
Write-Progress -Activity $progressActivity -Status $progressStatus -PercentComplete 0 | ||
|
||
# Synchronously download the file | ||
$webClient = New-Object System.Net.WebClient | ||
$webClient.DownloadFile($download.Uri, $download.Path) | ||
|
||
# Update progress | ||
Write-Progress -Activity $progressActivity -Status "Completed" -PercentComplete 100 | ||
|
||
Write-Output "[INFO] $($download.Name) downloaded successfully." | ||
} catch { | ||
Write-Output "[ERROR] Failed to download $($download.Name): $_" | ||
throw | ||
} | ||
} else { | ||
Write-Output "[INFO] $($download.Name) already exists. Skipping download." | ||
} | ||
} | ||
|
||
Write-Output "[INFO] All downloads completed" | ||
Read-Host "[DEBUG] Press Enter to proceed to the next step" | ||
} | ||
|
||
function Install-DCV { | ||
param ( | ||
[bool]$VirtualDisplayDriverRequired | ||
) | ||
Write-Output "[INFO] Starting Install-DCV function" | ||
|
||
if (-not (Get-Service -Name "dcvserver" -ErrorAction SilentlyContinue)) { | ||
if ($VirtualDisplayDriverRequired) { | ||
Write-Output "[INFO] Installing DCV Display Driver" | ||
Start-Process "C:\Windows\System32\msiexec.exe" -ArgumentList "/I C:\Windows\Temp\DCVDisplayDriver.msi /quiet /norestart" -Wait | ||
} else { | ||
Write-Output "[INFO] DCV Display Driver installation skipped (not required)." | ||
} | ||
Write-Output "[INFO] Installing DCV Server" | ||
Start-Process "C:\Windows\System32\msiexec.exe" -ArgumentList "/I C:\Windows\Temp\DCVServer.msi ADDLOCAL=ALL /quiet /norestart /l*v C:\Windows\Temp\dcv_install_msi.log" -Wait | ||
} else { | ||
Write-Output "[INFO] DCV Server already installed, skipping installation." | ||
} | ||
|
||
# Wait for the service to appear with a timeout | ||
$timeout = 10 # seconds | ||
$elapsed = 0 | ||
while (-not (Get-Service -Name "dcvserver" -ErrorAction SilentlyContinue) -and ($elapsed -lt $timeout)) { | ||
Start-Sleep -Seconds 1 | ||
$elapsed++ | ||
} | ||
|
||
if ($elapsed -ge $timeout) { | ||
Write-Output "[WARNING] Timeout waiting for dcvserver service. A restart is required to complete installation." | ||
Restart-SystemForDCV | ||
} else { | ||
Write-Output "[INFO] dcvserver service detected successfully." | ||
} | ||
} | ||
|
||
function Restart-SystemForDCV { | ||
Write-Output "[INFO] The system will restart in 10 seconds to finalize DCV installation." | ||
Start-Sleep -Seconds 10 | ||
|
||
# Initiate restart | ||
Restart-Computer -Force | ||
|
||
# Exit the script after initiating restart | ||
Write-Output "[INFO] Please wait for the system to restart..." | ||
|
||
Exit 1 | ||
} | ||
|
||
|
||
function Configure-DCV { | ||
Write-Output "[INFO] Starting Configure-DCV function" | ||
$dcvPath = "Microsoft.PowerShell.Core\Registry::\HKEY_USERS\S-1-5-18\Software\GSettings\com\nicesoftware\dcv" | ||
|
||
# Create the required paths | ||
@("$dcvPath\connectivity", "$dcvPath\session-management", "$dcvPath\session-management\automatic-console-session", "$dcvPath\display") | ForEach-Object { | ||
if (-not (Test-Path $_)) { | ||
New-Item -Path $_ -Force | Out-Null | ||
} | ||
} | ||
|
||
# Set registry keys | ||
New-ItemProperty -Path "$dcvPath\session-management" -Name create-session -PropertyType DWORD -Value 1 -Force | ||
New-ItemProperty -Path "$dcvPath\session-management\automatic-console-session" -Name owner -Value Administrator -Force | ||
New-ItemProperty -Path "$dcvPath\connectivity" -Name quic-port -PropertyType DWORD -Value $port -Force | ||
New-ItemProperty -Path "$dcvPath\connectivity" -Name web-port -PropertyType DWORD -Value $port -Force | ||
New-ItemProperty -Path "$dcvPath\connectivity" -Name web-url-path -PropertyType String -Value $webURLPath -Force | ||
|
||
# Attempt to restart service | ||
if (Get-Service -Name "dcvserver" -ErrorAction SilentlyContinue) { | ||
Restart-Service -Name "dcvserver" | ||
} else { | ||
Write-Output "[WARNING] dcvserver service not found. Ensure the system was restarted properly." | ||
} | ||
|
||
Write-Output "[INFO] DCV configuration completed" | ||
Read-Host "[DEBUG] Press Enter to proceed to the next step" | ||
} | ||
|
||
# Main Script Execution | ||
Write-Output "[INFO] Starting script" | ||
$VirtualDisplayDriverRequired = [bool](Get-VirtualDisplayDriverRequired) | ||
Set-LocalAdminUser | ||
Download-DCV -VirtualDisplayDriverRequired $VirtualDisplayDriverRequired | ||
Install-DCV -VirtualDisplayDriverRequired $VirtualDisplayDriverRequired | ||
Configure-DCV | ||
Write-Output "[INFO] Script completed" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
terraform { | ||
required_version = ">= 1.0" | ||
|
||
required_providers { | ||
coder = { | ||
source = "coder/coder" | ||
version = ">= 0.17" | ||
} | ||
} | ||
} | ||
|
||
variable "agent_id" { | ||
type = string | ||
description = "The ID of a Coder agent." | ||
} | ||
|
||
variable "admin_password" { | ||
type = string | ||
default = "coderDCV!" | ||
sensitive = true | ||
} | ||
|
||
variable "port" { | ||
type = number | ||
description = "The port number for the DCV server." | ||
default = 8443 | ||
} | ||
|
||
variable "subdomain" { | ||
type = bool | ||
description = "Whether to use a subdomain for the DCV server." | ||
default = true | ||
} | ||
|
||
variable "slug" { | ||
type = string | ||
description = "The slug of the web-dcv coder_app resource." | ||
default = "web-dcv" | ||
} | ||
|
||
resource "coder_app" "web-dcv" { | ||
agent_id = var.agent_id | ||
slug = var.slug | ||
display_name = "Web DCV" | ||
url = "https://localhost:${var.port}${local.web_url_path}?username=${local.admin_username}&password=${var.admin_password}" | ||
icon = "/icon/dcv.svg" | ||
subdomain = var.subdomain | ||
} | ||
|
||
resource "coder_script" "install-dcv" { | ||
agent_id = var.agent_id | ||
display_name = "Install DCV" | ||
icon = "/icon/dcv.svg" | ||
run_on_start = true | ||
script = templatefile("${path.module}/install-dcv.ps1", { | ||
admin_password : var.admin_password, | ||
port : var.port, | ||
web_url_path : local.web_url_path | ||
}) | ||
} | ||
|
||
data "coder_workspace" "me" {} | ||
data "coder_workspace_owner" "me" {} | ||
|
||
locals { | ||
web_url_path = var.subdomain ? "/" : format("/@%s/%s/apps/%s", data.coder_workspace_owner.me.name, data.coder_workspace.me.name, var.slug) | ||
admin_username = "Administrator" | ||
} | ||
|
||
output "web_url_path" { | ||
value = local.web_url_path | ||
} | ||
|
||
output "username" { | ||
value = local.admin_username | ||
} | ||
|
||
output "password" { | ||
value = var.admin_password | ||
sensitive = true | ||
} | ||
|
||
output "port" { | ||
value = var.port | ||
} |