summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pkg/machine/qemu/config.go11
-rw-r--r--pkg/machine/qemu/machine.go87
-rw-r--r--pkg/specgen/generate/container_create.go11
-rw-r--r--test/e2e/systemd_test.go27
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"})