mirror of
https://github.com/kemko/nomad.git
synced 2026-01-09 11:55:42 +03:00
documenting test for #9268
This commit is contained in:
@@ -6,14 +6,15 @@ import (
|
||||
"time"
|
||||
|
||||
msgpackrpc "github.com/hashicorp/net-rpc-msgpackrpc"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/hashicorp/nomad/acl"
|
||||
"github.com/hashicorp/nomad/helper"
|
||||
"github.com/hashicorp/nomad/helper/uuid"
|
||||
"github.com/hashicorp/nomad/nomad/mock"
|
||||
"github.com/hashicorp/nomad/nomad/structs"
|
||||
"github.com/hashicorp/nomad/testutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAllocEndpoint_List(t *testing.T) {
|
||||
@@ -318,16 +319,26 @@ func TestAllocEndpoint_List_AllNamespaces_OSS(t *testing.T) {
|
||||
defer cleanupS1()
|
||||
codec := rpcClient(t, s1)
|
||||
testutil.WaitForLeader(t, s1.RPC)
|
||||
|
||||
// Create the register request
|
||||
alloc := mock.Alloc()
|
||||
summary := mock.JobSummary(alloc.JobID)
|
||||
state := s1.fsm.State()
|
||||
|
||||
err := state.UpsertJobSummary(999, summary)
|
||||
require.NoError(t, err)
|
||||
err = state.UpsertAllocs(structs.MsgTypeTestSetup, 1000, []*structs.Allocation{alloc})
|
||||
require.NoError(t, err)
|
||||
// two namespaces
|
||||
ns1 := mock.Namespace()
|
||||
ns2 := mock.Namespace()
|
||||
require.NoError(t, state.UpsertNamespaces(900, []*structs.Namespace{ns1, ns2}))
|
||||
|
||||
// Create the allocations
|
||||
alloc1 := mock.Alloc()
|
||||
alloc1.ID = "a" + alloc1.ID[1:]
|
||||
alloc1.Namespace = ns1.Name
|
||||
alloc2 := mock.Alloc()
|
||||
alloc2.ID = "b" + alloc2.ID[1:]
|
||||
alloc2.Namespace = ns2.Name
|
||||
summary1 := mock.JobSummary(alloc1.JobID)
|
||||
summary2 := mock.JobSummary(alloc2.JobID)
|
||||
|
||||
require.NoError(t, state.UpsertJobSummary(999, summary1))
|
||||
require.NoError(t, state.UpsertJobSummary(999, summary2))
|
||||
require.NoError(t, state.UpsertAllocs(structs.MsgTypeTestSetup, 1000, []*structs.Allocation{alloc1, alloc2}))
|
||||
|
||||
t.Run("looking up all allocations", func(t *testing.T) {
|
||||
get := &structs.AllocListRequest{
|
||||
@@ -337,12 +348,12 @@ func TestAllocEndpoint_List_AllNamespaces_OSS(t *testing.T) {
|
||||
},
|
||||
}
|
||||
var resp structs.AllocListResponse
|
||||
err = msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp))
|
||||
require.Equal(t, uint64(1000), resp.Index)
|
||||
require.Len(t, resp.Allocations, 1)
|
||||
require.Equal(t, alloc.ID, resp.Allocations[0].ID)
|
||||
require.Equal(t, structs.DefaultNamespace, resp.Allocations[0].Namespace)
|
||||
require.Len(t, resp.Allocations, 2)
|
||||
require.ElementsMatch(t,
|
||||
[]string{resp.Allocations[0].ID, resp.Allocations[1].ID},
|
||||
[]string{alloc1.ID, alloc2.ID})
|
||||
})
|
||||
|
||||
t.Run("looking up allocations with prefix", func(t *testing.T) {
|
||||
@@ -350,26 +361,21 @@ func TestAllocEndpoint_List_AllNamespaces_OSS(t *testing.T) {
|
||||
QueryOptions: structs.QueryOptions{
|
||||
Region: "global",
|
||||
Namespace: "*",
|
||||
Prefix: alloc.ID[:4],
|
||||
// allocations were constructed above to have non-matching prefix
|
||||
Prefix: alloc1.ID[:4],
|
||||
},
|
||||
}
|
||||
var resp structs.AllocListResponse
|
||||
err = msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp))
|
||||
require.Equal(t, uint64(1000), resp.Index)
|
||||
require.Len(t, resp.Allocations, 1)
|
||||
require.Equal(t, alloc.ID, resp.Allocations[0].ID)
|
||||
require.Equal(t, structs.DefaultNamespace, resp.Allocations[0].Namespace)
|
||||
require.Equal(t, alloc1.ID, resp.Allocations[0].ID)
|
||||
require.Equal(t, alloc1.Namespace, resp.Allocations[0].Namespace)
|
||||
})
|
||||
|
||||
t.Run("looking up allocations with mismatch prefix", func(t *testing.T) {
|
||||
// ensure that prefix doesn't match the alloc
|
||||
badPrefix := alloc.ID[:4]
|
||||
if badPrefix[0] == '0' {
|
||||
badPrefix = "1" + badPrefix[1:]
|
||||
} else {
|
||||
badPrefix = "0" + badPrefix[1:]
|
||||
}
|
||||
// allocations were constructed above to have prefix starting with "a" or "b"
|
||||
badPrefix := "cc"
|
||||
|
||||
get := &structs.AllocListRequest{
|
||||
QueryOptions: structs.QueryOptions{
|
||||
@@ -379,12 +385,10 @@ func TestAllocEndpoint_List_AllNamespaces_OSS(t *testing.T) {
|
||||
},
|
||||
}
|
||||
var resp structs.AllocListResponse
|
||||
err = msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp))
|
||||
require.Equal(t, uint64(1000), resp.Index)
|
||||
require.Empty(t, resp.Allocations)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestAllocEndpoint_GetAlloc(t *testing.T) {
|
||||
@@ -844,3 +848,189 @@ func TestAllocEndpoint_Stop_ACL(t *testing.T) {
|
||||
require.True(*out1.DesiredTransition.Migrate)
|
||||
require.True(*out2.DesiredTransition.Migrate)
|
||||
}
|
||||
|
||||
func TestAllocEndpoint_List_AllNamespaces_ACL_OSS(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s1, root, cleanupS1 := TestACLServer(t, nil)
|
||||
defer cleanupS1()
|
||||
codec := rpcClient(t, s1)
|
||||
testutil.WaitForLeader(t, s1.RPC)
|
||||
state := s1.fsm.State()
|
||||
|
||||
// two namespaces
|
||||
ns1 := mock.Namespace()
|
||||
ns2 := mock.Namespace()
|
||||
require.NoError(t, state.UpsertNamespaces(900, []*structs.Namespace{ns1, ns2}))
|
||||
|
||||
// Create the allocations
|
||||
alloc1 := mock.Alloc()
|
||||
alloc1.ID = "a" + alloc1.ID[1:]
|
||||
alloc1.Namespace = ns1.Name
|
||||
alloc2 := mock.Alloc()
|
||||
alloc2.ID = "b" + alloc2.ID[1:]
|
||||
alloc2.Namespace = ns2.Name
|
||||
summary1 := mock.JobSummary(alloc1.JobID)
|
||||
summary2 := mock.JobSummary(alloc2.JobID)
|
||||
|
||||
require.NoError(t, state.UpsertJobSummary(999, summary1))
|
||||
require.NoError(t, state.UpsertJobSummary(999, summary2))
|
||||
require.NoError(t, state.UpsertAllocs(structs.MsgTypeTestSetup, 1000, []*structs.Allocation{alloc1, alloc2}))
|
||||
alloc1.CreateIndex = 1000
|
||||
alloc1.ModifyIndex = 1000
|
||||
alloc2.CreateIndex = 1000
|
||||
alloc2.ModifyIndex = 1000
|
||||
|
||||
everythingButReadJob := []string{
|
||||
acl.NamespaceCapabilityDeny,
|
||||
acl.NamespaceCapabilityListJobs,
|
||||
// acl.NamespaceCapabilityReadJob,
|
||||
acl.NamespaceCapabilitySubmitJob,
|
||||
acl.NamespaceCapabilityDispatchJob,
|
||||
acl.NamespaceCapabilityReadLogs,
|
||||
acl.NamespaceCapabilityReadFS,
|
||||
acl.NamespaceCapabilityAllocExec,
|
||||
acl.NamespaceCapabilityAllocNodeExec,
|
||||
acl.NamespaceCapabilityAllocLifecycle,
|
||||
acl.NamespaceCapabilitySentinelOverride,
|
||||
acl.NamespaceCapabilityCSIRegisterPlugin,
|
||||
acl.NamespaceCapabilityCSIWriteVolume,
|
||||
acl.NamespaceCapabilityCSIReadVolume,
|
||||
acl.NamespaceCapabilityCSIListVolume,
|
||||
acl.NamespaceCapabilityCSIMountVolume,
|
||||
acl.NamespaceCapabilityListScalingPolicies,
|
||||
acl.NamespaceCapabilityReadScalingPolicy,
|
||||
acl.NamespaceCapabilityReadJobScaling,
|
||||
acl.NamespaceCapabilityScaleJob,
|
||||
acl.NamespaceCapabilitySubmitRecommendation,
|
||||
}
|
||||
|
||||
ns1token := mock.CreatePolicyAndToken(t, state, 1001, "ns1",
|
||||
mock.NamespacePolicy(ns1.Name, "", []string{acl.NamespaceCapabilityReadJob}))
|
||||
ns1tokenInsufficient := mock.CreatePolicyAndToken(t, state, 1001, "ns1-insufficient",
|
||||
mock.NamespacePolicy(ns1.Name, "", everythingButReadJob))
|
||||
ns2token := mock.CreatePolicyAndToken(t, state, 1001, "ns2",
|
||||
mock.NamespacePolicy(ns2.Name, "", []string{acl.NamespaceCapabilityReadJob}))
|
||||
bothToken := mock.CreatePolicyAndToken(t, state, 1001, "nsBoth",
|
||||
mock.NamespacePolicy(ns1.Name, "", []string{acl.NamespaceCapabilityReadJob})+
|
||||
mock.NamespacePolicy(ns2.Name, "", []string{acl.NamespaceCapabilityReadJob}))
|
||||
|
||||
cases := []struct {
|
||||
Label string
|
||||
Namespace string
|
||||
Token string
|
||||
Allocs []*structs.Allocation
|
||||
Error bool
|
||||
Message string
|
||||
Prefix string
|
||||
}{
|
||||
{
|
||||
Label: "all namespaces with sufficient token",
|
||||
Namespace: "*",
|
||||
Token: bothToken.SecretID,
|
||||
Allocs: []*structs.Allocation{alloc1, alloc2},
|
||||
},
|
||||
{
|
||||
Label: "all namespaces with root token",
|
||||
Namespace: "*",
|
||||
Token: root.SecretID,
|
||||
Allocs: []*structs.Allocation{alloc1, alloc2},
|
||||
},
|
||||
{
|
||||
Label: "all namespaces with ns1 token",
|
||||
Namespace: "*",
|
||||
Token: ns1token.SecretID,
|
||||
Allocs: []*structs.Allocation{alloc1},
|
||||
},
|
||||
{
|
||||
Label: "all namespaces with ns2 token",
|
||||
Namespace: "*",
|
||||
Token: ns2token.SecretID,
|
||||
Allocs: []*structs.Allocation{alloc2},
|
||||
},
|
||||
{
|
||||
Label: "all namespaces with bad token",
|
||||
Namespace: "*",
|
||||
Token: uuid.Generate(),
|
||||
Error: true,
|
||||
Message: structs.ErrTokenNotFound.Error(),
|
||||
},
|
||||
{
|
||||
Label: "all namespaces with insufficient token",
|
||||
Namespace: "*",
|
||||
Allocs: []*structs.Allocation{},
|
||||
Token: ns1tokenInsufficient.SecretID,
|
||||
},
|
||||
{
|
||||
Label: "ns1 with ns1 token",
|
||||
Namespace: ns1.Name,
|
||||
Token: ns1token.SecretID,
|
||||
Allocs: []*structs.Allocation{alloc1},
|
||||
},
|
||||
{
|
||||
Label: "ns1 with root token",
|
||||
Namespace: ns1.Name,
|
||||
Token: root.SecretID,
|
||||
Allocs: []*structs.Allocation{alloc1},
|
||||
},
|
||||
{
|
||||
Label: "ns1 with ns2 token",
|
||||
Namespace: ns1.Name,
|
||||
Token: ns2token.SecretID,
|
||||
Error: true,
|
||||
},
|
||||
{
|
||||
Label: "ns1 with invalid token",
|
||||
Namespace: ns1.Name,
|
||||
Token: uuid.Generate(),
|
||||
Error: true,
|
||||
Message: structs.ErrTokenNotFound.Error(),
|
||||
},
|
||||
{
|
||||
Label: "bad namespace with root token",
|
||||
Namespace: uuid.Generate(),
|
||||
Token: root.SecretID,
|
||||
Allocs: []*structs.Allocation{},
|
||||
},
|
||||
{
|
||||
Label: "all namespaces with prefix",
|
||||
Namespace: "*",
|
||||
Prefix: alloc1.ID[:2],
|
||||
Token: root.SecretID,
|
||||
Allocs: []*structs.Allocation{alloc1},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.Label, func(t *testing.T) {
|
||||
|
||||
get := &structs.AllocListRequest{
|
||||
QueryOptions: structs.QueryOptions{
|
||||
Region: "global",
|
||||
Namespace: tc.Namespace,
|
||||
Prefix: tc.Prefix,
|
||||
AuthToken: tc.Token,
|
||||
},
|
||||
}
|
||||
var resp structs.AllocListResponse
|
||||
err := msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp)
|
||||
if tc.Error {
|
||||
require.Error(t, err)
|
||||
if tc.Message != "" {
|
||||
require.Equal(t, err.Error(), tc.Message)
|
||||
} else {
|
||||
require.Equal(t, err.Error(), structs.ErrPermissionDenied.Error())
|
||||
}
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint64(1000), resp.Index)
|
||||
exp := make([]*structs.AllocListStub, len(tc.Allocs))
|
||||
for i, a := range tc.Allocs {
|
||||
exp[i] = a.Stub(nil)
|
||||
}
|
||||
require.ElementsMatch(t, exp, resp.Allocations)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user