github.com/clly/consul@v1.4.5/agent/consul/operator_raft_endpoint_test.go (about) 1 package consul 2 3 import ( 4 "fmt" 5 "os" 6 "strings" 7 "testing" 8 "time" 9 10 "github.com/hashicorp/consul/acl" 11 "github.com/hashicorp/consul/agent/structs" 12 "github.com/hashicorp/consul/lib/freeport" 13 "github.com/hashicorp/consul/testrpc" 14 "github.com/hashicorp/net-rpc-msgpackrpc" 15 "github.com/hashicorp/raft" 16 "github.com/pascaldekloe/goe/verify" 17 ) 18 19 func TestOperator_RaftGetConfiguration(t *testing.T) { 20 t.Parallel() 21 dir1, s1 := testServer(t) 22 defer os.RemoveAll(dir1) 23 defer s1.Shutdown() 24 codec := rpcClient(t, s1) 25 defer codec.Close() 26 27 testrpc.WaitForTestAgent(t, s1.RPC, "dc1") 28 29 arg := structs.DCSpecificRequest{ 30 Datacenter: "dc1", 31 } 32 var reply structs.RaftConfigurationResponse 33 if err := msgpackrpc.CallWithCodec(codec, "Operator.RaftGetConfiguration", &arg, &reply); err != nil { 34 t.Fatalf("err: %v", err) 35 } 36 37 future := s1.raft.GetConfiguration() 38 if err := future.Error(); err != nil { 39 t.Fatalf("err: %v", err) 40 } 41 if len(future.Configuration().Servers) != 1 { 42 t.Fatalf("bad: %v", future.Configuration().Servers) 43 } 44 me := future.Configuration().Servers[0] 45 expected := structs.RaftConfigurationResponse{ 46 Servers: []*structs.RaftServer{ 47 &structs.RaftServer{ 48 ID: me.ID, 49 Node: s1.config.NodeName, 50 Address: me.Address, 51 Leader: true, 52 Voter: true, 53 ProtocolVersion: "3", 54 }, 55 }, 56 Index: future.Index(), 57 } 58 verify.Values(t, "", reply, expected) 59 } 60 61 func TestOperator_RaftGetConfiguration_ACLDeny(t *testing.T) { 62 t.Parallel() 63 dir1, s1 := testServerWithConfig(t, func(c *Config) { 64 c.ACLDatacenter = "dc1" 65 c.ACLsEnabled = true 66 c.ACLMasterToken = "root" 67 c.ACLDefaultPolicy = "deny" 68 }) 69 defer os.RemoveAll(dir1) 70 defer s1.Shutdown() 71 codec := rpcClient(t, s1) 72 defer codec.Close() 73 74 testrpc.WaitForTestAgent(t, s1.RPC, "dc1") 75 76 // Make a request with no token to make sure it gets denied. 77 arg := structs.DCSpecificRequest{ 78 Datacenter: "dc1", 79 } 80 var reply structs.RaftConfigurationResponse 81 err := msgpackrpc.CallWithCodec(codec, "Operator.RaftGetConfiguration", &arg, &reply) 82 if !acl.IsErrPermissionDenied(err) { 83 t.Fatalf("err: %v", err) 84 } 85 86 // Create an ACL with operator read permissions. 87 var token string 88 { 89 var rules = ` 90 operator = "read" 91 ` 92 93 req := structs.ACLRequest{ 94 Datacenter: "dc1", 95 Op: structs.ACLSet, 96 ACL: structs.ACL{ 97 Name: "User token", 98 Type: structs.ACLTokenTypeClient, 99 Rules: rules, 100 }, 101 WriteRequest: structs.WriteRequest{Token: "root"}, 102 } 103 if err := msgpackrpc.CallWithCodec(codec, "ACL.Apply", &req, &token); err != nil { 104 t.Fatalf("err: %v", err) 105 } 106 } 107 108 // Now it should go through. 109 arg.Token = token 110 if err := msgpackrpc.CallWithCodec(codec, "Operator.RaftGetConfiguration", &arg, &reply); err != nil { 111 t.Fatalf("err: %v", err) 112 } 113 114 future := s1.raft.GetConfiguration() 115 if err := future.Error(); err != nil { 116 t.Fatalf("err: %v", err) 117 } 118 if len(future.Configuration().Servers) != 1 { 119 t.Fatalf("bad: %v", future.Configuration().Servers) 120 } 121 me := future.Configuration().Servers[0] 122 expected := structs.RaftConfigurationResponse{ 123 Servers: []*structs.RaftServer{ 124 &structs.RaftServer{ 125 ID: me.ID, 126 Node: s1.config.NodeName, 127 Address: me.Address, 128 Leader: true, 129 Voter: true, 130 ProtocolVersion: "3", 131 }, 132 }, 133 Index: future.Index(), 134 } 135 verify.Values(t, "", reply, expected) 136 } 137 138 func TestOperator_RaftRemovePeerByAddress(t *testing.T) { 139 t.Parallel() 140 dir1, s1 := testServer(t) 141 defer os.RemoveAll(dir1) 142 defer s1.Shutdown() 143 codec := rpcClient(t, s1) 144 defer codec.Close() 145 146 testrpc.WaitForLeader(t, s1.RPC, "dc1") 147 148 // Try to remove a peer that's not there. 149 arg := structs.RaftRemovePeerRequest{ 150 Datacenter: "dc1", 151 Address: raft.ServerAddress(fmt.Sprintf("127.0.0.1:%d", freeport.Get(1)[0])), 152 } 153 var reply struct{} 154 err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByAddress", &arg, &reply) 155 if err == nil || !strings.Contains(err.Error(), "not found in the Raft configuration") { 156 t.Fatalf("err: %v", err) 157 } 158 159 // Add it manually to Raft. 160 { 161 id := raft.ServerID("fake-node-id") 162 future := s1.raft.AddVoter(id, arg.Address, 0, time.Second) 163 if err := future.Error(); err != nil { 164 t.Fatalf("err: %v", err) 165 } 166 } 167 168 // Make sure it's 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) != 2 { 176 t.Fatalf("bad: %v", configuration) 177 } 178 } 179 180 // Remove it, now it should go through. 181 if err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByAddress", &arg, &reply); err != nil { 182 t.Fatalf("err: %v", err) 183 } 184 185 // Make sure it's not there. 186 { 187 future := s1.raft.GetConfiguration() 188 if err := future.Error(); err != nil { 189 t.Fatalf("err: %v", err) 190 } 191 configuration := future.Configuration() 192 if len(configuration.Servers) != 1 { 193 t.Fatalf("bad: %v", configuration) 194 } 195 } 196 } 197 198 func TestOperator_RaftRemovePeerByAddress_ACLDeny(t *testing.T) { 199 t.Parallel() 200 dir1, s1 := testServerWithConfig(t, func(c *Config) { 201 c.ACLDatacenter = "dc1" 202 c.ACLsEnabled = true 203 c.ACLMasterToken = "root" 204 c.ACLDefaultPolicy = "deny" 205 }) 206 defer os.RemoveAll(dir1) 207 defer s1.Shutdown() 208 codec := rpcClient(t, s1) 209 defer codec.Close() 210 211 testrpc.WaitForTestAgent(t, s1.RPC, "dc1") 212 213 // Make a request with no token to make sure it gets denied. 214 arg := structs.RaftRemovePeerRequest{ 215 Datacenter: "dc1", 216 Address: raft.ServerAddress(s1.config.RPCAddr.String()), 217 } 218 var reply struct{} 219 err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByAddress", &arg, &reply) 220 if !acl.IsErrPermissionDenied(err) { 221 t.Fatalf("err: %v", err) 222 } 223 224 // Create an ACL with operator write permissions. 225 var token string 226 { 227 var rules = ` 228 operator = "write" 229 ` 230 231 req := structs.ACLRequest{ 232 Datacenter: "dc1", 233 Op: structs.ACLSet, 234 ACL: structs.ACL{ 235 Name: "User token", 236 Type: structs.ACLTokenTypeClient, 237 Rules: rules, 238 }, 239 WriteRequest: structs.WriteRequest{Token: "root"}, 240 } 241 if err := msgpackrpc.CallWithCodec(codec, "ACL.Apply", &req, &token); err != nil { 242 t.Fatalf("err: %v", err) 243 } 244 } 245 246 // Now it should kick back for being an invalid config, which means it 247 // tried to do the operation. 248 arg.Token = token 249 err = msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByAddress", &arg, &reply) 250 if err == nil || !strings.Contains(err.Error(), "at least one voter") { 251 t.Fatalf("err: %v", err) 252 } 253 } 254 255 func TestOperator_RaftRemovePeerByID(t *testing.T) { 256 t.Parallel() 257 dir1, s1 := testServerWithConfig(t, func(c *Config) { 258 c.RaftConfig.ProtocolVersion = 3 259 }) 260 defer os.RemoveAll(dir1) 261 defer s1.Shutdown() 262 codec := rpcClient(t, s1) 263 defer codec.Close() 264 265 testrpc.WaitForLeader(t, s1.RPC, "dc1") 266 267 // Try to remove a peer that's not there. 268 arg := structs.RaftRemovePeerRequest{ 269 Datacenter: "dc1", 270 ID: raft.ServerID("e35bde83-4e9c-434f-a6ef-453f44ee21ea"), 271 } 272 var reply struct{} 273 err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByID", &arg, &reply) 274 if err == nil || !strings.Contains(err.Error(), "not found in the Raft configuration") { 275 t.Fatalf("err: %v", err) 276 } 277 278 // Add it manually to Raft. 279 { 280 future := s1.raft.AddVoter(arg.ID, raft.ServerAddress(fmt.Sprintf("127.0.0.1:%d", freeport.Get(1)[0])), 0, 0) 281 if err := future.Error(); err != nil { 282 t.Fatalf("err: %v", err) 283 } 284 } 285 286 // Make sure it's there. 287 { 288 future := s1.raft.GetConfiguration() 289 if err := future.Error(); err != nil { 290 t.Fatalf("err: %v", err) 291 } 292 configuration := future.Configuration() 293 if len(configuration.Servers) != 2 { 294 t.Fatalf("bad: %v", configuration) 295 } 296 } 297 298 // Remove it, now it should go through. 299 if err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByID", &arg, &reply); err != nil { 300 t.Fatalf("err: %v", err) 301 } 302 303 // Make sure it's not there. 304 { 305 future := s1.raft.GetConfiguration() 306 if err := future.Error(); err != nil { 307 t.Fatalf("err: %v", err) 308 } 309 configuration := future.Configuration() 310 if len(configuration.Servers) != 1 { 311 t.Fatalf("bad: %v", configuration) 312 } 313 } 314 } 315 316 func TestOperator_RaftRemovePeerByID_ACLDeny(t *testing.T) { 317 t.Parallel() 318 dir1, s1 := testServerWithConfig(t, func(c *Config) { 319 c.ACLDatacenter = "dc1" 320 c.ACLsEnabled = true 321 c.ACLMasterToken = "root" 322 c.ACLDefaultPolicy = "deny" 323 c.RaftConfig.ProtocolVersion = 3 324 }) 325 defer os.RemoveAll(dir1) 326 defer s1.Shutdown() 327 codec := rpcClient(t, s1) 328 defer codec.Close() 329 330 testrpc.WaitForLeader(t, s1.RPC, "dc1") 331 332 // Make a request with no token to make sure it gets denied. 333 arg := structs.RaftRemovePeerRequest{ 334 Datacenter: "dc1", 335 ID: raft.ServerID(s1.config.NodeID), 336 } 337 var reply struct{} 338 err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByID", &arg, &reply) 339 if !acl.IsErrPermissionDenied(err) { 340 t.Fatalf("err: %v", err) 341 } 342 343 // Create an ACL with operator write permissions. 344 var token string 345 { 346 var rules = ` 347 operator = "write" 348 ` 349 350 req := structs.ACLRequest{ 351 Datacenter: "dc1", 352 Op: structs.ACLSet, 353 ACL: structs.ACL{ 354 Name: "User token", 355 Type: structs.ACLTokenTypeClient, 356 Rules: rules, 357 }, 358 WriteRequest: structs.WriteRequest{Token: "root"}, 359 } 360 if err := msgpackrpc.CallWithCodec(codec, "ACL.Apply", &req, &token); err != nil { 361 t.Fatalf("err: %v", err) 362 } 363 } 364 365 // Now it should kick back for being an invalid config, which means it 366 // tried to do the operation. 367 arg.Token = token 368 err = msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByID", &arg, &reply) 369 if err == nil || !strings.Contains(err.Error(), "at least one voter") { 370 t.Fatalf("err: %v", err) 371 } 372 }