Skip to content

Commit

Permalink
Merge pull request containers#21572 from mheon/hyperv_9p_mkdir
Browse files Browse the repository at this point in the history
Ensure HyperV 9p mounts work when a dir doesn't exist
  • Loading branch information
openshift-merge-bot[bot] authored Feb 27, 2024
2 parents fcce681 + 26ec570 commit 9d17043
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 5 deletions.
19 changes: 17 additions & 2 deletions cmd/podman/machine/client9p.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"os/exec"
"path/filepath"
"strconv"
"time"

"github.com/containers/common/pkg/completion"
"github.com/containers/podman/v5/cmd/podman/registry"
Expand Down Expand Up @@ -69,8 +70,22 @@ func client9p(portNum uint32, mountPath string) error {

logrus.Infof("Going to mount 9p on vsock port %d to directory %s", portNum, mountPath)

// Host connects to non-hypervisor processes on the host running the VM.
conn, err := vsock.Dial(vsock.Host, portNum, nil)
// The server is starting at the same time.
// Perform up to 5 retries with a backoff.
var (
conn *vsock.Conn
retries = 20
)
for i := 0; i < retries; i++ {
// Host connects to non-hypervisor processes on the host running the VM.
conn, err = vsock.Dial(vsock.Host, portNum, nil)
// If errors.Is worked on this error, we could detect non-timeout errors.
// But it doesn't. So retry 5 times regardless.
if err == nil {
break
}
time.Sleep(250 * time.Millisecond)
}
if err != nil {
return fmt.Errorf("dialing vsock port %d: %w", portNum, err)
}
Expand Down
29 changes: 29 additions & 0 deletions pkg/machine/e2e/basic_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package e2e_test

import (
"fmt"
"io"
"net"
"net/http"
"net/url"
"os"
"path"
"path/filepath"
"time"

. "github.com/onsi/ginkgo/v2"
Expand Down Expand Up @@ -93,6 +97,31 @@ var _ = Describe("run basic podman commands", func() {
Expect(out).ToNot(ContainSubstring("gvproxy"))
})

It("podman volume on non-standard path", func() {
skipIfWSL("Requires standard volume handling")
dir, err := os.MkdirTemp("", "machine-volume")
Expect(err).ToNot(HaveOccurred())
defer os.RemoveAll(dir)

testString := "abcdefg1234567"
testFile := "testfile"
err = os.WriteFile(filepath.Join(dir, testFile), []byte(testString), 0644)
Expect(err).ToNot(HaveOccurred())

name := randomString()
machinePath := "/does/not/exist"
init := new(initMachine).withVolume(fmt.Sprintf("%s:%s", dir, machinePath)).withImagePath(mb.imagePath).withNow()
session, err := mb.setName(name).setCmd(init).run()
Expect(err).ToNot(HaveOccurred())
Expect(session).To(Exit(0))

// Must use path.Join to ensure forward slashes are used, even on Windows.
ssh := new(sshMachine).withSSHCommand([]string{"cat", path.Join(machinePath, testFile)})
ls, err := mb.setName(name).setCmd(ssh).run()
Expect(err).ToNot(HaveOccurred())
Expect(ls).To(Exit(0))
Expect(ls.outputToString()).To(ContainSubstring(testString))
})
})

func testHTTPServer(port string, shouldErr bool, expectedResponse string) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/machine/hyperv/stubber.go
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ func (h HyperVStubber) PostStartNetworking(mc *vmconfigs.MachineConfig, noInfo b

for _, mount := range mc.Mounts {
if mount.VSockNumber == nil {
return fmt.Errorf("mount %s has not vsock port defined", mount.Source)
return fmt.Errorf("mount %s has no vsock port defined", mount.Source)
}
p9ServerArgs = append(p9ServerArgs, "--serve", fmt.Sprintf("%s:%s", mount.Source, winio.VsockServiceID(uint32(*mount.VSockNumber)).String()))
}
Expand Down
18 changes: 16 additions & 2 deletions pkg/machine/hyperv/volumes.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ package hyperv
import (
"errors"
"fmt"
"path"
"strings"

"github.com/containers/podman/v5/pkg/machine"
"github.com/containers/podman/v5/pkg/machine/hyperv/vsock"
Expand Down Expand Up @@ -40,15 +42,27 @@ func removeShares(mc *vmconfigs.MachineConfig) error {

func startShares(mc *vmconfigs.MachineConfig) error {
for _, mount := range mc.Mounts {
args := []string{"-q", "--", "sudo", "podman"}
args := []string{"-q", "--"}

cleanTarget := path.Clean(mount.Target)
requiresChattr := !strings.HasPrefix(cleanTarget, "/home") && !strings.HasPrefix(cleanTarget, "/mnt")
if requiresChattr {
args = append(args, "sudo", "chattr", "-i", "/", "; ")
}
args = append(args, "sudo", "mkdir", "-p", cleanTarget, "; ")
if requiresChattr {
args = append(args, "sudo", "chattr", "+i", "/", "; ")
}

args = append(args, "sudo", "podman")
if logrus.IsLevelEnabled(logrus.DebugLevel) {
args = append(args, "--log-level=debug")
}
// just being protective here; in a perfect world, this cannot happen
if mount.VSockNumber == nil {
return errors.New("cannot start 9p shares with undefined vsock number")
}
args = append(args, "machine", "client9p", fmt.Sprintf("%d", mount.VSockNumber), mount.Target)
args = append(args, "machine", "client9p", fmt.Sprintf("%d", *mount.VSockNumber), mount.Target)

if err := machine.CommonSSH(mc.SSH.RemoteUsername, mc.SSH.IdentityPath, mc.Name, mc.SSH.Port, args); err != nil {
return err
Expand Down

0 comments on commit 9d17043

Please sign in to comment.