diff --git a/app/api/api.go b/app/api/api.go index 43783eac..28211601 100644 --- a/app/api/api.go +++ b/app/api/api.go @@ -1654,9 +1654,6 @@ func (a *api) start() error { debug.SetMemoryLimit(math.MaxInt64) } - //p, _ := psutil.NewProcess(int32(os.Getpid()), false) - //a.process = p - // Start the restream processes restream.Start() @@ -1699,7 +1696,7 @@ func (a *api) stop() { } if a.cluster != nil { - a.cluster.Leave("", "") + // Hard shutdown without gracefully leaving the cluster a.cluster.Shutdown() } diff --git a/docs/docs.go b/docs/docs.go index 4fb6907a..5ad679bb 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -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": { "get": { "security": [ @@ -1056,14 +1088,14 @@ const docTemplate = `{ "type": "string" } }, - "403": { - "description": "Forbidden", + "400": { + "description": "Bad Request", "schema": { "$ref": "#/definitions/api.Error" } }, - "500": { - "description": "Internal Server Error", + "403": { + "description": "Forbidden", "schema": { "$ref": "#/definitions/api.Error" } @@ -3827,6 +3859,9 @@ const docTemplate = `{ "description": "percent 0-100*npcu", "type": "number" }, + "is_throttling": { + "type": "boolean" + }, "memory_limit_bytes": { "type": "integer" }, @@ -3877,6 +3912,7 @@ const docTemplate = `{ "type": "object", "properties": { "address": { + "description": "raft address", "type": "string" }, "id": { diff --git a/docs/swagger.json b/docs/swagger.json index 1022a429..ef67e421 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -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": { "get": { "security": [ @@ -1048,14 +1080,14 @@ "type": "string" } }, - "403": { - "description": "Forbidden", + "400": { + "description": "Bad Request", "schema": { "$ref": "#/definitions/api.Error" } }, - "500": { - "description": "Internal Server Error", + "403": { + "description": "Forbidden", "schema": { "$ref": "#/definitions/api.Error" } @@ -3819,6 +3851,9 @@ "description": "percent 0-100*npcu", "type": "number" }, + "is_throttling": { + "type": "boolean" + }, "memory_limit_bytes": { "type": "integer" }, @@ -3869,6 +3904,7 @@ "type": "object", "properties": { "address": { + "description": "raft address", "type": "string" }, "id": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 6897a331..03db6bb6 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -125,6 +125,8 @@ definitions: cpu_used: description: percent 0-100*npcu type: number + is_throttling: + type: boolean memory_limit_bytes: type: integer memory_used_bytes: @@ -158,6 +160,7 @@ definitions: api.ClusterServer: properties: address: + description: raft address type: string id: type: string @@ -2734,6 +2737,26 @@ paths: summary: Replace policies of an user tags: - 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: get: description: List of proxy nodes in the cluster @@ -2942,12 +2965,12 @@ paths: description: OK schema: type: string - "403": - description: Forbidden + "400": + description: Bad Request schema: $ref: '#/definitions/api.Error' - "500": - description: Internal Server Error + "403": + description: Forbidden schema: $ref: '#/definitions/api.Error' security: diff --git a/http/api/cluster.go b/http/api/cluster.go index 3427e606..f81c9e23 100644 --- a/http/api/cluster.go +++ b/http/api/cluster.go @@ -30,7 +30,7 @@ type ClusterNodeFiles struct { type ClusterServer struct { ID string `json:"id"` - Address string `json:"address"` + Address string `json:"address"` // raft address Voter bool `json:"voter"` Leader bool `json:"leader"` } diff --git a/http/handler/api/cluster.go b/http/handler/api/cluster.go index 5126aa92..bdef2c39 100644 --- a/http/handler/api/cluster.go +++ b/http/handler/api/cluster.go @@ -85,6 +85,27 @@ func (h *ClusterHandler) About(c echo.Context) error { 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 // @Summary List of processes in the cluster // @Description List of processes in the cluster diff --git a/http/server.go b/http/server.go index b995709d..8d53b3ff 100644 --- a/http/server.go +++ b/http/server.go @@ -686,12 +686,14 @@ func (s *server) setRoutesV3(v3 *echo.Group) { v3.GET("/cluster/node/:id/version", s.v3handler.cluster.GetNodeVersion) if !s.readOnly { + v3.PUT("/cluster/leave", s.v3handler.cluster.Leave) + v3.POST("/cluster/process", s.v3handler.cluster.AddProcess) v3.PUT("/cluster/process/:id", s.v3handler.cluster.UpdateProcess) v3.DELETE("/cluster/process/:id", s.v3handler.cluster.DeleteProcess) 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.PUT("/cluster/iam/user/:name", s.v3handler.cluster.UpdateIdentity) v3.PUT("/cluster/iam/user/:name/policy", s.v3handler.cluster.UpdateIdentityPolicies)