Add API endpoint to leave cluster gracefully, hard leave on exit

This commit is contained in:
Ingo Oppermann
2023-06-06 11:22:53 +02:00
parent 8829b8fff0
commit 1f6f7c9f59
7 changed files with 133 additions and 18 deletions

View File

@@ -1654,9 +1654,6 @@ func (a *api) start() error {
debug.SetMemoryLimit(math.MaxInt64) debug.SetMemoryLimit(math.MaxInt64)
} }
//p, _ := psutil.NewProcess(int32(os.Getpid()), false)
//a.process = p
// Start the restream processes // Start the restream processes
restream.Start() restream.Start()
@@ -1699,7 +1696,7 @@ func (a *api) stop() {
} }
if a.cluster != nil { if a.cluster != nil {
a.cluster.Leave("", "") // Hard shutdown without gracefully leaving the cluster
a.cluster.Shutdown() a.cluster.Shutdown()
} }

View File

@@ -660,6 +660,38 @@ const docTemplate = `{
} }
} }
}, },
"/api/v3/cluster/leave": {
"put": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Leave the cluster gracefully",
"produces": [
"application/json"
],
"tags": [
"v16.?.?"
],
"summary": "Leave the cluster gracefully",
"operationId": "cluster-3-leave",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/api.Error"
}
}
}
}
},
"/api/v3/cluster/node": { "/api/v3/cluster/node": {
"get": { "get": {
"security": [ "security": [
@@ -1056,14 +1088,14 @@ const docTemplate = `{
"type": "string" "type": "string"
} }
}, },
"403": { "400": {
"description": "Forbidden", "description": "Bad Request",
"schema": { "schema": {
"$ref": "#/definitions/api.Error" "$ref": "#/definitions/api.Error"
} }
}, },
"500": { "403": {
"description": "Internal Server Error", "description": "Forbidden",
"schema": { "schema": {
"$ref": "#/definitions/api.Error" "$ref": "#/definitions/api.Error"
} }
@@ -3827,6 +3859,9 @@ const docTemplate = `{
"description": "percent 0-100*npcu", "description": "percent 0-100*npcu",
"type": "number" "type": "number"
}, },
"is_throttling": {
"type": "boolean"
},
"memory_limit_bytes": { "memory_limit_bytes": {
"type": "integer" "type": "integer"
}, },
@@ -3877,6 +3912,7 @@ const docTemplate = `{
"type": "object", "type": "object",
"properties": { "properties": {
"address": { "address": {
"description": "raft address",
"type": "string" "type": "string"
}, },
"id": { "id": {

View File

@@ -652,6 +652,38 @@
} }
} }
}, },
"/api/v3/cluster/leave": {
"put": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Leave the cluster gracefully",
"produces": [
"application/json"
],
"tags": [
"v16.?.?"
],
"summary": "Leave the cluster gracefully",
"operationId": "cluster-3-leave",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/api.Error"
}
}
}
}
},
"/api/v3/cluster/node": { "/api/v3/cluster/node": {
"get": { "get": {
"security": [ "security": [
@@ -1048,14 +1080,14 @@
"type": "string" "type": "string"
} }
}, },
"403": { "400": {
"description": "Forbidden", "description": "Bad Request",
"schema": { "schema": {
"$ref": "#/definitions/api.Error" "$ref": "#/definitions/api.Error"
} }
}, },
"500": { "403": {
"description": "Internal Server Error", "description": "Forbidden",
"schema": { "schema": {
"$ref": "#/definitions/api.Error" "$ref": "#/definitions/api.Error"
} }
@@ -3819,6 +3851,9 @@
"description": "percent 0-100*npcu", "description": "percent 0-100*npcu",
"type": "number" "type": "number"
}, },
"is_throttling": {
"type": "boolean"
},
"memory_limit_bytes": { "memory_limit_bytes": {
"type": "integer" "type": "integer"
}, },
@@ -3869,6 +3904,7 @@
"type": "object", "type": "object",
"properties": { "properties": {
"address": { "address": {
"description": "raft address",
"type": "string" "type": "string"
}, },
"id": { "id": {

View File

@@ -125,6 +125,8 @@ definitions:
cpu_used: cpu_used:
description: percent 0-100*npcu description: percent 0-100*npcu
type: number type: number
is_throttling:
type: boolean
memory_limit_bytes: memory_limit_bytes:
type: integer type: integer
memory_used_bytes: memory_used_bytes:
@@ -158,6 +160,7 @@ definitions:
api.ClusterServer: api.ClusterServer:
properties: properties:
address: address:
description: raft address
type: string type: string
id: id:
type: string type: string
@@ -2734,6 +2737,26 @@ paths:
summary: Replace policies of an user summary: Replace policies of an user
tags: tags:
- v16.?.? - v16.?.?
/api/v3/cluster/leave:
put:
description: Leave the cluster gracefully
operationId: cluster-3-leave
produces:
- application/json
responses:
"200":
description: OK
schema:
type: string
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/api.Error'
security:
- ApiKeyAuth: []
summary: Leave the cluster gracefully
tags:
- v16.?.?
/api/v3/cluster/node: /api/v3/cluster/node:
get: get:
description: List of proxy nodes in the cluster description: List of proxy nodes in the cluster
@@ -2942,12 +2965,12 @@ paths:
description: OK description: OK
schema: schema:
type: string type: string
"403": "400":
description: Forbidden description: Bad Request
schema: schema:
$ref: '#/definitions/api.Error' $ref: '#/definitions/api.Error'
"500": "403":
description: Internal Server Error description: Forbidden
schema: schema:
$ref: '#/definitions/api.Error' $ref: '#/definitions/api.Error'
security: security:

View File

@@ -30,7 +30,7 @@ type ClusterNodeFiles struct {
type ClusterServer struct { type ClusterServer struct {
ID string `json:"id"` ID string `json:"id"`
Address string `json:"address"` Address string `json:"address"` // raft address
Voter bool `json:"voter"` Voter bool `json:"voter"`
Leader bool `json:"leader"` Leader bool `json:"leader"`
} }

View File

@@ -85,6 +85,27 @@ func (h *ClusterHandler) About(c echo.Context) error {
return c.JSON(http.StatusOK, about) return c.JSON(http.StatusOK, about)
} }
// Leave the cluster gracefully
// @Summary Leave the cluster gracefully
// @Description Leave the cluster gracefully
// @Tags v16.?.?
// @ID cluster-3-leave
// @Produce json
// @Success 200 {string} string
// @Failure 500 {object} api.Error
// @Security ApiKeyAuth
// @Router /api/v3/cluster/leave [put]
func (h *ClusterHandler) Leave(c echo.Context) error {
err := h.cluster.Leave("", "")
if err != nil {
return api.Err(http.StatusInternalServerError, "", "Failed to leave cluster gracefully: %s", err)
}
h.cluster.Shutdown()
return c.JSON(http.StatusOK, "OK")
}
// ListAllNodeProcesses returns the list of processes running on all nodes of the cluster // ListAllNodeProcesses returns the list of processes running on all nodes of the cluster
// @Summary List of processes in the cluster // @Summary List of processes in the cluster
// @Description List of processes in the cluster // @Description List of processes in the cluster

View File

@@ -686,12 +686,14 @@ func (s *server) setRoutesV3(v3 *echo.Group) {
v3.GET("/cluster/node/:id/version", s.v3handler.cluster.GetNodeVersion) v3.GET("/cluster/node/:id/version", s.v3handler.cluster.GetNodeVersion)
if !s.readOnly { if !s.readOnly {
v3.PUT("/cluster/leave", s.v3handler.cluster.Leave)
v3.POST("/cluster/process", s.v3handler.cluster.AddProcess) v3.POST("/cluster/process", s.v3handler.cluster.AddProcess)
v3.PUT("/cluster/process/:id", s.v3handler.cluster.UpdateProcess) v3.PUT("/cluster/process/:id", s.v3handler.cluster.UpdateProcess)
v3.DELETE("/cluster/process/:id", s.v3handler.cluster.DeleteProcess) v3.DELETE("/cluster/process/:id", s.v3handler.cluster.DeleteProcess)
v3.PUT("/cluster/process/:id/metadata/:key", s.v3handler.cluster.SetProcessMetadata) v3.PUT("/cluster/process/:id/metadata/:key", s.v3handler.cluster.SetProcessMetadata)
v3.GET("/cluster/iam/reload", s.v3handler.cluster.ReloadIAM) v3.PUT("/cluster/iam/reload", s.v3handler.cluster.ReloadIAM)
v3.POST("/cluster/iam/user", s.v3handler.cluster.AddIdentity) v3.POST("/cluster/iam/user", s.v3handler.cluster.AddIdentity)
v3.PUT("/cluster/iam/user/:name", s.v3handler.cluster.UpdateIdentity) v3.PUT("/cluster/iam/user/:name", s.v3handler.cluster.UpdateIdentity)
v3.PUT("/cluster/iam/user/:name/policy", s.v3handler.cluster.UpdateIdentityPolicies) v3.PUT("/cluster/iam/user/:name/policy", s.v3handler.cluster.UpdateIdentityPolicies)