// OperatorRaftPeer supports actions on Raft peers. Currently we only support // removing peers by address. func (s *HTTPServer) OperatorRaftPeer(resp http.ResponseWriter, req *http.Request) (interface{}, error) { if req.Method != "DELETE" { resp.WriteHeader(http.StatusMethodNotAllowed) return nil, nil } var args structs.RaftPeerByAddressRequest s.parseDC(req, &args.Datacenter) s.parseToken(req, &args.Token) params := req.URL.Query() if _, ok := params["address"]; ok { args.Address = raft.ServerAddress(params.Get("address")) } else { resp.WriteHeader(http.StatusBadRequest) resp.Write([]byte("Must specify ?address with IP:port of peer to remove")) return nil, nil } var reply struct{} if err := s.agent.RPC("Operator.RaftRemovePeerByAddress", &args, &reply); err != nil { return nil, err } return nil, nil }
func TestOperator_RaftRemovePeerByAddress_ACLDeny(t *testing.T) { dir1, s1 := testServerWithConfig(t, func(c *Config) { c.ACLDatacenter = "dc1" c.ACLMasterToken = "root" c.ACLDefaultPolicy = "deny" }) defer os.RemoveAll(dir1) defer s1.Shutdown() codec := rpcClient(t, s1) defer codec.Close() testutil.WaitForLeader(t, s1.RPC, "dc1") // Make a request with no token to make sure it gets denied. arg := structs.RaftPeerByAddressRequest{ Datacenter: "dc1", Address: raft.ServerAddress(s1.config.RPCAddr.String()), } var reply struct{} err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByAddress", &arg, &reply) if err == nil || !strings.Contains(err.Error(), permissionDenied) { t.Fatalf("err: %v", err) } // Create an ACL with operator write permissions. var token string { var rules = ` operator = "write" ` req := structs.ACLRequest{ Datacenter: "dc1", Op: structs.ACLSet, ACL: structs.ACL{ Name: "User token", Type: structs.ACLTypeClient, Rules: rules, }, WriteRequest: structs.WriteRequest{Token: "root"}, } if err := msgpackrpc.CallWithCodec(codec, "ACL.Apply", &req, &token); err != nil { t.Fatalf("err: %v", err) } } // Now it should kick back for being an invalid config, which means it // tried to do the operation. arg.Token = token err = msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByAddress", &arg, &reply) if err == nil || !strings.Contains(err.Error(), "at least one voter") { t.Fatalf("err: %v", err) } }