Skip to content

Commit

Permalink
feat(macOS): Support host DNS aliases for macos (#1085)
Browse files Browse the repository at this point in the history
This change adds:
1) `host.finch.internal`
2) `host.docker.internal`

as DNS names that are aliased to the host's loopback address. This allows
service and containers inside the VM to connect to services bound to the host's
loopback device.

Signed-off-by: Kern Walster <[email protected]>
  • Loading branch information
Kern-- authored Oct 1, 2024
1 parent 78012ca commit 6b7f053
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 19 deletions.
20 changes: 2 additions & 18 deletions e2e/vm/soci_remote_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ package vm
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"

Expand All @@ -31,29 +29,15 @@ const (
var testSoci = func(o *option.Option, installed bool) {
ginkgo.Describe("SOCI", func() {
var limactlO *option.Option
var fpath, realFinchPath, limactlPath, limaHomePathEnv, wd, vmType string
var vmType string
var err error
var port int

ginkgo.BeforeEach(func() {
// Find lima paths. limactl is used to shell into the Finch VM and verify
// mounted snapshots match the expected SOCI snapshotter behavior.
if installed {
fpath, err = exec.LookPath("finch")
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
realFinchPath, err = filepath.EvalSymlinks(fpath)
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
limactlPath = filepath.Join(realFinchPath, "../../lima/bin/limactl")
limaHomePathEnv = "LIMA_HOME=" + filepath.Join(realFinchPath, "../../lima/data")
} else {
wd, err = os.Getwd()
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
limactlPath = filepath.Join(wd, "../../_output/lima/bin/limactl")
limaHomePathEnv = "LIMA_HOME=" + filepath.Join(wd, "../../_output/lima/data")
}

limactlO, err = option.New([]string{limactlPath},
option.Env([]string{limaHomePathEnv}))
limactlO, err = limaCtlOpt(installed)
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
if runtime.GOOS == "windows" {
vmType = "wsl2"
Expand Down
1 change: 1 addition & 0 deletions e2e/vm/vm_darwin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ func TestVM(t *testing.T) {
testSupportBundle(o)
testCredHelper(o, *e2e.Installed, *e2e.Registry)
testSoci(o, *e2e.Installed)
testVMNetwork(o, *e2e.Installed)
})

gomega.RegisterFailHandler(ginkgo.Fail)
Expand Down
99 changes: 99 additions & 0 deletions e2e/vm/vm_network_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

//go:build darwin

package vm

import (
"context"
"fmt"
"net/http"
"time"

"github.com/onsi/ginkgo/v2"
"github.com/onsi/gomega"
"github.com/onsi/gomega/gbytes"
"github.com/runfinch/common-tests/command"
"github.com/runfinch/common-tests/option"
"golang.org/x/sync/errgroup"
)

const (
addr = "localhost"
port = "8888"
responseBody = "ack"
finchHost = "host.finch.internal"
dockerHost = "host.docker.internal"
)

func hostWithPort(host, port string) string {
return fmt.Sprintf("%s:%s", host, port)
}

func vmDNSValidationCommand(host, port string) []string {
// The finch rootfs has curl but not wget
return []string{
"shell",
"finch",
"curl",
"--silent",
"--connect-timeout", "1",
hostWithPort(host, port),
}
}

func containerDNSValidationCommand(host, port string) []string {
// The container rootfs has wget, but not curl
return []string{
"run",
"public.ecr.aws/docker/library/alpine:latest",
"wget",
"-O", "-", // output to stdout
"-q", // quiet
"-T", "1", // read timeout
hostWithPort(host, port),
}
}

func testVMNetwork(finchO *option.Option, installed bool) {
limaCtlO, err := limaCtlOpt(installed)
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
eg, _ := errgroup.WithContext(context.Background())
var srv *http.Server
ginkgo.Describe("vm networking", func() {
ginkgo.BeforeEach(func() {
srv = &http.Server{
Addr: hostWithPort(addr, port),
ReadHeaderTimeout: 1 * time.Second,
Handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
_, err := w.Write([]byte(responseBody))
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
}),
}
eg.Go(srv.ListenAndServe)
})
ginkgo.AfterEach(func() {
err := srv.Shutdown(context.Background())
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
err = eg.Wait()
gomega.Expect(err).To(gomega.MatchError(http.ErrServerClosed))
})
ginkgo.It("should resolve host.finch.internal in the vm", func() {
out := command.New(limaCtlO, vmDNSValidationCommand(finchHost, port)...).WithStdout(gbytes.NewBuffer()).Run().Out
gomega.Expect(out).To(gbytes.Say(responseBody))
})
ginkgo.It("should resolve host.docker.internal in the vm", func() {
out := command.New(limaCtlO, vmDNSValidationCommand(dockerHost, port)...).WithStdout(gbytes.NewBuffer()).Run().Out
gomega.Expect(out).To(gbytes.Say(responseBody))
})
ginkgo.It("should resolve host.finch.internal in a container", func() {
out := command.New(finchO, containerDNSValidationCommand(finchHost, port)...).WithStdout(gbytes.NewBuffer()).Run().Out
gomega.Expect(out).To(gbytes.Say(responseBody))
})
ginkgo.It("should resolve host.docker.internal in a container", func() {
out := command.New(finchO, containerDNSValidationCommand(dockerHost, port)...).WithStdout(gbytes.NewBuffer()).Run().Out
gomega.Expect(out).To(gbytes.Say(responseBody))
})
})
}
38 changes: 38 additions & 0 deletions e2e/vm/vm_util_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

//go:build darwin || windows

package vm

import (
"os"
"os/exec"
"path/filepath"

"github.com/runfinch/common-tests/option"
)

func limaCtlOpt(installed bool) (*option.Option, error) {
var limactlPath, limaHomePathEnv string
if installed {
fpath, err := exec.LookPath("finch")
if err != nil {
return nil, err
}
realFinchPath, err := filepath.EvalSymlinks(fpath)
if err != nil {
return nil, err
}
limactlPath = filepath.Join(realFinchPath, "../../lima/bin/limactl")
limaHomePathEnv = "LIMA_HOME=" + filepath.Join(realFinchPath, "../../lima/data")
} else {
wd, err := os.Getwd()
if err != nil {
return nil, err
}
limactlPath = filepath.Join(wd, "../../_output/lima/bin/limactl")
limaHomePathEnv = "LIMA_HOME=" + filepath.Join(wd, "../../_output/lima/data")
}
return option.New([]string{limactlPath}, option.Env([]string{limaHomePathEnv}))
}
5 changes: 5 additions & 0 deletions finch.yaml.d/mac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,8 @@ firmware:

video:
display: "none"

hostResolver:
hosts:
host.finch.internal: host.lima.internal
host.docker.internal: host.lima.internal
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ require (
github.com/xorcare/pointer v1.2.2
golang.org/x/crypto v0.27.0
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
golang.org/x/sync v0.8.0
golang.org/x/tools v0.25.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/apimachinery v0.31.1
Expand Down Expand Up @@ -71,7 +72,6 @@ require (
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
golang.org/x/image v0.18.0 // indirect
golang.org/x/sync v0.8.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240805194559-2c9e96a0b5d4 // indirect
google.golang.org/grpc v1.66.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
Expand Down

0 comments on commit 6b7f053

Please sign in to comment.