scripts/modules/prerequisites/docker/install-docker.ps1
# strangeloop Setup - Docker Installation Module # Version: 1.0.0 param( [switch]${test-only}, [switch]$AutoStart, [switch]$RequiresWSL, [switch]${what-if} ) # Import shared modules $SharedPath = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent | Join-Path -ChildPath "shared" . "$SharedPath\write-functions.ps1" . "$SharedPath\test-functions.ps1" function Test-Docker { param( [switch]$AutoStart ) try { Write-Info "Testing Docker installation..." # Check if Docker command is available if (-not (Test-Command "docker")) { Write-Warning "Docker command not found" return $false } # Check Docker version $dockerVersion = docker --version 2>$null if (-not $dockerVersion) { Write-Warning "Could not get Docker version" return $false } Write-Info "Docker client found: $dockerVersion" # Test Docker daemon connection Write-Info "Testing Docker daemon connection..." $dockerInfo = docker info 2>$null if ($LASTEXITCODE -ne 0) { Write-Warning "Docker daemon is not running" # Try to start Docker Desktop if AutoStart is enabled if ($AutoStart) { Write-Info "Attempting to start Docker Desktop..." try { $dockerDesktopPath = "C:\Program Files\Docker\Docker\Docker Desktop.exe" if (Test-Path $dockerDesktopPath) { Start-Process $dockerDesktopPath -WindowStyle Hidden Write-Info "Docker Desktop startup initiated. Waiting for daemon to start..." # Wait for Docker daemon to start (up to 60 seconds) $timeout = 60 $elapsed = 0 $interval = 3 while ($elapsed -lt $timeout) { Start-Sleep -Seconds $interval $elapsed += $interval $dockerInfo = docker info 2>$null if ($LASTEXITCODE -eq 0) { Write-Success "Docker daemon started successfully" Write-Success "Docker is properly installed and running: $dockerVersion" return $true } Write-Info "Waiting for Docker daemon... ($elapsed/$timeout seconds)" } Write-Warning "Docker daemon did not start within $timeout seconds" Write-Info "Docker Desktop may still be starting. Please wait a few more minutes." return $false } else { Write-Warning "Docker Desktop executable not found at expected location" return $false } } catch { Write-Warning "Failed to start Docker Desktop: $($_.Exception.Message)" return $false } } else { Write-Info "Docker is installed but daemon is not running. Use -AutoStart to automatically start Docker Desktop." return $false } } else { # Docker daemon is running, test basic functionality Write-Info "Testing Docker functionality..." try { # Test if we can run a simple container $testResult = docker run --rm hello-world 2>$null if ($LASTEXITCODE -eq 0) { Write-Success "Docker functionality test passed" } else { Write-Warning "Docker functionality test failed, but daemon is running" } } catch { Write-Warning "Could not test Docker functionality: $($_.Exception.Message)" } Write-Success "Docker is properly installed and running: $dockerVersion" return $true } } catch { Write-Warning "Error testing Docker: $($_.Exception.Message)" return $false } } function Set-DockerWSLIntegration { <# .SYNOPSIS Configures Docker Desktop for WSL integration .DESCRIPTION Enables WSL 2 based engine and default WSL distro integration in Docker Desktop settings .PARAMETER test-only Only test the configuration without making changes .OUTPUTS Boolean indicating success #> param( [switch]${test-only} ) try { Write-Info "Configuring Docker Desktop for WSL integration..." if (${test-only}) { Write-Info "Would configure Docker Desktop WSL integration settings" return $true } # Docker Desktop settings are stored in %APPDATA%\Docker\settings.json $dockerSettingsPath = Join-Path $env:APPDATA "Docker\settings.json" if (-not (Test-Path $dockerSettingsPath)) { Write-Warning "Docker Desktop settings file not found. Docker may need to be started first." Write-Info "WSL integration can be configured manually in Docker Desktop settings:" Write-Info " 1. Open Docker Desktop" Write-Info " 2. Go to Settings -> General -> 'Use the WSL 2 based engine'" Write-Info " 3. Go to Settings -> Resources -> WSL integration -> 'Enable integration with my default WSL distro'" return $false } try { # Read current settings $settingsContent = Get-Content $dockerSettingsPath -Raw | ConvertFrom-Json $settingsModified = $false # Enable WSL 2 based engine if (-not $settingsContent.PSObject.Properties['useWsl2'] -or -not $settingsContent.useWsl2) { Write-Info "Enabling WSL 2 based engine..." $settingsContent | Add-Member -Name "useWsl2" -Value $true -MemberType NoteProperty -Force $settingsModified = $true } else { Write-Info "WSL 2 based engine already enabled" } # Enable default WSL distro integration if (-not $settingsContent.PSObject.Properties['wslEngineEnabled'] -or -not $settingsContent.wslEngineEnabled) { Write-Info "Enabling WSL engine integration..." $settingsContent | Add-Member -Name "wslEngineEnabled" -Value $true -MemberType NoteProperty -Force $settingsModified = $true } else { Write-Info "WSL engine integration already enabled" } # Ensure WSL distros integration object exists if (-not $settingsContent.PSObject.Properties['enableIntegrationWithDefaultWslDistro'] -or -not $settingsContent.enableIntegrationWithDefaultWslDistro) { Write-Info "Enabling integration with default WSL distro..." $settingsContent | Add-Member -Name "enableIntegrationWithDefaultWslDistro" -Value $true -MemberType NoteProperty -Force $settingsModified = $true } else { Write-Info "Default WSL distro integration already enabled" } # Save settings if modified if ($settingsModified) { Write-Progress "Updating Docker Desktop settings..." $settingsContent | ConvertTo-Json -Depth 10 | Set-Content $dockerSettingsPath -Encoding UTF8 Write-Success "Docker Desktop WSL integration settings updated" Write-Info "Note: Docker Desktop may need to be restarted for settings to take effect" } else { Write-Success "Docker Desktop WSL integration already configured" } return $true } catch { Write-Warning "Failed to update Docker settings file: $($_.Exception.Message)" Write-Info "Please configure WSL integration manually in Docker Desktop:" Write-Info " 1. Open Docker Desktop" Write-Info " 2. Go to Settings -> General -> 'Use the WSL 2 based engine'" Write-Info " 3. Go to Settings -> Resources -> WSL integration -> 'Enable integration with my default WSL distro'" return $false } } catch { Write-Warning "Docker WSL integration configuration failed: $($_.Exception.Message)" return $false } } function Install-Docker { param( [switch]${test-only}, [switch]$AutoStart, [switch]$RequiresWSL, [switch]${what-if} ) # If test-only mode, just test current installation if (${test-only}) { return Test-Docker -AutoStart:$AutoStart } # If what-if mode, show what would be done if (${what-if}) { Write-Host "what if: Would test if Docker is already installed" -ForegroundColor Yellow if ($AutoStart) { Write-Host "what if: Would start Docker Desktop if daemon is not running" -ForegroundColor Yellow } if ($RequiresWSL) { Write-Host "what if: Would configure Docker for WSL integration" -ForegroundColor Yellow } Write-Host "what if: Would download Docker Desktop installer if not present" -ForegroundColor Yellow Write-Host "what if: Would install Docker Desktop with silent installation" -ForegroundColor Yellow Write-Host "what if: Would verify Docker installation and daemon connectivity" -ForegroundColor Yellow return $true } Write-Step "Installing Docker Desktop..." try { # Check if Docker is already installed if (Test-Command "docker") { $dockerVersion = docker --version 2>$null if ($dockerVersion) { Write-Success "Docker is already installed: $dockerVersion" # Try to start Docker Desktop if AutoStart is enabled and daemon is not running $dockerInfo = docker info 2>$null if ($LASTEXITCODE -ne 0 -and $AutoStart) { Write-Info "Docker daemon is not running. Attempting to start Docker Desktop..." try { $dockerDesktopPath = "C:\Program Files\Docker\Docker\Docker Desktop.exe" if (Test-Path $dockerDesktopPath) { Start-Process $dockerDesktopPath -WindowStyle Hidden Write-Info "Docker Desktop startup initiated. This may take a few minutes..." Write-Info "Please wait for Docker Desktop to fully start before using Docker commands." } else { Write-Warning "Docker Desktop executable not found at expected location" } } catch { Write-Warning "Failed to start Docker Desktop: $($_.Exception.Message)" } } # Configure WSL integration if required if ($RequiresWSL) { Write-Info "Configuring Docker for WSL integration..." $wslIntegrationResult = Set-DockerWSLIntegration -test-only:${test-only} if ($wslIntegrationResult) { Write-Success "Docker WSL integration configured" } else { Write-Warning "Docker WSL integration configuration failed - may need manual setup" } } return $true } } $installChoice = Read-UserPrompt -Prompt "Docker not found. Install Docker Desktop?" -ValidValues @("y","n") if (-not (Test-YesResponse $installChoice)) { Write-Warning "Skipping Docker installation" return $false } Write-Progress "Installing Docker Desktop..." # Try different installation methods $installSuccess = $false # Method 1: Try winget (Windows Package Manager) if (Test-Command "winget") { try { Write-Info "Installing Docker Desktop via winget..." $result = winget install Docker.DockerDesktop --accept-package-agreements --accept-source-agreements --silent if ($LASTEXITCODE -eq 0) { $installSuccess = $true Write-Success "Docker Desktop installed via winget" } } catch { Write-Warning "winget installation failed: $($_.Exception.Message)" } } # Method 2: Try chocolatey if winget failed if (-not $installSuccess -and (Test-Command "choco")) { try { Write-Info "Installing Docker Desktop via chocolatey..." choco install docker-desktop -y if ($LASTEXITCODE -eq 0) { $installSuccess = $true Write-Success "Docker Desktop installed via chocolatey" } } catch { Write-Warning "Chocolatey installation failed: $($_.Exception.Message)" } } # Method 3: Direct download if package managers failed if (-not $installSuccess) { try { Write-Info "Downloading Docker Desktop installer..." $dockerUrl = "https://desktop.docker.com/win/main/amd64/Docker%20Desktop%20Installer.exe" $installerPath = Join-Path $env:TEMP "DockerDesktopInstaller.exe" # Download with progress $webClient = New-Object System.Net.WebClient $webClient.DownloadFile($dockerUrl, $installerPath) Write-Info "Running Docker Desktop installer..." $installArgs = @("install", "--quiet", "--accept-license") $process = Start-Process -FilePath $installerPath -ArgumentList $installArgs -Wait -PassThru if ($process.ExitCode -eq 0) { $installSuccess = $true Write-Success "Docker Desktop installed via direct download" } else { Write-Warning "Docker installer returned exit code: $($process.ExitCode)" } # Cleanup if (Test-Path $installerPath) { Remove-Item $installerPath -Force } } catch { Write-Warning "Direct download installation failed: $($_.Exception.Message)" } } if ($installSuccess) { Write-Info "Docker Desktop has been installed. You may need to restart your computer." Write-Info "After restart, Docker Desktop will need to be started manually." # Add Docker to PATH if needed $dockerPath = "${env:ProgramFiles}\Docker\Docker\resources\bin" if (Test-Path $dockerPath) { $currentPath = [Environment]::GetEnvironmentVariable("PATH", "Machine") if ($currentPath -notlike "*$dockerPath*") { [Environment]::SetEnvironmentVariable("PATH", "$currentPath;$dockerPath", "Machine") Write-Info "Added Docker to system PATH" } } Write-Success "Docker installation completed" # Configure WSL integration if required if ($RequiresWSL) { Write-Info "Configuring Docker for WSL integration..." $wslIntegrationResult = Set-DockerWSLIntegration -test-only:${test-only} if ($wslIntegrationResult) { Write-Success "Docker WSL integration configured" } else { Write-Warning "Docker WSL integration configuration failed - may need manual setup" } } return $true } else { Write-Error "Failed to install Docker Desktop" Write-Info "Please install Docker Desktop manually from: https://docs.docker.com/desktop/install/windows-install/" return $false } } catch { Write-Error "Docker installation failed: $($_.Exception.Message)" return $false } } # Main execution if ($MyInvocation.InvocationName -ne '.') { $result = Install-Docker -test-only:${test-only} -AutoStart:$AutoStart -RequiresWSL:$RequiresWSL -what-if:${what-if} if ($result) { if (${test-only}) { Write-Success "Docker test completed successfully" } else { Write-Success "Docker installation completed successfully" } exit 0 } else { if (${test-only}) { Write-Error "Docker test failed" } else { Write-Error "Docker installation failed" } exit 1 } } # Export functions for module usage if ($MyInvocation.MyCommand.ModuleName) { Export-ModuleMember -Function @( 'Install-Docker' ) } |