lxd/api_cluster.go
func internalClusterPostRebalance(d *Daemon, r *http.Request) Response {
	// Redirect all requests to the leader, which is the one with with
	// up-to-date knowledge of what nodes are part of the raft cluster.
	localAddress, err := node.ClusterAddress(d.db)
	if err != nil {
		return SmartError(err)
	}
	leader, err := d.gateway.LeaderAddress()
	if err != nil {
		return InternalError(err)
	}
	if localAddress != leader {
		logger.Debugf("Redirect cluster rebalance request to %s", leader)
		url := &url.URL{
			Scheme: "https",
			Path:   "/internal/cluster/rebalance",
			Host:   leader,
		}
		return SyncResponseRedirect(url.String())
	}

	logger.Debugf("Rebalance cluster")

	// Check if we have a spare node to promote.
	address, nodes, err := cluster.Rebalance(d.State(), d.gateway)
	if err != nil {
		return SmartError(err)
	}
	if address == "" {
		return SyncResponse(true, nil) // Nothing to change
	}

	// Tell the node to promote itself.
	post := &internalClusterPostPromoteRequest{}
	for _, node := range nodes {
		post.RaftNodes = append(post.RaftNodes, internalRaftNode{
			ID:      node.ID,
			Address: node.Address,
		})
	}

	cert := d.endpoints.NetworkCert()
	client, err := cluster.Connect(address, cert, false)
	if err != nil {
		return SmartError(err)
	}
	_, _, err = client.RawQuery("POST", "/internal/cluster/promote", post, "")
	if err != nil {
		return SmartError(err)
	}

	return SyncResponse(true, nil)
}
func internalClusterPostRebalance(d *Daemon, r *http.Request) Response {
	// Redirect all requests to the leader, which is the one with with
	// up-to-date knowledge of what nodes are part of the raft cluster.
	localAddress, err := node.ClusterAddress(d.db)
	if err != nil {
		return SmartError(err)
	}
	leader, err := d.gateway.LeaderAddress()
	if err != nil {
		return InternalError(err)
	}
	if localAddress != leader {
		logger.Debugf("Redirect cluster rebalance request to %s", leader)
		url := &url.URL{
			Scheme: "https",
			Path:   "/internal/cluster/rebalance",
			Host:   leader,
		}
		return SyncResponseRedirect(url.String())
	}

	logger.Debugf("Rebalance cluster")

	// Check if we have a spare node to promote.
	address, nodes, err := cluster.Rebalance(d.State(), d.gateway)
	if err != nil {
		return SmartError(err)
	}
	if address == "" {
		return SyncResponse(true, nil) // Nothing to change
	}

	// Tell the node to promote itself.
	post := &internalClusterPostPromoteRequest{}
	for _, node := range nodes {
		post.RaftNodes = append(post.RaftNodes, internalRaftNode{
			ID:      node.ID,
			Address: node.Address,
		})
	}

	cert := d.endpoints.NetworkCert()
	client, err := cluster.Connect(address, cert, false)
	if err != nil {
		return SmartError(err)
	}
	_, _, err = client.RawQuery("POST", "/internal/cluster/promote", post, "")
	if err != nil {
		return SmartError(err)
	}

	return SyncResponse(true, nil)
}
// Used to update the cluster after a database node has been removed, and
// possibly promote another one as database node.