Set machine docker.sock according to rootful flag

Signed-off-by: Jason T. Greene <jason.greene@redhat.com>
This commit is contained in:
Jason T. Greene
2023-05-12 13:35:49 -05:00
parent 2783651005
commit 5a176f09c2
12 changed files with 265 additions and 50 deletions

View File

@ -8,6 +8,7 @@ import (
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v4/pkg/machine"
"github.com/containers/podman/v4/pkg/machine/applehv"
"github.com/containers/podman/v4/pkg/machine/qemu"
"github.com/sirupsen/logrus"
)
@ -30,6 +31,8 @@ func GetSystemProvider() (machine.VirtProvider, error) {
switch resolvedVMType {
case machine.QemuVirt:
return qemu.GetVirtualizationProvider(), nil
case machine.AppleHvVirt:
return applehv.GetVirtualizationProvider(), nil
default:
return nil, fmt.Errorf("unsupported virtualization provider: `%s`", resolvedVMType.String())
}

View File

@ -193,6 +193,7 @@ func (m *MacMachine) Init(opts machine.InitOptions) (bool, error) {
TimeZone: opts.TimeZone,
WritePath: m.IgnitionFile.GetPath(),
UID: m.UID,
Rootful: m.Rootful,
}
if err := ign.GenerateIgnitionConfig(); err != nil {
@ -278,10 +279,10 @@ func (m *MacMachine) Remove(name string, opts machine.RemoveOptions) (string, fu
logrus.Error(err)
}
}
if err := machine.RemoveConnection(m.Name); err != nil {
if err := machine.RemoveConnections(m.Name); err != nil {
logrus.Error(err)
}
if err := machine.RemoveConnection(m.Name + "-root"); err != nil {
if err := machine.RemoveConnections(m.Name + "-root"); err != nil {
logrus.Error(err)
}

View File

@ -359,6 +359,8 @@ type HostUser struct {
Rootful bool
// UID is the numerical id of the user that called machine
UID int
// Whether one of these fields has changed and actions should be taken
Modified bool `json:"HostUserModified"`
}
// SSHConfig contains remote access information for SSH

View File

@ -27,7 +27,7 @@ type initMachine struct {
memory *uint
now bool
timezone string
rootful bool //nolint:unused
rootful bool
volumes []string
cmd []string
@ -62,6 +62,9 @@ func (i *initMachine) buildCmd(m *machineTestBuilder) []string {
if i.now {
cmd = append(cmd, "--now")
}
if i.rootful {
cmd = append(cmd, "--rootful")
}
cmd = append(cmd, m.name)
i.cmd = cmd
return cmd
@ -110,3 +113,8 @@ func (i *initMachine) withVolume(v string) *initMachine {
i.volumes = append(i.volumes, v)
return i
}
func (i *initMachine) withRootful(r bool) *initMachine {
i.rootful = r
return i
}

View File

@ -8,6 +8,7 @@ type setMachine struct {
cpus *uint
diskSize *uint
memory *uint
rootful bool
cmd []string
}
@ -23,6 +24,9 @@ func (i *setMachine) buildCmd(m *machineTestBuilder) []string {
if i.memory != nil {
cmd = append(cmd, "--memory", strconv.Itoa(int(*i.memory)))
}
if i.rootful {
cmd = append(cmd, "--rootful")
}
cmd = append(cmd, m.name)
i.cmd = cmd
return cmd
@ -41,3 +45,8 @@ func (i *setMachine) withMemory(num uint) *setMachine {
i.memory = &num
return i
}
func (i *setMachine) withRootful(r bool) *setMachine {
i.rootful = r
return i
}

View File

@ -3,6 +3,7 @@ package e2e_test
import (
"os"
"strconv"
"strings"
"time"
"github.com/containers/podman/v4/pkg/machine"
@ -162,4 +163,46 @@ var _ = Describe("podman machine init", func() {
Expect(sshSession2.outputToString()).To(ContainSubstring("example"))
})
It("machine init rootless docker.sock check", func() {
i := initMachine{}
name := randomString()
session, err := mb.setName(name).setCmd(i.withImagePath(mb.imagePath)).run()
Expect(err).ToNot(HaveOccurred())
Expect(session).To(Exit(0))
s := startMachine{}
ssession, err := mb.setCmd(s).setTimeout(time.Minute * 10).run()
Expect(err).ToNot(HaveOccurred())
Expect(ssession).Should(Exit(0))
ssh2 := sshMachine{}
sshSession2, err := mb.setName(name).setCmd(ssh2.withSSHCommand([]string{"readlink /var/run/docker.sock"})).run()
Expect(err).ToNot(HaveOccurred())
Expect(sshSession2).To(Exit(0))
output := strings.TrimSpace(sshSession2.outputToString())
Expect(output).To(HavePrefix("/run/user"))
Expect(output).To(HaveSuffix("/podman/podman.sock"))
})
It("machine init rootful docker.sock check", func() {
i := initMachine{}
name := randomString()
session, err := mb.setName(name).setCmd(i.withImagePath(mb.imagePath).withRootful(true)).run()
Expect(err).ToNot(HaveOccurred())
Expect(session).To(Exit(0))
s := startMachine{}
ssession, err := mb.setCmd(s).setTimeout(time.Minute * 10).run()
Expect(err).ToNot(HaveOccurred())
Expect(ssession).Should(Exit(0))
ssh2 := sshMachine{}
sshSession2, err := mb.setName(name).setCmd(ssh2.withSSHCommand([]string{"readlink /var/run/docker.sock"})).run()
Expect(err).ToNot(HaveOccurred())
Expect(sshSession2).To(Exit(0))
output := strings.TrimSpace(sshSession2.outputToString())
Expect(output).To(Equal("/run/podman/podman.sock"))
})
})

View File

@ -2,6 +2,7 @@ package e2e_test
import (
"strconv"
"strings"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
@ -100,4 +101,28 @@ var _ = Describe("podman machine set", func() {
Expect(sshSession3.outputToString()).To(ContainSubstring("100 GiB"))
})
It("set rootful, docker sock change", func() {
name := randomString()
i := new(initMachine)
session, err := mb.setName(name).setCmd(i.withImagePath(mb.imagePath)).run()
Expect(err).ToNot(HaveOccurred())
Expect(session).To(Exit(0))
set := setMachine{}
setSession, err := mb.setName(name).setCmd(set.withRootful(true)).run()
Expect(err).ToNot(HaveOccurred())
Expect(setSession).To(Exit(0))
s := new(startMachine)
startSession, err := mb.setCmd(s).run()
Expect(err).ToNot(HaveOccurred())
Expect(startSession).To(Exit(0))
ssh2 := sshMachine{}
sshSession2, err := mb.setName(name).setCmd(ssh2.withSSHCommand([]string{"readlink /var/run/docker.sock"})).run()
Expect(err).ToNot(HaveOccurred())
Expect(sshSession2).To(Exit(0))
output := strings.TrimSpace(sshSession2.outputToString())
Expect(output).To(Equal("/run/podman/podman.sock"))
})
})

View File

@ -20,6 +20,7 @@ import (
"github.com/containers/podman/v4/pkg/machine"
"github.com/containers/podman/v4/utils"
"github.com/containers/storage/pkg/homedir"
"github.com/containers/storage/pkg/ioutils"
"github.com/docker/go-units"
"github.com/sirupsen/logrus"
)
@ -154,11 +155,7 @@ func (m *HyperVMachine) Init(opts machine.InitOptions) (bool, error) {
}
// Write the JSON file for the second time. First time was in NewMachine
b, err := json.MarshalIndent(m, "", " ")
if err != nil {
return false, err
}
if err := os.WriteFile(m.ConfigPath.GetPath(), b, 0644); err != nil {
if err := m.writeConfig(); err != nil {
return false, err
}
@ -391,7 +388,11 @@ func (m *HyperVMachine) Set(name string, opts machine.SetOptions) ([]error, erro
}
if opts.Rootful != nil && m.Rootful != *opts.Rootful {
setErrors = append(setErrors, hypervctl.ErrNotImplemented)
if err := m.setRootful(*opts.Rootful); err != nil {
setErrors = append(setErrors, fmt.Errorf("failed to set rootful option: %w", err))
} else {
m.Rootful = *opts.Rootful
}
}
if opts.DiskSize != nil && m.DiskSize != *opts.DiskSize {
setErrors = append(setErrors, hypervctl.ErrNotImplemented)
@ -405,27 +406,8 @@ func (m *HyperVMachine) Set(name string, opts machine.SetOptions) ([]error, erro
memoryChanged = true
}
if !cpuChanged && !memoryChanged {
switch len(setErrors) {
case 0:
return nil, nil
case 1:
return nil, setErrors[0]
default:
return setErrors[1:], setErrors[0]
}
}
// Write the new JSON out
// considering this a hard return if we cannot write the JSON file.
b, err := json.MarshalIndent(m, "", " ")
if err != nil {
return setErrors, err
}
if err := os.WriteFile(m.ConfigPath.GetPath(), b, 0644); err != nil {
return setErrors, err
}
return setErrors, vm.UpdateProcessorMemSettings(func(ps *hypervctl.ProcessorSettings) {
if cpuChanged || memoryChanged {
err := vm.UpdateProcessorMemSettings(func(ps *hypervctl.ProcessorSettings) {
if cpuChanged {
ps.VirtualQuantity = m.CPUs
}
@ -437,6 +419,18 @@ func (m *HyperVMachine) Set(name string, opts machine.SetOptions) ([]error, erro
ms.Reservation = m.Memory
}
})
if err != nil {
setErrors = append(setErrors, err)
}
}
if len(setErrors) > 0 {
return setErrors, setErrors[0]
}
// Write the new JSON out
// considering this a hard return if we cannot write the JSON file.
return setErrors, m.writeConfig()
}
func (m *HyperVMachine) SSH(name string, opts machine.SSHOptions) error {
@ -472,7 +466,20 @@ func (m *HyperVMachine) Start(name string, opts machine.StartOptions) error {
return err
}
// Wait on notification from the guest
return m.ReadyHVSock.Listen()
if err := m.ReadyHVSock.Listen(); err != nil {
return err
}
if m.HostUser.Modified {
if machine.UpdatePodmanDockerSockService(m, name, m.UID, m.Rootful) == nil {
// Reset modification state if there are no errors, otherwise ignore errors
// which are already logged
m.HostUser.Modified = false
_ = m.writeConfig()
}
}
return nil
}
func (m *HyperVMachine) State(_ bool) (machine.Status, error) {
@ -661,3 +668,44 @@ func (m *HyperVMachine) forwardSocketPath() (*machine.VMFile, error) {
}
return machine.NewMachineFile(filepath.Join(path, sockName), &sockName)
}
func (m *HyperVMachine) writeConfig() error {
// Write the JSON file
opts := &ioutils.AtomicFileWriterOptions{ExplicitCommit: true}
w, err := ioutils.NewAtomicFileWriterWithOpts(m.ConfigPath.GetPath(), 0644, opts)
if err != nil {
return err
}
defer w.Close()
enc := json.NewEncoder(w)
enc.SetIndent("", " ")
if err := enc.Encode(m); err != nil {
return err
}
// Commit the changes to disk if no errors
return w.Commit()
}
func (m *HyperVMachine) setRootful(rootful bool) error {
changeCon, err := machine.AnyConnectionDefault(m.Name, m.Name+"-root")
if err != nil {
return err
}
if changeCon {
newDefault := m.Name
if rootful {
newDefault += "-root"
}
err := machine.ChangeDefault(newDefault)
if err != nil {
return err
}
}
m.HostUser.Modified = true
return nil
}

View File

@ -26,6 +26,7 @@ import (
const (
UserCertsTargetPath = "/etc/containers/certs.d"
PodmanDockerTmpConfPath = "/etc/tmpfiles.d/podman-docker.conf"
)
// Convenience function to convert int to ptr
@ -60,6 +61,7 @@ type DynamicIgnition struct {
VMType VMType
WritePath string
Cfg Config
Rootful bool
}
func (ign *DynamicIgnition) Write() error {
@ -95,7 +97,7 @@ func (ign *DynamicIgnition) GenerateIgnitionConfig() error {
ignStorage := Storage{
Directories: getDirs(ign.Name),
Files: getFiles(ign.Name, ign.UID),
Files: getFiles(ign.Name, ign.UID, ign.Rootful),
Links: getLinks(ign.Name),
}
@ -285,7 +287,7 @@ func getDirs(usrName string) []Directory {
return dirs
}
func getFiles(usrName string, uid int) []File {
func getFiles(usrName string, uid int, rootful bool) []File {
files := make([]File, 0)
lingerExample := `[Unit]
@ -448,14 +450,13 @@ Delegate=memory pids cpu io
files = append(files, File{
Node: Node{
Path: "/etc/tmpfiles.d/podman-docker.conf",
Path: PodmanDockerTmpConfPath,
},
FileEmbedded1: FileEmbedded1{
Append: nil,
// Create a symlink from the docker socket to the podman socket.
// Taken from https://github.com/containers/podman/blob/main/contrib/systemd/system/podman-docker.conf
Contents: Resource{
Source: EncodeDataURLPtr("L+ /run/docker.sock - - - - /run/podman/podman.sock\n"),
Source: EncodeDataURLPtr(GetPodmanDockerTmpConfig(uid, rootful, true)),
},
Mode: IntToPtr(0644),
},
@ -645,3 +646,17 @@ func getLinks(usrName string) []Link {
func EncodeDataURLPtr(contents string) *string {
return StrToPtr(fmt.Sprintf("data:,%s", url.PathEscape(contents)))
}
func GetPodmanDockerTmpConfig(uid int, rootful bool, newline bool) string {
// Derived from https://github.com/containers/podman/blob/main/contrib/systemd/system/podman-docker.conf
podmanSock := "/run/podman/podman.sock"
if !rootful {
podmanSock = fmt.Sprintf("/run/user/%d/podman/podman.sock", uid)
}
suffix := ""
if newline {
suffix = "\n"
}
return fmt.Sprintf("L+ /run/docker.sock - - - - %s%s", podmanSock, suffix)
}

View File

@ -387,6 +387,7 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) {
TimeZone: opts.TimeZone,
WritePath: v.getIgnitionFile(),
UID: v.UID,
Rootful: v.Rootful,
}
if err := ign.GenerateIgnitionConfig(); err != nil {
@ -645,6 +646,15 @@ func (v *MachineVM) Start(name string, opts machine.StartOptions) error {
if err != nil {
return err
}
if v.HostUser.Modified {
if machine.UpdatePodmanDockerSockService(v, name, v.UID, v.Rootful) == nil {
// Reset modification state if there are no errors, otherwise ignore errors
// which are already logged
v.HostUser.Modified = false
_ = v.writeConfig()
}
}
if len(v.Mounts) > 0 {
state, err := v.State(true)
if err != nil {
@ -1668,6 +1678,8 @@ func (v *MachineVM) setRootful(rootful bool) error {
return err
}
}
v.HostUser.Modified = true
return nil
}

28
pkg/machine/update.go Normal file
View File

@ -0,0 +1,28 @@
//go:build amd64 || arm64
// +build amd64 arm64
package machine
import (
"fmt"
"github.com/sirupsen/logrus"
)
func UpdatePodmanDockerSockService(vm VM, name string, uid int, rootful bool) error {
content := GetPodmanDockerTmpConfig(uid, rootful, false)
command := fmt.Sprintf("'echo %q > %s'", content, PodmanDockerTmpConfPath)
args := []string{"sudo", "bash", "-c", command}
if err := vm.SSH(name, SSHOptions{Args: args}); err != nil {
logrus.Warnf("Could not not update internal docker sock config")
return err
}
args = []string{"sudo", "systemd-tmpfiles", "--create", "--prefix=/run/docker.sock"}
if err := vm.SSH(name, SSHOptions{Args: args}); err != nil {
logrus.Warnf("Could not create internal docker sock")
return err
}
return nil
}

View File

@ -214,6 +214,8 @@ const (
pipePrefix = "npipe:////./pipe/"
globalPipe = "docker_engine"
userModeDist = "podman-net-usermode"
rootfulSock = "/run/podman/podman.sock"
rootlessSock = "/run/user/1000/podman/podman.sock"
)
type Virtualization struct {
@ -501,8 +503,8 @@ func (v *MachineVM) writeConfig() 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")
uri := machine.SSHRemoteConnection.MakeSSHURL("localhost", rootlessSock, strconv.Itoa(v.Port), v.RemoteUsername)
uriRoot := machine.SSHRemoteConnection.MakeSSHURL("localhost", rootfulSock, strconv.Itoa(v.Port), "root")
identity := filepath.Join(sshDir, v.Name)
uris := []url.URL{uri, uriRoot}
@ -620,6 +622,10 @@ func configureSystem(v *MachineVM, dist string) error {
return err
}
if err := v.setupPodmanDockerSock(dist, v.Rootful); err != nil {
return err
}
if err := wslInvoke(dist, "sh", "-c", "echo wsl > /etc/containers/podman-machine"); err != nil {
return fmt.Errorf("could not create podman-machine file for guest OS: %w", err)
}
@ -627,6 +633,16 @@ func configureSystem(v *MachineVM, dist string) error {
return changeDistUserModeNetworking(dist, user, "", v.UserModeNetworking)
}
func (v *MachineVM) setupPodmanDockerSock(dist string, rootful bool) error {
content := machine.GetPodmanDockerTmpConfig(1000, rootful, true)
if err := wslPipe(content, dist, "sh", "-c", "cat > "+machine.PodmanDockerTmpConfPath); err != nil {
return fmt.Errorf("could not create internal docker sock conf: %w", err)
}
return nil
}
func configureProxy(dist string, useProxy bool, quiet bool) error {
if !useProxy {
_ = wslInvoke(dist, "sh", "-c", clearProxySettings)
@ -1020,6 +1036,9 @@ func (v *MachineVM) Set(_ string, opts machine.SetOptions) ([]error, error) {
if err != nil {
setErrors = append(setErrors, fmt.Errorf("setting rootful option: %w", err))
} else {
if v.isRunning() {
logrus.Warn("restart is necessary for rootful change to go into effect")
}
v.Rootful = *opts.Rootful
}
}
@ -1155,11 +1174,11 @@ func launchWinProxy(v *MachineVM) (bool, string, error) {
return globalName, "", err
}
destSock := "/run/user/1000/podman/podman.sock"
destSock := rootlessSock
forwardUser := v.RemoteUsername
if v.Rootful {
destSock = "/run/podman/podman.sock"
destSock = rootfulSock
forwardUser = "root"
}
@ -1660,7 +1679,9 @@ func (v *MachineVM) setRootful(rootful bool) error {
return err
}
}
return nil
dist := toDist(v.Name)
return v.setupPodmanDockerSock(dist, rootful)
}
// Inspect returns verbose detail about the machine