From 1a080672e95f7a98778b49200112c0ad8102aa61 Mon Sep 17 00:00:00 2001 From: Lili Deng Date: Tue, 12 May 2026 10:01:31 +0800 Subject: [PATCH 1/2] Add quick-install WSL installer script --- installers/quick-install-wsl.ps1 | 82 ++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 installers/quick-install-wsl.ps1 diff --git a/installers/quick-install-wsl.ps1 b/installers/quick-install-wsl.ps1 new file mode 100644 index 0000000000..d908e64526 --- /dev/null +++ b/installers/quick-install-wsl.ps1 @@ -0,0 +1,82 @@ +# Quick Install Script for Microsoft LISA inside WSL (from Windows host) +# This bootstraps WSL if missing, then runs quick-install.sh inside the chosen +# WSL distribution. Useful for Windows users who prefer the Linux toolchain. + +[CmdletBinding()] +param ( + [string]$Distro = "Ubuntu", + [string]$Branch = "main", + [string]$InstallPath = "/home/`$USER/lisa", + [switch]$SkipWslInstall +) + +$ErrorActionPreference = "Stop" + +Write-Host "===== Microsoft LISA Quick Install (WSL bootstrap) =====" -ForegroundColor Cyan +Write-Host "Target distro: $Distro" -ForegroundColor Cyan +Write-Host "LISA branch: $Branch" -ForegroundColor Cyan + +# Step 1: Verify wsl.exe is available +$wslCmd = Get-Command wsl.exe -ErrorAction SilentlyContinue +if (-not $wslCmd) { + Write-Host "[ERROR] wsl.exe not found. Windows 10 (build 19041+) or Windows 11 is required." -ForegroundColor Red + Write-Host "Enable WSL via Settings > Apps > Optional features, or run as Administrator:" -ForegroundColor Yellow + Write-Host " wsl --install" -ForegroundColor Yellow + exit 1 +} + +# Step 2: Check whether the requested distro is already installed +$installedDistros = @() +try { + # wsl --list -q emits UTF-16; pipe through Out-String to normalize + $rawList = & wsl.exe --list --quiet 2>$null | Out-String + $installedDistros = $rawList -split "`r?`n" | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne "" } +} +catch { + Write-Host "[WARN] Could not list installed WSL distributions: $_" -ForegroundColor Yellow +} + +$distroInstalled = $installedDistros -contains $Distro + +if (-not $distroInstalled) { + if ($SkipWslInstall) { + Write-Host "[ERROR] Distro '$Distro' is not installed and -SkipWslInstall was passed." -ForegroundColor Red + Write-Host "Installed distros: $($installedDistros -join ', ')" -ForegroundColor Yellow + exit 1 + } + Write-Host "`n[1/2] Distro '$Distro' is not installed. Installing now..." -ForegroundColor Yellow + Write-Host " This requires Administrator privileges and a reboot may be needed." -ForegroundColor Yellow + Write-Host " Running: wsl --install -d $Distro --no-launch" -ForegroundColor Gray + & wsl.exe --install -d $Distro --no-launch + if ($LASTEXITCODE -ne 0) { + Write-Host "[ERROR] 'wsl --install -d $Distro' failed (exit $LASTEXITCODE)." -ForegroundColor Red + Write-Host "Run PowerShell as Administrator and retry, or install the distro manually from the Microsoft Store." -ForegroundColor Yellow + exit 1 + } + Write-Host "`n[ACTION REQUIRED] WSL has been provisioned." -ForegroundColor Cyan + Write-Host " 1. Launch the '$Distro' app from the Start menu to create a UNIX user/password." -ForegroundColor Cyan + Write-Host " 2. Re-run this script after the user is created." -ForegroundColor Cyan + exit 0 +} +else { + Write-Host "`n[1/2] Distro '$Distro' is already installed." -ForegroundColor Green +} + +# Step 3: Run quick-install.sh inside the distro +Write-Host "`n[2/2] Running LISA quick-install.sh inside '$Distro'..." -ForegroundColor Yellow + +$scriptUrl = "https://raw.githubusercontent.com/microsoft/lisa/$Branch/installers/quick-install.sh" +# Pass the install path verbatim into bash; the literal $USER will be expanded +# inside the WSL shell, not in PowerShell. +$bashCmd = "set -e; curl -fsSL '$scriptUrl' -o /tmp/lisa-quick-install.sh && bash /tmp/lisa-quick-install.sh --install-path `"$InstallPath`" --branch '$Branch' --use-venv true" + +& wsl.exe -d $Distro -- bash -c $bashCmd +if ($LASTEXITCODE -ne 0) { + Write-Host "[ERROR] LISA installation inside WSL failed (exit $LASTEXITCODE)." -ForegroundColor Red + exit 1 +} + +Write-Host "`n===== Installation Completed =====" -ForegroundColor Green +Write-Host "Run LISA from PowerShell with:" -ForegroundColor Cyan +Write-Host " wsl -d $Distro -- lisa --help" -ForegroundColor White +Write-Host "Or open a WSL shell and run 'lisa' directly." -ForegroundColor Cyan From bac2e20875600c8364f6f44e7afd92cbedab6ab6 Mon Sep 17 00:00:00 2001 From: Lili Deng Date: Wed, 13 May 2026 10:53:39 +0800 Subject: [PATCH 2/2] Add Windows dev quick-install script and document WSL/Dev installers - installers/quick-install-dev.ps1: Windows-native dev install (clone, .venv, pip install -e .[azure,libvirt], writes .vscode/launch.json + settings.json for F5 debug; libvirt extra auto-falls back, -SkipLibvirt/-NoClone/-SkipLaunchJson switches) - .github/prompts/install-lisa.prompt.md: add WSL Bootstrap and Windows Dev sections; add troubleshooting entry for debugpy F5 hang when system Python is used instead of the venv --- .github/prompts/install-lisa.prompt.md | 110 +++++++++++ installers/quick-install-dev.ps1 | 244 +++++++++++++++++++++++++ 2 files changed, 354 insertions(+) create mode 100644 installers/quick-install-dev.ps1 diff --git a/.github/prompts/install-lisa.prompt.md b/.github/prompts/install-lisa.prompt.md index c3739b7047..184a2087be 100644 --- a/.github/prompts/install-lisa.prompt.md +++ b/.github/prompts/install-lisa.prompt.md @@ -142,6 +142,107 @@ chmod +x quick-install.sh --- +## WSL Bootstrap (from Windows) + +Use when you want LISA to run inside WSL but you're driving everything from a +Windows PowerShell prompt. The script will install the requested distro via +`wsl --install` (if missing), then run `quick-install.sh` inside it. + +```powershell +# Default: Ubuntu, main branch +.\installers\quick-install-wsl.ps1 + +# Custom distro / branch / install path inside WSL +.\installers\quick-install-wsl.ps1 -Distro Ubuntu-22.04 -Branch main -InstallPath '/home/$USER/lisa' + +# Distro must already exist; never run wsl --install +.\installers\quick-install-wsl.ps1 -SkipWslInstall +``` + +### Available Parameters + +| Parameter | Default | Description | +|---|---|---| +| `-Distro` | `Ubuntu` | WSL distro name (must match `wsl --list --quiet`) | +| `-Branch` | `main` | Git branch of `microsoft/lisa` to install | +| `-InstallPath` | `/home/$USER/lisa` | Install directory inside WSL (literal `$USER` expanded in WSL) | +| `-SkipWslInstall` | (switch) | Fail instead of running `wsl --install` | + +### What the script does + +1. Verifies `wsl.exe` is available on the host. +2. If the requested distro is not installed, runs `wsl --install -d --no-launch` (needs Administrator) and exits so the user can create a UNIX user. +3. Downloads `installers/quick-install.sh` from the chosen branch and runs it inside WSL with `--use-venv true`. +4. After install, run LISA from PowerShell with `wsl -d -- lisa --help`, or open a WSL shell. + +### When to use it + +- You don't want to maintain a Linux install yourself. +- You need the full Linux toolchain (`libvirt`, native deps) but only have a Windows machine. +- Avoid for live debugging — use the **Windows Dev** flow below for VS Code F5 debug. + +--- + +## Windows Dev Environment (VS Code F5 debug) + +Use when you want a Windows-native, editable LISA install you can step through +in VS Code without WSL. Sets up `.venv`, installs `pip install -e .[azure,libvirt]`, +and writes `.vscode/launch.json` + `.vscode/settings.json` so F5 just works. + +```powershell +# Default: clone microsoft/lisa to %USERPROFILE%\lisa +.\installers\quick-install-dev.ps1 + +# Custom path & branch +.\installers\quick-install-dev.ps1 -InstallPath C:\code\lisa -Branch main + +# Reuse existing checkout (your current LISA repo) +.\installers\quick-install-dev.ps1 -InstallPath C:\code\lisa -NoClone + +# Skip libvirt extra (libvirt-python often fails to build on Windows) +.\installers\quick-install-dev.ps1 -SkipLibvirt + +# Don't overwrite existing launch.json +.\installers\quick-install-dev.ps1 -SkipLaunchJson +``` + +### Available Parameters + +| Parameter | Default | Description | +|---|---|---| +| `-InstallPath` | `$env:USERPROFILE\lisa` | LISA checkout location | +| `-Branch` | `main` | Git branch to clone | +| `-PythonVersion` | `3.12` | Python version expected on host (installed via winget if missing) | +| `-NoClone` | (switch) | Reuse existing checkout at `-InstallPath` | +| `-SkipLibvirt` | (switch) | Install only `[azure]` extra; skip `[libvirt]` | +| `-SkipLaunchJson` | (switch) | Do not write `.vscode/launch.json` / `settings.json` | + +### What the script does + +1. Locates Python via `py -` or `python.exe`; installs `Python.Python.` through winget if absent. +2. Clones (or fast-forwards) `microsoft/lisa@` into `-InstallPath`. +3. Creates `.venv`, upgrades `pip setuptools wheel`, runs `pip install --editable ".[azure,libvirt]"` (auto-falls back to `[azure]` if libvirt build fails). +4. Writes `.vscode/settings.json` pinning `python.defaultInterpreterPath` to the venv, and `.vscode/launch.json` with two `debugpy` configs: + - `Python: lisa (module)` — runs `python -m lisa -r lisa/examples/runbook/hello_world.yml -d`. + - `Python: Current File` — debug whatever script is open. +5. Existing `launch.json` / `settings.json` are backed up to `*.bak`. + +### Verifying the dev install + +```powershell +& "$env:USERPROFILE\lisa\.venv\Scripts\python.exe" -m lisa --help +``` + +In VS Code: open the install folder, run **Python: Select Interpreter** → pick the `.venv` (already pinned via `settings.json`), then press **F5**. + +### When to use it + +- Source-level debugging of LISA core / extensions on Windows. +- Iterating on tests against an Azure subscription without spinning up WSL. +- Avoid if you need libvirt/baremetal features that only build on Linux — use the **WSL Bootstrap** flow above. + +--- + ## Prerequisites - **Python**: 3.11+ recommended (3.8+ minimum) @@ -181,4 +282,13 @@ lisa --help - Ubuntu/Debian: `sudo apt-get install -y python3-dev build-essential libssl-dev libffi-dev` - RHEL/CentOS: `sudo dnf install -y python3-devel gcc openssl-devel libffi-devel` +### VS Code F5 hangs / debugpy traceback in `importlib.metadata` +Symptom: hitting F5 launches `C:\Program Files\Python312\python.exe` (system Python), then debugpy stalls inside `describe_environment` reading broken package METADATA. +Cause: newer `ms-python` versions ignore `launch.json`'s `"python"` field and use the workspace interpreter, which defaults to system Python (no LISA installed there). +Fix: +1. Ensure `.vscode/settings.json` contains `"python.defaultInterpreterPath": ".../.venv/Scripts/python.exe"` (the dev installer writes this automatically). +2. `Ctrl+Shift+P` → **Python: Select Interpreter** → pick the `.venv`. +3. `Ctrl+Shift+P` → **Developer: Reload Window**, then F5 again. +4. Status bar (bottom-right) must show `('.venv': venv)` before launching. + For detailed documentation, see `installers/INSTALL.md` in the repository. diff --git a/installers/quick-install-dev.ps1 b/installers/quick-install-dev.ps1 new file mode 100644 index 0000000000..e1ab059eef --- /dev/null +++ b/installers/quick-install-dev.ps1 @@ -0,0 +1,244 @@ +# Quick Install Script for Microsoft LISA dev environment on Windows +# Sets up a Windows-native editable install in a .venv so you can F5-debug +# LISA in VS Code without WSL. +# +# Steps: +# 1. Verify (or install) a supported Python on Windows. +# 2. Clone (or reuse) the LISA repo. +# 3. Create .venv and pip install -e .[azure,libvirt] (libvirt is optional). +# 4. Drop a .vscode/launch.json with a "Python: lisa" debug configuration. +# +# Usage: +# .\quick-install-dev.ps1 +# .\quick-install-dev.ps1 -InstallPath C:\code\lisa -Branch main +# .\quick-install-dev.ps1 -NoClone # use existing checkout at -InstallPath +# .\quick-install-dev.ps1 -SkipLibvirt # skip [libvirt] extra (avoids native build) + +[CmdletBinding()] +param ( + [string]$InstallPath = "$env:USERPROFILE\lisa", + [string]$Branch = "main", + [string]$PythonVersion = "3.12", + [switch]$NoClone, + [switch]$SkipLibvirt, + [switch]$SkipLaunchJson +) + +$ErrorActionPreference = "Stop" + +Write-Host "===== Microsoft LISA Quick Install (Windows dev) =====" -ForegroundColor Cyan +Write-Host "Install path : $InstallPath" -ForegroundColor Cyan +Write-Host "Branch : $Branch" -ForegroundColor Cyan +Write-Host "Python target: $PythonVersion" -ForegroundColor Cyan + +function Get-PythonExe { + param([string]$Version) + # Prefer py launcher + $py = Get-Command py.exe -ErrorAction SilentlyContinue + if ($py) { + try { + $p = & py.exe -$Version -c "import sys; print(sys.executable)" 2>$null + if ($LASTEXITCODE -eq 0 -and $p) { return $p.Trim() } + } catch { } + } + # Fallback: any python on PATH that satisfies the version + $python = Get-Command python.exe -ErrorAction SilentlyContinue + if ($python) { + $v = & python.exe -c "import sys; print('{}.{}'.format(*sys.version_info[:2]))" 2>$null + if ($LASTEXITCODE -eq 0 -and $v -and ([version]$v -ge [version]"3.8")) { + return (& python.exe -c "import sys; print(sys.executable)").Trim() + } + } + return $null +} + +# ---- Step 1: Python ---------------------------------------------------------- +Write-Host "`n[1/4] Locating Python $PythonVersion..." -ForegroundColor Yellow +$pythonExe = Get-PythonExe -Version $PythonVersion +if (-not $pythonExe) { + Write-Host " Not found. Attempting install via winget..." -ForegroundColor Yellow + $winget = Get-Command winget.exe -ErrorAction SilentlyContinue + if (-not $winget) { + Write-Host "[ERROR] winget not available. Install Python $PythonVersion manually from python.org and re-run." -ForegroundColor Red + exit 1 + } + $pkgId = "Python.Python." + $PythonVersion + & winget.exe install -e --id $pkgId --accept-package-agreements --accept-source-agreements --silent + if ($LASTEXITCODE -ne 0) { + Write-Host "[ERROR] winget install $pkgId failed (exit $LASTEXITCODE)." -ForegroundColor Red + exit 1 + } + # Refresh PATH for current session + $env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + ` + [System.Environment]::GetEnvironmentVariable("Path", "User") + $pythonExe = Get-PythonExe -Version $PythonVersion + if (-not $pythonExe) { + Write-Host "[ERROR] Python $PythonVersion still not found after install. Open a new shell and re-run." -ForegroundColor Red + exit 1 + } +} +Write-Host " Using: $pythonExe" -ForegroundColor Green + +# ---- Step 2: Clone ----------------------------------------------------------- +Write-Host "`n[2/4] Preparing repository at $InstallPath..." -ForegroundColor Yellow +if ($NoClone) { + if (-not (Test-Path (Join-Path $InstallPath "pyproject.toml"))) { + Write-Host "[ERROR] -NoClone set but no pyproject.toml at $InstallPath" -ForegroundColor Red + exit 1 + } + Write-Host " Reusing existing checkout." -ForegroundColor Green +} +else { + if (-not (Get-Command git.exe -ErrorAction SilentlyContinue)) { + Write-Host "[ERROR] git.exe not on PATH. Install Git for Windows and re-run." -ForegroundColor Red + exit 1 + } + if (Test-Path $InstallPath) { + if (Test-Path (Join-Path $InstallPath ".git")) { + Write-Host " Existing repo detected, fetching and checking out $Branch..." -ForegroundColor Gray + Push-Location $InstallPath + try { + & git.exe fetch origin $Branch --quiet + & git.exe checkout $Branch --quiet + & git.exe pull --ff-only origin $Branch --quiet + } finally { Pop-Location } + } else { + Write-Host "[ERROR] $InstallPath exists but is not a git repo. Remove it or pass -NoClone." -ForegroundColor Red + exit 1 + } + } else { + Write-Host " Cloning microsoft/lisa@$Branch..." -ForegroundColor Gray + & git.exe clone --branch $Branch https://github.com/microsoft/lisa.git $InstallPath --quiet + if ($LASTEXITCODE -ne 0) { + Write-Host "[ERROR] git clone failed (exit $LASTEXITCODE)." -ForegroundColor Red + exit 1 + } + } +} + +# ---- Step 3: venv + editable install ---------------------------------------- +Write-Host "`n[3/4] Creating .venv and installing LISA (editable)..." -ForegroundColor Yellow +Push-Location $InstallPath +try { + $venvPath = Join-Path $InstallPath ".venv" + if (-not (Test-Path $venvPath)) { + & $pythonExe -m venv .venv + if ($LASTEXITCODE -ne 0) { + Write-Host "[ERROR] Failed to create .venv" -ForegroundColor Red + exit 1 + } + } else { + Write-Host " Reusing existing .venv" -ForegroundColor Gray + } + + $venvPython = Join-Path $venvPath "Scripts\python.exe" + if (-not (Test-Path $venvPython)) { + Write-Host "[ERROR] venv python not found at $venvPython" -ForegroundColor Red + exit 1 + } + + & $venvPython -m pip install --upgrade pip setuptools wheel + if ($LASTEXITCODE -ne 0) { + Write-Host "[ERROR] pip upgrade failed" -ForegroundColor Red + exit 1 + } + + $extras = if ($SkipLibvirt) { "azure" } else { "azure,libvirt" } + Write-Host " pip install -e .[$extras]" -ForegroundColor Gray + & $venvPython -m pip install --editable ".[$extras]" --config-settings editable_mode=compat + if ($LASTEXITCODE -ne 0) { + if (-not $SkipLibvirt) { + Write-Host "[WARN] Editable install with [libvirt] failed. Retrying with [azure] only..." -ForegroundColor Yellow + & $venvPython -m pip install --editable ".[azure]" --config-settings editable_mode=compat + if ($LASTEXITCODE -ne 0) { + Write-Host "[ERROR] Editable install failed." -ForegroundColor Red + exit 1 + } + } else { + Write-Host "[ERROR] Editable install failed." -ForegroundColor Red + exit 1 + } + } +} finally { + Pop-Location +} + +# ---- Step 4: VS Code launch.json -------------------------------------------- +Write-Host "`n[4/4] Writing VS Code debug configuration..." -ForegroundColor Yellow +if ($SkipLaunchJson) { + Write-Host " Skipped (-SkipLaunchJson)" -ForegroundColor Gray +} +else { + $vscodeDir = Join-Path $InstallPath ".vscode" + if (-not (Test-Path $vscodeDir)) { New-Item -ItemType Directory -Path $vscodeDir | Out-Null } + $launchPath = Join-Path $vscodeDir "launch.json" + + $venvPythonForJson = (Join-Path $InstallPath ".venv\Scripts\python.exe") -replace '\\', '\\' + $cwdForJson = $InstallPath -replace '\\', '\\' + + # settings.json — pins the workspace interpreter so the Python extension + # picks up the venv (newer ms-python ignores launch.json's "python" field). + $settingsPath = Join-Path $vscodeDir "settings.json" + $settingsJson = @" +{ + "python.defaultInterpreterPath": "${venvPythonForJson}", + "python.terminal.activateEnvironment": true +} +"@ + if (Test-Path $settingsPath) { + Copy-Item $settingsPath "$settingsPath.bak" -Force + Write-Host " Existing settings.json backed up to $settingsPath.bak" -ForegroundColor Gray + } + Set-Content -Path $settingsPath -Value $settingsJson -Encoding UTF8 + Write-Host " Wrote $settingsPath" -ForegroundColor Green + + $launchJson = @" +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Python: lisa (module)", + "type": "debugpy", + "request": "launch", + "module": "lisa", + "cwd": "`${workspaceFolder}", + "python": "`${command:python.interpreterPath}", + "console": "integratedTerminal", + "justMyCode": false, + "args": [ + "-r", + "lisa/examples/runbook/hello_world.yml", + "-d" + ] + }, + { + "name": "Python: Current File", + "type": "debugpy", + "request": "launch", + "program": "`${file}", + "python": "`${command:python.interpreterPath}", + "console": "integratedTerminal", + "justMyCode": false + } + ] +} +"@ + + if (Test-Path $launchPath) { + $backup = "$launchPath.bak" + Copy-Item $launchPath $backup -Force + Write-Host " Existing launch.json backed up to $backup" -ForegroundColor Gray + } + Set-Content -Path $launchPath -Value $launchJson -Encoding UTF8 + Write-Host " Wrote $launchPath" -ForegroundColor Green +} + +Write-Host "`n===== Dev environment ready =====" -ForegroundColor Green +Write-Host "Open the project in VS Code:" -ForegroundColor Cyan +Write-Host " code `"$InstallPath`"" -ForegroundColor White +Write-Host "Activate the venv from a shell:" -ForegroundColor Cyan +Write-Host " & `"$InstallPath\.venv\Scripts\Activate.ps1`"" -ForegroundColor White +Write-Host "Run LISA:" -ForegroundColor Cyan +Write-Host " & `"$InstallPath\.venv\Scripts\python.exe`" -m lisa --help" -ForegroundColor White +Write-Host "Debug in VS Code:" -ForegroundColor Cyan +Write-Host " Press F5 and pick 'Python: lisa (module)'." -ForegroundColor White