github.com/iqoqo/nomad@v0.11.3-0.20200911112621-d7021c74d101/nomad/scaling_endpoint_test.go (about) 1 package nomad 2 3 import ( 4 msgpackrpc "github.com/hashicorp/net-rpc-msgpackrpc" 5 "github.com/stretchr/testify/require" 6 "testing" 7 "time" 8 9 "github.com/hashicorp/nomad/acl" 10 "github.com/hashicorp/nomad/helper/uuid" 11 "github.com/hashicorp/nomad/nomad/mock" 12 "github.com/hashicorp/nomad/nomad/structs" 13 "github.com/hashicorp/nomad/testutil" 14 ) 15 16 func TestScalingEndpoint_GetPolicy(t *testing.T) { 17 t.Parallel() 18 require := require.New(t) 19 20 s1, cleanupS1 := TestServer(t, nil) 21 defer cleanupS1() 22 codec := rpcClient(t, s1) 23 testutil.WaitForLeader(t, s1.RPC) 24 25 p1 := mock.ScalingPolicy() 26 p2 := mock.ScalingPolicy() 27 s1.fsm.State().UpsertScalingPolicies(1000, []*structs.ScalingPolicy{p1, p2}) 28 29 // Lookup the policy 30 get := &structs.ScalingPolicySpecificRequest{ 31 ID: p1.ID, 32 QueryOptions: structs.QueryOptions{ 33 Region: "global", 34 }, 35 } 36 var resp structs.SingleScalingPolicyResponse 37 err := msgpackrpc.CallWithCodec(codec, "Scaling.GetPolicy", get, &resp) 38 require.NoError(err) 39 require.EqualValues(1000, resp.Index) 40 require.Equal(*p1, *resp.Policy) 41 42 // Lookup non-existing policy 43 get.ID = uuid.Generate() 44 resp = structs.SingleScalingPolicyResponse{} 45 err = msgpackrpc.CallWithCodec(codec, "Scaling.GetPolicy", get, &resp) 46 require.NoError(err) 47 require.EqualValues(1000, resp.Index) 48 require.Nil(resp.Policy) 49 } 50 51 func TestScalingEndpoint_GetPolicy_ACL(t *testing.T) { 52 t.Parallel() 53 require := require.New(t) 54 55 s1, root, cleanupS1 := TestACLServer(t, nil) 56 defer cleanupS1() 57 codec := rpcClient(t, s1) 58 testutil.WaitForLeader(t, s1.RPC) 59 state := s1.fsm.State() 60 61 p1 := mock.ScalingPolicy() 62 p2 := mock.ScalingPolicy() 63 state.UpsertScalingPolicies(1000, []*structs.ScalingPolicy{p1, p2}) 64 65 get := &structs.ScalingPolicySpecificRequest{ 66 ID: p1.ID, 67 QueryOptions: structs.QueryOptions{ 68 Region: "global", 69 }, 70 } 71 72 // lookup without token should fail 73 var resp structs.SingleScalingPolicyResponse 74 err := msgpackrpc.CallWithCodec(codec, "Scaling.GetPolicy", get, &resp) 75 require.Error(err) 76 require.Contains(err.Error(), "Permission denied") 77 78 // Expect failure for request with an invalid token 79 invalidToken := mock.CreatePolicyAndToken(t, state, 1003, "test-invalid", 80 mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityListScalingPolicies})) 81 get.AuthToken = invalidToken.SecretID 82 err = msgpackrpc.CallWithCodec(codec, "Scaling.GetPolicy", get, &resp) 83 require.Error(err) 84 require.Contains(err.Error(), "Permission denied") 85 type testCase struct { 86 authToken string 87 name string 88 } 89 cases := []testCase{ 90 { 91 name: "mgmt token should succeed", 92 authToken: root.SecretID, 93 }, 94 { 95 name: "read disposition should succeed", 96 authToken: mock.CreatePolicyAndToken(t, state, 1005, "test-valid-read", 97 mock.NamespacePolicy(structs.DefaultNamespace, "read", nil)).SecretID, 98 }, 99 { 100 name: "write disposition should succeed", 101 authToken: mock.CreatePolicyAndToken(t, state, 1005, "test-valid-write", 102 mock.NamespacePolicy(structs.DefaultNamespace, "write", nil)).SecretID, 103 }, 104 { 105 name: "autoscaler disposition should succeed", 106 authToken: mock.CreatePolicyAndToken(t, state, 1005, "test-valid-autoscaler", 107 mock.NamespacePolicy(structs.DefaultNamespace, "scale", nil)).SecretID, 108 }, 109 { 110 name: "list-jobs+read-job capability should succeed", 111 authToken: mock.CreatePolicyAndToken(t, state, 1005, "test-valid-read-job-scaling", 112 mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityListJobs, acl.NamespaceCapabilityReadJob})).SecretID, 113 }, 114 } 115 116 for _, tc := range cases { 117 get.AuthToken = tc.authToken 118 err = msgpackrpc.CallWithCodec(codec, "Scaling.GetPolicy", get, &resp) 119 require.NoError(err, tc.name) 120 require.EqualValues(1000, resp.Index) 121 require.NotNil(resp.Policy) 122 } 123 124 } 125 126 func TestScalingEndpoint_ListPolicies(t *testing.T) { 127 t.Parallel() 128 require := require.New(t) 129 130 s1, cleanupS1 := TestServer(t, nil) 131 defer cleanupS1() 132 codec := rpcClient(t, s1) 133 testutil.WaitForLeader(t, s1.RPC) 134 135 // Lookup the policies 136 get := &structs.ScalingPolicyListRequest{ 137 QueryOptions: structs.QueryOptions{ 138 Region: "global", 139 }, 140 } 141 var resp structs.ACLPolicyListResponse 142 err := msgpackrpc.CallWithCodec(codec, "Scaling.ListPolicies", get, &resp) 143 require.NoError(err) 144 require.Empty(resp.Policies) 145 146 p1 := mock.ScalingPolicy() 147 p2 := mock.ScalingPolicy() 148 s1.fsm.State().UpsertScalingPolicies(1000, []*structs.ScalingPolicy{p1, p2}) 149 150 err = msgpackrpc.CallWithCodec(codec, "Scaling.ListPolicies", get, &resp) 151 require.NoError(err) 152 require.EqualValues(1000, resp.Index) 153 require.Len(resp.Policies, 2) 154 } 155 156 func TestScalingEndpoint_ListPolicies_ACL(t *testing.T) { 157 t.Parallel() 158 require := require.New(t) 159 160 s1, root, cleanupS1 := TestACLServer(t, nil) 161 defer cleanupS1() 162 codec := rpcClient(t, s1) 163 testutil.WaitForLeader(t, s1.RPC) 164 state := s1.fsm.State() 165 166 p1 := mock.ScalingPolicy() 167 p2 := mock.ScalingPolicy() 168 state.UpsertScalingPolicies(1000, []*structs.ScalingPolicy{p1, p2}) 169 170 get := &structs.ScalingPolicyListRequest{ 171 QueryOptions: structs.QueryOptions{ 172 Region: "global", 173 }, 174 } 175 176 // lookup without token should fail 177 var resp structs.ACLPolicyListResponse 178 err := msgpackrpc.CallWithCodec(codec, "Scaling.ListPolicies", get, &resp) 179 require.Error(err) 180 require.Contains(err.Error(), "Permission denied") 181 182 // Expect failure for request with an invalid token 183 invalidToken := mock.CreatePolicyAndToken(t, state, 1003, "test-invalid", 184 mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityListScalingPolicies})) 185 get.AuthToken = invalidToken.SecretID 186 require.Error(err) 187 require.Contains(err.Error(), "Permission denied") 188 189 type testCase struct { 190 authToken string 191 name string 192 } 193 cases := []testCase{ 194 { 195 name: "mgmt token should succeed", 196 authToken: root.SecretID, 197 }, 198 { 199 name: "read disposition should succeed", 200 authToken: mock.CreatePolicyAndToken(t, state, 1005, "test-valid-read", 201 mock.NamespacePolicy(structs.DefaultNamespace, "read", nil)).SecretID, 202 }, 203 { 204 name: "write disposition should succeed", 205 authToken: mock.CreatePolicyAndToken(t, state, 1005, "test-valid-write", 206 mock.NamespacePolicy(structs.DefaultNamespace, "write", nil)).SecretID, 207 }, 208 { 209 name: "autoscaler disposition should succeed", 210 authToken: mock.CreatePolicyAndToken(t, state, 1005, "test-valid-autoscaler", 211 mock.NamespacePolicy(structs.DefaultNamespace, "scale", nil)).SecretID, 212 }, 213 { 214 name: "list-scaling-policies capability should succeed", 215 authToken: mock.CreatePolicyAndToken(t, state, 1005, "test-valid-list-scaling-policies", 216 mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityListScalingPolicies})).SecretID, 217 }, 218 { 219 name: "list-jobs+read-job capability should succeed", 220 authToken: mock.CreatePolicyAndToken(t, state, 1005, "test-valid-read-job-scaling", 221 mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityListJobs, acl.NamespaceCapabilityReadJob})).SecretID, 222 }, 223 } 224 225 for _, tc := range cases { 226 get.AuthToken = tc.authToken 227 err = msgpackrpc.CallWithCodec(codec, "Scaling.ListPolicies", get, &resp) 228 require.NoError(err, tc.name) 229 require.EqualValues(1000, resp.Index) 230 require.Len(resp.Policies, 2) 231 } 232 } 233 234 func TestScalingEndpoint_ListPolicies_Blocking(t *testing.T) { 235 t.Parallel() 236 require := require.New(t) 237 238 s1, cleanupS1 := TestServer(t, nil) 239 defer cleanupS1() 240 state := s1.fsm.State() 241 codec := rpcClient(t, s1) 242 testutil.WaitForLeader(t, s1.RPC) 243 244 // Create the policies 245 p1 := mock.ScalingPolicy() 246 p2 := mock.ScalingPolicy() 247 248 // First create an unrelated policy 249 time.AfterFunc(100*time.Millisecond, func() { 250 err := state.UpsertScalingPolicies(100, []*structs.ScalingPolicy{p1}) 251 require.NoError(err) 252 }) 253 254 // Upsert the policy we are watching later 255 time.AfterFunc(200*time.Millisecond, func() { 256 err := state.UpsertScalingPolicies(200, []*structs.ScalingPolicy{p2}) 257 require.NoError(err) 258 }) 259 260 // Lookup the policy 261 req := &structs.ScalingPolicyListRequest{ 262 QueryOptions: structs.QueryOptions{ 263 Region: "global", 264 MinQueryIndex: 150, 265 }, 266 } 267 var resp structs.ScalingPolicyListResponse 268 start := time.Now() 269 err := msgpackrpc.CallWithCodec(codec, "Scaling.ListPolicies", req, &resp) 270 require.NoError(err) 271 272 require.True(time.Since(start) > 200*time.Millisecond, "should block: %#v", resp) 273 require.EqualValues(200, resp.Index, "bad index") 274 require.Len(resp.Policies, 2) 275 require.ElementsMatch([]string{p1.ID, p2.ID}, []string{resp.Policies[0].ID, resp.Policies[1].ID}) 276 }