diff options
-rw-r--r-- | pkg/machine/qemu/config.go | 11 | ||||
-rw-r--r-- | pkg/machine/qemu/machine.go | 87 | ||||
-rw-r--r-- | pkg/specgen/generate/container_create.go | 11 | ||||
-rw-r--r-- | test/e2e/systemd_test.go | 27 |
4 files changed, 131 insertions, 5 deletions
diff --git a/pkg/machine/qemu/config.go b/pkg/machine/qemu/config.go index 408b33a33..05a1d74d3 100644 --- a/pkg/machine/qemu/config.go +++ b/pkg/machine/qemu/config.go @@ -49,7 +49,7 @@ type MachineVMV1 struct { // SSH port for user networking Port int // QMPMonitor is the qemu monitor object for sending commands - QMPMonitor Monitor + QMPMonitor Monitorv1 // RemoteUsername of the vm user RemoteUsername string // Whether this machine should run in a rootful or rootless manner @@ -134,6 +134,15 @@ type Mount struct { ReadOnly bool } +type Monitorv1 struct { + // Address portion of the qmp monitor (/tmp/tmp.sock) + Address string + // Network portion of the qmp monitor (unix) + Network string + // Timeout in seconds for qmp monitor transactions + Timeout time.Duration +} + type Monitor struct { // Address portion of the qmp monitor (/tmp/tmp.sock) Address MachineFile diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go index ac8e7d75c..07155bbcf 100644 --- a/pkg/machine/qemu/machine.go +++ b/pkg/machine/qemu/machine.go @@ -131,6 +131,75 @@ func (p *Provider) NewMachine(opts machine.InitOptions) (machine.VM, error) { return vm, nil } +// migrateVM takes the old configuration structure and migrates it +// to the new structure and writes it to the filesystem +func migrateVM(configPath string, config []byte, vm *MachineVM) error { + fmt.Printf("Migrating machine %q\n", vm.Name) + var old MachineVMV1 + err := json.Unmarshal(config, &old) + if err != nil { + return err + } + // Looks like we loaded the older structure; now we need to migrate + // from the old structure to the new structure + _, pidFile, err := vm.getSocketandPid() + if err != nil { + return err + } + + pidFilePath := MachineFile{Path: pidFile} + qmpMonitor := Monitor{ + Address: MachineFile{Path: old.QMPMonitor.Address}, + Network: old.QMPMonitor.Network, + Timeout: old.QMPMonitor.Timeout, + } + socketPath, err := getRuntimeDir() + if err != nil { + return err + } + virtualSocketPath := filepath.Join(socketPath, "podman", vm.Name+"_ready.sock") + readySocket := MachineFile{Path: virtualSocketPath} + + vm.HostUser = HostUser{} + vm.ImageConfig = ImageConfig{} + vm.ResourceConfig = ResourceConfig{} + vm.SSHConfig = SSHConfig{} + + vm.CPUs = old.CPUs + vm.CmdLine = old.CmdLine + vm.DiskSize = old.DiskSize + vm.IdentityPath = old.IdentityPath + vm.IgnitionFilePath = old.IgnitionFilePath + vm.ImagePath = old.ImagePath + vm.ImageStream = old.ImageStream + vm.Memory = old.Memory + vm.Mounts = old.Mounts + vm.Name = old.Name + vm.PidFilePath = pidFilePath + vm.Port = old.Port + vm.QMPMonitor = qmpMonitor + vm.ReadySocket = readySocket + vm.RemoteUsername = old.RemoteUsername + vm.Rootful = old.Rootful + vm.UID = old.UID + + // Backup the original config file + if err := os.Rename(configPath, configPath+".orig"); err != nil { + return err + } + // Write the config file + if err := vm.writeConfig(); err != nil { + // If the config file fails to be written, put the origina + // config file back before erroring + if renameError := os.Rename(configPath+".orig", configPath); renameError != nil { + logrus.Warn(renameError) + } + return err + } + // Remove the backup file + return os.Remove(configPath + ".orig") +} + // LoadByName reads a json file that describes a known qemu vm // and returns a vm instance func (p *Provider) LoadVMByName(name string) (machine.VM, error) { @@ -140,7 +209,8 @@ func (p *Provider) LoadVMByName(name string) (machine.VM, error) { if err != nil { return nil, err } - b, err := ioutil.ReadFile(filepath.Join(vmConfigDir, name+".json")) + path := filepath.Join(vmConfigDir, name+".json") + b, err := ioutil.ReadFile(path) if os.IsNotExist(err) { return nil, errors.Wrap(machine.ErrNoSuchVM, name) } @@ -148,7 +218,13 @@ func (p *Provider) LoadVMByName(name string) (machine.VM, error) { return nil, err } err = json.Unmarshal(b, vm) - + if err != nil { + migrateErr := migrateVM(path, b, vm) + if migrateErr != nil { + return nil, migrateErr + } + err = migrateErr + } // It is here for providing the ability to propagate // proxy settings (e.g. HTTP_PROXY and others) on a start // and avoid a need of re-creating/re-initiating a VM @@ -911,7 +987,12 @@ func GetVMInfos() ([]*machine.ListResponse, error) { } err = json.Unmarshal(b, vm) if err != nil { - return err + // Checking if the file did not unmarshal because it is using + // the deprecated config file format. + migrateErr := migrateVM(fullPath, b, vm) + if migrateErr != nil { + return migrateErr + } } listEntry := new(machine.ListResponse) diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go index 8ab0eae5a..a014f5047 100644 --- a/pkg/specgen/generate/container_create.go +++ b/pkg/specgen/generate/container_create.go @@ -304,7 +304,16 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen. "/usr/sbin/init": true, "/usr/local/sbin/init": true, } - if useSystemdCommands[command[0]] || (filepath.Base(command[0]) == "systemd") { + // Grab last command incase this is launched from a shell + cmd := command + if len(command) > 2 { + // Podman build will add "/bin/sh" "-c" to + // Entrypoint. Remove and search for systemd + if command[0] == "/bin/sh" && command[1] == "-c" { + cmd = command[2:] + } + } + if useSystemdCommands[cmd[0]] || (filepath.Base(cmd[0]) == "systemd") { useSystemd = true } } diff --git a/test/e2e/systemd_test.go b/test/e2e/systemd_test.go index f8d8db592..57fc323ce 100644 --- a/test/e2e/systemd_test.go +++ b/test/e2e/systemd_test.go @@ -1,8 +1,10 @@ package integration import ( + "fmt" "io/ioutil" "os" + "path/filepath" "strings" . "github.com/containers/podman/v4/test/utils" @@ -130,6 +132,31 @@ WantedBy=default.target Expect(conData[0].Config.SystemdMode).To(BeTrue()) }) + It("podman systemd in command triggers systemd mode", func() { + containerfile := fmt.Sprintf(`FROM %s +RUN mkdir -p /usr/lib/systemd/; touch /usr/lib/systemd/systemd +CMD /usr/lib/systemd/systemd`, ALPINE) + + containerfilePath := filepath.Join(podmanTest.TempDir, "Containerfile") + err := ioutil.WriteFile(containerfilePath, []byte(containerfile), 0755) + Expect(err).To(BeNil()) + session := podmanTest.Podman([]string{"build", "-t", "systemd", "--file", containerfilePath, podmanTest.TempDir}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + ctrName := "testCtr" + run := podmanTest.Podman([]string{"create", "--name", ctrName, "systemd"}) + run.WaitWithDefaultTimeout() + Expect(run).Should(Exit(0)) + + result := podmanTest.Podman([]string{"inspect", ctrName}) + result.WaitWithDefaultTimeout() + Expect(result).Should(Exit(0)) + conData := result.InspectContainerToJSON() + Expect(conData).To(HaveLen(1)) + Expect(conData[0].Config.SystemdMode).To(BeTrue()) + }) + It("podman create container with --uidmap and conmon PidFile accessible", func() { ctrName := "testCtrUidMap" run := podmanTest.Podman([]string{"run", "-d", "--uidmap=0:1:1000", "--name", ctrName, ALPINE, "top"}) |