github.com/thomasobenaus/nomad@v0.11.1/nomad/operator_endpoint_test.go (about) 1 package nomad 2 3 import ( 4 "fmt" 5 "reflect" 6 "strings" 7 "testing" 8 9 msgpackrpc "github.com/hashicorp/net-rpc-msgpackrpc" 10 "github.com/hashicorp/nomad/acl" 11 "github.com/hashicorp/nomad/helper/freeport" 12 "github.com/hashicorp/nomad/nomad/mock" 13 "github.com/hashicorp/nomad/nomad/structs" 14 "github.com/hashicorp/nomad/testutil" 15 "github.com/hashicorp/raft" 16 "github.com/stretchr/testify/assert" 17 "github.com/stretchr/testify/require" 18 ) 19 20 func TestOperator_RaftGetConfiguration(t *testing.T) { 21 t.Parallel() 22 23 s1, cleanupS1 := TestServer(t, nil) 24 defer cleanupS1() 25 codec := rpcClient(t, s1) 26 testutil.WaitForLeader(t, s1.RPC) 27 28 arg := structs.GenericRequest{ 29 QueryOptions: structs.QueryOptions{ 30 Region: s1.config.Region, 31 }, 32 } 33 var reply structs.RaftConfigurationResponse 34 if err := msgpackrpc.CallWithCodec(codec, "Operator.RaftGetConfiguration", &arg, &reply); err != nil { 35 t.Fatalf("err: %v", err) 36 } 37 38 future := s1.raft.GetConfiguration() 39 if err := future.Error(); err != nil { 40 t.Fatalf("err: %v", err) 41 } 42 if len(future.Configuration().Servers) != 1 { 43 t.Fatalf("bad: %v", future.Configuration().Servers) 44 } 45 me := future.Configuration().Servers[0] 46 expected := structs.RaftConfigurationResponse{ 47 Servers: []*structs.RaftServer{ 48 { 49 ID: me.ID, 50 Node: fmt.Sprintf("%v.%v", s1.config.NodeName, s1.config.Region), 51 Address: me.Address, 52 Leader: true, 53 Voter: true, 54 RaftProtocol: fmt.Sprintf("%d", s1.config.RaftConfig.ProtocolVersion), 55 }, 56 }, 57 Index: future.Index(), 58 } 59 if !reflect.DeepEqual(reply, expected) { 60 t.Fatalf("bad: got %+v; want %+v", reply, expected) 61 } 62 } 63 64 func TestOperator_RaftGetConfiguration_ACL(t *testing.T) { 65 t.Parallel() 66 67 s1, root, cleanupS1 := TestACLServer(t, nil) 68 defer cleanupS1() 69 codec := rpcClient(t, s1) 70 testutil.WaitForLeader(t, s1.RPC) 71 assert := assert.New(t) 72 state := s1.fsm.State() 73 74 // Create ACL token 75 invalidToken := mock.CreatePolicyAndToken(t, state, 1001, "test-invalid", mock.NodePolicy(acl.PolicyWrite)) 76 77 arg := structs.GenericRequest{ 78 QueryOptions: structs.QueryOptions{ 79 Region: s1.config.Region, 80 }, 81 } 82 83 // Try with no token and expect permission denied 84 { 85 var reply structs.RaftConfigurationResponse 86 err := msgpackrpc.CallWithCodec(codec, "Operator.RaftGetConfiguration", &arg, &reply) 87 assert.NotNil(err) 88 assert.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 89 } 90 91 // Try with an invalid token and expect permission denied 92 { 93 arg.AuthToken = invalidToken.SecretID 94 var reply structs.RaftConfigurationResponse 95 err := msgpackrpc.CallWithCodec(codec, "Operator.RaftGetConfiguration", &arg, &reply) 96 assert.NotNil(err) 97 assert.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 98 } 99 100 // Use management token 101 { 102 arg.AuthToken = root.SecretID 103 var reply structs.RaftConfigurationResponse 104 assert.Nil(msgpackrpc.CallWithCodec(codec, "Operator.RaftGetConfiguration", &arg, &reply)) 105 106 future := s1.raft.GetConfiguration() 107 assert.Nil(future.Error()) 108 assert.Len(future.Configuration().Servers, 1) 109 110 me := future.Configuration().Servers[0] 111 expected := structs.RaftConfigurationResponse{ 112 Servers: []*structs.RaftServer{ 113 { 114 ID: me.ID, 115 Node: fmt.Sprintf("%v.%v", s1.config.NodeName, s1.config.Region), 116 Address: me.Address, 117 Leader: true, 118 Voter: true, 119 RaftProtocol: fmt.Sprintf("%d", s1.config.RaftConfig.ProtocolVersion), 120 }, 121 }, 122 Index: future.Index(), 123 } 124 assert.Equal(expected, reply) 125 } 126 } 127 128 func TestOperator_RaftRemovePeerByAddress(t *testing.T) { 129 t.Parallel() 130 131 s1, cleanupS1 := TestServer(t, func(c *Config) { 132 c.RaftConfig.ProtocolVersion = raft.ProtocolVersion(2) 133 }) 134 defer cleanupS1() 135 codec := rpcClient(t, s1) 136 testutil.WaitForLeader(t, s1.RPC) 137 138 ports := freeport.MustTake(1) 139 defer freeport.Return(ports) 140 141 // Try to remove a peer that's not there. 142 arg := structs.RaftPeerByAddressRequest{ 143 Address: raft.ServerAddress(fmt.Sprintf("127.0.0.1:%d", ports[0])), 144 } 145 arg.Region = s1.config.Region 146 var reply struct{} 147 err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByAddress", &arg, &reply) 148 if err == nil || !strings.Contains(err.Error(), "not found in the Raft configuration") { 149 t.Fatalf("err: %v", err) 150 } 151 152 // Add it manually to Raft. 153 { 154 future := s1.raft.AddPeer(arg.Address) 155 if err := future.Error(); err != nil { 156 t.Fatalf("err: %v", err) 157 } 158 } 159 160 // Make sure it's there. 161 { 162 future := s1.raft.GetConfiguration() 163 if err := future.Error(); err != nil { 164 t.Fatalf("err: %v", err) 165 } 166 configuration := future.Configuration() 167 if len(configuration.Servers) != 2 { 168 t.Fatalf("bad: %v", configuration) 169 } 170 } 171 172 // Remove it, now it should go through. 173 if err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByAddress", &arg, &reply); err != nil { 174 t.Fatalf("err: %v", err) 175 } 176 177 // Make sure it's not there. 178 { 179 future := s1.raft.GetConfiguration() 180 if err := future.Error(); err != nil { 181 t.Fatalf("err: %v", err) 182 } 183 configuration := future.Configuration() 184 if len(configuration.Servers) != 1 { 185 t.Fatalf("bad: %v", configuration) 186 } 187 } 188 } 189 190 func TestOperator_RaftRemovePeerByAddress_ACL(t *testing.T) { 191 t.Parallel() 192 193 s1, root, cleanupS1 := TestACLServer(t, func(c *Config) { 194 c.RaftConfig.ProtocolVersion = raft.ProtocolVersion(2) 195 }) 196 197 defer cleanupS1() 198 codec := rpcClient(t, s1) 199 testutil.WaitForLeader(t, s1.RPC) 200 assert := assert.New(t) 201 state := s1.fsm.State() 202 203 // Create ACL token 204 invalidToken := mock.CreatePolicyAndToken(t, state, 1001, "test-invalid", mock.NodePolicy(acl.PolicyWrite)) 205 206 ports := freeport.MustTake(1) 207 defer freeport.Return(ports) 208 209 arg := structs.RaftPeerByAddressRequest{ 210 Address: raft.ServerAddress(fmt.Sprintf("127.0.0.1:%d", ports[0])), 211 } 212 arg.Region = s1.config.Region 213 214 // Add peer manually to Raft. 215 { 216 future := s1.raft.AddPeer(arg.Address) 217 assert.Nil(future.Error()) 218 } 219 220 var reply struct{} 221 222 // Try with no token and expect permission denied 223 { 224 err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByAddress", &arg, &reply) 225 assert.NotNil(err) 226 assert.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 227 } 228 229 // Try with an invalid token and expect permission denied 230 { 231 arg.AuthToken = invalidToken.SecretID 232 err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByAddress", &arg, &reply) 233 assert.NotNil(err) 234 assert.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 235 } 236 237 // Try with a management token 238 { 239 arg.AuthToken = root.SecretID 240 err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByAddress", &arg, &reply) 241 assert.Nil(err) 242 } 243 } 244 245 func TestOperator_RaftRemovePeerByID(t *testing.T) { 246 t.Parallel() 247 248 s1, cleanupS1 := TestServer(t, func(c *Config) { 249 c.RaftConfig.ProtocolVersion = 3 250 }) 251 defer cleanupS1() 252 codec := rpcClient(t, s1) 253 testutil.WaitForLeader(t, s1.RPC) 254 255 // Try to remove a peer that's not there. 256 arg := structs.RaftPeerByIDRequest{ 257 ID: raft.ServerID("e35bde83-4e9c-434f-a6ef-453f44ee21ea"), 258 } 259 arg.Region = s1.config.Region 260 var reply struct{} 261 err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByID", &arg, &reply) 262 if err == nil || !strings.Contains(err.Error(), "not found in the Raft configuration") { 263 t.Fatalf("err: %v", err) 264 } 265 266 ports := freeport.MustTake(1) 267 defer freeport.Return(ports) 268 269 // Add it manually to Raft. 270 { 271 future := s1.raft.AddVoter(arg.ID, raft.ServerAddress(fmt.Sprintf("127.0.0.1:%d", ports[0])), 0, 0) 272 if err := future.Error(); err != nil { 273 t.Fatalf("err: %v", err) 274 } 275 } 276 277 // Make sure it's there. 278 { 279 future := s1.raft.GetConfiguration() 280 if err := future.Error(); err != nil { 281 t.Fatalf("err: %v", err) 282 } 283 configuration := future.Configuration() 284 if len(configuration.Servers) != 2 { 285 t.Fatalf("bad: %v", configuration) 286 } 287 } 288 289 // Remove it, now it should go through. 290 if err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByID", &arg, &reply); err != nil { 291 t.Fatalf("err: %v", err) 292 } 293 294 // Make sure it's not there. 295 { 296 future := s1.raft.GetConfiguration() 297 if err := future.Error(); err != nil { 298 t.Fatalf("err: %v", err) 299 } 300 configuration := future.Configuration() 301 if len(configuration.Servers) != 1 { 302 t.Fatalf("bad: %v", configuration) 303 } 304 } 305 } 306 307 func TestOperator_RaftRemovePeerByID_ACL(t *testing.T) { 308 t.Parallel() 309 310 s1, root, cleanupS1 := TestACLServer(t, func(c *Config) { 311 c.RaftConfig.ProtocolVersion = 3 312 }) 313 defer cleanupS1() 314 codec := rpcClient(t, s1) 315 testutil.WaitForLeader(t, s1.RPC) 316 assert := assert.New(t) 317 state := s1.fsm.State() 318 319 // Create ACL token 320 invalidToken := mock.CreatePolicyAndToken(t, state, 1001, "test-invalid", mock.NodePolicy(acl.PolicyWrite)) 321 322 arg := structs.RaftPeerByIDRequest{ 323 ID: raft.ServerID("e35bde83-4e9c-434f-a6ef-453f44ee21ea"), 324 } 325 arg.Region = s1.config.Region 326 327 ports := freeport.MustTake(1) 328 defer freeport.Return(ports) 329 330 // Add peer manually to Raft. 331 { 332 future := s1.raft.AddVoter(arg.ID, raft.ServerAddress(fmt.Sprintf("127.0.0.1:%d", ports[0])), 0, 0) 333 assert.Nil(future.Error()) 334 } 335 336 var reply struct{} 337 338 // Try with no token and expect permission denied 339 { 340 err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByID", &arg, &reply) 341 assert.NotNil(err) 342 assert.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 343 } 344 345 // Try with an invalid token and expect permission denied 346 { 347 arg.AuthToken = invalidToken.SecretID 348 err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByID", &arg, &reply) 349 assert.NotNil(err) 350 assert.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 351 } 352 353 // Try with a management token 354 { 355 arg.AuthToken = root.SecretID 356 err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByID", &arg, &reply) 357 assert.Nil(err) 358 } 359 } 360 361 func TestOperator_SchedulerGetConfiguration(t *testing.T) { 362 t.Parallel() 363 364 s1, cleanupS1 := TestServer(t, func(c *Config) { 365 c.Build = "0.9.0+unittest" 366 }) 367 defer cleanupS1() 368 codec := rpcClient(t, s1) 369 testutil.WaitForLeader(t, s1.RPC) 370 371 arg := structs.GenericRequest{ 372 QueryOptions: structs.QueryOptions{ 373 Region: s1.config.Region, 374 }, 375 } 376 var reply structs.SchedulerConfigurationResponse 377 if err := msgpackrpc.CallWithCodec(codec, "Operator.SchedulerGetConfiguration", &arg, &reply); err != nil { 378 t.Fatalf("err: %v", err) 379 } 380 require := require.New(t) 381 require.NotZero(reply.Index) 382 require.True(reply.SchedulerConfig.PreemptionConfig.SystemSchedulerEnabled) 383 } 384 385 func TestOperator_SchedulerSetConfiguration(t *testing.T) { 386 t.Parallel() 387 388 s1, cleanupS1 := TestServer(t, func(c *Config) { 389 c.Build = "0.9.0+unittest" 390 }) 391 defer cleanupS1() 392 codec := rpcClient(t, s1) 393 testutil.WaitForLeader(t, s1.RPC) 394 395 require := require.New(t) 396 397 // Disable preemption 398 arg := structs.SchedulerSetConfigRequest{ 399 Config: structs.SchedulerConfiguration{ 400 PreemptionConfig: structs.PreemptionConfig{ 401 SystemSchedulerEnabled: false, 402 }, 403 }, 404 } 405 arg.Region = s1.config.Region 406 407 var setResponse structs.SchedulerSetConfigurationResponse 408 err := msgpackrpc.CallWithCodec(codec, "Operator.SchedulerSetConfiguration", &arg, &setResponse) 409 require.Nil(err) 410 require.NotZero(setResponse.Index) 411 412 // Read and verify that preemption is disabled 413 readConfig := structs.GenericRequest{ 414 QueryOptions: structs.QueryOptions{ 415 Region: s1.config.Region, 416 }, 417 } 418 var reply structs.SchedulerConfigurationResponse 419 if err := msgpackrpc.CallWithCodec(codec, "Operator.SchedulerGetConfiguration", &readConfig, &reply); err != nil { 420 t.Fatalf("err: %v", err) 421 } 422 423 require.NotZero(reply.Index) 424 require.False(reply.SchedulerConfig.PreemptionConfig.SystemSchedulerEnabled) 425 } 426 427 func TestOperator_SchedulerGetConfiguration_ACL(t *testing.T) { 428 t.Parallel() 429 430 s1, root, cleanupS1 := TestACLServer(t, func(c *Config) { 431 c.RaftConfig.ProtocolVersion = 3 432 c.Build = "0.9.0+unittest" 433 }) 434 defer cleanupS1() 435 codec := rpcClient(t, s1) 436 testutil.WaitForLeader(t, s1.RPC) 437 state := s1.fsm.State() 438 439 // Create ACL token 440 invalidToken := mock.CreatePolicyAndToken(t, state, 1001, "test-invalid", mock.NodePolicy(acl.PolicyWrite)) 441 442 arg := structs.GenericRequest{ 443 QueryOptions: structs.QueryOptions{ 444 Region: s1.config.Region, 445 }, 446 } 447 require := require.New(t) 448 var reply structs.SchedulerConfigurationResponse 449 450 // Try with no token and expect permission denied 451 { 452 err := msgpackrpc.CallWithCodec(codec, "Operator.SchedulerGetConfiguration", &arg, &reply) 453 require.NotNil(err) 454 require.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 455 } 456 457 // Try with an invalid token and expect permission denied 458 { 459 arg.AuthToken = invalidToken.SecretID 460 err := msgpackrpc.CallWithCodec(codec, "Operator.SchedulerGetConfiguration", &arg, &reply) 461 require.NotNil(err) 462 require.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 463 } 464 465 // Try with root token, should succeed 466 { 467 arg.AuthToken = root.SecretID 468 err := msgpackrpc.CallWithCodec(codec, "Operator.SchedulerGetConfiguration", &arg, &reply) 469 require.Nil(err) 470 } 471 472 } 473 474 func TestOperator_SchedulerSetConfiguration_ACL(t *testing.T) { 475 t.Parallel() 476 477 s1, root, cleanupS1 := TestACLServer(t, func(c *Config) { 478 c.RaftConfig.ProtocolVersion = 3 479 c.Build = "0.9.0+unittest" 480 }) 481 defer cleanupS1() 482 codec := rpcClient(t, s1) 483 testutil.WaitForLeader(t, s1.RPC) 484 state := s1.fsm.State() 485 486 // Create ACL token 487 invalidToken := mock.CreatePolicyAndToken(t, state, 1001, "test-invalid", mock.NodePolicy(acl.PolicyWrite)) 488 489 arg := structs.SchedulerSetConfigRequest{ 490 Config: structs.SchedulerConfiguration{ 491 PreemptionConfig: structs.PreemptionConfig{ 492 SystemSchedulerEnabled: true, 493 }, 494 }, 495 } 496 arg.Region = s1.config.Region 497 498 require := require.New(t) 499 var reply structs.SchedulerSetConfigurationResponse 500 501 // Try with no token and expect permission denied 502 { 503 err := msgpackrpc.CallWithCodec(codec, "Operator.SchedulerSetConfiguration", &arg, &reply) 504 require.NotNil(err) 505 require.Equal(structs.ErrPermissionDenied.Error(), err.Error()) 506 } 507 508 // Try with an invalid token and expect permission denied 509 { 510 arg.AuthToken = invalidToken.SecretID 511 err := msgpackrpc.CallWithCodec(codec, "Operator.SchedulerSetConfiguration", &arg, &reply) 512 require.NotNil(err) 513 require.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 514 } 515 516 // Try with root token, should succeed 517 { 518 arg.AuthToken = root.SecretID 519 err := msgpackrpc.CallWithCodec(codec, "Operator.SchedulerSetConfiguration", &arg, &reply) 520 require.Nil(err) 521 } 522 523 }