mirror of
https://github.com/containers/podman.git
synced 2025-06-08 00:00:51 +08:00
Add small fixes for 'podman run' from diffing inspect
To try and identify differences between Podman v1.9 and master, I ran a series of `podman run` commands with various flags through each, then inspecting the resulting containers and diffed the inspect JSON between each. This identified a number of issues which are fixed in this PR. In order of discovery: - Podman v2 gave short names for images, where Podman v1 gave the fully-qualified name. Simple enough fix (get image tags and use the first one if they're available) - The --restart flag was not being parsed correctly when a number of retries was specified. Parsing has been corrected. - The -m flag was not setting the swap limit (simple fix to set swap in that case if it's not explicitly set by the user) - The --cpus flag was completely nonfunctional (wired in its logic) Tests have been added for all of these to catch future regressions. Signed-off-by: Matthew Heon <matthew.heon@pm.me>
This commit is contained in:
@ -26,6 +26,16 @@ func getCPULimits(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string)
|
|||||||
cpu := &specs.LinuxCPU{}
|
cpu := &specs.LinuxCPU{}
|
||||||
hasLimits := false
|
hasLimits := false
|
||||||
|
|
||||||
|
const cpuPeriod = 100000
|
||||||
|
|
||||||
|
if c.CPUS > 0 {
|
||||||
|
quota := int64(c.CPUS * cpuPeriod)
|
||||||
|
period := uint64(cpuPeriod)
|
||||||
|
|
||||||
|
cpu.Period = &period
|
||||||
|
cpu.Quota = "a
|
||||||
|
hasLimits = true
|
||||||
|
}
|
||||||
if c.CPUShares > 0 {
|
if c.CPUShares > 0 {
|
||||||
cpu.Shares = &c.CPUShares
|
cpu.Shares = &c.CPUShares
|
||||||
hasLimits = true
|
hasLimits = true
|
||||||
@ -142,6 +152,10 @@ func getMemoryLimits(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []strin
|
|||||||
return nil, errors.Wrapf(err, "invalid value for memory")
|
return nil, errors.Wrapf(err, "invalid value for memory")
|
||||||
}
|
}
|
||||||
memory.Limit = &ml
|
memory.Limit = &ml
|
||||||
|
if c.MemorySwap == "" {
|
||||||
|
limit := 2 * ml
|
||||||
|
memory.Swap = &(limit)
|
||||||
|
}
|
||||||
hasLimits = true
|
hasLimits = true
|
||||||
}
|
}
|
||||||
if m := c.MemoryReservation; len(m) > 0 {
|
if m := c.MemoryReservation; len(m) > 0 {
|
||||||
@ -606,7 +620,29 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
|
|||||||
s.Name = c.Name
|
s.Name = c.Name
|
||||||
|
|
||||||
s.OOMScoreAdj = &c.OOMScoreAdj
|
s.OOMScoreAdj = &c.OOMScoreAdj
|
||||||
s.RestartPolicy = c.Restart
|
if c.Restart != "" {
|
||||||
|
splitRestart := strings.Split(c.Restart, ":")
|
||||||
|
switch len(splitRestart) {
|
||||||
|
case 1:
|
||||||
|
// No retries specified
|
||||||
|
case 2:
|
||||||
|
if strings.ToLower(splitRestart[0]) != "on-failure" {
|
||||||
|
return errors.Errorf("restart policy retries can only be specified with on-failure restart policy")
|
||||||
|
}
|
||||||
|
retries, err := strconv.Atoi(splitRestart[1])
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error parsing restart policy retry count")
|
||||||
|
}
|
||||||
|
if retries < 0 {
|
||||||
|
return errors.Errorf("must specify restart policy retry count as a number greater than 0")
|
||||||
|
}
|
||||||
|
var retriesUint uint = uint(retries)
|
||||||
|
s.RestartRetries = &retriesUint
|
||||||
|
default:
|
||||||
|
return errors.Errorf("invalid restart policy: may specify retries at most once")
|
||||||
|
}
|
||||||
|
s.RestartPolicy = splitRestart[0]
|
||||||
|
}
|
||||||
s.Remove = c.Rm
|
s.Remove = c.Rm
|
||||||
s.StopTimeout = &c.StopTimeout
|
s.StopTimeout = &c.StopTimeout
|
||||||
|
|
||||||
|
@ -85,7 +85,12 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
options = append(options, libpod.WithRootFSFromImage(newImage.ID(), s.Image, s.RawImageName))
|
imgName := s.Image
|
||||||
|
names := newImage.Names()
|
||||||
|
if len(names) > 0 {
|
||||||
|
imgName = names[0]
|
||||||
|
}
|
||||||
|
options = append(options, libpod.WithRootFSFromImage(newImage.ID(), imgName, s.Image))
|
||||||
}
|
}
|
||||||
if err := s.Validate(); err != nil {
|
if err := s.Validate(); err != nil {
|
||||||
return nil, errors.Wrap(err, "invalid config provided")
|
return nil, errors.Wrap(err, "invalid config provided")
|
||||||
|
@ -140,10 +140,6 @@ type ContainerStorageConfig struct {
|
|||||||
// Conflicts with Rootfs.
|
// Conflicts with Rootfs.
|
||||||
// At least one of Image or Rootfs must be specified.
|
// At least one of Image or Rootfs must be specified.
|
||||||
Image string `json:"image"`
|
Image string `json:"image"`
|
||||||
// RawImageName is the unprocessed and not-normalized user-specified image
|
|
||||||
// name. One use case for having this data at hand are auto-updates where
|
|
||||||
// the _exact_ user input is needed in order to look-up the correct image.
|
|
||||||
RawImageName string `json:"raw_image_name,omitempty"`
|
|
||||||
// Rootfs is the path to a directory that will be used as the
|
// Rootfs is the path to a directory that will be used as the
|
||||||
// container's root filesystem. No modification will be made to the
|
// container's root filesystem. No modification will be made to the
|
||||||
// directory, it will be directly mounted into the container as root.
|
// directory, it will be directly mounted into the container as root.
|
||||||
|
@ -342,4 +342,53 @@ var _ = Describe("Podman create", func() {
|
|||||||
Expect(ok2).To(BeTrue())
|
Expect(ok2).To(BeTrue())
|
||||||
Expect(val2).To(Equal("bar"))
|
Expect(val2).To(Equal("bar"))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("podman create with --restart=on-failure:5 parses correctly", func() {
|
||||||
|
ctrName := "testctr"
|
||||||
|
session := podmanTest.Podman([]string{"create", "-t", "--restart", "on-failure:5", "--name", ctrName, ALPINE, "/bin/sh"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
|
inspect := podmanTest.Podman([]string{"inspect", ctrName})
|
||||||
|
inspect.WaitWithDefaultTimeout()
|
||||||
|
data := inspect.InspectContainerToJSON()
|
||||||
|
Expect(len(data)).To(Equal(1))
|
||||||
|
Expect(data[0].HostConfig.RestartPolicy.Name).To(Equal("on-failure"))
|
||||||
|
Expect(data[0].HostConfig.RestartPolicy.MaximumRetryCount).To(Equal(uint(5)))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("podman create with --restart-policy=always:5 fails", func() {
|
||||||
|
session := podmanTest.Podman([]string{"create", "-t", "--restart", "always:5", ALPINE, "/bin/sh"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Not(Equal(0)))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("podman create with -m 1000000 sets swap to 2000000", func() {
|
||||||
|
numMem := 1000000
|
||||||
|
ctrName := "testCtr"
|
||||||
|
session := podmanTest.Podman([]string{"create", "-t", "-m", fmt.Sprintf("%db", numMem), "--name", ctrName, ALPINE, "/bin/sh"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
|
inspect := podmanTest.Podman([]string{"inspect", ctrName})
|
||||||
|
inspect.WaitWithDefaultTimeout()
|
||||||
|
data := inspect.InspectContainerToJSON()
|
||||||
|
Expect(len(data)).To(Equal(1))
|
||||||
|
Expect(data[0].HostConfig.MemorySwap).To(Equal(int64(2 * numMem)))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("podman create --cpus 5 sets nanocpus", func() {
|
||||||
|
numCpus := 5
|
||||||
|
nanoCPUs := numCpus * 1000000000
|
||||||
|
ctrName := "testCtr"
|
||||||
|
session := podmanTest.Podman([]string{"create", "-t", "--cpus", fmt.Sprintf("%d", numCpus), "--name", ctrName, ALPINE, "/bin/sh"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
|
inspect := podmanTest.Podman([]string{"inspect", ctrName})
|
||||||
|
inspect.WaitWithDefaultTimeout()
|
||||||
|
data := inspect.InspectContainerToJSON()
|
||||||
|
Expect(len(data)).To(Equal(1))
|
||||||
|
Expect(data[0].HostConfig.NanoCpus).To(Equal(int64(nanoCPUs)))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user