Skip to content

Commit ab1714a

Browse files
camjjacknywilken
authored andcommitted
Support for running within WSL2
1 parent 3c8d1e6 commit ab1714a

File tree

6 files changed

+227
-6
lines changed

6 files changed

+227
-6
lines changed

builder/hyperv/common/driver_ps_4.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,21 @@ import (
1313

1414
"github.com/hashicorp/packer-plugin-hyperv/builder/hyperv/common/powershell"
1515
"github.com/hashicorp/packer-plugin-hyperv/builder/hyperv/common/powershell/hyperv"
16+
"github.com/hashicorp/packer-plugin-hyperv/builder/hyperv/common/wsl"
1617
)
1718

1819
type HypervPS4Driver struct {
1920
}
2021

2122
func NewHypervPS4Driver() (Driver, error) {
22-
appliesTo := "Applies to Windows 8.1, Windows PowerShell 4.0, Windows Server 2012 R2 only"
23+
appliesTo := "Applies to Windows 8.1+, Windows PowerShell 4.0, Windows Server 2012 R2+, WSL2 only"
2324

24-
// Check this is Windows
25-
if runtime.GOOS != "windows" {
25+
if !wsl.IsWSL() && runtime.GOOS != "windows" {
2626
err := fmt.Errorf("%s", appliesTo)
2727
return nil, err
2828
}
2929

3030
ps4Driver := &HypervPS4Driver{}
31-
3231
if err := ps4Driver.Verify(); err != nil {
3332
return nil, err
3433
}

builder/hyperv/common/powershell/powershell.go

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ import (
77
"bytes"
88
"fmt"
99
"io"
10+
"io/ioutil"
1011
"log"
1112
"os"
1213
"os/exec"
1314
"strconv"
1415
"strings"
1516

17+
"github.com/hashicorp/packer-plugin-hyperv/builder/hyperv/common/wsl"
1618
"github.com/hashicorp/packer-plugin-sdk/tmp"
1719
)
1820

@@ -57,6 +59,12 @@ func (ps *PowerShellCmd) Output(fileContents string, params ...string) (string,
5759
if !debug {
5860
defer os.Remove(filename)
5961
}
62+
if wsl.IsWSL() {
63+
filename, err = wsl.ConvertWSlPathToWindowsPath(filename)
64+
if err != nil {
65+
return "", err
66+
}
67+
}
6068

6169
args := createArgs(filename, params...)
6270

@@ -105,7 +113,7 @@ func (ps *PowerShellCmd) Output(fileContents string, params ...string) (string,
105113
}
106114

107115
func IsPowershellAvailable() (bool, string, error) {
108-
path, err := exec.LookPath("powershell")
116+
path, err := exec.LookPath("powershell.exe")
109117
if err != nil {
110118
return false, "", err
111119
} else {
@@ -127,7 +135,25 @@ func (ps *PowerShellCmd) getPowerShellPath() (string, error) {
127135
}
128136

129137
func saveScript(fileContents string) (string, error) {
130-
file, err := tmp.File("powershell")
138+
139+
file, err := tmp.File("Powershell")
140+
// If under WSL2 then we need a file on the windows drive
141+
if wsl.IsWSL() {
142+
tmpDir, err := wsl.GetWSlTemp()
143+
if err != nil {
144+
return "", err
145+
}
146+
147+
wslTempDir, err := wsl.ConvertWindowsPathToWSlPath(tmpDir)
148+
if err != nil {
149+
return "", err
150+
}
151+
file, err = ioutil.TempFile(wslTempDir, "powershell")
152+
if err != nil {
153+
return "", err
154+
}
155+
}
156+
131157
if err != nil {
132158
return "", err
133159
}

builder/hyperv/common/step_mount_dvddrive.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"path/filepath"
1111
"strings"
1212

13+
"github.com/hashicorp/packer-plugin-hyperv/builder/hyperv/common/wsl"
1314
"github.com/hashicorp/packer-plugin-sdk/multistep"
1415
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
1516
)
@@ -35,6 +36,16 @@ func (s *StepMountDvdDrive) Run(ctx context.Context, state multistep.StateBag) m
3536
return multistep.ActionContinue
3637
}
3738

39+
if wsl.IsWSL() {
40+
var err error
41+
isoPath, err = wsl.ConvertWSlPathToWindowsPath(isoPath)
42+
if err != nil {
43+
state.Put("error", err)
44+
ui.Error(err.Error())
45+
return multistep.ActionHalt
46+
}
47+
}
48+
3849
// Determine if its a virtual hdd to mount
3950
if strings.ToLower(filepath.Ext(isoPath)) == ".vhd" || strings.ToLower(filepath.Ext(isoPath)) == ".vhdx" {
4051
log.Println("Its a hard disk, not attaching.")

builder/hyperv/common/step_run.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ import (
77
"context"
88
"fmt"
99
"log"
10+
"net"
1011

12+
"github.com/hashicorp/packer-plugin-hyperv/builder/hyperv/common/wsl"
1113
"github.com/hashicorp/packer-plugin-sdk/multistep"
1214
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
1315
)
@@ -33,6 +35,22 @@ func (s *StepRun) Run(ctx context.Context, state multistep.StateBag) multistep.S
3335
return multistep.ActionHalt
3436
}
3537

38+
// If running in WSL and the user has specified the WSL switch, then they
39+
// almost certainly want the WSL distribution IP as the host IP as this is
40+
// what our http server will be listening on.
41+
if wsl.IsWSL() {
42+
switchNet := net.IPNet{IP: net.ParseIP(hostIp), Mask: net.IPv4Mask(255, 255, 240, 0)}
43+
addrs, err := net.InterfaceAddrs()
44+
if err == nil {
45+
for _, address := range addrs {
46+
if ipnet, ok := address.(*net.IPNet); ok && switchNet.Contains(ipnet.IP) {
47+
hostIp = ipnet.IP.String()
48+
break
49+
}
50+
}
51+
}
52+
}
53+
3654
ui.Say(fmt.Sprintf("Host IP for the HyperV machine: %s", hostIp))
3755
state.Put("http_ip", hostIp)
3856

builder/hyperv/common/wsl/wsl.go

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package wsl
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"io/ioutil"
7+
"os/exec"
8+
"runtime"
9+
"strings"
10+
)
11+
12+
func IsWSL() bool {
13+
var isWSL bool
14+
isWSL = false
15+
if runtime.GOOS == "linux" {
16+
content, err := ioutil.ReadFile("/proc/version")
17+
if err == nil {
18+
s := string(content)
19+
if strings.Contains(s, "WSL2") {
20+
isWSL = true
21+
}
22+
}
23+
}
24+
return isWSL
25+
}
26+
27+
func GetWSlTemp() (string, error) {
28+
29+
var stdout, stderr bytes.Buffer
30+
args := make([]string, 3)
31+
args[0] = "/c"
32+
args[1] = "echo"
33+
34+
args[2] = "%TEMP%"
35+
command := exec.Command("cmd.exe", args...)
36+
command.Stdout = &stdout
37+
command.Stderr = &stderr
38+
39+
err := command.Run()
40+
41+
stderrString := strings.TrimSpace(stderr.String())
42+
43+
if _, ok := err.(*exec.ExitError); ok {
44+
err = fmt.Errorf("Error getting wsl TEMP dir: %s", stderrString)
45+
return "", err
46+
}
47+
48+
if len(stderrString) > 0 {
49+
err = fmt.Errorf("Error getting wsl TEMP dir: %s", stderrString)
50+
return "", err
51+
}
52+
53+
return strings.TrimSpace(stdout.String()), err
54+
}
55+
56+
func ConvertWindowsPathToWSlPath(winPath string) (string, error) {
57+
58+
var stdout, stderr bytes.Buffer
59+
args := make([]string, 3)
60+
args[0] = "-a"
61+
args[1] = "-u"
62+
63+
args[2] = winPath
64+
command := exec.Command("wslpath", args...)
65+
command.Stdout = &stdout
66+
command.Stderr = &stderr
67+
68+
err := command.Run()
69+
70+
stderrString := strings.TrimSpace(stderr.String())
71+
72+
if _, ok := err.(*exec.ExitError); ok {
73+
err = fmt.Errorf("wslpath error: %s", stderrString)
74+
return "", err
75+
}
76+
77+
if len(stderrString) > 0 {
78+
err = fmt.Errorf("wslpath error: %s", stderrString)
79+
return "", err
80+
}
81+
82+
return strings.TrimSpace(stdout.String()), err
83+
}
84+
85+
func ConvertWSlPathToWindowsPath(wslPath string) (string, error) {
86+
87+
var stdout, stderr bytes.Buffer
88+
args := make([]string, 3)
89+
args[0] = "-a"
90+
args[1] = "-w"
91+
92+
args[2] = wslPath
93+
command := exec.Command("wslpath", args...)
94+
command.Stdout = &stdout
95+
command.Stderr = &stderr
96+
97+
err := command.Run()
98+
99+
stderrString := strings.TrimSpace(stderr.String())
100+
101+
if _, ok := err.(*exec.ExitError); ok {
102+
err = fmt.Errorf("wslpath error: %s", stderrString)
103+
return "", err
104+
}
105+
106+
if len(stderrString) > 0 {
107+
err = fmt.Errorf("wslpath error: %s", stderrString)
108+
return "", err
109+
}
110+
111+
return strings.TrimSpace(stdout.String()), err
112+
}

builder/hyperv/common/wsl/wsl_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package wsl
2+
3+
import (
4+
"os"
5+
"testing"
6+
)
7+
8+
func TestGetWSlTemp(t *testing.T) {
9+
10+
if !IsWSL() {
11+
t.Skipf("not running in WSL")
12+
return
13+
}
14+
tempDir, err := GetWSlTemp()
15+
if err != nil {
16+
t.Fatalf("should not have error: %s", err)
17+
}
18+
if tempDir == "" {
19+
t.Fatalf("tempDir is not polulated correctly")
20+
}
21+
}
22+
23+
func TestConvertWindowsPathToWSlPath(t *testing.T) {
24+
25+
if !IsWSL() {
26+
t.Skipf("not running in WSL")
27+
return
28+
}
29+
wslPath, err := ConvertWindowsPathToWSlPath("C:\\Users\\User\\path with spaces")
30+
if err != nil {
31+
t.Fatalf("should not have error: %s", err)
32+
}
33+
if wslPath == "" {
34+
t.Fatalf("wslPath is not polulated correctly")
35+
}
36+
}
37+
38+
func TestConvertWSlPathToWindowsPath(t *testing.T) {
39+
40+
if !IsWSL() {
41+
t.Skipf("not running in WSL")
42+
return
43+
}
44+
curDir, err := os.Getwd()
45+
if err != nil {
46+
t.Fatalf("Getwd should not have error: %s", err)
47+
}
48+
winPath, err := ConvertWSlPathToWindowsPath(curDir)
49+
if err != nil {
50+
t.Fatalf("ConvertWSlPathToWindowsPath should not have error: %s", err)
51+
}
52+
if winPath == "" {
53+
t.Fatalf("wslPath is not polulated correctly")
54+
}
55+
}

0 commit comments

Comments
 (0)