github.phpd.cn/hashicorp/consul@v1.4.5/agent/consul/operator_autopilot_endpoint_test.go (about) 1 package consul 2 3 import ( 4 "os" 5 "strings" 6 "testing" 7 "time" 8 9 "github.com/hashicorp/consul/acl" 10 "github.com/hashicorp/consul/agent/consul/autopilot" 11 "github.com/hashicorp/consul/agent/structs" 12 "github.com/hashicorp/consul/testrpc" 13 "github.com/hashicorp/consul/testutil/retry" 14 "github.com/hashicorp/net-rpc-msgpackrpc" 15 "github.com/hashicorp/raft" 16 ) 17 18 func TestOperator_Autopilot_GetConfiguration(t *testing.T) { 19 t.Parallel() 20 dir1, s1 := testServerWithConfig(t, func(c *Config) { 21 c.AutopilotConfig.CleanupDeadServers = false 22 }) 23 defer os.RemoveAll(dir1) 24 defer s1.Shutdown() 25 codec := rpcClient(t, s1) 26 defer codec.Close() 27 28 testrpc.WaitForLeader(t, s1.RPC, "dc1") 29 30 arg := structs.DCSpecificRequest{ 31 Datacenter: "dc1", 32 } 33 var reply autopilot.Config 34 err := msgpackrpc.CallWithCodec(codec, "Operator.AutopilotGetConfiguration", &arg, &reply) 35 if err != nil { 36 t.Fatalf("err: %v", err) 37 } 38 if reply.CleanupDeadServers { 39 t.Fatalf("bad: %#v", reply) 40 } 41 } 42 43 func TestOperator_Autopilot_GetConfiguration_ACLDeny(t *testing.T) { 44 t.Parallel() 45 dir1, s1 := testServerWithConfig(t, func(c *Config) { 46 c.ACLDatacenter = "dc1" 47 c.ACLsEnabled = true 48 c.ACLMasterToken = "root" 49 c.ACLDefaultPolicy = "deny" 50 c.AutopilotConfig.CleanupDeadServers = false 51 }) 52 defer os.RemoveAll(dir1) 53 defer s1.Shutdown() 54 codec := rpcClient(t, s1) 55 defer codec.Close() 56 57 testrpc.WaitForLeader(t, s1.RPC, "dc1") 58 59 // Try to get config without permissions 60 arg := structs.DCSpecificRequest{ 61 Datacenter: "dc1", 62 } 63 var reply autopilot.Config 64 err := msgpackrpc.CallWithCodec(codec, "Operator.AutopilotGetConfiguration", &arg, &reply) 65 if !acl.IsErrPermissionDenied(err) { 66 t.Fatalf("err: %v", err) 67 } 68 69 // Create an ACL with operator read permissions. 70 var token string 71 { 72 var rules = ` 73 operator = "read" 74 ` 75 76 req := structs.ACLRequest{ 77 Datacenter: "dc1", 78 Op: structs.ACLSet, 79 ACL: structs.ACL{ 80 Name: "User token", 81 Type: structs.ACLTokenTypeClient, 82 Rules: rules, 83 }, 84 WriteRequest: structs.WriteRequest{Token: "root"}, 85 } 86 if err := msgpackrpc.CallWithCodec(codec, "ACL.Apply", &req, &token); err != nil { 87 t.Fatalf("err: %v", err) 88 } 89 } 90 91 // Now we can read and verify the config 92 arg.Token = token 93 err = msgpackrpc.CallWithCodec(codec, "Operator.AutopilotGetConfiguration", &arg, &reply) 94 if err != nil { 95 t.Fatalf("err: %v", err) 96 } 97 if reply.CleanupDeadServers { 98 t.Fatalf("bad: %#v", reply) 99 } 100 } 101 102 func TestOperator_Autopilot_SetConfiguration(t *testing.T) { 103 t.Parallel() 104 dir1, s1 := testServerWithConfig(t, func(c *Config) { 105 c.AutopilotConfig.CleanupDeadServers = false 106 }) 107 defer os.RemoveAll(dir1) 108 defer s1.Shutdown() 109 codec := rpcClient(t, s1) 110 defer codec.Close() 111 112 testrpc.WaitForLeader(t, s1.RPC, "dc1") 113 114 // Change the autopilot config from the default 115 arg := structs.AutopilotSetConfigRequest{ 116 Datacenter: "dc1", 117 Config: autopilot.Config{ 118 CleanupDeadServers: true, 119 }, 120 } 121 var reply *bool 122 err := msgpackrpc.CallWithCodec(codec, "Operator.AutopilotSetConfiguration", &arg, &reply) 123 if err != nil { 124 t.Fatalf("err: %v", err) 125 } 126 127 // Make sure it's changed 128 state := s1.fsm.State() 129 _, config, err := state.AutopilotConfig() 130 if err != nil { 131 t.Fatal(err) 132 } 133 if !config.CleanupDeadServers { 134 t.Fatalf("bad: %#v", config) 135 } 136 } 137 138 func TestOperator_Autopilot_SetConfiguration_ACLDeny(t *testing.T) { 139 t.Parallel() 140 dir1, s1 := testServerWithConfig(t, func(c *Config) { 141 c.ACLDatacenter = "dc1" 142 c.ACLsEnabled = true 143 c.ACLMasterToken = "root" 144 c.ACLDefaultPolicy = "deny" 145 c.AutopilotConfig.CleanupDeadServers = false 146 }) 147 defer os.RemoveAll(dir1) 148 defer s1.Shutdown() 149 codec := rpcClient(t, s1) 150 defer codec.Close() 151 152 testrpc.WaitForLeader(t, s1.RPC, "dc1") 153 154 // Try to set config without permissions 155 arg := structs.AutopilotSetConfigRequest{ 156 Datacenter: "dc1", 157 Config: autopilot.Config{ 158 CleanupDeadServers: true, 159 }, 160 } 161 var reply *bool 162 err := msgpackrpc.CallWithCodec(codec, "Operator.AutopilotSetConfiguration", &arg, &reply) 163 if !acl.IsErrPermissionDenied(err) { 164 t.Fatalf("err: %v", err) 165 } 166 167 // Create an ACL with operator write permissions. 168 var token string 169 { 170 var rules = ` 171 operator = "write" 172 ` 173 174 req := structs.ACLRequest{ 175 Datacenter: "dc1", 176 Op: structs.ACLSet, 177 ACL: structs.ACL{ 178 Name: "User token", 179 Type: structs.ACLTokenTypeClient, 180 Rules: rules, 181 }, 182 WriteRequest: structs.WriteRequest{Token: "root"}, 183 } 184 if err := msgpackrpc.CallWithCodec(codec, "ACL.Apply", &req, &token); err != nil { 185 t.Fatalf("err: %v", err) 186 } 187 } 188 189 // Now we can update the config 190 arg.Token = token 191 err = msgpackrpc.CallWithCodec(codec, "Operator.AutopilotSetConfiguration", &arg, &reply) 192 if err != nil { 193 t.Fatalf("err: %v", err) 194 } 195 196 // Make sure it's changed 197 state := s1.fsm.State() 198 _, config, err := state.AutopilotConfig() 199 if err != nil { 200 t.Fatal(err) 201 } 202 if !config.CleanupDeadServers { 203 t.Fatalf("bad: %#v", config) 204 } 205 } 206 207 func TestOperator_ServerHealth(t *testing.T) { 208 t.Parallel() 209 conf := func(c *Config) { 210 c.Datacenter = "dc1" 211 c.Bootstrap = false 212 c.BootstrapExpect = 3 213 c.RaftConfig.ProtocolVersion = 3 214 c.ServerHealthInterval = 100 * time.Millisecond 215 c.AutopilotInterval = 100 * time.Millisecond 216 } 217 dir1, s1 := testServerWithConfig(t, conf) 218 defer os.RemoveAll(dir1) 219 defer s1.Shutdown() 220 codec := rpcClient(t, s1) 221 defer codec.Close() 222 223 dir2, s2 := testServerWithConfig(t, conf) 224 defer os.RemoveAll(dir2) 225 defer s2.Shutdown() 226 joinLAN(t, s2, s1) 227 228 dir3, s3 := testServerWithConfig(t, conf) 229 defer os.RemoveAll(dir3) 230 defer s3.Shutdown() 231 joinLAN(t, s3, s1) 232 233 testrpc.WaitForLeader(t, s1.RPC, "dc1") 234 retry.Run(t, func(r *retry.R) { 235 arg := structs.DCSpecificRequest{ 236 Datacenter: "dc1", 237 } 238 var reply autopilot.OperatorHealthReply 239 err := msgpackrpc.CallWithCodec(codec, "Operator.ServerHealth", &arg, &reply) 240 if err != nil { 241 r.Fatalf("err: %v", err) 242 } 243 if !reply.Healthy { 244 r.Fatalf("bad: %v", reply) 245 } 246 if reply.FailureTolerance != 1 { 247 r.Fatalf("bad: %v", reply) 248 } 249 if len(reply.Servers) != 3 { 250 r.Fatalf("bad: %v", reply) 251 } 252 // Leader should have LastContact == 0, others should be positive 253 for _, s := range reply.Servers { 254 isLeader := s1.raft.Leader() == raft.ServerAddress(s.Address) 255 if isLeader && s.LastContact != 0 { 256 r.Fatalf("bad: %v", reply) 257 } 258 if !isLeader && s.LastContact <= 0 { 259 r.Fatalf("bad: %v", reply) 260 } 261 } 262 }) 263 } 264 265 func TestOperator_ServerHealth_UnsupportedRaftVersion(t *testing.T) { 266 t.Parallel() 267 dir1, s1 := testServerWithConfig(t, func(c *Config) { 268 c.Datacenter = "dc1" 269 c.Bootstrap = true 270 c.RaftConfig.ProtocolVersion = 2 271 }) 272 defer os.RemoveAll(dir1) 273 defer s1.Shutdown() 274 codec := rpcClient(t, s1) 275 defer codec.Close() 276 277 arg := structs.DCSpecificRequest{ 278 Datacenter: "dc1", 279 } 280 var reply autopilot.OperatorHealthReply 281 err := msgpackrpc.CallWithCodec(codec, "Operator.ServerHealth", &arg, &reply) 282 if err == nil || !strings.Contains(err.Error(), "raft_protocol set to 3 or higher") { 283 t.Fatalf("bad: %v", err) 284 } 285 }