Skip to content

Commit

Permalink
Merge pull request containers#10488 from baude/machinehostnetwork
Browse files Browse the repository at this point in the history
Enable port forwarding on host
  • Loading branch information
openshift-merge-robot committed Jun 1, 2021
2 parents 7a52440 + 7ef3981 commit cbffddd
Show file tree
Hide file tree
Showing 11 changed files with 169 additions and 21 deletions.
9 changes: 7 additions & 2 deletions cmd/podman/common/netflags.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,10 @@ func DefineNetFlags(cmd *cobra.Command) {
)
}

func NetFlagsToNetOptions(cmd *cobra.Command) (*entities.NetOptions, error) {
// NetFlagsToNetOptions parses the network flags for the given cmd.
// The netnsFromConfig bool is used to indicate if the --network flag
// should always be parsed regardless if it was set on the cli.
func NetFlagsToNetOptions(cmd *cobra.Command, netnsFromConfig bool) (*entities.NetOptions, error) {
var (
err error
)
Expand Down Expand Up @@ -193,7 +196,9 @@ func NetFlagsToNetOptions(cmd *cobra.Command) (*entities.NetOptions, error) {
return nil, err
}

if cmd.Flags().Changed("network") {
// parse the --network value only when the flag is set or we need to use
// the netns config value, e.g. when --pod is not used
if netnsFromConfig || cmd.Flag("network").Changed {
network, err := cmd.Flags().GetString("network")
if err != nil {
return nil, err
Expand Down
2 changes: 1 addition & 1 deletion cmd/podman/containers/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func create(cmd *cobra.Command, args []string) error {
var (
err error
)
cliVals.Net, err = common.NetFlagsToNetOptions(cmd)
cliVals.Net, err = common.NetFlagsToNetOptions(cmd, cliVals.Pod == "")
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/podman/containers/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func init() {

func run(cmd *cobra.Command, args []string) error {
var err error
cliVals.Net, err = common.NetFlagsToNetOptions(cmd)
cliVals.Net, err = common.NetFlagsToNetOptions(cmd, cliVals.Pod == "")
if err != nil {
return err
}
Expand Down
3 changes: 2 additions & 1 deletion cmd/podman/pods/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,11 @@ func create(cmd *cobra.Command, args []string) error {
defer errorhandling.SyncQuiet(podIDFD)
}

createOptions.Net, err = common.NetFlagsToNetOptions(cmd)
createOptions.Net, err = common.NetFlagsToNetOptions(cmd, createOptions.Infra)
if err != nil {
return err
}

if len(createOptions.Net.PublishPorts) > 0 {
if !createOptions.Infra {
return errors.Errorf("you must have an infra container to publish port bindings to the host")
Expand Down
24 changes: 23 additions & 1 deletion libpod/networking_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,6 @@ func (r *Runtime) GetRootlessCNINetNs(new bool) (*RootlessCNI, error) {
if err != nil {
return nil, errors.Wrap(err, "error creating rootless cni network namespace")
}

// setup slirp4netns here
path := r.config.Engine.NetworkCmdPath
if path == "" {
Expand Down Expand Up @@ -437,9 +436,32 @@ func (r *Runtime) GetRootlessCNINetNs(new bool) (*RootlessCNI, error) {
return rootlessCNINS, nil
}

// setPrimaryMachineIP is used for podman-machine and it sets
// and environment variable with the IP address of the podman-machine
// host.
func setPrimaryMachineIP() error {
// no connection is actually made here
conn, err := net.Dial("udp", "8.8.8.8:80")
if err != nil {
return err
}
defer func() {
if err := conn.Close(); err != nil {
logrus.Error(err)
}
}()
addr := conn.LocalAddr().(*net.UDPAddr)
return os.Setenv("PODMAN_MACHINE_HOST", addr.IP.String())
}

// setUpOCICNIPod will set up the cni networks, on error it will also tear down the cni
// networks. If rootless it will join/create the rootless cni namespace.
func (r *Runtime) setUpOCICNIPod(podNetwork ocicni.PodNetwork) ([]ocicni.NetResult, error) {
if r.config.MachineEnabled() {
if err := setPrimaryMachineIP(); err != nil {
return nil, err
}
}
rootlessCNINS, err := r.GetRootlessCNINetNs(true)
if err != nil {
return nil, err
Expand Down
1 change: 1 addition & 0 deletions pkg/machine/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
17 changes: 17 additions & 0 deletions pkg/machine/ignition.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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{
Expand Down
118 changes: 107 additions & 11 deletions pkg/machine/qemu/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
Expand All @@ -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
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}
2 changes: 1 addition & 1 deletion pkg/machine/qemu/options_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
2 changes: 1 addition & 1 deletion pkg/machine/qemu/options_darwin_amd64.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ var (
)

func (v *MachineVM) addArchOptions() []string {
opts := []string{"-cpu", "host"}
opts := []string{"-machine", "q35,accel=hvf:tcg"}
return opts
}

Expand Down
10 changes: 8 additions & 2 deletions pkg/machine/qemu/options_linux.go
Original file line number Diff line number Diff line change
@@ -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()
}

0 comments on commit cbffddd

Please sign in to comment.