summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/common/netflags.go9
-rw-r--r--cmd/podman/containers/create.go2
-rw-r--r--cmd/podman/containers/run.go2
-rw-r--r--cmd/podman/pods/create.go3
-rw-r--r--libpod/networking_linux.go24
-rw-r--r--pkg/machine/config.go1
-rw-r--r--pkg/machine/ignition.go17
-rw-r--r--pkg/machine/qemu/machine.go118
-rw-r--r--pkg/machine/qemu/options_darwin.go2
-rw-r--r--pkg/machine/qemu/options_darwin_amd64.go2
-rw-r--r--pkg/machine/qemu/options_linux.go10
11 files changed, 169 insertions, 21 deletions
diff --git a/cmd/podman/common/netflags.go b/cmd/podman/common/netflags.go
index 9941bc716..4f634f355 100644
--- a/cmd/podman/common/netflags.go
+++ b/cmd/podman/common/netflags.go
@@ -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
)
@@ -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
diff --git a/cmd/podman/containers/create.go b/cmd/podman/containers/create.go
index 07a859983..68a17abd0 100644
--- a/cmd/podman/containers/create.go
+++ b/cmd/podman/containers/create.go
@@ -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
}
diff --git a/cmd/podman/containers/run.go b/cmd/podman/containers/run.go
index 2611c5b6e..579af4eb1 100644
--- a/cmd/podman/containers/run.go
+++ b/cmd/podman/containers/run.go
@@ -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
}
diff --git a/cmd/podman/pods/create.go b/cmd/podman/pods/create.go
index 3c2c8a3bc..735dfa78c 100644
--- a/cmd/podman/pods/create.go
+++ b/cmd/podman/pods/create.go
@@ -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")
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index 0e8a4f768..c928e02a6 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -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 == "" {
@@ -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
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()
}