mirror of
https://github.com/0x1d/rcond.git
synced 2025-12-14 18:25:21 +01:00
feat: add cluster join and leave handlers
This commit is contained in:
@@ -130,6 +130,9 @@ All endpoints except `/health` require authentication via an API token passed in
|
|||||||
| POST | `/system/restart` | Restart the system |
|
| POST | `/system/restart` | Restart the system |
|
||||||
| POST | `/system/shutdown` | Shutdown the system |
|
| POST | `/system/shutdown` | Shutdown the system |
|
||||||
| GET | `/cluster/members` | Get the cluster members |
|
| GET | `/cluster/members` | Get the cluster members |
|
||||||
|
| POST | `/cluster/join` | Join cluster nodes |
|
||||||
|
| POST | `/cluster/leave` | Leave the cluster |
|
||||||
|
|
||||||
|
|
||||||
### Response Codes
|
### Response Codes
|
||||||
|
|
||||||
|
|||||||
@@ -601,3 +601,70 @@ paths:
|
|||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/Error'
|
$ref: '#/components/schemas/Error'
|
||||||
|
/cluster/join:
|
||||||
|
post:
|
||||||
|
summary: Join the cluster
|
||||||
|
description: Join the cluster with the provided addresses
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
join:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Successfully joined the cluster
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
joined:
|
||||||
|
description: Number of nodes successfully joined
|
||||||
|
type: integer
|
||||||
|
example: 1
|
||||||
|
'400':
|
||||||
|
description: Bad request
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
'500':
|
||||||
|
description: Internal server error
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
/cluster/leave:
|
||||||
|
post:
|
||||||
|
summary: Leave the cluster
|
||||||
|
description: Leave the cluster
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Successfully left the cluster
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
success:
|
||||||
|
description: Indicates if the node has left the cluster
|
||||||
|
type: boolean
|
||||||
|
example: true
|
||||||
|
'400':
|
||||||
|
description: Bad request
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
'500':
|
||||||
|
description: Internal server error
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
|||||||
@@ -11,5 +11,5 @@ cluster:
|
|||||||
advertise_port: 7947
|
advertise_port: 7947
|
||||||
bind_addr: 0.0.0.0
|
bind_addr: 0.0.0.0
|
||||||
bind_port: 7947
|
bind_port: 7947
|
||||||
join:
|
# join:
|
||||||
- 127.0.0.1:7946
|
# - 127.0.0.1:7946
|
||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/0x1d/rcond/pkg/cluster"
|
"github.com/0x1d/rcond/pkg/cluster"
|
||||||
network "github.com/0x1d/rcond/pkg/network"
|
network "github.com/0x1d/rcond/pkg/network"
|
||||||
@@ -289,12 +290,49 @@ func HandleShutdown(w http.ResponseWriter, r *http.Request) {
|
|||||||
json.NewEncoder(w).Encode(map[string]string{"status": "success"})
|
json.NewEncoder(w).Encode(map[string]string{"status": "success"})
|
||||||
}
|
}
|
||||||
|
|
||||||
func ClusterAgentWrapper(agent *cluster.Agent) func(http.ResponseWriter, *http.Request) {
|
func ClusterAgentHandler(agent *cluster.Agent, handler func(http.ResponseWriter, *http.Request, *cluster.Agent)) func(http.ResponseWriter, *http.Request) {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
HandleClusterMembers(w, r, agent)
|
handler(w, r, agent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func HandleClusterJoin(w http.ResponseWriter, r *http.Request, agent *cluster.Agent) {
|
||||||
|
var joinRequest struct {
|
||||||
|
Join []string `json:"join"`
|
||||||
|
}
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&joinRequest)
|
||||||
|
if err != nil {
|
||||||
|
writeError(w, "Invalid request body", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
joinAddrs := strings.Join(joinRequest.Join, ",")
|
||||||
|
if joinAddrs == "" {
|
||||||
|
writeError(w, "No join addresses provided", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
addrs := strings.Split(joinAddrs, ",")
|
||||||
|
n, err := agent.Join(addrs, true)
|
||||||
|
if err != nil {
|
||||||
|
writeError(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(map[string]int{"joined": n})
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleClusterLeave(w http.ResponseWriter, r *http.Request, agent *cluster.Agent) {
|
||||||
|
err := agent.Leave()
|
||||||
|
if err != nil {
|
||||||
|
writeError(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(map[string]string{"status": "success"})
|
||||||
|
}
|
||||||
|
|
||||||
func HandleClusterMembers(w http.ResponseWriter, r *http.Request, agent *cluster.Agent) {
|
func HandleClusterMembers(w http.ResponseWriter, r *http.Request, agent *cluster.Agent) {
|
||||||
if agent == nil {
|
if agent == nil {
|
||||||
writeError(w, "cluster agent is not initialized", http.StatusInternalServerError)
|
writeError(w, "cluster agent is not initialized", http.StatusInternalServerError)
|
||||||
|
|||||||
@@ -76,7 +76,9 @@ func (s *Server) RegisterRoutes() {
|
|||||||
s.router.HandleFunc("/users/{user}/keys/{fingerprint}", s.verifyToken(HandleRemoveAuthorizedKey)).Methods(http.MethodDelete)
|
s.router.HandleFunc("/users/{user}/keys/{fingerprint}", s.verifyToken(HandleRemoveAuthorizedKey)).Methods(http.MethodDelete)
|
||||||
s.router.HandleFunc("/system/restart", s.verifyToken(HandleReboot)).Methods(http.MethodPost)
|
s.router.HandleFunc("/system/restart", s.verifyToken(HandleReboot)).Methods(http.MethodPost)
|
||||||
s.router.HandleFunc("/system/shutdown", s.verifyToken(HandleShutdown)).Methods(http.MethodPost)
|
s.router.HandleFunc("/system/shutdown", s.verifyToken(HandleShutdown)).Methods(http.MethodPost)
|
||||||
s.router.HandleFunc("/cluster/members", s.verifyToken(ClusterAgentWrapper(s.clusterAgent))).Methods(http.MethodGet)
|
s.router.HandleFunc("/cluster/members", s.verifyToken(ClusterAgentHandler(s.clusterAgent, HandleClusterMembers))).Methods(http.MethodGet)
|
||||||
|
s.router.HandleFunc("/cluster/join", s.verifyToken(ClusterAgentHandler(s.clusterAgent, HandleClusterJoin))).Methods(http.MethodPost)
|
||||||
|
s.router.HandleFunc("/cluster/leave", s.verifyToken(ClusterAgentHandler(s.clusterAgent, HandleClusterLeave))).Methods(http.MethodPost)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) healthHandler(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) healthHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|||||||
Reference in New Issue
Block a user