summaryrefslogtreecommitdiff
path: root/pkg/machine
diff options
context:
space:
mode:
authorJason T. Greene <jason.greene@redhat.com>2022-01-29 03:10:28 -0600
committerJason T. Greene <jason.greene@redhat.com>2022-02-16 03:49:17 -0600
commitc74f8f04fd368ce74e35cc081e32133f7502d89e (patch)
tree1a098c2671edeaef87996fcdad018d1171122d41 /pkg/machine
parent8f5ba05ec4e0f58da80137f24fcb4ab27a2998fe (diff)
downloadpodman-c74f8f04fd368ce74e35cc081e32133f7502d89e.tar.gz
podman-c74f8f04fd368ce74e35cc081e32133f7502d89e.tar.bz2
podman-c74f8f04fd368ce74e35cc081e32133f7502d89e.zip
Introduce podman machine init --root=t|f and podman machine set --root=t|f
Switch default to rootless for mac and windows Signed-off-by: Jason T. Greene <jason.greene@redhat.com>
Diffstat (limited to 'pkg/machine')
-rw-r--r--pkg/machine/config.go9
-rw-r--r--pkg/machine/connection.go25
-rw-r--r--pkg/machine/qemu/config.go2
-rw-r--r--pkg/machine/qemu/machine.go122
-rw-r--r--pkg/machine/wsl/machine.go70
5 files changed, 189 insertions, 39 deletions
diff --git a/pkg/machine/config.go b/pkg/machine/config.go
index 97237f5e5..efb1eda15 100644
--- a/pkg/machine/config.go
+++ b/pkg/machine/config.go
@@ -27,6 +27,7 @@ type InitOptions struct {
URI url.URL
Username string
ReExec bool
+ Rootful bool
}
type QemuMachineStatus = string
@@ -35,7 +36,8 @@ const (
// Running indicates the qemu vm is running
Running QemuMachineStatus = "running"
// Stopped indicates the vm has stopped
- Stopped QemuMachineStatus = "stopped"
+ Stopped QemuMachineStatus = "stopped"
+ DefaultMachineName string = "podman-machine-default"
)
type Provider interface {
@@ -89,6 +91,10 @@ type ListResponse struct {
IdentityPath string
}
+type SetOptions struct {
+ Rootful bool
+}
+
type SSHOptions struct {
Username string
Args []string
@@ -107,6 +113,7 @@ type RemoveOptions struct {
type VM interface {
Init(opts InitOptions) (bool, error)
Remove(name string, opts RemoveOptions) (string, func() error, error)
+ Set(name string, opts SetOptions) error
SSH(name string, opts SSHOptions) error
Start(name string, opts StartOptions) error
Stop(name string, opts StopOptions) error
diff --git a/pkg/machine/connection.go b/pkg/machine/connection.go
index d28ffcef1..841b2afa6 100644
--- a/pkg/machine/connection.go
+++ b/pkg/machine/connection.go
@@ -39,6 +39,31 @@ func AddConnection(uri fmt.Stringer, name, identity string, isDefault bool) erro
return cfg.Write()
}
+func AnyConnectionDefault(name ...string) (bool, error) {
+ cfg, err := config.ReadCustomConfig()
+ if err != nil {
+ return false, err
+ }
+ for _, n := range name {
+ if n == cfg.Engine.ActiveService {
+ return true, nil
+ }
+ }
+
+ return false, nil
+}
+
+func ChangeDefault(name string) error {
+ cfg, err := config.ReadCustomConfig()
+ if err != nil {
+ return err
+ }
+
+ cfg.Engine.ActiveService = name
+
+ return cfg.Write()
+}
+
func RemoveConnection(name string) error {
cfg, err := config.ReadCustomConfig()
if err != nil {
diff --git a/pkg/machine/qemu/config.go b/pkg/machine/qemu/config.go
index e76509bb1..c619b7dd4 100644
--- a/pkg/machine/qemu/config.go
+++ b/pkg/machine/qemu/config.go
@@ -33,6 +33,8 @@ type MachineVM struct {
QMPMonitor Monitor
// RemoteUsername of the vm user
RemoteUsername string
+ // Whether this machine should run in a rootful or rootless manner
+ Rootful bool
}
type Mount struct {
diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go
index 81a6b4935..9beec2173 100644
--- a/pkg/machine/qemu/machine.go
+++ b/pkg/machine/qemu/machine.go
@@ -5,14 +5,15 @@ package qemu
import (
"bufio"
- "encoding/base64"
"context"
+ "encoding/base64"
"encoding/json"
"fmt"
"io/fs"
"io/ioutil"
"net"
"net/http"
+ "net/url"
"os"
"os/exec"
"path/filepath"
@@ -166,14 +167,8 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) {
key string
)
sshDir := filepath.Join(homedir.Get(), ".ssh")
- // GetConfDir creates the directory so no need to check for
- // its existence
- vmConfigDir, err := machine.GetConfDir(vmtype)
- if err != nil {
- return false, err
- }
- jsonFile := filepath.Join(vmConfigDir, v.Name) + ".json"
v.IdentityPath = filepath.Join(sshDir, v.Name)
+ v.Rootful = opts.Rootful
switch opts.ImagePath {
case "testing", "next", "stable", "":
@@ -256,29 +251,33 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) {
// This kind of stinks but no other way around this r/n
if len(opts.IgnitionPath) < 1 {
uri := machine.SSHRemoteConnection.MakeSSHURL("localhost", "/run/user/1000/podman/podman.sock", strconv.Itoa(v.Port), v.RemoteUsername)
- if err := machine.AddConnection(&uri, v.Name, filepath.Join(sshDir, v.Name), opts.IsDefault); err != nil {
- return false, err
+ uriRoot := machine.SSHRemoteConnection.MakeSSHURL("localhost", "/run/podman/podman.sock", strconv.Itoa(v.Port), "root")
+ identity := filepath.Join(sshDir, v.Name)
+
+ uris := []url.URL{uri, uriRoot}
+ names := []string{v.Name, v.Name + "-root"}
+
+ // The first connection defined when connections is empty will become the default
+ // regardless of IsDefault, so order according to rootful
+ if opts.Rootful {
+ uris[0], names[0], uris[1], names[1] = uris[1], names[1], uris[0], names[0]
}
- uriRoot := machine.SSHRemoteConnection.MakeSSHURL("localhost", "/run/podman/podman.sock", strconv.Itoa(v.Port), "root")
- if err := machine.AddConnection(&uriRoot, v.Name+"-root", filepath.Join(sshDir, v.Name), opts.IsDefault); err != nil {
- return false, err
+ for i := 0; i < 2; i++ {
+ if err := machine.AddConnection(&uris[i], names[i], identity, opts.IsDefault && i == 0); err != nil {
+ return false, err
+ }
}
} else {
fmt.Println("An ignition path was provided. No SSH connection was added to Podman")
}
// Write the JSON file
- b, err := json.MarshalIndent(v, "", " ")
- if err != nil {
- return false, err
- }
- if err := ioutil.WriteFile(jsonFile, b, 0644); err != nil {
- return false, err
- }
+ v.writeConfig()
// User has provided ignition file so keygen
// will be skipped.
if len(opts.IgnitionPath) < 1 {
+ var err error
key, err = machine.CreateSSHKeys(v.IdentityPath)
if err != nil {
return false, err
@@ -325,6 +324,30 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) {
return err == nil, err
}
+func (v *MachineVM) Set(name string, opts machine.SetOptions) error {
+ if v.Rootful == opts.Rootful {
+ return nil
+ }
+
+ changeCon, err := machine.AnyConnectionDefault(v.Name, v.Name+"-root")
+ if err != nil {
+ return err
+ }
+
+ if changeCon {
+ newDefault := v.Name
+ if opts.Rootful {
+ newDefault += "-root"
+ }
+ if err := machine.ChangeDefault(newDefault); err != nil {
+ return err
+ }
+ }
+
+ v.Rootful = opts.Rootful
+ return v.writeConfig()
+}
+
// Start executes the qemu command line and forks it
func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
var (
@@ -457,7 +480,7 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
}
}
- printAPIForwardInstructions(forwardState, forwardSock)
+ waitAPIAndPrintInfo(forwardState, forwardSock, v.Rootful, v.Name)
return nil
}
@@ -929,9 +952,17 @@ func (v *MachineVM) setupAPIForwarding(cmd []string) ([]string, string, apiForwa
return cmd, "", noForwarding
}
+ destSock := "/run/user/1000/podman/podman.sock"
+ forwardUser := "core"
+
+ if v.Rootful {
+ destSock = "/run/podman/podman.sock"
+ forwardUser = "root"
+ }
+
cmd = append(cmd, []string{"-forward-sock", socket}...)
- cmd = append(cmd, []string{"-forward-dest", "/run/podman/podman.sock"}...)
- cmd = append(cmd, []string{"-forward-user", "root"}...)
+ cmd = append(cmd, []string{"-forward-dest", destSock}...)
+ cmd = append(cmd, []string{"-forward-user", forwardUser}...)
cmd = append(cmd, []string{"-forward-identity", v.IdentityPath}...)
link := filepath.Join(filepath.Dir(filepath.Dir(socket)), "podman.sock")
@@ -1031,19 +1062,32 @@ func waitAndPingAPI(sock string) {
}
}
-func printAPIForwardInstructions(forwardState apiForwardingState, forwardSock string) {
+func waitAPIAndPrintInfo(forwardState apiForwardingState, forwardSock string, rootFul bool, name string) {
if forwardState != noForwarding {
waitAndPingAPI(forwardSock)
+ if !rootFul {
+ fmt.Printf("\nThis machine is currently configured in rootless mode. If your containers\n")
+ fmt.Printf("require root permissions (e.g. ports < 1024), or if you run into compatibility\n")
+ fmt.Printf("issues with non-podman clients, you can switch using the following command: \n")
+
+ suffix := ""
+ if name != machine.DefaultMachineName {
+ suffix = " " + name
+ }
+ fmt.Printf("\n\tpodman machine set --rootful%s\n\n", suffix)
+ }
+
fmt.Printf("API forwarding listening on: %s\n", forwardSock)
if forwardState == dockerGlobal {
- fmt.Printf("\nDocker API clients default to this address. You do not need to set DOCKER_HOST.\n\n")
+ fmt.Printf("Docker API clients default to this address. You do not need to set DOCKER_HOST.\n\n")
} else {
stillString := "still "
switch forwardState {
case notInstalled:
- fmt.Printf("\nThe system helper service is not installed; the default Docker API socket address can't be used by podman.\n")
+ fmt.Printf("\nThe system helper service is not installed; the default Docker API socket\n")
+ fmt.Printf("address can't be used by podman. ")
if helper := findClaimHelper(); len(helper) > 0 {
- fmt.Printf("If you would like to install it run the following command:\n")
+ fmt.Printf("If you would like to install it run the\nfollowing command:\n")
fmt.Printf("\n\tsudo %s install\n\n", helper)
}
case machineLocal:
@@ -1053,9 +1097,31 @@ func printAPIForwardInstructions(forwardState apiForwardingState, forwardSock st
default:
stillString = ""
}
- fmt.Printf("You can %sconnect Docker API clients by setting DOCKER HOST using the\n", stillString)
+
+ fmt.Printf("You can %sconnect Docker API clients by setting DOCKER_HOST using the\n", stillString)
fmt.Printf("following command in your terminal session:\n")
fmt.Printf("\n\texport DOCKER_HOST='unix://%s'\n\n", forwardSock)
}
}
}
+
+func (v *MachineVM) writeConfig() error {
+ // GetConfDir creates the directory so no need to check for
+ // its existence
+ vmConfigDir, err := machine.GetConfDir(vmtype)
+ if err != nil {
+ return err
+ }
+
+ jsonFile := filepath.Join(vmConfigDir, v.Name) + ".json"
+ // Write the JSON file
+ b, err := json.MarshalIndent(v, "", " ")
+ if err != nil {
+ return err
+ }
+ if err := ioutil.WriteFile(jsonFile, b, 0644); err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/pkg/machine/wsl/machine.go b/pkg/machine/wsl/machine.go
index 3edf3ddf6..6fe79863f 100644
--- a/pkg/machine/wsl/machine.go
+++ b/pkg/machine/wsl/machine.go
@@ -1,3 +1,4 @@
+//go:build windows
// +build windows
package wsl
@@ -8,6 +9,7 @@ import (
"fmt"
"io"
"io/ioutil"
+ "net/url"
"os"
"os/exec"
"path/filepath"
@@ -35,9 +37,6 @@ const (
ErrorSuccessRebootRequired = 3010
)
-// Usermode networking avoids potential nftables compatibility issues between the distro
-// and the WSL Kernel. Additionally it avoids fw rule conflicts between distros, since
-// all instances run under the same Kernel at runtime
const containersConf = `[containers]
[engine]
@@ -162,6 +161,8 @@ type MachineVM struct {
Port int
// RemoteUsername of the vm user
RemoteUsername string
+ // Whether this machine should run in a rootful or rootless manner
+ Rootful bool
}
type ExitCodeError struct {
@@ -227,12 +228,13 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) {
homeDir := homedir.Get()
sshDir := filepath.Join(homeDir, ".ssh")
v.IdentityPath = filepath.Join(sshDir, v.Name)
+ v.Rootful = opts.Rootful
if err := downloadDistro(v, opts); err != nil {
return false, err
}
- if err := writeJSON(v); err != nil {
+ if err := v.writeConfig(); err != nil {
return false, err
}
@@ -282,7 +284,7 @@ func downloadDistro(v *MachineVM, opts machine.InitOptions) error {
return machine.DownloadImage(dd)
}
-func writeJSON(v *MachineVM) error {
+func (v *MachineVM) writeConfig() error {
vmConfigDir, err := machine.GetConfDir(vmtype)
if err != nil {
return err
@@ -302,14 +304,26 @@ func writeJSON(v *MachineVM) error {
}
func setupConnections(v *MachineVM, opts machine.InitOptions, sshDir string) error {
+ uri := machine.SSHRemoteConnection.MakeSSHURL("localhost", "/run/user/1000/podman/podman.sock", strconv.Itoa(v.Port), v.RemoteUsername)
uriRoot := machine.SSHRemoteConnection.MakeSSHURL("localhost", "/run/podman/podman.sock", strconv.Itoa(v.Port), "root")
- if err := machine.AddConnection(&uriRoot, v.Name+"-root", filepath.Join(sshDir, v.Name), opts.IsDefault); err != nil {
- return err
+ identity := filepath.Join(sshDir, v.Name)
+
+ uris := []url.URL{uri, uriRoot}
+ names := []string{v.Name, v.Name + "-root"}
+
+ // The first connection defined when connections is empty will become the default
+ // regardless of IsDefault, so order according to rootful
+ if opts.Rootful {
+ uris[0], names[0], uris[1], names[1] = uris[1], names[1], uris[0], names[0]
+ }
+
+ for i := 0; i < 2; i++ {
+ if err := machine.AddConnection(&uris[i], names[i], identity, opts.IsDefault && i == 0); err != nil {
+ return err
+ }
}
- user := opts.Username
- uri := machine.SSHRemoteConnection.MakeSSHURL("localhost", withUser("/run/[USER]/1000/podman/podman.sock", user), strconv.Itoa(v.Port), v.RemoteUsername)
- return machine.AddConnection(&uri, v.Name, filepath.Join(sshDir, v.Name), opts.IsDefault)
+ return nil
}
func provisionWSLDist(v *MachineVM) (string, error) {
@@ -704,6 +718,30 @@ func pipeCmdPassThrough(name string, input string, arg ...string) error {
return cmd.Run()
}
+func (v *MachineVM) Set(name string, opts machine.SetOptions) error {
+ if v.Rootful == opts.Rootful {
+ return nil
+ }
+
+ changeCon, err := machine.AnyConnectionDefault(v.Name, v.Name+"-root")
+ if err != nil {
+ return err
+ }
+
+ if changeCon {
+ newDefault := v.Name
+ if opts.Rootful {
+ newDefault += "-root"
+ }
+ if err := machine.ChangeDefault(newDefault); err != nil {
+ return err
+ }
+ }
+
+ v.Rootful = opts.Rootful
+ return v.writeConfig()
+}
+
func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
if v.isRunning() {
return errors.Errorf("%q is already running", name)
@@ -716,6 +754,18 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
return errors.Wrap(err, "WSL bootstrap script failed")
}
+ if !v.Rootful {
+ fmt.Printf("\nThis machine is currently configured in rootless mode. If your containers\n")
+ fmt.Printf("require root permissions (e.g. ports < 1024), or if you run into compatibility\n")
+ fmt.Printf("issues with non-podman clients, you can switch using the following command: \n")
+
+ suffix := ""
+ if name != machine.DefaultMachineName {
+ suffix = " " + name
+ }
+ fmt.Printf("\n\tpodman machine set --rootful%s\n\n", suffix)
+ }
+
globalName, pipeName, err := launchWinProxy(v)
if err != nil {
fmt.Fprintln(os.Stderr, "API forwarding for Docker API clients is not available due to the following startup failures.")