Skip to content

Commit

Permalink
documenting test for #9268
Browse files Browse the repository at this point in the history
  • Loading branch information
cgbaker committed Nov 5, 2020
1 parent 4daf5a4 commit c5fe588
Showing 1 changed file with 220 additions and 30 deletions.
250 changes: 220 additions & 30 deletions nomad/alloc_endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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{
Expand All @@ -337,39 +348,34 @@ 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) {
get := &structs.AllocListRequest{
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{
Expand All @@ -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) {
Expand Down Expand Up @@ -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)
}
})
}

}

0 comments on commit c5fe588

Please sign in to comment.