mirror of
https://github.com/kemko/nomad.git
synced 2026-01-03 17:05:43 +03:00
* exec2: implement a dynamic users pool This PR adds an implementation of a Pool from which dynamic users can be allocated on behalf of tasks making use of an upcoming feature of Nomad client (dynamic users). A task hook and client plumbing, etc. will be in follow up PRs. * no need for randomness assertion
120 lines
2.1 KiB
Go
120 lines
2.1 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
//go:build linux
|
|
|
|
package dynamic
|
|
|
|
import (
|
|
"fmt"
|
|
"slices"
|
|
"testing"
|
|
|
|
"github.com/shoenig/test/must"
|
|
)
|
|
|
|
var testPoolConfig = &PoolConfig{
|
|
MinUGID: 200,
|
|
MaxUGID: 209,
|
|
}
|
|
|
|
func TestPool_Release_unused(t *testing.T) {
|
|
p := New(testPoolConfig)
|
|
|
|
cases := []struct {
|
|
id UGID
|
|
}{
|
|
{id: 0},
|
|
{id: 200},
|
|
{id: 205},
|
|
{id: 209},
|
|
{id: 210},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(fmt.Sprintf("id%s", tc.id), func(t *testing.T) {
|
|
err := p.Release(tc.id)
|
|
must.ErrorIs(t, ErrReleaseUnused, err)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestPool_Acquire_exhausted(t *testing.T) {
|
|
p := New(testPoolConfig)
|
|
|
|
// consume all 10 ugids
|
|
for i := 200; i <= 209; i++ {
|
|
v, err := p.Acquire()
|
|
must.NoError(t, err)
|
|
must.Between[UGID](t, 200, v, 209)
|
|
}
|
|
|
|
// next acquire should fail
|
|
v, err := p.Acquire()
|
|
must.Eq(t, none, v)
|
|
must.ErrorIs(t, ErrPoolExhausted, err)
|
|
|
|
// let go of one ugid
|
|
err2 := p.Release(204)
|
|
must.NoError(t, err2)
|
|
|
|
// now an acquire should succeed
|
|
v2, err3 := p.Acquire()
|
|
must.NoError(t, err3)
|
|
must.Eq(t, 204, v2)
|
|
}
|
|
|
|
func TestPool_Acquire_random(t *testing.T) {
|
|
run1 := make([]UGID, 10)
|
|
run2 := make([]UGID, 10)
|
|
|
|
p1 := New(testPoolConfig)
|
|
p2 := New(testPoolConfig)
|
|
|
|
// acquire all 10 UGIDs and record the order of each
|
|
for i := 0; i < 10; i++ {
|
|
v1, err1 := p1.Acquire()
|
|
must.NoError(t, err1)
|
|
|
|
v2, err2 := p2.Acquire()
|
|
must.NoError(t, err2)
|
|
|
|
run1[i] = v1
|
|
run2[i] = v2
|
|
}
|
|
|
|
// ensure both runs contain the expected ugids
|
|
exp := []UGID{200, 201, 202, 203, 204, 205, 206, 207, 208, 209}
|
|
must.SliceContainsAll(t, exp, run1)
|
|
must.SliceContainsAll(t, exp, run2)
|
|
}
|
|
|
|
func TestPool_Restore(t *testing.T) {
|
|
p := New(&PoolConfig{
|
|
MinUGID: 500,
|
|
MaxUGID: 505,
|
|
}) // 6 GUIDs
|
|
|
|
// restore 501, 502, 504
|
|
p.Restore(501)
|
|
p.Restore(502)
|
|
p.Restore(504)
|
|
|
|
v1, err1 := p.Acquire()
|
|
must.NoError(t, err1)
|
|
|
|
v2, err2 := p.Acquire()
|
|
must.NoError(t, err2)
|
|
|
|
v3, err3 := p.Acquire()
|
|
must.NoError(t, err3)
|
|
|
|
// ensure the next 3 are the UGIDs that were not already consumed
|
|
// and set via Restore
|
|
ids := []UGID{v1, v2, v3}
|
|
slices.Sort(ids)
|
|
must.Eq(t, 500, ids[0])
|
|
must.Eq(t, 503, ids[1])
|
|
must.Eq(t, 505, ids[2])
|
|
}
|