Fix cluster api responses

This commit is contained in:
Ingo Oppermann
2022-09-28 21:49:25 +02:00
parent 692b65b97c
commit 9ef4ae9b5e
6 changed files with 89 additions and 33 deletions

View File

@@ -2,6 +2,7 @@ package cluster
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"io" "io"
"sync" "sync"
@@ -11,6 +12,8 @@ import (
"github.com/datarhei/core/v16/net" "github.com/datarhei/core/v16/net"
) )
var ErrNodeNotFound = errors.New("node not found")
type ClusterReader interface { type ClusterReader interface {
GetURL(path string) (string, error) GetURL(path string) (string, error)
GetFile(path string) (io.ReadCloser, error) GetFile(path string) (io.ReadCloser, error)
@@ -182,7 +185,7 @@ func (c *cluster) RemoveNode(id string) error {
node, ok := c.nodes[id] node, ok := c.nodes[id]
if !ok { if !ok {
return nil return ErrNodeNotFound
} }
node.stop() node.stop()

View File

@@ -62,7 +62,7 @@ const docTemplate = `{
"operationId": "graph-playground", "operationId": "graph-playground",
"responses": { "responses": {
"200": { "200": {
"description": "" "description": "OK"
} }
} }
} }
@@ -327,14 +327,14 @@ const docTemplate = `{
"ApiKeyAuth": [] "ApiKeyAuth": []
} }
], ],
"description": "Replace an existing Node", "description": "Replaces an existing node and returns the new node ID",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"produces": [ "produces": [
"application/json" "application/json"
], ],
"summary": "Replace an existing Node", "summary": "Replaces an existing node",
"operationId": "cluster-3-update-node", "operationId": "cluster-3-update-node",
"parameters": [ "parameters": [
{ {
@@ -403,8 +403,14 @@ const docTemplate = `{
"type": "string" "type": "string"
} }
}, },
"400": { "404": {
"description": "Bad Request", "description": "Not Found",
"schema": {
"$ref": "#/definitions/api.Error"
}
},
"500": {
"description": "Internal Server Error",
"schema": { "schema": {
"$ref": "#/definitions/api.Error" "$ref": "#/definitions/api.Error"
} }
@@ -438,10 +444,7 @@ const docTemplate = `{
"200": { "200": {
"description": "OK", "description": "OK",
"schema": { "schema": {
"type": "array", "$ref": "#/definitions/api.ClusterNodeFiles"
"items": {
"type": "string"
}
} }
}, },
"404": { "404": {
@@ -2581,6 +2584,15 @@ const docTemplate = `{
} }
} }
}, },
"api.ClusterNodeFiles": {
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
},
"api.Command": { "api.Command": {
"type": "object", "type": "object",
"required": [ "required": [

View File

@@ -54,7 +54,7 @@
"operationId": "graph-playground", "operationId": "graph-playground",
"responses": { "responses": {
"200": { "200": {
"description": "" "description": "OK"
} }
} }
} }
@@ -319,14 +319,14 @@
"ApiKeyAuth": [] "ApiKeyAuth": []
} }
], ],
"description": "Replace an existing Node", "description": "Replaces an existing node and returns the new node ID",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"produces": [ "produces": [
"application/json" "application/json"
], ],
"summary": "Replace an existing Node", "summary": "Replaces an existing node",
"operationId": "cluster-3-update-node", "operationId": "cluster-3-update-node",
"parameters": [ "parameters": [
{ {
@@ -395,8 +395,14 @@
"type": "string" "type": "string"
} }
}, },
"400": { "404": {
"description": "Bad Request", "description": "Not Found",
"schema": {
"$ref": "#/definitions/api.Error"
}
},
"500": {
"description": "Internal Server Error",
"schema": { "schema": {
"$ref": "#/definitions/api.Error" "$ref": "#/definitions/api.Error"
} }
@@ -430,10 +436,7 @@
"200": { "200": {
"description": "OK", "description": "OK",
"schema": { "schema": {
"type": "array", "$ref": "#/definitions/api.ClusterNodeFiles"
"items": {
"type": "string"
}
} }
}, },
"404": { "404": {
@@ -2573,6 +2576,15 @@
} }
} }
}, },
"api.ClusterNodeFiles": {
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
},
"api.Command": { "api.Command": {
"type": "object", "type": "object",
"required": [ "required": [

View File

@@ -76,6 +76,12 @@ definitions:
username: username:
type: string type: string
type: object type: object
api.ClusterNodeFiles:
additionalProperties:
items:
type: string
type: array
type: object
api.Command: api.Command:
properties: properties:
command: command:
@@ -1774,7 +1780,7 @@ paths:
- text/html - text/html
responses: responses:
"200": "200":
description: "" description: OK
security: security:
- ApiKeyAuth: [] - ApiKeyAuth: []
summary: Load GraphQL playground summary: Load GraphQL playground
@@ -1933,8 +1939,12 @@ paths:
description: OK description: OK
schema: schema:
type: string type: string
"400": "404":
description: Bad Request description: Not Found
schema:
$ref: '#/definitions/api.Error'
"500":
description: Internal Server Error
schema: schema:
$ref: '#/definitions/api.Error' $ref: '#/definitions/api.Error'
security: security:
@@ -1966,7 +1976,7 @@ paths:
put: put:
consumes: consumes:
- application/json - application/json
description: Replace an existing Node description: Replaces an existing node and returns the new node ID
operationId: cluster-3-update-node operationId: cluster-3-update-node
parameters: parameters:
- description: Node ID - description: Node ID
@@ -1997,7 +2007,7 @@ paths:
$ref: '#/definitions/api.Error' $ref: '#/definitions/api.Error'
security: security:
- ApiKeyAuth: [] - ApiKeyAuth: []
summary: Replace an existing Node summary: Replaces an existing node
/api/v3/cluster/node/{id}/proxy: /api/v3/cluster/node/{id}/proxy:
get: get:
description: List the files of a node by its ID description: List the files of a node by its ID
@@ -2014,9 +2024,7 @@ paths:
"200": "200":
description: OK description: OK
schema: schema:
items: $ref: '#/definitions/api.ClusterNodeFiles'
type: string
type: array
"404": "404":
description: Not Found description: Not Found
schema: schema:

View File

@@ -13,4 +13,4 @@ type ClusterNode struct {
State string `json:"state"` State string `json:"state"`
} }
type ClusterNodeFiles []string type ClusterNodeFiles map[string][]string

View File

@@ -2,7 +2,9 @@ package api
import ( import (
"net/http" "net/http"
"regexp"
"sort" "sort"
"strings"
"github.com/datarhei/core/v16/cluster" "github.com/datarhei/core/v16/cluster"
"github.com/datarhei/core/v16/http/api" "github.com/datarhei/core/v16/http/api"
@@ -14,12 +16,14 @@ import (
// The ClusterHandler type provides handler functions for manipulating the cluster config. // The ClusterHandler type provides handler functions for manipulating the cluster config.
type ClusterHandler struct { type ClusterHandler struct {
cluster cluster.Cluster cluster cluster.Cluster
prefix *regexp.Regexp
} }
// NewCluster return a new ClusterHandler type. You have to provide a cluster. // NewCluster return a new ClusterHandler type. You have to provide a cluster.
func NewCluster(cluster cluster.Cluster) *ClusterHandler { func NewCluster(cluster cluster.Cluster) *ClusterHandler {
return &ClusterHandler{ return &ClusterHandler{
cluster: cluster, cluster: cluster,
prefix: regexp.MustCompile(`^[a-z]+:`),
} }
} }
@@ -85,14 +89,19 @@ func (h *ClusterHandler) AddNode(c echo.Context) error {
// @Produce json // @Produce json
// @Param id path string true "Node ID" // @Param id path string true "Node ID"
// @Success 200 {string} string // @Success 200 {string} string
// @Failure 400 {object} api.Error // @Failure 404 {object} api.Error
// @Failure 500 {object} api.Error
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /api/v3/cluster/node/{id} [delete] // @Router /api/v3/cluster/node/{id} [delete]
func (h *ClusterHandler) DeleteNode(c echo.Context) error { func (h *ClusterHandler) DeleteNode(c echo.Context) error {
id := util.PathParam(c, "id") id := util.PathParam(c, "id")
if err := h.cluster.RemoveNode(id); err != nil { if err := h.cluster.RemoveNode(id); err != nil {
return api.Err(http.StatusBadRequest, "Failed to remove node", "%s", err) if err == cluster.ErrNodeNotFound {
return api.Err(http.StatusNotFound, err.Error(), "%s", id)
}
return api.Err(http.StatusInternalServerError, "Failed to remove node", "%s", err)
} }
return c.JSON(http.StatusOK, "OK") return c.JSON(http.StatusOK, "OK")
@@ -146,16 +155,25 @@ func (h *ClusterHandler) GetNodeProxy(c echo.Context) error {
return api.Err(http.StatusNotFound, "Node not found", "%s", err) return api.Err(http.StatusNotFound, "Node not found", "%s", err)
} }
files := api.ClusterNodeFiles{}
state := peer.State() state := peer.State()
sort.Strings(state.Files) sort.Strings(state.Files)
return c.JSON(http.StatusOK, state.Files) for _, path := range state.Files {
prefix := strings.TrimSuffix(h.prefix.FindString(path), ":")
path = h.prefix.ReplaceAllString(path, "")
files[prefix] = append(files[prefix], path)
}
return c.JSON(http.StatusOK, files)
} }
// UpdateNode replaces an existing node // UpdateNode replaces an existing node
// @Summary Replace an existing Node // @Summary Replaces an existing node
// @Description Replace an existing Node // @Description Replaces an existing node and returns the new node ID
// @ID cluster-3-update-node // @ID cluster-3-update-node
// @Accept json // @Accept json
// @Produce json // @Produce json
@@ -176,6 +194,9 @@ func (h *ClusterHandler) UpdateNode(c echo.Context) error {
} }
if err := h.cluster.RemoveNode(id); err != nil { if err := h.cluster.RemoveNode(id); err != nil {
if err == cluster.ErrNodeNotFound {
return api.Err(http.StatusNotFound, err.Error(), "%s", id)
}
return api.Err(http.StatusBadRequest, "Failed to remove node", "%s", err) return api.Err(http.StatusBadRequest, "Failed to remove node", "%s", err)
} }