|
7 | 7 | "context" |
8 | 8 | _ "embed" |
9 | 9 | "fmt" |
| 10 | + "net" |
10 | 11 | "os" |
11 | 12 | "os/exec" |
12 | 13 | "path/filepath" |
@@ -179,6 +180,33 @@ func unregisterVM(ctx context.Context, distroName string) error { |
179 | 180 | return nil |
180 | 181 | } |
181 | 182 |
|
| 183 | +// GetWslStatus runs `wsl --list --verbose` and parses its output. |
| 184 | +// There are several possible outputs, all listed with their whitespace preserved output below. |
| 185 | +// |
| 186 | +// (1) Expected output if at least one distro is installed: |
| 187 | +// PS > wsl --list --verbose |
| 188 | +// |
| 189 | +// NAME STATE VERSION |
| 190 | +// |
| 191 | +// * Ubuntu Stopped 2 |
| 192 | +// |
| 193 | +// (2) Expected output when no distros are installed, but WSL is configured properly: |
| 194 | +// PS > wsl --list --verbose |
| 195 | +// Windows Subsystem for Linux has no installed distributions. |
| 196 | +// |
| 197 | +// Use 'wsl.exe --list --online' to list available distributions |
| 198 | +// and 'wsl.exe --install <Distro>' to install. |
| 199 | +// |
| 200 | +// Distributions can also be installed by visiting the Microsoft Store: |
| 201 | +// https://aka.ms/wslstore |
| 202 | +// Error code: Wsl/WSL_E_DEFAULT_DISTRO_NOT_FOUND |
| 203 | +// |
| 204 | +// (3) Expected output when no distros are installed, and WSL2 has no kernel installed: |
| 205 | +// |
| 206 | +// PS > wsl --list --verbose |
| 207 | +// Windows Subsystem for Linux has no installed distributions. |
| 208 | +// Distributions can be installed by visiting the Microsoft Store: |
| 209 | +// https://aka.ms/wslstore |
182 | 210 | func getWslStatus(instName string) (string, error) { |
183 | 211 | distroName := "lima-" + instName |
184 | 212 | out, err := executil.RunUTF16leCommand([]string{ |
@@ -229,3 +257,34 @@ func getWslStatus(instName string) (string, error) { |
229 | 257 |
|
230 | 258 | return instState, nil |
231 | 259 | } |
| 260 | + |
| 261 | +// GetSSHAddress runs a hostname command to get the IP from inside of a wsl2 VM. |
| 262 | +// |
| 263 | +// Expected output (whitespace preserved, [] for optional): |
| 264 | +// PS > wsl -d <distroName> bash -c hostname -I | cut -d' ' -f1 |
| 265 | +// 168.1.1.1 [10.0.0.1] |
| 266 | +// But busybox hostname does not implement --all-ip-addresses: |
| 267 | +// hostname: unrecognized option: I |
| 268 | +func getSSHAddress(ctx context.Context, instName string) (string, error) { |
| 269 | + distroName := "lima-" + instName |
| 270 | + // Ubuntu |
| 271 | + cmd := exec.CommandContext(ctx, "wsl.exe", "-d", distroName, "bash", "-c", `hostname -I | cut -d ' ' -f1`) |
| 272 | + out, err := cmd.CombinedOutput() |
| 273 | + if err == nil { |
| 274 | + return strings.TrimSpace(string(out)), nil |
| 275 | + } |
| 276 | + // Alpine |
| 277 | + cmd = exec.CommandContext(ctx, "wsl.exe", "-d", distroName, "sh", "-c", `ip route get 1 | awk '{gsub("^.*src ",""); print $1; exit}'`) |
| 278 | + out, err = cmd.CombinedOutput() |
| 279 | + if err == nil { |
| 280 | + return strings.TrimSpace(string(out)), nil |
| 281 | + } |
| 282 | + // fallback |
| 283 | + cmd = exec.CommandContext(ctx, "wsl.exe", "-d", distroName, "hostname", "-i") |
| 284 | + out, err = cmd.CombinedOutput() |
| 285 | + if err != nil || strings.HasPrefix(string(out), "127.") { |
| 286 | + return "", fmt.Errorf("failed to get hostname for instance %q, err: %w (out=%q)", instName, err, string(out)) |
| 287 | + } |
| 288 | + |
| 289 | + return strings.TrimSpace(string(out)), nil |
| 290 | +} |
0 commit comments