62 lines
2.6 KiB
Go
62 lines
2.6 KiB
Go
package bootstrap
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
type HyperVStatus struct {
|
|
Edition string
|
|
Supported bool
|
|
Enabled bool
|
|
RestartRequired bool
|
|
}
|
|
|
|
func DetectHyperV(ctx context.Context, runner Runner) (HyperVStatus, error) {
|
|
script := `$edition=(Get-ComputerInfo -Property WindowsProductName).WindowsProductName; ` +
|
|
`$supported=($edition -match 'Pro|Enterprise|Education'); ` +
|
|
`$enabled=$false; if ($supported) { $feature=Get-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V-All -ErrorAction SilentlyContinue; $enabled=($feature.State -eq 'Enabled') }; ` +
|
|
`$reboot=(Test-Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending') -or (Test-Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired'); ` +
|
|
`Write-Output ('Edition='+$edition); Write-Output ('Supported='+$supported); Write-Output ('Enabled='+$enabled); Write-Output ('RestartRequired='+$reboot)`
|
|
result := runner.Run(ctx, "powershell.exe", "-NoLogo", "-NoProfile", "-NonInteractive", "-Command", script)
|
|
if result.Err != nil {
|
|
return HyperVStatus{}, fmt.Errorf("detect Hyper-V: %w: %s", result.Err, result.CombinedOutput())
|
|
}
|
|
values := parseValues(result.Stdout)
|
|
return HyperVStatus{
|
|
Edition: values["Edition"],
|
|
Supported: strings.EqualFold(values["Supported"], "True"),
|
|
Enabled: strings.EqualFold(values["Enabled"], "True"),
|
|
RestartRequired: strings.EqualFold(values["RestartRequired"], "True"),
|
|
}, nil
|
|
}
|
|
|
|
func EnableHyperV(ctx context.Context, runner Runner, status HyperVStatus) (string, error) {
|
|
if !status.Supported {
|
|
return "Vagrant installed, but Hyper-V provider setup is unavailable on Windows " + status.Edition + "; no alternate provider is substituted.", nil
|
|
}
|
|
if status.RestartRequired {
|
|
return "A pending Windows restart must be completed before Hyper-V-backed Vagrant setup can continue.", nil
|
|
}
|
|
if status.Enabled {
|
|
return "Hyper-V is enabled for the Vagrant provider.", nil
|
|
}
|
|
result := runner.Run(ctx, "dism.exe", "/Online", "/Enable-Feature", "/FeatureName:Microsoft-Hyper-V-All", "/All", "/NoRestart")
|
|
if result.Err != nil {
|
|
return "", fmt.Errorf("enable Hyper-V: %w: %s", result.Err, result.CombinedOutput())
|
|
}
|
|
return "Hyper-V features were enabled; restart Windows and rerun to complete Vagrant provider setup.", nil
|
|
}
|
|
|
|
func parseValues(output string) map[string]string {
|
|
values := make(map[string]string)
|
|
for _, line := range strings.Split(strings.ReplaceAll(output, "\r\n", "\n"), "\n") {
|
|
key, value, ok := strings.Cut(strings.TrimSpace(line), "=")
|
|
if ok {
|
|
values[key] = value
|
|
}
|
|
}
|
|
return values
|
|
}
|