diff --git a/cluster/cluster.go b/cluster/cluster.go index 09f1884f..24fd7ffb 100644 --- a/cluster/cluster.go +++ b/cluster/cluster.go @@ -65,6 +65,7 @@ type Cluster interface { UpdateProcess(origin string, id app.ProcessID, config *app.Config) error SetProcessCommand(origin string, id app.ProcessID, order string) error SetProcessMetadata(origin string, id app.ProcessID, key string, data interface{}) error + GetProcessNodeMap() map[string]string IAM(superuser iamidentity.User, jwtRealm, jwtSecret string) (iam.IAM, error) ListIdentities() (time.Time, []iamidentity.User) diff --git a/cluster/docs/ClusterAPI_docs.go b/cluster/docs/ClusterAPI_docs.go index be033cca..7abd844b 100644 --- a/cluster/docs/ClusterAPI_docs.go +++ b/cluster/docs/ClusterAPI_docs.go @@ -1428,7 +1428,12 @@ const docTemplateClusterAPI = `{ "type": "string" }, "debug": { - "type": "boolean" + "type": "object", + "properties": { + "disable_ffmpeg_check": { + "type": "boolean" + } + } }, "emergency_leader_timeout_sec": { "description": "seconds", diff --git a/cluster/docs/ClusterAPI_swagger.json b/cluster/docs/ClusterAPI_swagger.json index 42812c7b..6ed4513c 100644 --- a/cluster/docs/ClusterAPI_swagger.json +++ b/cluster/docs/ClusterAPI_swagger.json @@ -1420,7 +1420,12 @@ "type": "string" }, "debug": { - "type": "boolean" + "type": "object", + "properties": { + "disable_ffmpeg_check": { + "type": "boolean" + } + } }, "emergency_leader_timeout_sec": { "description": "seconds", diff --git a/cluster/docs/ClusterAPI_swagger.yaml b/cluster/docs/ClusterAPI_swagger.yaml index 2c9de87f..f7a29101 100644 --- a/cluster/docs/ClusterAPI_swagger.yaml +++ b/cluster/docs/ClusterAPI_swagger.yaml @@ -228,7 +228,10 @@ definitions: description: ip:port type: string debug: - type: boolean + properties: + disable_ffmpeg_check: + type: boolean + type: object emergency_leader_timeout_sec: description: seconds format: int64 diff --git a/cluster/leader.go b/cluster/leader.go index c8919a3a..c60ff5cd 100644 --- a/cluster/leader.go +++ b/cluster/leader.go @@ -593,6 +593,7 @@ func (c *cluster) doSynchronize(emergency bool) { opStack, _, reality := synchronize(wish, want, have, nodesMap, c.nodeRecoverTimeout) if !emergency && len(opStack) != 0 { + // TODO: only apply a new map if there are actually changes cmd := &store.Command{ Operation: store.OpSetProcessNodeMap, Data: store.CommandSetProcessNodeMap{ diff --git a/cluster/process.go b/cluster/process.go index c2805e73..0884a043 100644 --- a/cluster/process.go +++ b/cluster/process.go @@ -122,3 +122,7 @@ func (c *cluster) SetProcessMetadata(origin string, id app.ProcessID, key string return c.applyCommand(cmd) } + +func (c *cluster) GetProcessNodeMap() map[string]string { + return c.store.GetProcessNodeMap() +} diff --git a/docs/docs.go b/docs/docs.go index 401bdbda..2ba1e22e 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -814,6 +814,32 @@ const docTemplate = `{ } } }, + "/api/v3/cluster/map/process": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Retrieve a map of which process is running on which node", + "produces": [ + "application/json" + ], + "tags": [ + "v16.?.?" + ], + "summary": "Retrieve a map of which process is running on which node", + "operationId": "cluster-3-process-node-map", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.ClusterProcessMap" + } + } + } + } + }, "/api/v3/cluster/node": { "get": { "security": [ @@ -4453,6 +4479,12 @@ const docTemplate = `{ } } }, + "api.ClusterProcessMap": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, "api.ClusterRaft": { "type": "object", "properties": { @@ -4616,7 +4648,12 @@ const docTemplate = `{ "type": "string" }, "debug": { - "type": "boolean" + "type": "object", + "properties": { + "disable_ffmpeg_check": { + "type": "boolean" + } + } }, "emergency_leader_timeout_sec": { "description": "seconds", @@ -6849,7 +6886,12 @@ const docTemplate = `{ "type": "string" }, "debug": { - "type": "boolean" + "type": "object", + "properties": { + "disable_ffmpeg_check": { + "type": "boolean" + } + } }, "emergency_leader_timeout_sec": { "description": "seconds", diff --git a/docs/swagger.json b/docs/swagger.json index 69f48ec3..2e762b1b 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -806,6 +806,32 @@ } } }, + "/api/v3/cluster/map/process": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Retrieve a map of which process is running on which node", + "produces": [ + "application/json" + ], + "tags": [ + "v16.?.?" + ], + "summary": "Retrieve a map of which process is running on which node", + "operationId": "cluster-3-process-node-map", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.ClusterProcessMap" + } + } + } + } + }, "/api/v3/cluster/node": { "get": { "security": [ @@ -4445,6 +4471,12 @@ } } }, + "api.ClusterProcessMap": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, "api.ClusterRaft": { "type": "object", "properties": { @@ -4608,7 +4640,12 @@ "type": "string" }, "debug": { - "type": "boolean" + "type": "object", + "properties": { + "disable_ffmpeg_check": { + "type": "boolean" + } + } }, "emergency_leader_timeout_sec": { "description": "seconds", @@ -6841,7 +6878,12 @@ "type": "string" }, "debug": { - "type": "boolean" + "type": "object", + "properties": { + "disable_ffmpeg_check": { + "type": "boolean" + } + } }, "emergency_leader_timeout_sec": { "description": "seconds", diff --git a/docs/swagger.yaml b/docs/swagger.yaml index b0fd9e69..759d9435 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -160,6 +160,10 @@ definitions: ncpu: type: number type: object + api.ClusterProcessMap: + additionalProperties: + type: string + type: object api.ClusterRaft: properties: server: @@ -267,7 +271,10 @@ definitions: description: ip:port type: string debug: - type: boolean + properties: + disable_ffmpeg_check: + type: boolean + type: object emergency_leader_timeout_sec: description: seconds format: int64 @@ -1843,7 +1850,10 @@ definitions: description: ip:port type: string debug: - type: boolean + properties: + disable_ffmpeg_check: + type: boolean + type: object emergency_leader_timeout_sec: description: seconds format: int64 @@ -2916,6 +2926,22 @@ paths: summary: Leave the cluster gracefully tags: - v16.?.? + /api/v3/cluster/map/process: + get: + description: Retrieve a map of which process is running on which node + operationId: cluster-3-process-node-map + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/api.ClusterProcessMap' + security: + - ApiKeyAuth: [] + summary: Retrieve a map of which process is running on which node + tags: + - v16.?.? /api/v3/cluster/node: get: description: List of proxy nodes in the cluster diff --git a/http/api/cluster.go b/http/api/cluster.go index 2215264d..28a335da 100644 --- a/http/api/cluster.go +++ b/http/api/cluster.go @@ -99,3 +99,5 @@ type ClusterKVSValue struct { } type ClusterKVS map[string]ClusterKVSValue + +type ClusterProcessMap map[string]string diff --git a/http/handler/api/cluster.go b/http/handler/api/cluster.go index a5f27e1e..19e8e72f 100644 --- a/http/handler/api/cluster.go +++ b/http/handler/api/cluster.go @@ -1425,3 +1425,18 @@ func (h *ClusterHandler) GetSnapshot(c echo.Context) error { return c.Stream(http.StatusOK, "application/octet-stream", r) } + +// GetProcessNodeMap returns a map of which process is running on which node +// @Summary Retrieve a map of which process is running on which node +// @Description Retrieve a map of which process is running on which node +// @Tags v16.?.? +// @ID cluster-3-process-node-map +// @Produce json +// @Success 200 {object} api.ClusterProcessMap +// @Security ApiKeyAuth +// @Router /api/v3/cluster/map/process [get] +func (h *ClusterHandler) GetProcessNodeMap(c echo.Context) error { + m := h.cluster.GetProcessNodeMap() + + return c.JSON(http.StatusOK, m) +} diff --git a/http/server.go b/http/server.go index c15e5247..0d06bd64 100644 --- a/http/server.go +++ b/http/server.go @@ -700,6 +700,7 @@ func (s *server) setRoutesV3(v3 *echo.Group) { v3.GET("/cluster/db/policies", s.v3handler.cluster.ListStorePolicies) v3.GET("/cluster/db/locks", s.v3handler.cluster.ListStoreLocks) v3.GET("/cluster/db/kv", s.v3handler.cluster.ListStoreKV) + v3.GET("/cluster/db/map/process", s.v3handler.cluster.GetProcessNodeMap) v3.GET("/cluster/iam/user", s.v3handler.cluster.ListIdentities) v3.GET("/cluster/iam/user/:name", s.v3handler.cluster.ListIdentity)