diff --git a/api/handlers/container/create.go b/api/handlers/container/create.go index d19a7742..70abb148 100644 --- a/api/handlers/container/create.go +++ b/api/handlers/container/create.go @@ -117,6 +117,16 @@ func (h *handler) create(w http.ResponseWriter, r *http.Request) { } } + // Sysctls: + // Sysctls are passed in as a map of strings, + // but nerdctl expects an array of strings with format [Sysctls1=VALUE1, Sysctls2=VALUE2, ...]. + sysctls := []string{} + if req.HostConfig.Sysctls != nil { + for key, val := range req.HostConfig.Sysctls { + sysctls = append(sysctls, fmt.Sprintf("%s=%s", key, val)) + } + } + // Environment vars: env := []string{} if req.Env != nil { @@ -141,19 +151,29 @@ func (h *handler) create(w http.ResponseWriter, r *http.Request) { memoryReservation := "" if req.HostConfig.MemoryReservation != 0 { - memoryReservation = strconv.FormatInt(req.HostConfig.MemoryReservation, 10) + memoryReservation = fmt.Sprint(req.HostConfig.MemoryReservation) } memorySwap := "" if req.HostConfig.MemorySwap != 0 { - memorySwap = strconv.FormatInt(req.HostConfig.MemorySwap, 10) + memorySwap = fmt.Sprint(req.HostConfig.MemorySwap) } memorySwappiness := int64(-1) - if req.HostConfig.MemorySwappiness != 0 && req.HostConfig.MemorySwappiness > -1 { + if req.HostConfig.MemorySwappiness > 0 { memorySwappiness = req.HostConfig.MemorySwappiness } + shmSize := "" + if req.HostConfig.ShmSize > 0 { + shmSize = fmt.Sprint(req.HostConfig.ShmSize) + } + + runtime := defaults.Runtime + if req.HostConfig.Runtime != "" { + runtime = req.HostConfig.Runtime + } + volumesFrom := []string{} if req.HostConfig.VolumesFrom != nil { volumesFrom = req.HostConfig.VolumesFrom @@ -212,6 +232,7 @@ func (h *handler) create(w http.ResponseWriter, r *http.Request) { MemoryReservation: memoryReservation, // Memory soft limit (in bytes) MemorySwap: memorySwap, // Total memory usage (memory + swap); set `-1` to enable unlimited swap IPC: req.HostConfig.IpcMode, // IPC namespace to use + ShmSize: shmSize, // ShmSize set the size of /dev/shm // #endregion // #region for user flags @@ -227,7 +248,8 @@ func (h *handler) create(w http.ResponseWriter, r *http.Request) { // #endregion // #region for runtime flags - Runtime: defaults.Runtime, // nerdctl default. + Runtime: runtime, // Runtime to use for this container, e.g. "crun", or "io.containerd.runc.v2". + Sysctl: sysctls, // Sysctl set sysctl options, e.g "net.ipv4.ip_forward=1" // #endregion // #region for volume flags diff --git a/api/handlers/container/create_test.go b/api/handlers/container/create_test.go index daff5369..c280abca 100644 --- a/api/handlers/container/create_test.go +++ b/api/handlers/container/create_test.go @@ -698,6 +698,31 @@ var _ = Describe("Container Create API ", func() { Expect(rr.Body).Should(MatchJSON(jsonResponse)) }) + It("should set ShmSize, Sysctl and Runtime option", func() { + body := []byte(`{ + "Image": "test-image", + "HostConfig": { + "Sysctls": { "net.ipv4.ip_forward": "1" }, + "ShmSize": 302348, + "Runtime": "crun" + } + }`) + req, _ := http.NewRequest(http.MethodPost, "/containers/create", bytes.NewReader(body)) + + // expected create options + createOpt.ShmSize = "302348" + createOpt.Sysctl = []string{"net.ipv4.ip_forward=1"} + createOpt.Runtime = "crun" + + service.EXPECT().Create(gomock.Any(), "test-image", nil, equalTo(createOpt), equalTo(netOpt)).Return( + cid, nil) + + // handler should return success message with 201 status code. + h.create(rr, req) + Expect(rr).Should(HaveHTTPStatus(http.StatusCreated)) + Expect(rr.Body).Should(MatchJSON(jsonResponse)) + }) + It("should return 404 if the image was not found", func() { body := []byte(`{"Image": "test-image"}`) req, _ := http.NewRequest(http.MethodPost, "/containers/create", bytes.NewReader(body)) @@ -899,6 +924,7 @@ func getDefaultCreateOpt(conf config.Config) types.ContainerCreateOptions { // #region for runtime flags Runtime: defaults.Runtime, // nerdctl default. + Sysctl: []string{}, // #endregion // #region for volume flags diff --git a/api/types/container_types.go b/api/types/container_types.go index 9062f822..ac0d7d2d 100644 --- a/api/types/container_types.go +++ b/api/types/container_types.go @@ -89,12 +89,12 @@ type ContainerHostConfig struct { SecurityOpt []string // List of string values to customize labels for MLS systems, such as SELinux. (["key=value"]) Tmpfs map[string]string `json:",omitempty"` // List of tmpfs (mounts) used for the container UTSMode string // UTS namespace to use for the container + ShmSize int64 // Size of /dev/shm in bytes. The size must be greater than 0. + Sysctls map[string]string `json:",omitempty"` // List of Namespaced sysctls used for the container + Runtime string `json:",omitempty"` // Runtime to use with this container // TODO: PublishAllPorts bool // Should docker publish all exposed port for the container // TODO: StorageOpt map[string]string `json:",omitempty"` // Storage driver options per container. // TODO: UsernsMode UsernsMode // The user namespace to use for the container - // TODO: ShmSize int64 // Total shm memory usage - // TODO: Sysctls map[string]string `json:",omitempty"` // List of Namespaced sysctls used for the container - // TODO: Runtime string `json:",omitempty"` // Runtime to use with this container // Applicable to Windows // TODO: Isolation Isolation // Isolation technology of the container (e.g. default, hyperv)