diff --git a/pkg/api/handlers/libpod/containers_create.go b/pkg/api/handlers/libpod/containers_create.go index 4f9dc008d2..1043dec4d5 100644 --- a/pkg/api/handlers/libpod/containers_create.go +++ b/pkg/api/handlers/libpod/containers_create.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "net/http" + "strconv" "github.com/containers/podman/v4/libpod" "github.com/containers/podman/v4/pkg/api/handlers/utils" @@ -11,6 +12,7 @@ import ( "github.com/containers/podman/v4/pkg/domain/entities" "github.com/containers/podman/v4/pkg/specgen" "github.com/containers/podman/v4/pkg/specgen/generate" + "github.com/containers/podman/v4/pkg/specgenutil" "github.com/pkg/errors" ) @@ -39,6 +41,20 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) { t := true sg.Passwd = &t } + + // need to check for memory limit to adjust swap + if sg.ResourceLimits != nil && sg.ResourceLimits.Memory != nil { + s := "" + var l int64 = 0 + if sg.ResourceLimits.Memory.Swap != nil { + s = strconv.Itoa(int(*sg.ResourceLimits.Memory.Swap)) + } + if sg.ResourceLimits.Memory.Limit != nil { + l = *sg.ResourceLimits.Memory.Limit + } + specgenutil.LimitToSwap(sg.ResourceLimits.Memory, s, l) + } + warn, err := generate.CompleteSpec(r.Context(), runtime, &sg) if err != nil { utils.InternalServerError(w, err) @@ -54,6 +70,7 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) { utils.InternalServerError(w, err) return } + response := entities.ContainerCreateResponse{ID: ctr.ID(), Warnings: warn} utils.WriteJSON(w, http.StatusCreated, response) } diff --git a/pkg/specgenutil/specgen.go b/pkg/specgenutil/specgen.go index c86af72953..00de99817a 100644 --- a/pkg/specgenutil/specgen.go +++ b/pkg/specgenutil/specgen.go @@ -126,6 +126,16 @@ func getIOLimits(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions) ( return io, nil } +func LimitToSwap(memory *specs.LinuxMemory, swap string, ml int64) { + if ml > 0 { + memory.Limit = &ml + if swap == "" { + limit := 2 * ml + memory.Swap = &(limit) + } + } +} + func getMemoryLimits(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions) (*specs.LinuxMemory, error) { var err error memory := &specs.LinuxMemory{} @@ -135,14 +145,8 @@ func getMemoryLimits(s *specgen.SpecGenerator, c *entities.ContainerCreateOption if err != nil { return nil, errors.Wrapf(err, "invalid value for memory") } - if ml > 0 { - memory.Limit = &ml - if c.MemorySwap == "" { - limit := 2 * ml - memory.Swap = &(limit) - } - hasLimits = true - } + LimitToSwap(memory, c.MemorySwap, ml) + hasLimits = true } if m := c.MemoryReservation; len(m) > 0 { mr, err := units.RAMInBytes(m) diff --git a/test/apiv2/python/rest_api/test_v2_0_0_container.py b/test/apiv2/python/rest_api/test_v2_0_0_container.py index 0386116a87..a44786c0df 100644 --- a/test/apiv2/python/rest_api/test_v2_0_0_container.py +++ b/test/apiv2/python/rest_api/test_v2_0_0_container.py @@ -328,6 +328,35 @@ def _impl(fifo, stop): self.fail("Server failed to respond in 10s") top.join() + def test_memory(self): + r = requests.post( + self.podman_url + "/v1.4.0/libpod/containers/create", + json={ + "Name": "memory", + "Cmd": ["top"], + "Image": "alpine:latest", + "Resource_Limits": { + "Memory":{ + "Limit": 1000, + }, + "CPU":{ + "Shares": 200, + }, + }, + }, + ) + self.assertEqual(r.status_code, 201, r.text) + payload = r.json() + container_id = payload["Id"] + self.assertIsNotNone(container_id) + + r = requests.get(self.podman_url + f"/v1.40/containers/{container_id}/json") + self.assertEqual(r.status_code, 200, r.text) + self.assertId(r.content) + out = r.json() + self.assertEqual(2000, out["HostConfig"]["MemorySwap"]) + self.assertEqual(1000, out["HostConfig"]["Memory"]) + if __name__ == "__main__": unittest.main()