mirror of https://github.com/containers/podman.git
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>
This commit is contained in:
parent
7dd463bad1
commit
7ef3981abe
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
@ -237,10 +240,33 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
|
|||
var (
|
||||
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)
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -5,7 +5,7 @@ var (
|
|||
)
|
||||
|
||||
func (v *MachineVM) addArchOptions() []string {
|
||||
opts := []string{"-cpu", "host"}
|
||||
opts := []string{"-machine", "q35,accel=hvf:tcg"}
|
||||
return opts
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue