mirror of
https://github.com/kemko/nomad.git
synced 2026-01-01 16:05:42 +03:00
api: apply consistent behaviour of the reverse query parameter (#12244)
This commit is contained in:
@@ -665,12 +665,12 @@ func (a *ACL) ListTokens(args *structs.ACLTokenListRequest, reply *structs.ACLTo
|
||||
var opts paginator.StructsTokenizerOptions
|
||||
|
||||
if prefix := args.QueryOptions.Prefix; prefix != "" {
|
||||
iter, err = state.ACLTokenByAccessorIDPrefix(ws, prefix)
|
||||
iter, err = state.ACLTokenByAccessorIDPrefix(ws, prefix, sort)
|
||||
opts = paginator.StructsTokenizerOptions{
|
||||
WithID: true,
|
||||
}
|
||||
} else if args.GlobalOnly {
|
||||
iter, err = state.ACLTokensByGlobal(ws, true)
|
||||
iter, err = state.ACLTokensByGlobal(ws, true, sort)
|
||||
opts = paginator.StructsTokenizerOptions{
|
||||
WithID: true,
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ func (a *Alloc) List(args *structs.AllocListRequest, reply *structs.AllocListRes
|
||||
return err
|
||||
} else {
|
||||
if prefix := args.QueryOptions.Prefix; prefix != "" {
|
||||
iter, err = state.AllocsByIDPrefix(ws, namespace, prefix)
|
||||
iter, err = state.AllocsByIDPrefix(ws, namespace, prefix, sort)
|
||||
opts = paginator.StructsTokenizerOptions{
|
||||
WithID: true,
|
||||
}
|
||||
|
||||
@@ -414,7 +414,7 @@ func (d *Deployment) List(args *structs.DeploymentListRequest, reply *structs.De
|
||||
var opts paginator.StructsTokenizerOptions
|
||||
|
||||
if prefix := args.QueryOptions.Prefix; prefix != "" {
|
||||
iter, err = store.DeploymentsByIDPrefix(ws, namespace, prefix)
|
||||
iter, err = store.DeploymentsByIDPrefix(ws, namespace, prefix, sort)
|
||||
opts = paginator.StructsTokenizerOptions{
|
||||
WithID: true,
|
||||
}
|
||||
|
||||
@@ -419,7 +419,7 @@ func (e *Eval) List(args *structs.EvalListRequest, reply *structs.EvalListRespon
|
||||
var opts paginator.StructsTokenizerOptions
|
||||
|
||||
if prefix := args.QueryOptions.Prefix; prefix != "" {
|
||||
iter, err = store.EvalsByIDPrefix(ws, namespace, prefix)
|
||||
iter, err = store.EvalsByIDPrefix(ws, namespace, prefix, sort)
|
||||
opts = paginator.StructsTokenizerOptions{
|
||||
WithID: true,
|
||||
}
|
||||
|
||||
@@ -1524,13 +1524,13 @@ ERR_WAIT:
|
||||
// diffACLTokens is used to perform a two-way diff between the local
|
||||
// tokens and the remote tokens to determine which tokens need to
|
||||
// be deleted or updated.
|
||||
func diffACLTokens(state *state.StateStore, minIndex uint64, remoteList []*structs.ACLTokenListStub) (delete []string, update []string) {
|
||||
func diffACLTokens(store *state.StateStore, minIndex uint64, remoteList []*structs.ACLTokenListStub) (delete []string, update []string) {
|
||||
// Construct a set of the local and remote policies
|
||||
local := make(map[string][]byte)
|
||||
remote := make(map[string]struct{})
|
||||
|
||||
// Add all the local global tokens
|
||||
iter, err := state.ACLTokensByGlobal(nil, true)
|
||||
iter, err := store.ACLTokensByGlobal(nil, true, state.SortDefault)
|
||||
if err != nil {
|
||||
panic("failed to iterate local tokens")
|
||||
}
|
||||
|
||||
@@ -2063,11 +2063,11 @@ func TestClientEndpoint_GetClientAllocs_Blocking(t *testing.T) {
|
||||
alloc := mock.Alloc()
|
||||
alloc.NodeID = node.ID
|
||||
alloc.ModifyTime = now
|
||||
state := s1.fsm.State()
|
||||
state.UpsertJobSummary(99, mock.JobSummary(alloc.JobID))
|
||||
store := s1.fsm.State()
|
||||
store.UpsertJobSummary(99, mock.JobSummary(alloc.JobID))
|
||||
start := time.Now()
|
||||
time.AfterFunc(100*time.Millisecond, func() {
|
||||
err := state.UpsertAllocs(structs.MsgTypeTestSetup, 100, []*structs.Allocation{alloc})
|
||||
err := store.UpsertAllocs(structs.MsgTypeTestSetup, 100, []*structs.Allocation{alloc})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -2101,7 +2101,7 @@ func TestClientEndpoint_GetClientAllocs_Blocking(t *testing.T) {
|
||||
t.Fatalf("bad: %#v", resp2.Allocs)
|
||||
}
|
||||
|
||||
iter, err := state.AllocsByIDPrefix(nil, structs.DefaultNamespace, alloc.ID)
|
||||
iter, err := store.AllocsByIDPrefix(nil, structs.DefaultNamespace, alloc.ID, state.SortDefault)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -2133,8 +2133,8 @@ func TestClientEndpoint_GetClientAllocs_Blocking(t *testing.T) {
|
||||
allocUpdate.NodeID = alloc.NodeID
|
||||
allocUpdate.ID = alloc.ID
|
||||
allocUpdate.ClientStatus = structs.AllocClientStatusRunning
|
||||
state.UpsertJobSummary(199, mock.JobSummary(allocUpdate.JobID))
|
||||
err := state.UpsertAllocs(structs.MsgTypeTestSetup, 200, []*structs.Allocation{allocUpdate})
|
||||
store.UpsertJobSummary(199, mock.JobSummary(allocUpdate.JobID))
|
||||
err := store.UpsertAllocs(structs.MsgTypeTestSetup, 200, []*structs.Allocation{allocUpdate})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
@@ -355,26 +355,26 @@ func sortSet(matches []fuzzyMatch) {
|
||||
|
||||
// getResourceIter takes a context and returns a memdb iterator specific to
|
||||
// that context
|
||||
func getResourceIter(context structs.Context, aclObj *acl.ACL, namespace, prefix string, ws memdb.WatchSet, state *state.StateStore) (memdb.ResultIterator, error) {
|
||||
func getResourceIter(context structs.Context, aclObj *acl.ACL, namespace, prefix string, ws memdb.WatchSet, store *state.StateStore) (memdb.ResultIterator, error) {
|
||||
switch context {
|
||||
case structs.Jobs:
|
||||
return state.JobsByIDPrefix(ws, namespace, prefix)
|
||||
return store.JobsByIDPrefix(ws, namespace, prefix)
|
||||
case structs.Evals:
|
||||
return state.EvalsByIDPrefix(ws, namespace, prefix)
|
||||
return store.EvalsByIDPrefix(ws, namespace, prefix, state.SortDefault)
|
||||
case structs.Allocs:
|
||||
return state.AllocsByIDPrefix(ws, namespace, prefix)
|
||||
return store.AllocsByIDPrefix(ws, namespace, prefix, state.SortDefault)
|
||||
case structs.Nodes:
|
||||
return state.NodesByIDPrefix(ws, prefix)
|
||||
return store.NodesByIDPrefix(ws, prefix)
|
||||
case structs.Deployments:
|
||||
return state.DeploymentsByIDPrefix(ws, namespace, prefix)
|
||||
return store.DeploymentsByIDPrefix(ws, namespace, prefix, state.SortDefault)
|
||||
case structs.Plugins:
|
||||
return state.CSIPluginsByIDPrefix(ws, prefix)
|
||||
return store.CSIPluginsByIDPrefix(ws, prefix)
|
||||
case structs.ScalingPolicies:
|
||||
return state.ScalingPoliciesByIDPrefix(ws, namespace, prefix)
|
||||
return store.ScalingPoliciesByIDPrefix(ws, namespace, prefix)
|
||||
case structs.Volumes:
|
||||
return state.CSIVolumesByIDPrefix(ws, namespace, prefix)
|
||||
return store.CSIVolumesByIDPrefix(ws, namespace, prefix)
|
||||
case structs.Namespaces:
|
||||
iter, err := state.NamespacesByNamePrefix(ws, prefix)
|
||||
iter, err := store.NamespacesByNamePrefix(ws, prefix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -383,7 +383,7 @@ func getResourceIter(context structs.Context, aclObj *acl.ACL, namespace, prefix
|
||||
}
|
||||
return memdb.NewFilterIterator(iter, nsCapFilter(aclObj)), nil
|
||||
default:
|
||||
return getEnterpriseResourceIter(context, aclObj, namespace, prefix, ws, state)
|
||||
return getEnterpriseResourceIter(context, aclObj, namespace, prefix, ws, store)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -617,11 +617,19 @@ func (s *StateStore) DeploymentsByNamespaceOrdered(ws memdb.WatchSet, namespace
|
||||
return it, nil
|
||||
}
|
||||
|
||||
func (s *StateStore) DeploymentsByIDPrefix(ws memdb.WatchSet, namespace, deploymentID string) (memdb.ResultIterator, error) {
|
||||
func (s *StateStore) DeploymentsByIDPrefix(ws memdb.WatchSet, namespace, deploymentID string, sort SortOption) (memdb.ResultIterator, error) {
|
||||
txn := s.db.ReadTxn()
|
||||
|
||||
var iter memdb.ResultIterator
|
||||
var err error
|
||||
|
||||
// Walk the entire deployments table
|
||||
iter, err := txn.Get("deployment", "id_prefix", deploymentID)
|
||||
switch sort {
|
||||
case SortReverse:
|
||||
iter, err = txn.GetReverse("deployment", "id_prefix", deploymentID)
|
||||
default:
|
||||
iter, err = txn.Get("deployment", "id_prefix", deploymentID)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -3171,11 +3179,19 @@ func (s *StateStore) EvalByID(ws memdb.WatchSet, id string) (*structs.Evaluation
|
||||
|
||||
// EvalsByIDPrefix is used to lookup evaluations by prefix in a particular
|
||||
// namespace
|
||||
func (s *StateStore) EvalsByIDPrefix(ws memdb.WatchSet, namespace, id string) (memdb.ResultIterator, error) {
|
||||
func (s *StateStore) EvalsByIDPrefix(ws memdb.WatchSet, namespace, id string, sort SortOption) (memdb.ResultIterator, error) {
|
||||
txn := s.db.ReadTxn()
|
||||
|
||||
var iter memdb.ResultIterator
|
||||
var err error
|
||||
|
||||
// Get an iterator over all evals by the id prefix
|
||||
iter, err := txn.Get("evals", "id_prefix", id)
|
||||
switch sort {
|
||||
case SortReverse:
|
||||
iter, err = txn.GetReverse("evals", "id_prefix", id)
|
||||
default:
|
||||
iter, err = txn.Get("evals", "id_prefix", id)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("eval lookup failed: %v", err)
|
||||
}
|
||||
@@ -3631,10 +3647,18 @@ func (s *StateStore) allocByIDImpl(txn Txn, ws memdb.WatchSet, id string) (*stru
|
||||
}
|
||||
|
||||
// AllocsByIDPrefix is used to lookup allocs by prefix
|
||||
func (s *StateStore) AllocsByIDPrefix(ws memdb.WatchSet, namespace, id string) (memdb.ResultIterator, error) {
|
||||
func (s *StateStore) AllocsByIDPrefix(ws memdb.WatchSet, namespace, id string, sort SortOption) (memdb.ResultIterator, error) {
|
||||
txn := s.db.ReadTxn()
|
||||
|
||||
iter, err := txn.Get("allocs", "id_prefix", id)
|
||||
var iter memdb.ResultIterator
|
||||
var err error
|
||||
|
||||
switch sort {
|
||||
case SortReverse:
|
||||
iter, err = txn.GetReverse("allocs", "id_prefix", id)
|
||||
default:
|
||||
iter, err = txn.Get("allocs", "id_prefix", id)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("alloc lookup failed: %v", err)
|
||||
}
|
||||
@@ -5535,13 +5559,22 @@ func (s *StateStore) ACLTokenBySecretID(ws memdb.WatchSet, secretID string) (*st
|
||||
}
|
||||
|
||||
// ACLTokenByAccessorIDPrefix is used to lookup tokens by prefix
|
||||
func (s *StateStore) ACLTokenByAccessorIDPrefix(ws memdb.WatchSet, prefix string) (memdb.ResultIterator, error) {
|
||||
func (s *StateStore) ACLTokenByAccessorIDPrefix(ws memdb.WatchSet, prefix string, sort SortOption) (memdb.ResultIterator, error) {
|
||||
txn := s.db.ReadTxn()
|
||||
|
||||
iter, err := txn.Get("acl_token", "id_prefix", prefix)
|
||||
var iter memdb.ResultIterator
|
||||
var err error
|
||||
|
||||
switch sort {
|
||||
case SortReverse:
|
||||
iter, err = txn.GetReverse("acl_token", "id_prefix", prefix)
|
||||
default:
|
||||
iter, err = txn.Get("acl_token", "id_prefix", prefix)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("acl token lookup failed: %v", err)
|
||||
}
|
||||
|
||||
ws.Add(iter.WatchCh())
|
||||
return iter, nil
|
||||
}
|
||||
@@ -5568,14 +5601,23 @@ func (s *StateStore) ACLTokens(ws memdb.WatchSet, sort SortOption) (memdb.Result
|
||||
}
|
||||
|
||||
// ACLTokensByGlobal returns an iterator over all the tokens filtered by global value
|
||||
func (s *StateStore) ACLTokensByGlobal(ws memdb.WatchSet, globalVal bool) (memdb.ResultIterator, error) {
|
||||
func (s *StateStore) ACLTokensByGlobal(ws memdb.WatchSet, globalVal bool, sort SortOption) (memdb.ResultIterator, error) {
|
||||
txn := s.db.ReadTxn()
|
||||
|
||||
var iter memdb.ResultIterator
|
||||
var err error
|
||||
|
||||
// Walk the entire table
|
||||
iter, err := txn.Get("acl_token", "global", globalVal)
|
||||
switch sort {
|
||||
case SortReverse:
|
||||
iter, err = txn.GetReverse("acl_token", "global", globalVal)
|
||||
default:
|
||||
iter, err = txn.Get("acl_token", "global", globalVal)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ws.Add(iter.WatchCh())
|
||||
return iter, nil
|
||||
}
|
||||
|
||||
@@ -694,16 +694,7 @@ func TestStateStore_DeploymentsByIDPrefix(t *testing.T) {
|
||||
|
||||
deploy.ID = "11111111-662e-d0ab-d1c9-3e434af7bdb4"
|
||||
err := state.UpsertDeployment(1000, deploy)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// Create a watchset so we can test that getters don't cause it to fire
|
||||
ws := memdb.NewWatchSet()
|
||||
iter, err := state.DeploymentsByIDPrefix(ws, deploy.Namespace, deploy.ID)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
gatherDeploys := func(iter memdb.ResultIterator) []*structs.Deployment {
|
||||
var deploys []*structs.Deployment
|
||||
@@ -718,60 +709,67 @@ func TestStateStore_DeploymentsByIDPrefix(t *testing.T) {
|
||||
return deploys
|
||||
}
|
||||
|
||||
deploys := gatherDeploys(iter)
|
||||
if len(deploys) != 1 {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
t.Run("first deployment", func(t *testing.T) {
|
||||
// Create a watchset so we can test that getters don't cause it to fire
|
||||
ws := memdb.NewWatchSet()
|
||||
iter, err := state.DeploymentsByIDPrefix(ws, deploy.Namespace, deploy.ID, SortDefault)
|
||||
require.NoError(t, err)
|
||||
|
||||
if watchFired(ws) {
|
||||
t.Fatalf("bad")
|
||||
}
|
||||
deploys := gatherDeploys(iter)
|
||||
require.Len(t, deploys, 1)
|
||||
require.False(t, watchFired(ws))
|
||||
})
|
||||
|
||||
iter, err = state.DeploymentsByIDPrefix(ws, deploy.Namespace, "11")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
t.Run("using prefix", func(t *testing.T) {
|
||||
ws := memdb.NewWatchSet()
|
||||
iter, err := state.DeploymentsByIDPrefix(ws, deploy.Namespace, "11", SortDefault)
|
||||
require.NoError(t, err)
|
||||
|
||||
deploys = gatherDeploys(iter)
|
||||
if len(deploys) != 1 {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
deploys := gatherDeploys(iter)
|
||||
require.Len(t, deploys, 1)
|
||||
require.False(t, watchFired(ws))
|
||||
})
|
||||
|
||||
deploy = mock.Deployment()
|
||||
deploy.ID = "11222222-662e-d0ab-d1c9-3e434af7bdb4"
|
||||
err = state.UpsertDeployment(1001, deploy)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
if !watchFired(ws) {
|
||||
t.Fatalf("bad")
|
||||
}
|
||||
t.Run("more than one", func(t *testing.T) {
|
||||
ws := memdb.NewWatchSet()
|
||||
iter, err := state.DeploymentsByIDPrefix(ws, deploy.Namespace, "11", SortDefault)
|
||||
require.NoError(t, err)
|
||||
|
||||
ws = memdb.NewWatchSet()
|
||||
iter, err = state.DeploymentsByIDPrefix(ws, deploy.Namespace, "11")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
deploys := gatherDeploys(iter)
|
||||
require.Len(t, deploys, 2)
|
||||
})
|
||||
|
||||
deploys = gatherDeploys(iter)
|
||||
if len(deploys) != 2 {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
t.Run("filter to one", func(t *testing.T) {
|
||||
ws := memdb.NewWatchSet()
|
||||
iter, err := state.DeploymentsByIDPrefix(ws, deploy.Namespace, "1111", SortDefault)
|
||||
require.NoError(t, err)
|
||||
|
||||
iter, err = state.DeploymentsByIDPrefix(ws, deploy.Namespace, "1111")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
deploys := gatherDeploys(iter)
|
||||
require.Len(t, deploys, 1)
|
||||
require.False(t, watchFired(ws))
|
||||
})
|
||||
|
||||
deploys = gatherDeploys(iter)
|
||||
if len(deploys) != 1 {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
t.Run("reverse order", func(t *testing.T) {
|
||||
ws := memdb.NewWatchSet()
|
||||
iter, err := state.DeploymentsByIDPrefix(ws, deploy.Namespace, "11", SortReverse)
|
||||
require.NoError(t, err)
|
||||
|
||||
if watchFired(ws) {
|
||||
t.Fatalf("bad")
|
||||
}
|
||||
got := []string{}
|
||||
for _, d := range gatherDeploys(iter) {
|
||||
got = append(got, d.ID)
|
||||
}
|
||||
expected := []string{
|
||||
"11222222-662e-d0ab-d1c9-3e434af7bdb4",
|
||||
"11111111-662e-d0ab-d1c9-3e434af7bdb4",
|
||||
}
|
||||
require.Equal(t, expected, got)
|
||||
require.False(t, watchFired(ws))
|
||||
})
|
||||
}
|
||||
|
||||
func TestStateStore_UpsertNode_Node(t *testing.T) {
|
||||
@@ -3874,12 +3872,6 @@ func TestStateStore_EvalsByIDPrefix(t *testing.T) {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
ws := memdb.NewWatchSet()
|
||||
iter, err := state.EvalsByIDPrefix(ws, structs.DefaultNamespace, "aaaa")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
gatherEvals := func(iter memdb.ResultIterator) []*structs.Evaluation {
|
||||
var evals []*structs.Evaluation
|
||||
for {
|
||||
@@ -3892,32 +3884,57 @@ func TestStateStore_EvalsByIDPrefix(t *testing.T) {
|
||||
return evals
|
||||
}
|
||||
|
||||
out := gatherEvals(iter)
|
||||
if len(out) != 5 {
|
||||
t.Fatalf("bad: expected five evaluations, got: %#v", out)
|
||||
}
|
||||
t.Run("list by prefix", func(t *testing.T) {
|
||||
ws := memdb.NewWatchSet()
|
||||
iter, err := state.EvalsByIDPrefix(ws, structs.DefaultNamespace, "aaaa", SortDefault)
|
||||
require.NoError(t, err)
|
||||
|
||||
sort.Sort(EvalIDSort(evals))
|
||||
|
||||
for index, eval := range out {
|
||||
if ids[index] != eval.ID {
|
||||
t.Fatalf("bad: got unexpected id: %s", eval.ID)
|
||||
got := []string{}
|
||||
for _, e := range gatherEvals(iter) {
|
||||
got = append(got, e.ID)
|
||||
}
|
||||
}
|
||||
|
||||
iter, err = state.EvalsByIDPrefix(ws, structs.DefaultNamespace, "b-a7bfb")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
expected := []string{
|
||||
"aaaaaaaa-7bfb-395d-eb95-0685af2176b2",
|
||||
"aaaaaaab-7bfb-395d-eb95-0685af2176b2",
|
||||
"aaaaaabb-7bfb-395d-eb95-0685af2176b2",
|
||||
"aaaaabbb-7bfb-395d-eb95-0685af2176b2",
|
||||
"aaaabbbb-7bfb-395d-eb95-0685af2176b2",
|
||||
}
|
||||
require.Len(t, got, 5, "expected five evaluations")
|
||||
require.Equal(t, expected, got) // Must be in this order.
|
||||
})
|
||||
|
||||
out = gatherEvals(iter)
|
||||
if len(out) != 0 {
|
||||
t.Fatalf("bad: unexpected zero evaluations, got: %#v", out)
|
||||
}
|
||||
t.Run("invalid prefix", func(t *testing.T) {
|
||||
ws := memdb.NewWatchSet()
|
||||
iter, err := state.EvalsByIDPrefix(ws, structs.DefaultNamespace, "b-a7bfb", SortDefault)
|
||||
require.NoError(t, err)
|
||||
|
||||
if watchFired(ws) {
|
||||
t.Fatalf("bad")
|
||||
}
|
||||
out := gatherEvals(iter)
|
||||
require.Len(t, out, 0, "expected zero evaluations")
|
||||
require.False(t, watchFired(ws))
|
||||
})
|
||||
|
||||
t.Run("reverse order", func(t *testing.T) {
|
||||
ws := memdb.NewWatchSet()
|
||||
iter, err := state.EvalsByIDPrefix(ws, structs.DefaultNamespace, "aaaa", SortReverse)
|
||||
require.NoError(t, err)
|
||||
|
||||
got := []string{}
|
||||
for _, e := range gatherEvals(iter) {
|
||||
got = append(got, e.ID)
|
||||
}
|
||||
|
||||
expected := []string{
|
||||
"aaaabbbb-7bfb-395d-eb95-0685af2176b2",
|
||||
"aaaaabbb-7bfb-395d-eb95-0685af2176b2",
|
||||
"aaaaaabb-7bfb-395d-eb95-0685af2176b2",
|
||||
"aaaaaaab-7bfb-395d-eb95-0685af2176b2",
|
||||
"aaaaaaaa-7bfb-395d-eb95-0685af2176b2",
|
||||
}
|
||||
require.Len(t, got, 5, "expected five evaluations")
|
||||
require.Equal(t, expected, got) // Must be in this order.
|
||||
})
|
||||
}
|
||||
|
||||
func TestStateStore_UpdateAllocsFromClient(t *testing.T) {
|
||||
@@ -5362,15 +5379,7 @@ func TestStateStore_AllocsByIDPrefix(t *testing.T) {
|
||||
}
|
||||
|
||||
err := state.UpsertAllocs(structs.MsgTypeTestSetup, 1000, allocs)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
ws := memdb.NewWatchSet()
|
||||
iter, err := state.AllocsByIDPrefix(ws, structs.DefaultNamespace, "aaaa")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
gatherAllocs := func(iter memdb.ResultIterator) []*structs.Allocation {
|
||||
var allocs []*structs.Allocation
|
||||
@@ -5384,32 +5393,61 @@ func TestStateStore_AllocsByIDPrefix(t *testing.T) {
|
||||
return allocs
|
||||
}
|
||||
|
||||
out := gatherAllocs(iter)
|
||||
if len(out) != 5 {
|
||||
t.Fatalf("bad: expected five allocations, got: %#v", out)
|
||||
}
|
||||
t.Run("allocs by prefix", func(t *testing.T) {
|
||||
ws := memdb.NewWatchSet()
|
||||
iter, err := state.AllocsByIDPrefix(ws, structs.DefaultNamespace, "aaaa", SortDefault)
|
||||
require.NoError(t, err)
|
||||
|
||||
sort.Sort(AllocIDSort(allocs))
|
||||
out := gatherAllocs(iter)
|
||||
require.Len(t, out, 5, "expected five allocations")
|
||||
|
||||
for index, alloc := range out {
|
||||
if ids[index] != alloc.ID {
|
||||
t.Fatalf("bad: got unexpected id: %s", alloc.ID)
|
||||
got := []string{}
|
||||
for _, a := range out {
|
||||
got = append(got, a.ID)
|
||||
}
|
||||
}
|
||||
expected := []string{
|
||||
"aaaaaaaa-7bfb-395d-eb95-0685af2176b2",
|
||||
"aaaaaaab-7bfb-395d-eb95-0685af2176b2",
|
||||
"aaaaaabb-7bfb-395d-eb95-0685af2176b2",
|
||||
"aaaaabbb-7bfb-395d-eb95-0685af2176b2",
|
||||
"aaaabbbb-7bfb-395d-eb95-0685af2176b2",
|
||||
}
|
||||
require.Equal(t, expected, got)
|
||||
require.False(t, watchFired(ws))
|
||||
})
|
||||
|
||||
iter, err = state.AllocsByIDPrefix(ws, structs.DefaultNamespace, "b-a7bfb")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
t.Run("invalid prefix", func(t *testing.T) {
|
||||
ws := memdb.NewWatchSet()
|
||||
iter, err := state.AllocsByIDPrefix(ws, structs.DefaultNamespace, "b-a7bfb", SortDefault)
|
||||
require.NoError(t, err)
|
||||
|
||||
out = gatherAllocs(iter)
|
||||
if len(out) != 0 {
|
||||
t.Fatalf("bad: unexpected zero allocations, got: %#v", out)
|
||||
}
|
||||
out := gatherAllocs(iter)
|
||||
require.Len(t, out, 0)
|
||||
require.False(t, watchFired(ws))
|
||||
})
|
||||
|
||||
if watchFired(ws) {
|
||||
t.Fatalf("bad")
|
||||
}
|
||||
t.Run("reverse", func(t *testing.T) {
|
||||
ws := memdb.NewWatchSet()
|
||||
iter, err := state.AllocsByIDPrefix(ws, structs.DefaultNamespace, "aaaa", SortReverse)
|
||||
require.NoError(t, err)
|
||||
|
||||
out := gatherAllocs(iter)
|
||||
require.Len(t, out, 5, "expected five allocations")
|
||||
|
||||
got := []string{}
|
||||
for _, a := range out {
|
||||
got = append(got, a.ID)
|
||||
}
|
||||
expected := []string{
|
||||
"aaaabbbb-7bfb-395d-eb95-0685af2176b2",
|
||||
"aaaaabbb-7bfb-395d-eb95-0685af2176b2",
|
||||
"aaaaaabb-7bfb-395d-eb95-0685af2176b2",
|
||||
"aaaaaaab-7bfb-395d-eb95-0685af2176b2",
|
||||
"aaaaaaaa-7bfb-395d-eb95-0685af2176b2",
|
||||
}
|
||||
require.Equal(t, expected, got)
|
||||
require.False(t, watchFired(ws))
|
||||
})
|
||||
}
|
||||
|
||||
func TestStateStore_Allocs(t *testing.T) {
|
||||
@@ -7717,36 +7755,54 @@ func TestStateStore_ACLTokenByAccessorIDPrefix(t *testing.T) {
|
||||
for _, prefix := range prefixes {
|
||||
tk := mock.ACLToken()
|
||||
tk.AccessorID = prefix + tk.AccessorID[4:]
|
||||
if err := state.UpsertACLTokens(structs.MsgTypeTestSetup, baseIndex, []*structs.ACLToken{tk}); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
err := state.UpsertACLTokens(structs.MsgTypeTestSetup, baseIndex, []*structs.ACLToken{tk})
|
||||
require.NoError(t, err)
|
||||
baseIndex++
|
||||
}
|
||||
|
||||
// Scan by prefix
|
||||
iter, err := state.ACLTokenByAccessorIDPrefix(nil, "aa")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// Ensure we see both tokens
|
||||
count := 0
|
||||
out := []string{}
|
||||
for {
|
||||
raw := iter.Next()
|
||||
if raw == nil {
|
||||
break
|
||||
gatherTokens := func(iter memdb.ResultIterator) []*structs.ACLToken {
|
||||
var tokens []*structs.ACLToken
|
||||
for {
|
||||
raw := iter.Next()
|
||||
if raw == nil {
|
||||
break
|
||||
}
|
||||
tokens = append(tokens, raw.(*structs.ACLToken))
|
||||
}
|
||||
count++
|
||||
out = append(out, raw.(*structs.ACLToken).AccessorID[:4])
|
||||
return tokens
|
||||
}
|
||||
if count != 2 {
|
||||
t.Fatalf("bad: %d %v", count, out)
|
||||
}
|
||||
sort.Strings(out)
|
||||
|
||||
expect := []string{"aaaa", "aabb"}
|
||||
assert.Equal(t, expect, out)
|
||||
t.Run("scan by prefix", func(t *testing.T) {
|
||||
iter, err := state.ACLTokenByAccessorIDPrefix(nil, "aa", SortDefault)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Ensure we see both tokens
|
||||
out := gatherTokens(iter)
|
||||
require.Len(t, out, 2)
|
||||
|
||||
got := []string{}
|
||||
for _, t := range out {
|
||||
got = append(got, t.AccessorID[:4])
|
||||
}
|
||||
expect := []string{"aaaa", "aabb"}
|
||||
require.Equal(t, expect, got)
|
||||
})
|
||||
|
||||
t.Run("reverse order", func(t *testing.T) {
|
||||
iter, err := state.ACLTokenByAccessorIDPrefix(nil, "aa", SortReverse)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Ensure we see both tokens
|
||||
out := gatherTokens(iter)
|
||||
require.Len(t, out, 2)
|
||||
|
||||
got := []string{}
|
||||
for _, t := range out {
|
||||
got = append(got, t.AccessorID[:4])
|
||||
}
|
||||
expect := []string{"aabb", "aaaa"}
|
||||
require.Equal(t, expect, got)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStateStore_ACLTokensByGlobal(t *testing.T) {
|
||||
@@ -7754,32 +7810,51 @@ func TestStateStore_ACLTokensByGlobal(t *testing.T) {
|
||||
|
||||
state := testStateStore(t)
|
||||
tk1 := mock.ACLToken()
|
||||
tk1.AccessorID = "aaaa" + tk1.AccessorID[4:]
|
||||
|
||||
tk2 := mock.ACLToken()
|
||||
tk2.AccessorID = "aabb" + tk2.AccessorID[4:]
|
||||
|
||||
tk3 := mock.ACLToken()
|
||||
tk4 := mock.ACLToken()
|
||||
tk3.AccessorID = "bbbb" + tk3.AccessorID[4:]
|
||||
tk3.Global = true
|
||||
|
||||
if err := state.UpsertACLTokens(structs.MsgTypeTestSetup, 1000, []*structs.ACLToken{tk1, tk2, tk3, tk4}); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
tk4 := mock.ACLToken()
|
||||
tk4.AccessorID = "ffff" + tk4.AccessorID[4:]
|
||||
|
||||
iter, err := state.ACLTokensByGlobal(nil, true)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
err := state.UpsertACLTokens(structs.MsgTypeTestSetup, 1000, []*structs.ACLToken{tk1, tk2, tk3, tk4})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Ensure we see the one global policies
|
||||
count := 0
|
||||
for {
|
||||
raw := iter.Next()
|
||||
if raw == nil {
|
||||
break
|
||||
gatherTokens := func(iter memdb.ResultIterator) []*structs.ACLToken {
|
||||
var tokens []*structs.ACLToken
|
||||
for {
|
||||
raw := iter.Next()
|
||||
if raw == nil {
|
||||
break
|
||||
}
|
||||
tokens = append(tokens, raw.(*structs.ACLToken))
|
||||
}
|
||||
count++
|
||||
}
|
||||
if count != 1 {
|
||||
t.Fatalf("bad: %d", count)
|
||||
return tokens
|
||||
}
|
||||
|
||||
t.Run("only global tokens", func(t *testing.T) {
|
||||
iter, err := state.ACLTokensByGlobal(nil, true, SortDefault)
|
||||
require.NoError(t, err)
|
||||
|
||||
got := gatherTokens(iter)
|
||||
require.Len(t, got, 1)
|
||||
require.Equal(t, tk3.AccessorID, got[0].AccessorID)
|
||||
})
|
||||
|
||||
t.Run("reverse order", func(t *testing.T) {
|
||||
iter, err := state.ACLTokensByGlobal(nil, false, SortReverse)
|
||||
require.NoError(t, err)
|
||||
|
||||
expected := []*structs.ACLToken{tk4, tk2, tk1}
|
||||
got := gatherTokens(iter)
|
||||
require.Len(t, got, 3)
|
||||
require.Equal(t, expected, got)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStateStore_OneTimeTokens(t *testing.T) {
|
||||
|
||||
@@ -70,11 +70,19 @@ The table below shows this endpoint's support for
|
||||
|
||||
### Parameters
|
||||
|
||||
- `global` `(bool: false)` - If true, only return ACL tokens that are
|
||||
replicated globally to all regions.
|
||||
|
||||
- `prefix` `(string: "")` - Specifies a string to filter ACL tokens based on an
|
||||
accessor ID prefix. Because the value is decoded to bytes, the prefix must
|
||||
have an even number of hexadecimal characters (0-9a-f). This is specified as
|
||||
a query string parameter.
|
||||
|
||||
- `reverse` `(bool: false)` - Specifies the list of returned ACL tokens should
|
||||
be sorted in the reverse order. By default ACL tokens are returned sorted in
|
||||
chronological order (older ACL tokens first), or in lexicographical order by
|
||||
their ID if the `prefix` or `global` query parameters are used.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```shell-session
|
||||
|
||||
@@ -43,6 +43,11 @@ The table below shows this endpoint's support for
|
||||
a large number of allocations may set `task_states=false` to significantly
|
||||
reduce the size of the response.
|
||||
|
||||
- `reverse` `(bool: false)` - Specifies the list of returned allocations should
|
||||
be sorted in the reverse order. By default allocations are returned sorted in
|
||||
chronological order (older evaluations first), or in lexicographical order by
|
||||
their ID if the `prefix` query parameter is used.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```shell-session
|
||||
|
||||
@@ -50,9 +50,10 @@ The table below shows this endpoint's support for
|
||||
results. Consider using pagination or a query parameter to reduce resource
|
||||
used to serve the request.
|
||||
|
||||
- `ascending` `(bool: false)` - Specifies the list of returned deployments should
|
||||
be sorted in chronological order (oldest evaluations first). By default deployments
|
||||
are returned sorted in reverse chronological order (newest deployments first).
|
||||
- `reverse` `(bool: false)` - Specifies the list of returned deployments should
|
||||
be sorted in the reverse order. By default deployments are returned sorted in
|
||||
chronological order (older deployments first), or in lexicographical order
|
||||
by their ID if the `prefix` query parameter is used.
|
||||
|
||||
### Sample Request
|
||||
|
||||
|
||||
@@ -57,9 +57,10 @@ The table below shows this endpoint's support for
|
||||
Specifying `*` will return all evaluations across all authorized namespaces.
|
||||
This parameter is used before any `filter` expression is applied.
|
||||
|
||||
- `ascending` `(bool: false)` - Specifies the list of returned evaluations should
|
||||
be sorted in chronological order (oldest evaluations first). By default evaluations
|
||||
are returned sorted in reverse chronological order (newest evaluations first).
|
||||
- `reverse` `(bool: false)` - Specifies the list of returned evaluations should
|
||||
be sorted in the reverse order. By default evaluations are returned sorted in
|
||||
chronological order (older evaluations first), or in lexicographical order by
|
||||
their ID if the `prefix` query parameter is used.
|
||||
|
||||
### Sample Request
|
||||
|
||||
|
||||
Reference in New Issue
Block a user