github.com/djenriquez/nomad-1@v0.8.1/nomad/operator_endpoint_test.go (about) 1 package nomad 2 3 import ( 4 "fmt" 5 "reflect" 6 "strings" 7 "testing" 8 9 "github.com/hashicorp/consul/lib/freeport" 10 "github.com/hashicorp/net-rpc-msgpackrpc" 11 "github.com/hashicorp/nomad/acl" 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 ) 18 19 func TestOperator_RaftGetConfiguration(t *testing.T) { 20 t.Parallel() 21 s1 := TestServer(t, nil) 22 defer s1.Shutdown() 23 codec := rpcClient(t, s1) 24 testutil.WaitForLeader(t, s1.RPC) 25 26 arg := structs.GenericRequest{ 27 QueryOptions: structs.QueryOptions{ 28 Region: s1.config.Region, 29 }, 30 } 31 var reply structs.RaftConfigurationResponse 32 if err := msgpackrpc.CallWithCodec(codec, "Operator.RaftGetConfiguration", &arg, &reply); err != nil { 33 t.Fatalf("err: %v", err) 34 } 35 36 future := s1.raft.GetConfiguration() 37 if err := future.Error(); err != nil { 38 t.Fatalf("err: %v", err) 39 } 40 if len(future.Configuration().Servers) != 1 { 41 t.Fatalf("bad: %v", future.Configuration().Servers) 42 } 43 me := future.Configuration().Servers[0] 44 expected := structs.RaftConfigurationResponse{ 45 Servers: []*structs.RaftServer{ 46 { 47 ID: me.ID, 48 Node: fmt.Sprintf("%v.%v", s1.config.NodeName, s1.config.Region), 49 Address: me.Address, 50 Leader: true, 51 Voter: true, 52 RaftProtocol: fmt.Sprintf("%d", s1.config.RaftConfig.ProtocolVersion), 53 }, 54 }, 55 Index: future.Index(), 56 } 57 if !reflect.DeepEqual(reply, expected) { 58 t.Fatalf("bad: got %+v; want %+v", reply, expected) 59 } 60 } 61 62 func TestOperator_RaftGetConfiguration_ACL(t *testing.T) { 63 t.Parallel() 64 s1, root := TestACLServer(t, nil) 65 defer s1.Shutdown() 66 codec := rpcClient(t, s1) 67 testutil.WaitForLeader(t, s1.RPC) 68 assert := assert.New(t) 69 state := s1.fsm.State() 70 71 // Create ACL token 72 invalidToken := mock.CreatePolicyAndToken(t, state, 1001, "test-invalid", mock.NodePolicy(acl.PolicyWrite)) 73 74 arg := structs.GenericRequest{ 75 QueryOptions: structs.QueryOptions{ 76 Region: s1.config.Region, 77 }, 78 } 79 80 // Try with no token and expect permission denied 81 { 82 var reply structs.RaftConfigurationResponse 83 err := msgpackrpc.CallWithCodec(codec, "Operator.RaftGetConfiguration", &arg, &reply) 84 assert.NotNil(err) 85 assert.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 86 } 87 88 // Try with an invalid token and expect permission denied 89 { 90 arg.AuthToken = invalidToken.SecretID 91 var reply structs.RaftConfigurationResponse 92 err := msgpackrpc.CallWithCodec(codec, "Operator.RaftGetConfiguration", &arg, &reply) 93 assert.NotNil(err) 94 assert.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 95 } 96 97 // Use management token 98 { 99 arg.AuthToken = root.SecretID 100 var reply structs.RaftConfigurationResponse 101 assert.Nil(msgpackrpc.CallWithCodec(codec, "Operator.RaftGetConfiguration", &arg, &reply)) 102 103 future := s1.raft.GetConfiguration() 104 assert.Nil(future.Error()) 105 assert.Len(future.Configuration().Servers, 1) 106 107 me := future.Configuration().Servers[0] 108 expected := structs.RaftConfigurationResponse{ 109 Servers: []*structs.RaftServer{ 110 { 111 ID: me.ID, 112 Node: fmt.Sprintf("%v.%v", s1.config.NodeName, s1.config.Region), 113 Address: me.Address, 114 Leader: true, 115 Voter: true, 116 RaftProtocol: fmt.Sprintf("%d", s1.config.RaftConfig.ProtocolVersion), 117 }, 118 }, 119 Index: future.Index(), 120 } 121 assert.Equal(expected, reply) 122 } 123 } 124 125 func TestOperator_RaftRemovePeerByAddress(t *testing.T) { 126 t.Parallel() 127 s1 := TestServer(t, nil) 128 defer s1.Shutdown() 129 codec := rpcClient(t, s1) 130 testutil.WaitForLeader(t, s1.RPC) 131 132 // Try to remove a peer that's not there. 133 arg := structs.RaftPeerByAddressRequest{ 134 Address: raft.ServerAddress(fmt.Sprintf("127.0.0.1:%d", freeport.GetT(t, 1)[0])), 135 } 136 arg.Region = s1.config.Region 137 var reply struct{} 138 err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByAddress", &arg, &reply) 139 if err == nil || !strings.Contains(err.Error(), "not found in the Raft configuration") { 140 t.Fatalf("err: %v", err) 141 } 142 143 // Add it manually to Raft. 144 { 145 future := s1.raft.AddPeer(arg.Address) 146 if err := future.Error(); err != nil { 147 t.Fatalf("err: %v", err) 148 } 149 } 150 151 // Make sure it's there. 152 { 153 future := s1.raft.GetConfiguration() 154 if err := future.Error(); err != nil { 155 t.Fatalf("err: %v", err) 156 } 157 configuration := future.Configuration() 158 if len(configuration.Servers) != 2 { 159 t.Fatalf("bad: %v", configuration) 160 } 161 } 162 163 // Remove it, now it should go through. 164 if err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByAddress", &arg, &reply); err != nil { 165 t.Fatalf("err: %v", err) 166 } 167 168 // Make sure it's not there. 169 { 170 future := s1.raft.GetConfiguration() 171 if err := future.Error(); err != nil { 172 t.Fatalf("err: %v", err) 173 } 174 configuration := future.Configuration() 175 if len(configuration.Servers) != 1 { 176 t.Fatalf("bad: %v", configuration) 177 } 178 } 179 } 180 181 func TestOperator_RaftRemovePeerByAddress_ACL(t *testing.T) { 182 t.Parallel() 183 s1, root := TestACLServer(t, nil) 184 defer s1.Shutdown() 185 codec := rpcClient(t, s1) 186 testutil.WaitForLeader(t, s1.RPC) 187 assert := assert.New(t) 188 state := s1.fsm.State() 189 190 // Create ACL token 191 invalidToken := mock.CreatePolicyAndToken(t, state, 1001, "test-invalid", mock.NodePolicy(acl.PolicyWrite)) 192 193 arg := structs.RaftPeerByAddressRequest{ 194 Address: raft.ServerAddress(fmt.Sprintf("127.0.0.1:%d", freeport.GetT(t, 1)[0])), 195 } 196 arg.Region = s1.config.Region 197 198 // Add peer manually to Raft. 199 { 200 future := s1.raft.AddPeer(arg.Address) 201 assert.Nil(future.Error()) 202 } 203 204 var reply struct{} 205 206 // Try with no token and expect permission denied 207 { 208 err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByAddress", &arg, &reply) 209 assert.NotNil(err) 210 assert.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 211 } 212 213 // Try with an invalid token and expect permission denied 214 { 215 arg.AuthToken = invalidToken.SecretID 216 err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByAddress", &arg, &reply) 217 assert.NotNil(err) 218 assert.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 219 } 220 221 // Try with a management token 222 { 223 arg.AuthToken = root.SecretID 224 err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByAddress", &arg, &reply) 225 assert.Nil(err) 226 } 227 } 228 229 func TestOperator_RaftRemovePeerByID(t *testing.T) { 230 t.Parallel() 231 s1 := TestServer(t, func(c *Config) { 232 c.RaftConfig.ProtocolVersion = 3 233 }) 234 defer s1.Shutdown() 235 codec := rpcClient(t, s1) 236 testutil.WaitForLeader(t, s1.RPC) 237 238 // Try to remove a peer that's not there. 239 arg := structs.RaftPeerByIDRequest{ 240 ID: raft.ServerID("e35bde83-4e9c-434f-a6ef-453f44ee21ea"), 241 } 242 arg.Region = s1.config.Region 243 var reply struct{} 244 err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByID", &arg, &reply) 245 if err == nil || !strings.Contains(err.Error(), "not found in the Raft configuration") { 246 t.Fatalf("err: %v", err) 247 } 248 249 // Add it manually to Raft. 250 { 251 future := s1.raft.AddVoter(arg.ID, raft.ServerAddress(fmt.Sprintf("127.0.0.1:%d", freeport.GetT(t, 1)[0])), 0, 0) 252 if err := future.Error(); err != nil { 253 t.Fatalf("err: %v", err) 254 } 255 } 256 257 // Make sure it's there. 258 { 259 future := s1.raft.GetConfiguration() 260 if err := future.Error(); err != nil { 261 t.Fatalf("err: %v", err) 262 } 263 configuration := future.Configuration() 264 if len(configuration.Servers) != 2 { 265 t.Fatalf("bad: %v", configuration) 266 } 267 } 268 269 // Remove it, now it should go through. 270 if err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByID", &arg, &reply); err != nil { 271 t.Fatalf("err: %v", err) 272 } 273 274 // Make sure it's not there. 275 { 276 future := s1.raft.GetConfiguration() 277 if err := future.Error(); err != nil { 278 t.Fatalf("err: %v", err) 279 } 280 configuration := future.Configuration() 281 if len(configuration.Servers) != 1 { 282 t.Fatalf("bad: %v", configuration) 283 } 284 } 285 } 286 287 func TestOperator_RaftRemovePeerByID_ACL(t *testing.T) { 288 t.Parallel() 289 s1, root := TestACLServer(t, func(c *Config) { 290 c.RaftConfig.ProtocolVersion = 3 291 }) 292 defer s1.Shutdown() 293 codec := rpcClient(t, s1) 294 testutil.WaitForLeader(t, s1.RPC) 295 assert := assert.New(t) 296 state := s1.fsm.State() 297 298 // Create ACL token 299 invalidToken := mock.CreatePolicyAndToken(t, state, 1001, "test-invalid", mock.NodePolicy(acl.PolicyWrite)) 300 301 arg := structs.RaftPeerByIDRequest{ 302 ID: raft.ServerID("e35bde83-4e9c-434f-a6ef-453f44ee21ea"), 303 } 304 arg.Region = s1.config.Region 305 306 // Add peer manually to Raft. 307 { 308 future := s1.raft.AddVoter(arg.ID, raft.ServerAddress(fmt.Sprintf("127.0.0.1:%d", freeport.GetT(t, 1)[0])), 0, 0) 309 assert.Nil(future.Error()) 310 } 311 312 var reply struct{} 313 314 // Try with no token and expect permission denied 315 { 316 err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByID", &arg, &reply) 317 assert.NotNil(err) 318 assert.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 319 } 320 321 // Try with an invalid token and expect permission denied 322 { 323 arg.AuthToken = invalidToken.SecretID 324 err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByID", &arg, &reply) 325 assert.NotNil(err) 326 assert.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 327 } 328 329 // Try with a management token 330 { 331 arg.AuthToken = root.SecretID 332 err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByID", &arg, &reply) 333 assert.Nil(err) 334 } 335 }