Skip to content

Commit c37fc59

Browse files
committed
enforce limits are consistent with deploy section
Signed-off-by: Nicolas De Loof <[email protected]>
1 parent 40843e6 commit c37fc59

File tree

3 files changed

+57
-7
lines changed

3 files changed

+57
-7
lines changed

loader/full-struct_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,11 @@ func services(workingDir, homeDir string) types.Services {
121121
},
122122
Resources: types.Resources{
123123
Limits: &types.Resource{
124-
NanoCPUs: "0.001",
124+
NanoCPUs: 0.001,
125125
MemoryBytes: 50 * 1024 * 1024,
126126
},
127127
Reservations: &types.Resource{
128-
NanoCPUs: "0.0001",
128+
NanoCPUs: 0.0001,
129129
MemoryBytes: 20 * 1024 * 1024,
130130
GenericResources: []types.GenericResource{
131131
{
@@ -690,10 +690,10 @@ services:
690690
order: start-first
691691
resources:
692692
limits:
693-
cpus: "0.001"
693+
cpus: 0.001
694694
memory: "52428800"
695695
reservations:
696-
cpus: "0.0001"
696+
cpus: 0.0001
697697
memory: "20971520"
698698
generic_resources:
699699
- discrete_resource_spec:
@@ -1267,11 +1267,11 @@ func fullExampleJSON(workingDir, homeDir string) string {
12671267
},
12681268
"resources": {
12691269
"limits": {
1270-
"cpus": "0.001",
1270+
"cpus": 0.001,
12711271
"memory": "52428800"
12721272
},
12731273
"reservations": {
1274-
"cpus": "0.0001",
1274+
"cpus": 0.0001,
12751275
"memory": "20971520",
12761276
"generic_resources": [
12771277
{

loader/validate.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,31 @@ func checkConsistency(project *types.Project) error {
117117
s.Deploy.Replicas = s.Scale
118118
}
119119

120+
if s.CPUS != 0 && s.Deploy != nil {
121+
if s.Deploy.Resources.Limits != nil && s.Deploy.Resources.Limits.NanoCPUs.Value() != s.CPUS {
122+
return fmt.Errorf("services.%s: can't set distinct values on 'cpus' and 'deploy.resources.limits.cpus': %w",
123+
s.Name, errdefs.ErrInvalid)
124+
}
125+
}
126+
if s.MemLimit != 0 && s.Deploy != nil {
127+
if s.Deploy.Resources.Limits != nil && s.Deploy.Resources.Limits.MemoryBytes != s.MemLimit {
128+
return fmt.Errorf("services.%s: can't set distinct values on 'mem_limit' and 'deploy.resources.limits.memory': %w",
129+
s.Name, errdefs.ErrInvalid)
130+
}
131+
}
132+
if s.MemReservation != 0 && s.Deploy != nil {
133+
if s.Deploy.Resources.Reservations != nil && s.Deploy.Resources.Reservations.MemoryBytes != s.MemReservation {
134+
return fmt.Errorf("services.%s: can't set distinct values on 'mem_reservation' and 'deploy.resources.reservations.memory': %w",
135+
s.Name, errdefs.ErrInvalid)
136+
}
137+
}
138+
if s.PidsLimit != 0 && s.Deploy != nil {
139+
if s.Deploy.Resources.Limits != nil && s.Deploy.Resources.Limits.Pids != s.PidsLimit {
140+
return fmt.Errorf("services.%s: can't set distinct values on 'pids_limit' and 'deploy.resources.limits.pids': %w",
141+
s.Name, errdefs.ErrInvalid)
142+
}
143+
}
144+
120145
if s.ContainerName != "" {
121146
if existing, ok := containerNames[s.ContainerName]; ok {
122147
return fmt.Errorf(`"services.%s": container name "%s" is already in use by "services.%s": %w`, s.Name, s.ContainerName, existing, errdefs.ErrInvalid)

types/types.go

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"encoding/json"
2121
"fmt"
2222
"sort"
23+
"strconv"
2324
"strings"
2425

2526
"github.com/docker/go-connections/nat"
@@ -365,7 +366,7 @@ type Resources struct {
365366
// Resource is a resource to be limited or reserved
366367
type Resource struct {
367368
// TODO: types to convert from units and ratios
368-
NanoCPUs string `yaml:"cpus,omitempty" json:"cpus,omitempty"`
369+
NanoCPUs NanoCPUs `yaml:"cpus,omitempty" json:"cpus,omitempty"`
369370
MemoryBytes UnitBytes `yaml:"memory,omitempty" json:"memory,omitempty"`
370371
Pids int64 `yaml:"pids,omitempty" json:"pids,omitempty"`
371372
Devices []DeviceRequest `yaml:"devices,omitempty" json:"devices,omitempty"`
@@ -374,6 +375,30 @@ type Resource struct {
374375
Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
375376
}
376377

378+
type NanoCPUs float32
379+
380+
func (n *NanoCPUs) DecodeMapstructure(a any) error {
381+
switch v := a.(type) {
382+
case string:
383+
f, err := strconv.ParseFloat(v, 64)
384+
if err != nil {
385+
return err
386+
}
387+
*n = NanoCPUs(f)
388+
case float32:
389+
*n = NanoCPUs(v)
390+
case float64:
391+
*n = NanoCPUs(v)
392+
default:
393+
return fmt.Errorf("unexpected value type %T for cpus", v)
394+
}
395+
return nil
396+
}
397+
398+
func (n *NanoCPUs) Value() float32 {
399+
return float32(*n)
400+
}
401+
377402
// GenericResource represents a "user defined" resource which can
378403
// only be an integer (e.g: SSD=3) for a service
379404
type GenericResource struct {

0 commit comments

Comments
 (0)