diff options
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/api/handlers/compat/images_build.go | 22 | ||||
-rw-r--r-- | pkg/api/handlers/compat/images_remove.go | 35 | ||||
-rw-r--r-- | pkg/api/server/swagger.go | 2 | ||||
-rw-r--r-- | pkg/bindings/images/build.go | 7 | ||||
-rw-r--r-- | pkg/domain/infra/abi/system.go | 2 | ||||
-rw-r--r-- | pkg/machine/config.go | 14 | ||||
-rw-r--r-- | pkg/machine/ignition.go | 51 | ||||
-rw-r--r-- | pkg/machine/qemu/machine.go | 61 | ||||
-rw-r--r-- | pkg/machine/qemu/options_linux_amd64.go | 7 | ||||
-rw-r--r-- | pkg/specgen/generate/kube/volume.go | 2 | ||||
-rw-r--r-- | pkg/systemd/generate/common.go | 36 | ||||
-rw-r--r-- | pkg/systemd/generate/common_test.go | 147 | ||||
-rw-r--r-- | pkg/systemd/generate/containers.go | 21 | ||||
-rw-r--r-- | pkg/systemd/generate/containers_test.go | 91 | ||||
-rw-r--r-- | pkg/systemd/generate/pods.go | 8 | ||||
-rw-r--r-- | pkg/systemd/generate/pods_test.go | 19 |
16 files changed, 437 insertions, 88 deletions
diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go index 0a63d6e1c..36785a362 100644 --- a/pkg/api/handlers/compat/images_build.go +++ b/pkg/api/handlers/compat/images_build.go @@ -13,6 +13,7 @@ import ( "time" "github.com/containers/buildah" + "github.com/containers/buildah/define" "github.com/containers/buildah/imagebuildah" "github.com/containers/buildah/util" "github.com/containers/image/v5/types" @@ -98,6 +99,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { OutputFormat string `schema:"outputformat"` Platform string `schema:"platform"` Pull bool `schema:"pull"` + PullPolicy string `schema:"pullpolicy"` Quiet bool `schema:"q"` Registry string `schema:"registry"` Rm bool `schema:"rm"` @@ -199,13 +201,9 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { } format := buildah.Dockerv2ImageManifest registry := query.Registry - isolation := buildah.IsolationChroot - /* - // FIXME, This is very broken. Buildah will only work with chroot - isolation := buildah.IsolationDefault - */ + isolation := buildah.IsolationDefault if utils.IsLibpodRequest(r) { - // isolation = parseLibPodIsolation(query.Isolation) + isolation = parseLibPodIsolation(query.Isolation) registry = "" format = query.OutputFormat } else { @@ -279,10 +277,14 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { jobs = query.Jobs } - pullPolicy := buildah.PullIfMissing - if _, found := r.URL.Query()["pull"]; found { - if query.Pull { - pullPolicy = buildah.PullAlways + pullPolicy := define.PullIfMissing + if utils.IsLibpodRequest(r) { + pullPolicy = define.PolicyMap[query.PullPolicy] + } else { + if _, found := r.URL.Query()["pull"]; found { + if query.Pull { + pullPolicy = define.PullAlways + } } } diff --git a/pkg/api/handlers/compat/images_remove.go b/pkg/api/handlers/compat/images_remove.go index 874c57f16..e89558a86 100644 --- a/pkg/api/handlers/compat/images_remove.go +++ b/pkg/api/handlers/compat/images_remove.go @@ -4,7 +4,10 @@ import ( "net/http" "github.com/containers/podman/v3/libpod" + "github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/pkg/api/handlers/utils" + "github.com/containers/podman/v3/pkg/domain/entities" + "github.com/containers/podman/v3/pkg/domain/infra/abi" "github.com/gorilla/schema" "github.com/pkg/errors" ) @@ -30,28 +33,32 @@ func RemoveImage(w http.ResponseWriter, r *http.Request) { } } name := utils.GetName(r) - newImage, err := runtime.ImageRuntime().NewFromLocal(name) - if err != nil { - utils.ImageNotFound(w, name, errors.Wrapf(err, "failed to find image %s", name)) - return + imageEngine := abi.ImageEngine{Libpod: runtime} + + options := entities.ImageRemoveOptions{ + Force: query.Force, } + report, rmerrors := imageEngine.Remove(r.Context(), []string{name}, options) + if len(rmerrors) > 0 && rmerrors[0] != nil { + err := rmerrors[0] + if errors.Cause(err) == define.ErrNoSuchImage { + utils.ImageNotFound(w, name, errors.Wrapf(err, "failed to find image %s", name)) + return + } - results, err := runtime.RemoveImage(r.Context(), newImage, query.Force) - if err != nil { utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err) return } - - response := make([]map[string]string, 0, len(results.Untagged)+1) - deleted := make(map[string]string, 1) - deleted["Deleted"] = results.Deleted - response = append(response, deleted) - - for _, u := range results.Untagged { + response := make([]map[string]string, 0, len(report.Untagged)+1) + for _, d := range report.Deleted { + deleted := make(map[string]string, 1) + deleted["Deleted"] = d + response = append(response, deleted) + } + for _, u := range report.Untagged { untagged := make(map[string]string, 1) untagged["Untagged"] = u response = append(response, untagged) } - utils.WriteResponse(w, http.StatusOK, response) } diff --git a/pkg/api/server/swagger.go b/pkg/api/server/swagger.go index 12fd083bb..d282edf23 100644 --- a/pkg/api/server/swagger.go +++ b/pkg/api/server/swagger.go @@ -205,7 +205,7 @@ type swagHealthCheckRunResponse struct { type swagVersion struct { // in:body Body struct { - entities.SystemVersionReport + entities.ComponentVersion } } diff --git a/pkg/bindings/images/build.go b/pkg/bindings/images/build.go index 9d77883f9..17095b84b 100644 --- a/pkg/bindings/images/build.go +++ b/pkg/bindings/images/build.go @@ -15,7 +15,6 @@ import ( "strconv" "strings" - "github.com/containers/buildah" "github.com/containers/podman/v3/pkg/auth" "github.com/containers/podman/v3/pkg/bindings" "github.com/containers/podman/v3/pkg/domain/entities" @@ -175,9 +174,9 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO if len(platform) > 0 { params.Set("platform", platform) } - if options.PullPolicy == buildah.PullAlways { - params.Set("pull", "1") - } + + params.Set("pullpolicy", options.PullPolicy.String()) + if options.Quiet { params.Set("q", "1") } diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go index 9f7c8919b..a3e753384 100644 --- a/pkg/domain/infra/abi/system.go +++ b/pkg/domain/infra/abi/system.go @@ -67,7 +67,7 @@ func (ic *ContainerEngine) SetupRootless(_ context.Context, cmd *cobra.Command) if os.Geteuid() == 0 { ownsCgroup, err := cgroups.UserOwnsCurrentSystemdCgroup() if err != nil { - logrus.Warnf("Failed to detect the owner for the current cgroup: %v", err) + logrus.Infof("Failed to detect the owner for the current cgroup: %v", err) } if !ownsCgroup { conf, err := ic.Config(context.Background()) diff --git a/pkg/machine/config.go b/pkg/machine/config.go index 4933deee8..273deca00 100644 --- a/pkg/machine/config.go +++ b/pkg/machine/config.go @@ -7,19 +7,19 @@ import ( "path/filepath" "github.com/containers/storage/pkg/homedir" + "github.com/pkg/errors" ) type InitOptions struct { - Name string CPUS uint64 - Memory uint64 + DiskSize uint64 IgnitionPath string ImagePath string - Username string - URI url.URL IsDefault bool - //KernelPath string - //Devices []VMDevices + Memory uint64 + Name string + URI url.URL + Username string } type RemoteConnectionType string @@ -27,6 +27,8 @@ type RemoteConnectionType string var ( SSHRemoteConnection RemoteConnectionType = "ssh" DefaultIgnitionUserName = "core" + ErrNoSuchVM = errors.New("VM does not exist") + ErrVMAlreadyExists = errors.New("VM already exists") ) type Download struct { diff --git a/pkg/machine/ignition.go b/pkg/machine/ignition.go index ff79d5afb..a68d68ac3 100644 --- a/pkg/machine/ignition.go +++ b/pkg/machine/ignition.go @@ -2,6 +2,7 @@ package machine import ( "encoding/json" + "fmt" "io/ioutil" ) @@ -37,10 +38,17 @@ func getNodeGrp(grpName string) NodeGroup { return NodeGroup{Name: &grpName} } +type DynamicIgnition struct { + Name string + Key string + VMName string + WritePath string +} + // NewIgnitionFile -func NewIgnitionFile(name, key, writePath string) error { - if len(name) < 1 { - name = DefaultIgnitionUserName +func NewIgnitionFile(ign DynamicIgnition) error { + if len(ign.Name) < 1 { + ign.Name = DefaultIgnitionUserName } ignVersion := Ignition{ Version: "3.2.0", @@ -48,23 +56,44 @@ func NewIgnitionFile(name, key, writePath string) error { ignPassword := Passwd{ Users: []PasswdUser{{ - Name: name, - SSHAuthorizedKeys: []SSHAuthorizedKey{SSHAuthorizedKey(key)}, + Name: ign.Name, + SSHAuthorizedKeys: []SSHAuthorizedKey{SSHAuthorizedKey(ign.Key)}, }}, } ignStorage := Storage{ - Directories: getDirs(name), - Files: getFiles(name), - Links: getLinks(name), + Directories: getDirs(ign.Name), + Files: getFiles(ign.Name), + Links: getLinks(ign.Name), } + + // ready is a unit file that sets up the virtual serial device + // where when the VM is done configuring, it will send an ack + // so a listening host knows it can being interacting with it + ready := `[Unit] +Requires=dev-virtio\\x2dports-%s.device +OnFailure=emergency.target +OnFailureJobMode=isolate +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/bin/sh -c '/usr/bin/echo Ready >/dev/%s' +[Install] +RequiredBy=multi-user.target +` + _ = ready ignSystemd := Systemd{ Units: []Unit{ { Enabled: boolToPtr(true), Name: "podman.socket", - }}} - + }, + { + Enabled: boolToPtr(true), + Name: "ready.service", + Contents: strToPtr(fmt.Sprintf(ready, "vport1p1", "vport1p1")), + }, + }} ignConfig := Config{ Ignition: ignVersion, Passwd: ignPassword, @@ -75,7 +104,7 @@ func NewIgnitionFile(name, key, writePath string) error { if err != nil { return err } - return ioutil.WriteFile(writePath, b, 0644) + return ioutil.WriteFile(ign.WritePath, b, 0644) } func getDirs(usrName string) []Directory { diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go index b97eb991a..fe155750f 100644 --- a/pkg/machine/qemu/machine.go +++ b/pkg/machine/qemu/machine.go @@ -1,9 +1,11 @@ package qemu import ( + "bufio" "encoding/json" "fmt" "io/ioutil" + "net" "os" "os/exec" "path/filepath" @@ -22,9 +24,6 @@ import ( var ( // vmtype refers to qemu (vs libvirt, krun, etc) vmtype = "qemu" - // qemuCommon are the common command line arguments between the arches - //qemuCommon = []string{"-cpu", "host", "-qmp", "unix://tmp/qmp.sock,server,nowait"} - //qemuCommon = []string{"-cpu", "host", "-qmp", "tcp:localhost:4444,server,nowait"} ) // NewMachine initializes an instance of a virtual machine based on the qemu @@ -89,6 +88,16 @@ func NewMachine(opts machine.InitOptions) (machine.VM, error) { // Add network cmd = append(cmd, "-nic", "user,model=virtio,hostfwd=tcp::"+strconv.Itoa(vm.Port)+"-:22") + socketPath, err := getSocketDir() + if err != nil { + return nil, err + } + virtualSocketPath := filepath.Join(socketPath, "podman", vm.Name+"_ready.sock") + // Add serial port for readiness + cmd = append(cmd, []string{ + "-device", "virtio-serial", + "-chardev", "socket,path=" + virtualSocketPath + ",server,nowait,id=" + vm.Name + "_ready", + "-device", "virtserialport,chardev=" + vm.Name + "_ready" + ",name=org.fedoraproject.port.0"}...) vm.CmdLine = cmd return vm, nil } @@ -96,13 +105,15 @@ func NewMachine(opts machine.InitOptions) (machine.VM, error) { // LoadByName reads a json file that describes a known qemu vm // and returns a vm instance func LoadVMByName(name string) (machine.VM, error) { - // TODO need to define an error relating to ErrMachineNotFound vm := new(MachineVM) vmConfigDir, err := machine.GetConfDir(vmtype) if err != nil { return nil, err } b, err := ioutil.ReadFile(filepath.Join(vmConfigDir, name+".json")) + if os.IsNotExist(err) { + return nil, errors.Wrap(machine.ErrNoSuchVM, name) + } if err != nil { return nil, err } @@ -159,14 +170,28 @@ func (v *MachineVM) Init(opts machine.InitOptions) error { if err := v.prepare(); err != nil { return err } + + // Resize the disk image to input disk size + resize := exec.Command("qemu-img", []string{"resize", v.ImagePath, strconv.Itoa(int(opts.DiskSize)) + "G"}...) + if err := resize.Run(); err != nil { + return errors.Errorf("error resizing image: %q", err) + } // Write the ignition file - return machine.NewIgnitionFile(opts.Username, key, v.IgnitionFilePath) + ign := machine.DynamicIgnition{ + Name: opts.Username, + Key: key, + VMName: v.Name, + WritePath: v.IgnitionFilePath, + } + return machine.NewIgnitionFile(ign) } // Start executes the qemu command line and forks it func (v *MachineVM) Start(name string, _ machine.StartOptions) error { var ( - err error + conn net.Conn + err error + wait time.Duration = time.Millisecond * 500 ) attr := new(os.ProcAttr) files := []*os.File{os.Stdin, os.Stdout, os.Stderr} @@ -181,6 +206,30 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error { } _, err = os.StartProcess(v.CmdLine[0], cmd, attr) + if err != nil { + return err + } + fmt.Println("Waiting for VM ...") + socketPath, err := getSocketDir() + if err != nil { + return err + } + + // The socket is not made until the qemu process is running so here + // we do a backoff waiting for it. Once we have a conn, we break and + // then wait to read it. + for i := 0; i < 6; i++ { + conn, err = net.Dial("unix", filepath.Join(socketPath, "podman", v.Name+"_ready.sock")) + if err == nil { + break + } + time.Sleep(wait) + wait++ + } + if err != nil { + return err + } + _, err = bufio.NewReader(conn).ReadString('\n') return err } diff --git a/pkg/machine/qemu/options_linux_amd64.go b/pkg/machine/qemu/options_linux_amd64.go index cc0a4bab2..3edd97ea1 100644 --- a/pkg/machine/qemu/options_linux_amd64.go +++ b/pkg/machine/qemu/options_linux_amd64.go @@ -1,11 +1,14 @@ package qemu var ( - QemuCommand = "qemu-kvm" + QemuCommand = "qemu-system-x86_64" ) func (v *MachineVM) addArchOptions() []string { - opts := []string{"-cpu", "host"} + opts := []string{ + "-accel", "kvm", + "-cpu", "host", + } return opts } diff --git a/pkg/specgen/generate/kube/volume.go b/pkg/specgen/generate/kube/volume.go index e4f3eb196..a8042b532 100644 --- a/pkg/specgen/generate/kube/volume.go +++ b/pkg/specgen/generate/kube/volume.go @@ -116,7 +116,7 @@ func InitializeVolumes(specVolumes []v1.Volume) (map[string]*KubeVolume, error) for _, specVolume := range specVolumes { volume, err := VolumeFromSource(specVolume.VolumeSource) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "failed to create volume %q", specVolume.Name) } volumes[specVolume.Name] = volume diff --git a/pkg/systemd/generate/common.go b/pkg/systemd/generate/common.go index 19d468403..eafd45528 100644 --- a/pkg/systemd/generate/common.go +++ b/pkg/systemd/generate/common.go @@ -39,20 +39,46 @@ After=network-online.target RequiresMountsFor={{{{.GraphRoot}}}} {{{{.RunRoot}}}} ` -// filterPodFlags removes --pod and --pod-id-file from the specified command. -func filterPodFlags(command []string) []string { +// filterPodFlags removes --pod, --pod-id-file and --infra-conmon-pidfile from the specified command. +// argCount is the number of last arguments which should not be filtered, e.g. the container entrypoint. +func filterPodFlags(command []string, argCount int) []string { processed := []string{} - for i := 0; i < len(command); i++ { + for i := 0; i < len(command)-argCount; i++ { s := command[i] - if s == "--pod" || s == "--pod-id-file" { + if s == "--pod" || s == "--pod-id-file" || s == "--infra-conmon-pidfile" { i++ continue } - if strings.HasPrefix(s, "--pod=") || strings.HasPrefix(s, "--pod-id-file=") { + if strings.HasPrefix(s, "--pod=") || + strings.HasPrefix(s, "--pod-id-file=") || + strings.HasPrefix(s, "--infra-conmon-pidfile=") { continue } processed = append(processed, s) } + processed = append(processed, command[len(command)-argCount:]...) + return processed +} + +// filterCommonContainerFlags removes --conmon-pidfile, --cidfile and --cgroups from the specified command. +// argCount is the number of last arguments which should not be filtered, e.g. the container entrypoint. +func filterCommonContainerFlags(command []string, argCount int) []string { + processed := []string{} + for i := 0; i < len(command)-argCount; i++ { + s := command[i] + + switch { + case s == "--conmon-pidfile", s == "--cidfile", s == "--cgroups": + i++ + continue + case strings.HasPrefix(s, "--conmon-pidfile="), + strings.HasPrefix(s, "--cidfile="), + strings.HasPrefix(s, "--cgroups="): + continue + } + processed = append(processed, s) + } + processed = append(processed, command[len(command)-argCount:]...) return processed } diff --git a/pkg/systemd/generate/common_test.go b/pkg/systemd/generate/common_test.go index 3787e461e..30e758127 100644 --- a/pkg/systemd/generate/common_test.go +++ b/pkg/systemd/generate/common_test.go @@ -1,7 +1,6 @@ package generate import ( - "strings" "testing" "github.com/stretchr/testify/assert" @@ -9,22 +8,144 @@ import ( func TestFilterPodFlags(t *testing.T) { tests := []struct { - input []string + input []string + output []string + argCount int }{ - {[]string{"podman", "pod", "create"}}, - {[]string{"podman", "pod", "create", "--name", "foo"}}, - {[]string{"podman", "pod", "create", "--pod-id-file", "foo"}}, - {[]string{"podman", "pod", "create", "--pod-id-file=foo"}}, - {[]string{"podman", "run", "--pod", "foo"}}, - {[]string{"podman", "run", "--pod=foo"}}, + { + []string{"podman", "pod", "create"}, + []string{"podman", "pod", "create"}, + 0, + }, + { + []string{"podman", "pod", "create", "--name", "foo"}, + []string{"podman", "pod", "create", "--name", "foo"}, + 0, + }, + { + []string{"podman", "pod", "create", "--pod-id-file", "foo"}, + []string{"podman", "pod", "create"}, + 0, + }, + { + []string{"podman", "pod", "create", "--pod-id-file=foo"}, + []string{"podman", "pod", "create"}, + 0, + }, + { + []string{"podman", "pod", "create", "--pod-id-file", "foo", "--infra-conmon-pidfile", "foo"}, + []string{"podman", "pod", "create"}, + 0, + }, + { + []string{"podman", "pod", "create", "--pod-id-file", "foo", "--infra-conmon-pidfile=foo"}, + []string{"podman", "pod", "create"}, + 0, + }, + { + []string{"podman", "run", "--pod", "foo"}, + []string{"podman", "run"}, + 0, + }, + { + []string{"podman", "run", "--pod=foo"}, + []string{"podman", "run"}, + 0, + }, + { + []string{"podman", "run", "--pod=foo", "fedora", "podman", "run", "--pod=test", "alpine"}, + []string{"podman", "run", "fedora", "podman", "run", "--pod=test", "alpine"}, + 5, + }, + { + []string{"podman", "run", "--pod", "foo", "fedora", "podman", "run", "--pod", "test", "alpine"}, + []string{"podman", "run", "fedora", "podman", "run", "--pod", "test", "alpine"}, + 6, + }, + { + []string{"podman", "run", "--pod-id-file=foo", "fedora", "podman", "run", "--pod-id-file=test", "alpine"}, + []string{"podman", "run", "fedora", "podman", "run", "--pod-id-file=test", "alpine"}, + 5, + }, + { + []string{"podman", "run", "--pod-id-file", "foo", "fedora", "podman", "run", "--pod-id-file", "test", "alpine"}, + []string{"podman", "run", "fedora", "podman", "run", "--pod-id-file", "test", "alpine"}, + 6, + }, + } + + for _, test := range tests { + processed := filterPodFlags(test.input, test.argCount) + assert.Equal(t, test.output, processed) + } +} + +func TestFilterCommonContainerFlags(t *testing.T) { + tests := []struct { + input []string + output []string + argCount int + }{ + { + []string{"podman", "run", "alpine"}, + []string{"podman", "run", "alpine"}, + 1, + }, + { + []string{"podman", "run", "--conmon-pidfile", "foo", "alpine"}, + []string{"podman", "run", "alpine"}, + 1, + }, + { + []string{"podman", "run", "--conmon-pidfile=foo", "alpine"}, + []string{"podman", "run", "alpine"}, + 1, + }, + { + []string{"podman", "run", "--cidfile", "foo", "alpine"}, + []string{"podman", "run", "alpine"}, + 1, + }, + { + []string{"podman", "run", "--cidfile=foo", "alpine"}, + []string{"podman", "run", "alpine"}, + 1, + }, + { + []string{"podman", "run", "--cgroups", "foo", "alpine"}, + []string{"podman", "run", "alpine"}, + 1, + }, + { + []string{"podman", "run", "--cgroups=foo", "alpine"}, + []string{"podman", "run", "alpine"}, + 1, + }, + { + []string{"podman", "run", "--cgroups", "foo", "--conmon-pidfile", "foo", "--cidfile", "foo", "alpine"}, + []string{"podman", "run", "alpine"}, + 1, + }, + { + []string{"podman", "run", "--cgroups=foo", "--conmon-pidfile=foo", "--cidfile=foo", "alpine"}, + []string{"podman", "run", "alpine"}, + 1, + }, + { + []string{"podman", "run", "--cgroups", "foo", "--conmon-pidfile", "foo", "--cidfile", "foo", "alpine", "--cgroups", "foo", "--conmon-pidfile", "foo", "--cidfile", "foo"}, + []string{"podman", "run", "alpine", "--cgroups", "foo", "--conmon-pidfile", "foo", "--cidfile", "foo"}, + 7, + }, + { + []string{"podman", "run", "--cgroups=foo", "--conmon-pidfile=foo", "--cidfile=foo", "alpine", "--cgroups=foo", "--conmon-pidfile=foo", "--cidfile=foo"}, + []string{"podman", "run", "alpine", "--cgroups=foo", "--conmon-pidfile=foo", "--cidfile=foo"}, + 4, + }, } for _, test := range tests { - processed := filterPodFlags(test.input) - for _, s := range processed { - assert.False(t, strings.HasPrefix(s, "--pod-id-file")) - assert.False(t, strings.HasPrefix(s, "--pod")) - } + processed := filterCommonContainerFlags(test.input, test.argCount) + assert.Equal(t, test.output, processed) } } diff --git a/pkg/systemd/generate/containers.go b/pkg/systemd/generate/containers.go index bc13a6116..e06655a8d 100644 --- a/pkg/systemd/generate/containers.go +++ b/pkg/systemd/generate/containers.go @@ -238,13 +238,7 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst "--cidfile", "{{{{.ContainerIDFile}}}}", "--cgroups=no-conmon", ) - // If the container is in a pod, make sure that the - // --pod-id-file is set correctly. - if info.Pod != nil { - podFlags := []string{"--pod-id-file", "{{{{.Pod.PodIDFile}}}}"} - startCommand = append(startCommand, podFlags...) - info.CreateCommand = filterPodFlags(info.CreateCommand) - } + remainingCmd := info.CreateCommand[index:] // Presence check for certain flags/options. fs := pflag.NewFlagSet("args", pflag.ContinueOnError) @@ -254,7 +248,16 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst fs.BoolP("detach", "d", false, "") fs.String("name", "", "") fs.Bool("replace", false, "") - fs.Parse(info.CreateCommand[index:]) + fs.Parse(remainingCmd) + + remainingCmd = filterCommonContainerFlags(remainingCmd, fs.NArg()) + // If the container is in a pod, make sure that the + // --pod-id-file is set correctly. + if info.Pod != nil { + podFlags := []string{"--pod-id-file", "{{{{.Pod.PodIDFile}}}}"} + startCommand = append(startCommand, podFlags...) + remainingCmd = filterPodFlags(remainingCmd, fs.NArg()) + } hasDetachParam, err := fs.GetBool("detach") if err != nil { @@ -266,8 +269,6 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst return "", err } - remainingCmd := info.CreateCommand[index:] - if !hasDetachParam { // Enforce detaching // diff --git a/pkg/systemd/generate/containers_test.go b/pkg/systemd/generate/containers_test.go index 1359c1a37..899ba6bfa 100644 --- a/pkg/systemd/generate/containers_test.go +++ b/pkg/systemd/generate/containers_test.go @@ -395,6 +395,56 @@ Type=forking [Install] WantedBy=multi-user.target default.target ` + + goodNewWithIDFiles := `# jadda-jadda.service +# autogenerated by Podman CI + +[Unit] +Description=Podman jadda-jadda.service +Documentation=man:podman-generate-systemd(1) +Wants=network.target +After=network-online.target +RequiresMountsFor=/var/lib/containers/storage /var/run/containers/storage + +[Service] +Environment=PODMAN_SYSTEMD_UNIT=%n +Restart=always +TimeoutStopSec=70 +ExecStartPre=/bin/rm -f %t/jadda-jadda.pid %t/jadda-jadda.ctr-id +ExecStart=/usr/bin/podman run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon -d awesome-image:latest podman run --cgroups=foo --conmon-pidfile=foo --cidfile=foo alpine +ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 10 +ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id +PIDFile=%t/jadda-jadda.pid +Type=forking + +[Install] +WantedBy=multi-user.target default.target +` + + goodNewWithPodIDFiles := `# jadda-jadda.service +# autogenerated by Podman CI + +[Unit] +Description=Podman jadda-jadda.service +Documentation=man:podman-generate-systemd(1) +Wants=network.target +After=network-online.target +RequiresMountsFor=/var/lib/containers/storage /var/run/containers/storage + +[Service] +Environment=PODMAN_SYSTEMD_UNIT=%n +Restart=always +TimeoutStopSec=70 +ExecStartPre=/bin/rm -f %t/jadda-jadda.pid %t/jadda-jadda.ctr-id +ExecStart=/usr/bin/podman run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon --pod-id-file %t/pod-foobar.pod-id-file -d awesome-image:latest podman run --cgroups=foo --conmon-pidfile=foo --cidfile=foo --pod-id-file /tmp/pod-foobar.pod-id-file alpine +ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 10 +ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id +PIDFile=%t/jadda-jadda.pid +Type=forking + +[Install] +WantedBy=multi-user.target default.target +` tests := []struct { name string info containerInfo @@ -782,6 +832,47 @@ WantedBy=multi-user.target default.target false, false, }, + {"good with ID files", + containerInfo{ + Executable: "/usr/bin/podman", + ServiceName: "jadda-jadda", + ContainerNameOrID: "jadda-jadda", + RestartPolicy: "always", + PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid", + StopTimeout: 10, + PodmanVersion: "CI", + GraphRoot: "/var/lib/containers/storage", + RunRoot: "/var/run/containers/storage", + CreateCommand: []string{"I'll get stripped", "create", "--cgroups=foo", "--conmon-pidfile=foo", "--cidfile=foo", "awesome-image:latest", "podman", "run", "--cgroups=foo", "--conmon-pidfile=foo", "--cidfile=foo", "alpine"}, + EnvVariable: define.EnvVariable, + }, + goodNewWithIDFiles, + true, + false, + false, + }, + {"good with pod ID files", + containerInfo{ + Executable: "/usr/bin/podman", + ServiceName: "jadda-jadda", + ContainerNameOrID: "jadda-jadda", + RestartPolicy: "always", + PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid", + StopTimeout: 10, + PodmanVersion: "CI", + GraphRoot: "/var/lib/containers/storage", + RunRoot: "/var/run/containers/storage", + CreateCommand: []string{"I'll get stripped", "create", "--cgroups=foo", "--conmon-pidfile=foo", "--cidfile=foo", "--pod", "test", "awesome-image:latest", "podman", "run", "--cgroups=foo", "--conmon-pidfile=foo", "--cidfile=foo", "--pod-id-file", "/tmp/pod-foobar.pod-id-file", "alpine"}, + EnvVariable: define.EnvVariable, + Pod: &podInfo{ + PodIDFile: "%t/pod-foobar.pod-id-file", + }, + }, + goodNewWithPodIDFiles, + true, + false, + false, + }, } for _, tt := range tests { test := tt diff --git a/pkg/systemd/generate/pods.go b/pkg/systemd/generate/pods.go index a76979ecf..1b92649e8 100644 --- a/pkg/systemd/generate/pods.go +++ b/pkg/systemd/generate/pods.go @@ -279,16 +279,16 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions) } podRootArgs = info.CreateCommand[1 : podCreateIndex-1] info.RootFlags = strings.Join(escapeSystemdArguments(podRootArgs), " ") - podCreateArgs = filterPodFlags(info.CreateCommand[podCreateIndex+1:]) + podCreateArgs = filterPodFlags(info.CreateCommand[podCreateIndex+1:], 0) } // We're hard-coding the first five arguments and append the // CreateCommand with a stripped command and subcommand. startCommand := []string{info.Executable} startCommand = append(startCommand, podRootArgs...) startCommand = append(startCommand, - []string{"pod", "create", - "--infra-conmon-pidfile", "{{{{.PIDFile}}}}", - "--pod-id-file", "{{{{.PodIDFile}}}}"}...) + "pod", "create", + "--infra-conmon-pidfile", "{{{{.PIDFile}}}}", + "--pod-id-file", "{{{{.PodIDFile}}}}") // Presence check for certain flags/options. fs := pflag.NewFlagSet("args", pflag.ContinueOnError) diff --git a/pkg/systemd/generate/pods_test.go b/pkg/systemd/generate/pods_test.go index 559f7365f..0e4d92c50 100644 --- a/pkg/systemd/generate/pods_test.go +++ b/pkg/systemd/generate/pods_test.go @@ -320,6 +320,25 @@ WantedBy=multi-user.target default.target false, false, }, + {"pod --new with ID files", + podInfo{ + Executable: "/usr/bin/podman", + ServiceName: "pod-123abc", + InfraNameOrID: "jadda-jadda-infra", + RestartPolicy: "on-failure", + PIDFile: "/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid", + StopTimeout: 10, + PodmanVersion: "CI", + GraphRoot: "/var/lib/containers/storage", + RunRoot: "/var/run/containers/storage", + RequiredServices: []string{"container-1", "container-2"}, + CreateCommand: []string{"podman", "pod", "create", "--infra-conmon-pidfile", "/tmp/pod-123abc.pid", "--pod-id-file", "/tmp/pod-123abc.pod-id", "--name", "foo", "bar=arg with space"}, + }, + podGoodNamedNew, + true, + false, + false, + }, } for _, tt := range tests { |