diff options
author | Brent Baude <bbaude@redhat.com> | 2021-05-07 14:14:59 -0500 |
---|---|---|
committer | Brent Baude <bbaude@redhat.com> | 2021-06-01 10:13:18 -0500 |
commit | 7ef3981abe2412727840a2886489a08c03a05299 (patch) | |
tree | a616723311b745a6902199d296c6655d1307497e /pkg | |
parent | 7dd463bad1b53802caf3cc1e1e1cc4a250e1667a (diff) | |
download | podman-7ef3981abe2412727840a2886489a08c03a05299.tar.gz podman-7ef3981abe2412727840a2886489a08c03a05299.tar.bz2 podman-7ef3981abe2412727840a2886489a08c03a05299.zip |
Enable port forwarding on host
Using the gvproxy application on the host, we can now port forward from
the machine vm on the host. It requires that 'gvproxy' be installed in
an executable location. gvproxy can be found in the
containers/gvisor-tap-vsock github repo.
[NO TESTS NEEDED]
Signed-off-by: Brent Baude <bbaude@redhat.com>
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/machine/config.go | 1 | ||||
-rw-r--r-- | pkg/machine/ignition.go | 17 | ||||
-rw-r--r-- | pkg/machine/qemu/machine.go | 118 | ||||
-rw-r--r-- | pkg/machine/qemu/options_darwin.go | 2 | ||||
-rw-r--r-- | pkg/machine/qemu/options_darwin_amd64.go | 2 | ||||
-rw-r--r-- | pkg/machine/qemu/options_linux.go | 10 |
6 files changed, 135 insertions, 15 deletions
diff --git a/pkg/machine/config.go b/pkg/machine/config.go index 652229963..58794ce42 100644 --- a/pkg/machine/config.go +++ b/pkg/machine/config.go @@ -32,6 +32,7 @@ var ( ErrVMAlreadyExists = errors.New("VM already exists") ErrVMAlreadyRunning = errors.New("VM already running") ErrMultipleActiveVM = errors.New("only one VM can be active at a time") + ForwarderBinaryName = "gvproxy" ) type Download struct { diff --git a/pkg/machine/ignition.go b/pkg/machine/ignition.go index 00068a136..a5c7210af 100644 --- a/pkg/machine/ignition.go +++ b/pkg/machine/ignition.go @@ -118,6 +118,7 @@ func getDirs(usrName string) []Directory { // in one swoop, then the leading dirs are creates as root. newDirs := []string{ "/home/" + usrName + "/.config", + "/home/" + usrName + "/.config/containers", "/home/" + usrName + "/.config/systemd", "/home/" + usrName + "/.config/systemd/user", "/home/" + usrName + "/.config/systemd/user/default.target.wants", @@ -159,6 +160,22 @@ func getFiles(usrName string) []File { }, }) + // Set containers.conf up for core user to use cni networks + // by default + files = append(files, File{ + Node: Node{ + Group: getNodeGrp(usrName), + Path: "/home/" + usrName + "/.config/containers/containers.conf", + User: getNodeUsr(usrName), + }, + FileEmbedded1: FileEmbedded1{ + Append: nil, + Contents: Resource{ + Source: strToPtr("data:,%5Bcontainers%5D%0D%0Anetns%3D%22bridge%22%0D%0Arootless_networking%3D%22cni%22"), + }, + Mode: intToPtr(484), + }, + }) // Add a file into linger files = append(files, File{ Node: Node{ diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go index 0bd711c90..31c355d4a 100644 --- a/pkg/machine/qemu/machine.go +++ b/pkg/machine/qemu/machine.go @@ -13,6 +13,8 @@ import ( "strings" "time" + "github.com/containers/podman/v3/pkg/rootless" + "github.com/containers/podman/v3/pkg/machine" "github.com/containers/podman/v3/utils" "github.com/containers/storage/pkg/homedir" @@ -82,9 +84,10 @@ func NewMachine(opts machine.InitOptions) (machine.VM, error) { cmd = append(cmd, []string{"-qmp", monitor.Network + ":/" + monitor.Address + ",server=on,wait=off"}...) // Add network - cmd = append(cmd, "-nic", "user,model=virtio,hostfwd=tcp::"+strconv.Itoa(vm.Port)+"-:22") - - socketPath, err := getSocketDir() + // Right now the mac address is hardcoded so that the host networking gives it a specific IP address. This is + // why we can only run one vm at a time right now + cmd = append(cmd, []string{"-netdev", "socket,id=vlan,fd=3", "-device", "virtio-net-pci,netdev=vlan,mac=5a:94:ef:e4:0c:ee"}...) + socketPath, err := getRuntimeDir() if err != nil { return nil, err } @@ -235,12 +238,35 @@ func (v *MachineVM) Init(opts machine.InitOptions) error { // Start executes the qemu command line and forks it func (v *MachineVM) Start(name string, _ machine.StartOptions) error { var ( - conn net.Conn - err error - wait time.Duration = time.Millisecond * 500 + conn net.Conn + err error + qemuSocketConn net.Conn + wait time.Duration = time.Millisecond * 500 ) + if err := v.startHostNetworking(); err != nil { + return errors.Errorf("unable to start host networking: %q", err) + } + qemuSocketPath, _, err := v.getSocketandPid() + + for i := 0; i < 6; i++ { + qemuSocketConn, err = net.Dial("unix", qemuSocketPath) + if err == nil { + break + } + time.Sleep(wait) + wait++ + } + if err != nil { + return err + } + + fd, err := qemuSocketConn.(*net.UnixConn).File() + if err != nil { + return err + } + attr := new(os.ProcAttr) - files := []*os.File{os.Stdin, os.Stdout, os.Stderr} + files := []*os.File{os.Stdin, os.Stdout, os.Stderr, fd} attr.Files = files logrus.Debug(v.CmdLine) cmd := v.CmdLine @@ -256,7 +282,7 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error { return err } fmt.Println("Waiting for VM ...") - socketPath, err := getSocketDir() + socketPath, err := getRuntimeDir() if err != nil { return err } @@ -309,16 +335,42 @@ func (v *MachineVM) Stop(name string, _ machine.StopOptions) error { logrus.Error(err) } }() - _, err = qmpMonitor.Run(input) - return err + if _, err = qmpMonitor.Run(input); err != nil { + return err + } + _, pidFile, err := v.getSocketandPid() + if err != nil { + return err + } + if _, err := os.Stat(pidFile); os.IsNotExist(err) { + logrus.Infof("pid file %s does not exist", pidFile) + return nil + } + pidString, err := ioutil.ReadFile(pidFile) + if err != nil { + return err + } + pidNum, err := strconv.Atoi(string(pidString)) + if err != nil { + return err + } + + p, err := os.FindProcess(pidNum) + if p == nil && err != nil { + return err + } + return p.Kill() } // NewQMPMonitor creates the monitor subsection of our vm func NewQMPMonitor(network, name string, timeout time.Duration) (Monitor, error) { - rtDir, err := getSocketDir() + rtDir, err := getRuntimeDir() if err != nil { return Monitor{}, err } + if !rootless.IsRootless() { + rtDir = "/run" + } rtDir = filepath.Join(rtDir, "podman") if _, err := os.Stat(filepath.Join(rtDir)); os.IsNotExist(err) { // TODO 0644 is fine on linux but macos is weird @@ -533,3 +585,47 @@ func CheckActiveVM() (bool, string, error) { } return false, "", nil } + +// startHostNetworking runs a binary on the host system that allows users +// to setup port forwarding to the podman virtual machine +func (v *MachineVM) startHostNetworking() error { + binary, err := exec.LookPath(machine.ForwarderBinaryName) + if err != nil { + return err + } + // Listen on all at port 7777 for setting up and tearing + // down forwarding + listenSocket := "tcp://0.0.0.0:7777" + qemuSocket, pidFile, err := v.getSocketandPid() + if err != nil { + return err + } + attr := new(os.ProcAttr) + // Pass on stdin, stdout, stderr + files := []*os.File{os.Stdin, os.Stdout, os.Stderr} + attr.Files = files + cmd := []string{binary} + cmd = append(cmd, []string{"-listen", listenSocket, "-listen-qemu", fmt.Sprintf("unix://%s", qemuSocket), "-pid-file", pidFile}...) + // Add the ssh port + cmd = append(cmd, []string{"-ssh-port", fmt.Sprintf("%d", v.Port)}...) + if logrus.GetLevel() == logrus.DebugLevel { + cmd = append(cmd, "--debug") + fmt.Println(cmd) + } + _, err = os.StartProcess(cmd[0], cmd, attr) + return err +} + +func (v *MachineVM) getSocketandPid() (string, string, error) { + rtPath, err := getRuntimeDir() + if err != nil { + return "", "", err + } + if !rootless.IsRootless() { + rtPath = "/run" + } + socketDir := filepath.Join(rtPath, "podman") + pidFile := filepath.Join(socketDir, fmt.Sprintf("%s.pid", v.Name)) + qemuSocket := filepath.Join(socketDir, fmt.Sprintf("qemu_%s.sock", v.Name)) + return qemuSocket, pidFile, nil +} diff --git a/pkg/machine/qemu/options_darwin.go b/pkg/machine/qemu/options_darwin.go index 46ccf24cb..440937131 100644 --- a/pkg/machine/qemu/options_darwin.go +++ b/pkg/machine/qemu/options_darwin.go @@ -6,7 +6,7 @@ import ( "github.com/pkg/errors" ) -func getSocketDir() (string, error) { +func getRuntimeDir() (string, error) { tmpDir, ok := os.LookupEnv("TMPDIR") if !ok { return "", errors.New("unable to resolve TMPDIR") diff --git a/pkg/machine/qemu/options_darwin_amd64.go b/pkg/machine/qemu/options_darwin_amd64.go index 69f7982b2..ee1036291 100644 --- a/pkg/machine/qemu/options_darwin_amd64.go +++ b/pkg/machine/qemu/options_darwin_amd64.go @@ -5,7 +5,7 @@ var ( ) func (v *MachineVM) addArchOptions() []string { - opts := []string{"-cpu", "host"} + opts := []string{"-machine", "q35,accel=hvf:tcg"} return opts } diff --git a/pkg/machine/qemu/options_linux.go b/pkg/machine/qemu/options_linux.go index 0a2e40d8f..c73a68cc6 100644 --- a/pkg/machine/qemu/options_linux.go +++ b/pkg/machine/qemu/options_linux.go @@ -1,7 +1,13 @@ package qemu -import "github.com/containers/podman/v3/pkg/util" +import ( + "github.com/containers/podman/v3/pkg/rootless" + "github.com/containers/podman/v3/pkg/util" +) -func getSocketDir() (string, error) { +func getRuntimeDir() (string, error) { + if !rootless.IsRootless() { + return "/run", nil + } return util.GetRuntimeDir() } |