diff options
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/autoupdate/autoupdate.go | 80 | ||||
-rw-r--r-- | pkg/domain/entities/auto-update.go | 3 | ||||
-rw-r--r-- | pkg/domain/infra/abi/pods.go | 4 | ||||
-rw-r--r-- | pkg/machine/qemu/machine.go | 2 | ||||
-rw-r--r-- | pkg/specgen/generate/container.go | 21 | ||||
-rw-r--r-- | pkg/specgen/generate/container_create.go | 5 | ||||
-rw-r--r-- | pkg/specgen/generate/oci.go | 3 | ||||
-rw-r--r-- | pkg/specgen/specgen.go | 8 | ||||
-rw-r--r-- | pkg/systemd/generate/common.go | 3 | ||||
-rw-r--r-- | pkg/systemd/generate/containers.go | 9 | ||||
-rw-r--r-- | pkg/systemd/generate/containers_test.go | 69 | ||||
-rw-r--r-- | pkg/util/utils.go | 6 | ||||
-rw-r--r-- | pkg/util/utils_test.go | 15 |
13 files changed, 185 insertions, 43 deletions
diff --git a/pkg/autoupdate/autoupdate.go b/pkg/autoupdate/autoupdate.go index c51e2cd03..b1ebbfa8e 100644 --- a/pkg/autoupdate/autoupdate.go +++ b/pkg/autoupdate/autoupdate.go @@ -88,7 +88,7 @@ func ValidateImageReference(imageName string) error { } else if err != nil { repo, err := reference.Parse(imageName) if err != nil { - return errors.Wrap(err, "error enforcing fully-qualified docker transport reference for auto updates") + return errors.Wrap(err, "enforcing fully-qualified docker transport reference for auto updates") } if _, ok := repo.(reference.NamedTagged); !ok { return errors.Errorf("auto updates require fully-qualified image references (no tag): %q", imageName) @@ -181,13 +181,13 @@ func autoUpdateRegistry(ctx context.Context, image *libimage.Image, ctr *libpod. cid := ctr.ID() rawImageName := ctr.RawImageName() if rawImageName == "" { - return nil, errors.Errorf("error registry auto-updating container %q: raw-image name is empty", cid) + return nil, errors.Errorf("registry auto-updating container %q: raw-image name is empty", cid) } labels := ctr.Labels() unit, exists := labels[systemdDefine.EnvVariable] if !exists { - return nil, errors.Errorf("error auto-updating container %q: no %s label found", ctr.ID(), systemdDefine.EnvVariable) + return nil, errors.Errorf("auto-updating container %q: no %s label found", ctr.ID(), systemdDefine.EnvVariable) } report := &entities.AutoUpdateReport{ @@ -201,7 +201,7 @@ func autoUpdateRegistry(ctx context.Context, image *libimage.Image, ctr *libpod. if _, updated := updatedRawImages[rawImageName]; updated { logrus.Infof("Auto-updating container %q using registry image %q", cid, rawImageName) - if err := restartSystemdUnit(ctr, unit, conn); err != nil { + if err := restartSystemdUnit(ctx, ctr, unit, conn); err != nil { return report, err } report.Updated = "true" @@ -211,7 +211,7 @@ func autoUpdateRegistry(ctx context.Context, image *libimage.Image, ctr *libpod. authfile := getAuthfilePath(ctr, options) needsUpdate, err := newerRemoteImageAvailable(ctx, runtime, image, rawImageName, authfile) if err != nil { - return report, errors.Wrapf(err, "error registry auto-updating container %q: image check for %q failed", cid, rawImageName) + return report, errors.Wrapf(err, "registry auto-updating container %q: image check for %q failed", cid, rawImageName) } if !needsUpdate { @@ -225,16 +225,30 @@ func autoUpdateRegistry(ctx context.Context, image *libimage.Image, ctr *libpod. } if _, err := updateImage(ctx, runtime, rawImageName, options); err != nil { - return report, errors.Wrapf(err, "error registry auto-updating container %q: image update for %q failed", cid, rawImageName) + return report, errors.Wrapf(err, "registry auto-updating container %q: image update for %q failed", cid, rawImageName) } updatedRawImages[rawImageName] = true logrus.Infof("Auto-updating container %q using registry image %q", cid, rawImageName) - if err := restartSystemdUnit(ctr, unit, conn); err != nil { - return report, err + updateErr := restartSystemdUnit(ctx, ctr, unit, conn) + if updateErr == nil { + report.Updated = "true" + return report, nil + } + + if !options.Rollback { + return report, updateErr + } + + // To fallback, simply retag the old image and restart the service. + if err := image.Tag(rawImageName); err != nil { + return report, errors.Wrap(err, "falling back to previous image") + } + if err := restartSystemdUnit(ctx, ctr, unit, conn); err != nil { + return report, errors.Wrap(err, "restarting unit with old image during fallback") } - report.Updated = "true" + report.Updated = "rolled back" return report, nil } @@ -243,13 +257,13 @@ func autoUpdateLocally(ctx context.Context, image *libimage.Image, ctr *libpod.C cid := ctr.ID() rawImageName := ctr.RawImageName() if rawImageName == "" { - return nil, errors.Errorf("error locally auto-updating container %q: raw-image name is empty", cid) + return nil, errors.Errorf("locally auto-updating container %q: raw-image name is empty", cid) } labels := ctr.Labels() unit, exists := labels[systemdDefine.EnvVariable] if !exists { - return nil, errors.Errorf("error auto-updating container %q: no %s label found", ctr.ID(), systemdDefine.EnvVariable) + return nil, errors.Errorf("auto-updating container %q: no %s label found", ctr.ID(), systemdDefine.EnvVariable) } report := &entities.AutoUpdateReport{ @@ -263,7 +277,7 @@ func autoUpdateLocally(ctx context.Context, image *libimage.Image, ctr *libpod.C needsUpdate, err := newerLocalImageAvailable(runtime, image, rawImageName) if err != nil { - return report, errors.Wrapf(err, "error locally auto-updating container %q: image check for %q failed", cid, rawImageName) + return report, errors.Wrapf(err, "locally auto-updating container %q: image check for %q failed", cid, rawImageName) } if !needsUpdate { @@ -277,23 +291,47 @@ func autoUpdateLocally(ctx context.Context, image *libimage.Image, ctr *libpod.C } logrus.Infof("Auto-updating container %q using local image %q", cid, rawImageName) - if err := restartSystemdUnit(ctr, unit, conn); err != nil { - return report, err + updateErr := restartSystemdUnit(ctx, ctr, unit, conn) + if updateErr == nil { + report.Updated = "true" + return report, nil } - report.Updated = "true" + if !options.Rollback { + return report, updateErr + } + + // To fallback, simply retag the old image and restart the service. + if err := image.Tag(rawImageName); err != nil { + return report, errors.Wrap(err, "falling back to previous image") + } + if err := restartSystemdUnit(ctx, ctr, unit, conn); err != nil { + return report, errors.Wrap(err, "restarting unit with old image during fallback") + } + + report.Updated = "rolled back" return report, nil } // restartSystemdUnit restarts the systemd unit the container is running in. -func restartSystemdUnit(ctr *libpod.Container, unit string, conn *dbus.Conn) error { - _, err := conn.RestartUnit(unit, "replace", nil) - if err != nil { - return errors.Wrapf(err, "error auto-updating container %q: restarting systemd unit %q failed", ctr.ID(), unit) +func restartSystemdUnit(ctx context.Context, ctr *libpod.Container, unit string, conn *dbus.Conn) error { + restartChan := make(chan string) + if _, err := conn.RestartUnitContext(ctx, unit, "replace", restartChan); err != nil { + return errors.Wrapf(err, "auto-updating container %q: restarting systemd unit %q failed", ctr.ID(), unit) } - logrus.Infof("Successfully restarted systemd unit %q of container %q", unit, ctr.ID()) - return nil + // Wait for the restart to finish and actually check if it was + // successful or not. + result := <-restartChan + + switch result { + case "done": + logrus.Infof("Successfully restarted systemd unit %q of container %q", unit, ctr.ID()) + return nil + + default: + return errors.Errorf("auto-updating container %q: restarting systemd unit %q failed: expected %q but received %q", ctr.ID(), unit, "done", result) + } } // imageContainersMap generates a map[image ID] -> [containers using the image] diff --git a/pkg/domain/entities/auto-update.go b/pkg/domain/entities/auto-update.go index eed617bf8..5ea2cdf15 100644 --- a/pkg/domain/entities/auto-update.go +++ b/pkg/domain/entities/auto-update.go @@ -8,6 +8,9 @@ type AutoUpdateOptions struct { // pending, it will be indicated in the Updated field of // AutoUpdateReport. DryRun bool + // If restarting the service with the new image failed, restart it + // another time with the previous image. + Rollback bool } // AutoUpdateReport contains the results from running auto-update. diff --git a/pkg/domain/infra/abi/pods.go b/pkg/domain/infra/abi/pods.go index 9f033a4c0..055c495d5 100644 --- a/pkg/domain/infra/abi/pods.go +++ b/pkg/domain/infra/abi/pods.go @@ -250,7 +250,9 @@ func (ic *ContainerEngine) prunePodHelper(ctx context.Context) ([]*entities.PodP func (ic *ContainerEngine) PodCreate(ctx context.Context, opts entities.PodCreateOptions) (*entities.PodCreateReport, error) { podSpec := specgen.NewPodSpecGenerator() - opts.ToPodSpecGen(podSpec) + if err := opts.ToPodSpecGen(podSpec); err != nil { + return nil, err + } pod, err := generate.MakePod(podSpec, ic.Libpod) if err != nil { return nil, err diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go index 0740a2b2c..7b1ebcb03 100644 --- a/pkg/machine/qemu/machine.go +++ b/pkg/machine/qemu/machine.go @@ -482,6 +482,8 @@ func (v *MachineVM) SSH(name string, opts machine.SSHOptions) error { } cmd := exec.Command("ssh", args...) + logrus.Debugf("Executing: ssh %v\n", args) + cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Stdin = os.Stdin diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go index 1f6d00eb7..ae26807a9 100644 --- a/pkg/specgen/generate/container.go +++ b/pkg/specgen/generate/container.go @@ -140,10 +140,29 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat // VM, which is the default behavior // - "container" denotes the container should join the VM of the SandboxID // (the infra container) - if len(s.Pod) > 0 { annotations[ann.SandboxID] = s.Pod annotations[ann.ContainerType] = ann.ContainerTypeContainer + // Check if this is an init-ctr and if so, check if + // the pod is running. we do not want to add init-ctrs to + // a running pod because it creates confusion for us. + if len(s.InitContainerType) > 0 { + p, err := r.LookupPod(s.Pod) + if err != nil { + return nil, err + } + containerStatuses, err := p.Status() + if err != nil { + return nil, err + } + // If any one of the containers is running, the pod is considered to be + // running + for _, con := range containerStatuses { + if con == define.ContainerStateRunning { + return nil, errors.New("cannot add init-ctr to a running pod") + } + } + } } for _, v := range rtc.Containers.Annotations { diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go index 4e3a86ae4..5101a6ccb 100644 --- a/pkg/specgen/generate/container_create.go +++ b/pkg/specgen/generate/container_create.go @@ -144,11 +144,14 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener options = append(options, libpod.WithNetworkAliases(s.Aliases)) } + if containerType := s.InitContainerType; len(containerType) > 0 { + options = append(options, libpod.WithInitCtrType(containerType)) + } + if len(s.Devices) > 0 { opts = extractCDIDevices(s) options = append(options, opts...) } - runtimeSpec, err := SpecGenToOCI(ctx, s, rt, rtc, newImage, finalMounts, pod, command) if err != nil { return nil, err diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go index 6e310d8a6..1f3f9e832 100644 --- a/pkg/specgen/generate/oci.go +++ b/pkg/specgen/generate/oci.go @@ -285,6 +285,9 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt } g.AddMount(cgroupMnt) } + + g.Config.Linux.Personality = s.Personality + g.SetProcessCwd(s.WorkDir) g.SetProcessArgs(finalCmd) diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go index 7eec48a55..fc647227e 100644 --- a/pkg/specgen/specgen.go +++ b/pkg/specgen/specgen.go @@ -183,6 +183,14 @@ type ContainerBasicConfig struct { // EnvSecrets are secrets that will be set as environment variables // Optional. EnvSecrets map[string]string `json:"secret_env,omitempty"` + // InitContainerType describes if this container is an init container + // and if so, what type: always or oneshot + InitContainerType string `json:"init_container_type"` + // Personality allows users to configure different execution domains. + // Execution domains tell Linux how to map signal numbers into signal actions. + // The execution domain system allows Linux to provide limited support + // for binaries compiled under other UNIX-like operating systems. + Personality *spec.LinuxPersonality `json:"personality,omitempty"` } // ContainerStorageConfig contains information on the storage configuration of a diff --git a/pkg/systemd/generate/common.go b/pkg/systemd/generate/common.go index 349805980..45e12014a 100644 --- a/pkg/systemd/generate/common.go +++ b/pkg/systemd/generate/common.go @@ -74,8 +74,7 @@ func filterCommonContainerFlags(command []string, argCount int) []string { case s == "--sdnotify", s == "--cgroups": i++ continue - case strings.HasPrefix(s, "--sdnotify="), - strings.HasPrefix(s, "--rm="), + case strings.HasPrefix(s, "--rm="), strings.HasPrefix(s, "--cgroups="): continue } diff --git a/pkg/systemd/generate/containers.go b/pkg/systemd/generate/containers.go index 083520316..78b81b54b 100644 --- a/pkg/systemd/generate/containers.go +++ b/pkg/systemd/generate/containers.go @@ -258,7 +258,6 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst } startCommand = append(startCommand, "run", - "--sdnotify=conmon", "--cgroups=no-conmon", "--rm", ) @@ -273,6 +272,7 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst fs.String("name", "", "") fs.Bool("replace", false, "") fs.StringArrayP("env", "e", nil, "") + fs.String("sdnotify", "", "") fs.Parse(remainingCmd) remainingCmd = filterCommonContainerFlags(remainingCmd, fs.NArg()) @@ -294,6 +294,13 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst return "", err } + // Default to --sdnotify=conmon unless already set by the + // container. + hasSdnotifyParam := fs.Lookup("sdnotify").Changed + if !hasSdnotifyParam { + startCommand = append(startCommand, "--sdnotify=conmon") + } + if !hasDetachParam { // Enforce detaching // diff --git a/pkg/systemd/generate/containers_test.go b/pkg/systemd/generate/containers_test.go index 1d24cc4a9..6141950d0 100644 --- a/pkg/systemd/generate/containers_test.go +++ b/pkg/systemd/generate/containers_test.go @@ -130,7 +130,29 @@ RequiresMountsFor=/var/run/containers/storage Environment=PODMAN_SYSTEMD_UNIT=%n Restart=always TimeoutStopSec=70 -ExecStart=/usr/bin/podman container run --sdnotify=conmon --cgroups=no-conmon --rm -d --replace --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN "foo=arg \"with \" space" +ExecStart=/usr/bin/podman container run --cgroups=no-conmon --rm --sdnotify=conmon -d --replace --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN "foo=arg \"with \" space" +Type=notify +NotifyAccess=all + +[Install] +WantedBy=multi-user.target default.target +` + + goodWithNameAndSdnotify := `# jadda-jadda.service +# autogenerated by Podman CI + +[Unit] +Description=Podman jadda-jadda.service +Documentation=man:podman-generate-systemd(1) +Wants=network-online.target +After=network-online.target +RequiresMountsFor=/var/run/containers/storage + +[Service] +Environment=PODMAN_SYSTEMD_UNIT=%n +Restart=always +TimeoutStopSec=70 +ExecStart=/usr/bin/podman container run --cgroups=no-conmon --rm -d --replace --sdnotify=container --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN "foo=arg \"with \" space" Type=notify NotifyAccess=all @@ -152,7 +174,7 @@ RequiresMountsFor=/var/run/containers/storage Environment=PODMAN_SYSTEMD_UNIT=%n Restart=always TimeoutStopSec=70 -ExecStart=/usr/bin/podman run --sdnotify=conmon --cgroups=no-conmon --rm --replace -d --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN +ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --sdnotify=conmon --replace -d --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN Type=notify NotifyAccess=all @@ -174,7 +196,7 @@ RequiresMountsFor=/var/run/containers/storage Environment=PODMAN_SYSTEMD_UNIT=%n Restart=always TimeoutStopSec=70 -ExecStart=/usr/bin/podman run --sdnotify=conmon --cgroups=no-conmon --rm --pod-id-file %t/pod-foobar.pod-id-file --replace -d --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN +ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --pod-id-file %t/pod-foobar.pod-id-file --sdnotify=conmon --replace -d --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN Type=notify NotifyAccess=all @@ -196,7 +218,7 @@ RequiresMountsFor=/var/run/containers/storage Environment=PODMAN_SYSTEMD_UNIT=%n Restart=always TimeoutStopSec=70 -ExecStart=/usr/bin/podman run --sdnotify=conmon --cgroups=no-conmon --rm --replace --detach --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN +ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --sdnotify=conmon --replace --detach --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN Type=notify NotifyAccess=all @@ -218,7 +240,7 @@ RequiresMountsFor=/var/run/containers/storage Environment=PODMAN_SYSTEMD_UNIT=%n Restart=always TimeoutStopSec=70 -ExecStart=/usr/bin/podman run --sdnotify=conmon --cgroups=no-conmon --rm -d awesome-image:latest +ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --sdnotify=conmon -d awesome-image:latest Type=notify NotifyAccess=all @@ -241,7 +263,7 @@ RequiresMountsFor=/var/run/containers/storage Environment=PODMAN_SYSTEMD_UNIT=%n Restart=always TimeoutStopSec=102 -ExecStart=/usr/bin/podman run --sdnotify=conmon --cgroups=no-conmon --rm ` + +ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --sdnotify=conmon ` + detachparam + ` awesome-image:latest Type=notify @@ -267,7 +289,7 @@ RequiresMountsFor=/var/run/containers/storage Environment=PODMAN_SYSTEMD_UNIT=%n Restart=always TimeoutStopSec=102 -ExecStart=/usr/bin/podman run --sdnotify=conmon --cgroups=no-conmon --rm -d --replace --name test -p 80:80 awesome-image:latest somecmd --detach=false +ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --sdnotify=conmon -d --replace --name test -p 80:80 awesome-image:latest somecmd --detach=false Type=notify NotifyAccess=all @@ -289,7 +311,7 @@ RequiresMountsFor=/var/run/containers/storage Environment=PODMAN_SYSTEMD_UNIT=%n Restart=always TimeoutStopSec=102 -ExecStart=/usr/bin/podman --events-backend none --runroot /root run --sdnotify=conmon --cgroups=no-conmon --rm -d awesome-image:latest +ExecStart=/usr/bin/podman --events-backend none --runroot /root run --cgroups=no-conmon --rm --sdnotify=conmon -d awesome-image:latest Type=notify NotifyAccess=all @@ -311,7 +333,7 @@ RequiresMountsFor=/var/run/containers/storage Environment=PODMAN_SYSTEMD_UNIT=%n Restart=always TimeoutStopSec=70 -ExecStart=/usr/bin/podman container run --sdnotify=conmon --cgroups=no-conmon --rm -d awesome-image:latest +ExecStart=/usr/bin/podman container run --cgroups=no-conmon --rm --sdnotify=conmon -d awesome-image:latest Type=notify NotifyAccess=all @@ -333,7 +355,7 @@ RequiresMountsFor=/var/run/containers/storage Environment=PODMAN_SYSTEMD_UNIT=%n Restart=always TimeoutStopSec=70 -ExecStart=/usr/bin/podman run --sdnotify=conmon --cgroups=no-conmon --rm -d --replace --name test --log-driver=journald --log-opt=tag={{.Name}} awesome-image:latest +ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --sdnotify=conmon -d --replace --name test --log-driver=journald --log-opt=tag={{.Name}} awesome-image:latest Type=notify NotifyAccess=all @@ -355,7 +377,7 @@ RequiresMountsFor=/var/run/containers/storage Environment=PODMAN_SYSTEMD_UNIT=%n Restart=always TimeoutStopSec=70 -ExecStart=/usr/bin/podman run --sdnotify=conmon --cgroups=no-conmon --rm -d --replace --name test awesome-image:latest sh -c "kill $$$$ && echo %%\\" +ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --sdnotify=conmon -d --replace --name test awesome-image:latest sh -c "kill $$$$ && echo %%\\" Type=notify NotifyAccess=all @@ -377,7 +399,7 @@ RequiresMountsFor=/var/run/containers/storage Environment=PODMAN_SYSTEMD_UNIT=%n Restart=always TimeoutStopSec=70 -ExecStart=/usr/bin/podman run --sdnotify=conmon --cgroups=no-conmon --rm -d --conmon-pidfile=foo --cidfile=foo awesome-image:latest podman run --cgroups=foo --conmon-pidfile=foo --cidfile=foo alpine +ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --sdnotify=conmon -d --conmon-pidfile=foo --cidfile=foo awesome-image:latest podman run --cgroups=foo --conmon-pidfile=foo --cidfile=foo alpine Type=notify NotifyAccess=all @@ -399,7 +421,7 @@ RequiresMountsFor=/var/run/containers/storage Environment=PODMAN_SYSTEMD_UNIT=%n Restart=always TimeoutStopSec=70 -ExecStart=/usr/bin/podman run --sdnotify=conmon --cgroups=no-conmon --rm --pod-id-file %t/pod-foobar.pod-id-file -d --conmon-pidfile=foo --cidfile=foo awesome-image:latest podman run --cgroups=foo --conmon-pidfile=foo --cidfile=foo --pod-id-file /tmp/pod-foobar.pod-id-file alpine +ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --pod-id-file %t/pod-foobar.pod-id-file --sdnotify=conmon -d --conmon-pidfile=foo --cidfile=foo awesome-image:latest podman run --cgroups=foo --conmon-pidfile=foo --cidfile=foo --pod-id-file /tmp/pod-foobar.pod-id-file alpine Type=notify NotifyAccess=all @@ -422,7 +444,7 @@ Environment=PODMAN_SYSTEMD_UNIT=%n Environment=FOO=abc "BAR=my test" USER=%%a Restart=always TimeoutStopSec=70 -ExecStart=/usr/bin/podman run --sdnotify=conmon --cgroups=no-conmon --rm -d --env FOO --env=BAR --env=MYENV=2 -e USER awesome-image:latest +ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --sdnotify=conmon -d --env FOO --env=BAR --env=MYENV=2 -e USER awesome-image:latest Type=notify NotifyAccess=all @@ -547,6 +569,25 @@ WantedBy=multi-user.target default.target false, false, }, + {"good with name and sdnotify", + containerInfo{ + Executable: "/usr/bin/podman", + ServiceName: "jadda-jadda", + ContainerNameOrID: "jadda-jadda", + RestartPolicy: "always", + PIDFile: "/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid", + StopTimeout: 10, + PodmanVersion: "CI", + CreateCommand: []string{"I'll get stripped", "container", "run", "--sdnotify=container", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN", "foo=arg \"with \" space"}, + EnvVariable: define.EnvVariable, + GraphRoot: "/var/lib/containers/storage", + RunRoot: "/var/run/containers/storage", + }, + goodWithNameAndSdnotify, + true, + false, + false, + }, {"good with explicit short detach param", containerInfo{ Executable: "/usr/bin/podman", diff --git a/pkg/util/utils.go b/pkg/util/utils.go index 60aa64ac1..774590f44 100644 --- a/pkg/util/utils.go +++ b/pkg/util/utils.go @@ -3,6 +3,7 @@ package util import ( "encoding/json" "fmt" + "math" "os" "os/user" "path/filepath" @@ -530,9 +531,10 @@ func ParseInputTime(inputTime string) (time.Time, error) { } } - unixTimestamp, err := strconv.ParseInt(inputTime, 10, 64) + unixTimestamp, err := strconv.ParseFloat(inputTime, 64) if err == nil { - return time.Unix(unixTimestamp, 0), nil + iPart, fPart := math.Modf(unixTimestamp) + return time.Unix(int64(iPart), int64(fPart*1_000_000_000)).UTC(), nil } // input might be a duration diff --git a/pkg/util/utils_test.go b/pkg/util/utils_test.go index cb737bd76..027acbdab 100644 --- a/pkg/util/utils_test.go +++ b/pkg/util/utils_test.go @@ -2,6 +2,7 @@ package util import ( "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -277,3 +278,17 @@ func TestPeriodAndQuotaToCores(t *testing.T) { assert.Equal(t, PeriodAndQuotaToCores(period, quota), expectedCores) } + +func TestParseInputTime(t *testing.T) { + tm, err := ParseInputTime("1.5") + if err != nil { + t.Errorf("expected error to be nil but was: %v", err) + } + + expected, err := time.ParseInLocation(time.RFC3339Nano, "1970-01-01T00:00:01.500000000Z", time.UTC) + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, expected, tm) +} |