Skip to content

Commit 5ecea04

Browse files
committed
ulimit-adjuster: add validation for hard limits
hard limits should always be >= soft limits Signed-off-by: Samuel Karp <[email protected]>
1 parent db3de10 commit 5ecea04

2 files changed

Lines changed: 97 additions & 4 deletions

File tree

plugins/ulimit-adjuster/adjuster.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,10 @@ func (p *plugin) CreateContainer(
123123
log.G(ctx).WithError(err).Debug("failed to parse annotations")
124124
return nil, nil, err
125125
}
126-
adjust := &api.ContainerAdjustment{}
127-
for _, u := range ulimits {
128-
log.G(ctx).WithField("type", u.Type).WithField("hard", u.Hard).WithField("soft", u.Soft).Debug("adjust rlimit")
129-
adjust.AddRlimit(u.Type, u.Hard, u.Soft)
126+
127+
adjust, err := adjustUlimits(ctx, ulimits)
128+
if err != nil {
129+
return nil, nil, err
130130
}
131131
return adjust, nil, nil
132132
}
@@ -159,3 +159,17 @@ func parseUlimits(ctx context.Context, container string, annotations map[string]
159159
}
160160
return ulimits, nil
161161
}
162+
163+
func adjustUlimits(ctx context.Context, ulimits []ulimit) (*api.ContainerAdjustment, error) {
164+
adjust := &api.ContainerAdjustment{}
165+
for _, u := range ulimits {
166+
l := log.G(ctx).WithField("type", u.Type).WithField("hard", u.Hard).WithField("soft", u.Soft)
167+
if u.Hard < u.Soft {
168+
l.Debug("failed to apply ulimit with hard < soft")
169+
return nil, fmt.Errorf("ulimit %q must have hard limit >= soft limit", u.Type)
170+
}
171+
log.G(ctx).WithField("type", u.Type).WithField("hard", u.Hard).WithField("soft", u.Soft).Debug("adjust rlimit")
172+
adjust.AddRlimit(u.Type, u.Hard, u.Soft)
173+
}
174+
return adjust, nil
175+
}

plugins/ulimit-adjuster/adjuster_test.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import (
2121
"testing"
2222

2323
"github.com/stretchr/testify/assert"
24+
25+
"github.com/containerd/nri/pkg/api"
2426
)
2527

2628
func TestParseAnnotations(t *testing.T) {
@@ -161,3 +163,80 @@ func TestParseAnnotations(t *testing.T) {
161163
})
162164
}
163165
}
166+
167+
func TestAdjustUlimits(t *testing.T) {
168+
tests := map[string]struct {
169+
ulimits []ulimit
170+
expected *api.ContainerAdjustment
171+
errStr string
172+
}{
173+
"empty": {
174+
ulimits: nil,
175+
expected: &api.ContainerAdjustment{},
176+
},
177+
"invalid-hard": {
178+
ulimits: []ulimit{{
179+
Type: "RLIMIT_NOFILE",
180+
Hard: 0,
181+
Soft: 100,
182+
}},
183+
errStr: `ulimit "RLIMIT_NOFILE" must have hard limit >= soft limit`,
184+
},
185+
"one": {
186+
ulimits: []ulimit{{
187+
Type: "RLIMIT_MEMLOCK",
188+
Hard: 100,
189+
Soft: 99,
190+
}},
191+
expected: &api.ContainerAdjustment{Rlimits: []*api.POSIXRlimit{{
192+
Type: "RLIMIT_MEMLOCK",
193+
Hard: 100,
194+
Soft: 99,
195+
}}},
196+
},
197+
"one-invalid": {
198+
ulimits: []ulimit{{
199+
Type: "RLIMIT_MEMLOCK",
200+
Hard: 100,
201+
Soft: 99,
202+
}, {
203+
Type: "RLIMIT_NOFILE",
204+
Hard: 0,
205+
Soft: 100,
206+
}},
207+
errStr: `ulimit "RLIMIT_NOFILE" must have hard limit >= soft limit`,
208+
},
209+
"multiple-valid": {
210+
ulimits: []ulimit{{
211+
Type: "RLIMIT_MEMLOCK",
212+
Hard: 100,
213+
Soft: 99,
214+
}, {
215+
Type: "RLIMIT_AS",
216+
Hard: 10,
217+
Soft: 0,
218+
}},
219+
expected: &api.ContainerAdjustment{Rlimits: []*api.POSIXRlimit{{
220+
Type: "RLIMIT_MEMLOCK",
221+
Hard: 100,
222+
Soft: 99,
223+
}, {
224+
Type: "RLIMIT_AS",
225+
Hard: 10,
226+
Soft: 0,
227+
}}},
228+
},
229+
}
230+
for name, tc := range tests {
231+
t.Run(name, func(t *testing.T) {
232+
adjust, err := adjustUlimits(context.Background(), tc.ulimits)
233+
if tc.errStr != "" {
234+
assert.EqualError(t, err, tc.errStr)
235+
assert.Nil(t, adjust)
236+
} else {
237+
assert.NoError(t, err)
238+
assert.Equal(t, tc.expected, adjust)
239+
}
240+
})
241+
}
242+
}

0 commit comments

Comments
 (0)