Skip to content

Commit 7f92a5d

Browse files
committed
feat: add --ulimit flag for 'uc run' command
1 parent a5c9085 commit 7f92a5d

File tree

1 file changed

+37
-5
lines changed

1 file changed

+37
-5
lines changed

cmd/uncloud/service/run.go

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
dockeropts "github.com/docker/cli/opts"
1010
"github.com/docker/compose/v2/pkg/progress"
1111
"github.com/docker/docker/daemon/names"
12+
"github.com/docker/go-units"
1213
"github.com/psviderski/uncloud/internal/cli"
1314
"github.com/psviderski/uncloud/internal/secret"
1415
"github.com/psviderski/uncloud/pkg/api"
@@ -32,6 +33,7 @@ type runOptions struct {
3233
publish []string
3334
pull string
3435
replicas uint
36+
ulimits []string
3537
user string
3638
volumes []string
3739
}
@@ -102,6 +104,12 @@ func NewRunCommand(groupID string) *cobra.Command {
102104
cmd.Flags().StringVarP(&opts.user, "user", "u", "",
103105
"User name or UID and optionally group name or GID used for running the command inside service containers.\n"+
104106
"Format: USER[:GROUP] or UID[:GID]. If not specified, the user is set to the default user of the image.")
107+
cmd.Flags().StringSliceVar(&opts.ulimits, "ulimit", nil,
108+
"Set resource limits for service containers. Can be specified multiple times.\n"+
109+
"Format: type=soft_limit[:hard_limit]. If hard limit is not specified, soft limit is used for both.\n"+
110+
"Examples:\n"+
111+
" --ulimit nofile=1024:2048 Set soft limit to 1024 and hard limit to 2048 for number of open files\n"+
112+
" --ulimit nproc=65535 Set both soft and hard limits to 65535 for number of processes")
105113
cmd.Flags().StringSliceVarP(&opts.volumes, "volume", "v", nil,
106114
"Mount a data volume or host path into service containers. Service containers will be scheduled on the machine(s) where\n"+
107115
"the volume is located. Can be specified multiple times.\n"+
@@ -194,13 +202,18 @@ func prepareServiceSpec(opts runOptions) (api.ServiceSpec, error) {
194202
ports[i] = port
195203
}
196204

197-
volumes, mounts, err := parseVolumeFlags(opts.volumes)
205+
placement := api.Placement{
206+
Machines: cli.ExpandCommaSeparatedValues(opts.machines),
207+
}
208+
209+
ulimits, err := parseUlimits(opts.ulimits)
198210
if err != nil {
199211
return spec, err
200212
}
201213

202-
placement := api.Placement{
203-
Machines: cli.ExpandCommaSeparatedValues(opts.machines),
214+
volumes, mounts, err := parseVolumeFlags(opts.volumes)
215+
if err != nil {
216+
return spec, err
204217
}
205218

206219
spec = api.ServiceSpec{
@@ -211,8 +224,9 @@ func prepareServiceSpec(opts runOptions) (api.ServiceSpec, error) {
211224
Privileged: opts.privileged,
212225
PullPolicy: opts.pull,
213226
Resources: api.ContainerResources{
214-
CPU: opts.cpu.Value(),
215-
Memory: opts.memory.Value(),
227+
CPU: opts.cpu.Value(),
228+
Memory: opts.memory.Value(),
229+
Ulimits: ulimits,
216230
},
217231
User: opts.user,
218232
VolumeMounts: mounts,
@@ -302,6 +316,24 @@ func parseVolumeFlags(volumes []string) ([]api.VolumeSpec, []api.VolumeMount, er
302316
return specs, mounts, nil
303317
}
304318

319+
// parseUlimits parses ulimit flag values in Docker CLI format (type=soft[:hard]).
320+
func parseUlimits(ulimits []string) (map[string]api.Ulimit, error) {
321+
if len(ulimits) == 0 {
322+
return nil, nil
323+
}
324+
325+
result := make(map[string]api.Ulimit, len(ulimits))
326+
for _, u := range ulimits {
327+
parsed, err := units.ParseUlimit(u)
328+
if err != nil {
329+
return nil, fmt.Errorf("invalid ulimit '%s': %w", u, err)
330+
}
331+
result[parsed.Name] = api.Ulimit{Soft: parsed.Soft, Hard: parsed.Hard}
332+
}
333+
334+
return result, nil
335+
}
336+
305337
func parseVolumeFlagValue(volume string) (api.VolumeSpec, api.VolumeMount, error) {
306338
var spec api.VolumeSpec
307339
var mount api.VolumeMount

0 commit comments

Comments
 (0)