// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api // RaftServer has information about a server in the Raft configuration. type RaftServer struct { // ID is the unique ID for the server. These are currently the same // as the address, but they will be changed to a real GUID in a future // release of Consul. ID string // Node is the node name of the server, as known by Consul, or this // will be set to "(unknown)" otherwise. Node string // Address is the IP:port of the server, used for Raft communications. Address string // Leader is true if this server is the current cluster leader. Leader bool // Protocol version is the raft protocol version used by the server ProtocolVersion string // Voter is true if this server has a vote in the cluster. This might // be false if the server is staging and still coming online, or if // it's a non-voting server, which will be added in a future release of // Consul. Voter bool // LastIndex is the last log index this server has a record of in its Raft log. LastIndex uint64 } // RaftConfiguration is returned when querying for the current Raft configuration. type RaftConfiguration struct { // Servers has the list of servers in the Raft configuration. Servers []*RaftServer // Index has the Raft index of this configuration. Index uint64 } // TransferLeaderResponse is returned when querying for the current Raft configuration. type TransferLeaderResponse struct { Success bool } // RaftGetConfiguration is used to query the current Raft peer set. func (op *Operator) RaftGetConfiguration(q *QueryOptions) (*RaftConfiguration, error) { r := op.c.newRequest("GET", "/v1/operator/raft/configuration") r.setQueryOptions(q) _, resp, err := op.c.doRequest(r) if err != nil { return nil, err } defer closeResponseBody(resp) if err := requireOK(resp); err != nil { return nil, err } var out RaftConfiguration if err := decodeBody(resp, &out); err != nil { return nil, err } return &out, nil } // RaftLeaderTransfer is used to transfer the current raft leader to another node // Optionally accepts a non-empty id of another node to transfer leadership to. func (op *Operator) RaftLeaderTransfer(id string, q *QueryOptions) (*TransferLeaderResponse, error) { r := op.c.newRequest("POST", "/v1/operator/raft/transfer-leader") r.setQueryOptions(q) if id != "" { r.params.Set("id", id) } _, resp, err := op.c.doRequest(r) if err != nil { return nil, err } defer closeResponseBody(resp) if err := requireOK(resp); err != nil { return nil, err } var out TransferLeaderResponse if err := decodeBody(resp, &out); err != nil { return nil, err } return &out, nil } // RaftRemovePeerByAddress is used to kick a stale peer (one that it in the Raft // quorum but no longer known to Serf or the catalog) by address in the form of // "IP:port". func (op *Operator) RaftRemovePeerByAddress(address string, q *WriteOptions) error { r := op.c.newRequest("DELETE", "/v1/operator/raft/peer") r.setWriteOptions(q) r.params.Set("address", address) _, resp, err := op.c.doRequest(r) if err != nil { return err } defer closeResponseBody(resp) if err := requireOK(resp); err != nil { return err } return nil } // RaftRemovePeerByID is used to kick a stale peer (one that it in the Raft // quorum but no longer known to Serf or the catalog) by ID. func (op *Operator) RaftRemovePeerByID(id string, q *WriteOptions) error { r := op.c.newRequest("DELETE", "/v1/operator/raft/peer") r.setWriteOptions(q) r.params.Set("id", id) _, resp, err := op.c.doRequest(r) if err != nil { return err } defer closeResponseBody(resp) if err := requireOK(resp); err != nil { return err } return nil }