From cbe6754b2f640da408088861f0aaeb985ae7f99d Mon Sep 17 00:00:00 2001 From: Ingo Oppermann Date: Thu, 22 Jun 2023 16:33:06 +0200 Subject: [PATCH] Add /v1/core/config endpoint to cluster API --- cluster/api.go | 73 +-- cluster/cluster.go | 5 + cluster/docs/ClusterAPI_docs.go | 698 ++++++++++++++++++++++++++- cluster/docs/ClusterAPI_swagger.json | 698 ++++++++++++++++++++++++++- cluster/docs/ClusterAPI_swagger.yaml | 470 +++++++++++++++++- 5 files changed, 1905 insertions(+), 39 deletions(-) diff --git a/cluster/api.go b/cluster/api.go index 94dacd56..f42e82af 100644 --- a/cluster/api.go +++ b/cluster/api.go @@ -16,6 +16,7 @@ package cluster import ( "context" "fmt" + "io/fs" "net/http" "strings" @@ -125,6 +126,7 @@ func NewAPI(config APIConfig) (API, error) { a.router.DELETE("/v1/kv/:key", a.UnsetKV) a.router.GET("/v1/core", a.CoreAPIAddress) + a.router.GET("/v1/core/config", a.CoreConfig) return a, nil } @@ -157,7 +159,7 @@ func (a *api) AddServer(c echo.Context) error { r := client.JoinRequest{} if err := util.ShouldBindJSON(c, &r); err != nil { - return Err(http.StatusBadRequest, "Invalid JSON", "%s", err.Error()) + return Err(http.StatusBadRequest, "", "Invalid JSON: %s", err.Error()) } a.logger.Debug().WithFields(log.Fields{ @@ -174,7 +176,7 @@ func (a *api) AddServer(c echo.Context) error { err := a.cluster.Join(origin, r.ID, r.RaftAddress, "") if err != nil { a.logger.Debug().WithError(err).WithField("id", r.ID).Log("Unable to join cluster") - return Err(http.StatusInternalServerError, "unable to join cluster", "%s", err.Error()) + return Err(http.StatusInternalServerError, "", "unable to join cluster: %s", err.Error()) } return c.JSON(http.StatusOK, "OK") @@ -208,7 +210,7 @@ func (a *api) RemoveServer(c echo.Context) error { err := a.cluster.Leave(origin, id) if err != nil { a.logger.Debug().WithError(err).WithField("id", id).Log("Unable to leave cluster") - return Err(http.StatusInternalServerError, "unable to leave cluster", "%s", err.Error()) + return Err(http.StatusInternalServerError, "", "unable to leave cluster%s", err.Error()) } return c.JSON(http.StatusOK, "OK") @@ -227,7 +229,7 @@ func (a *api) Snapshot(c echo.Context) error { data, err := a.cluster.Snapshot() if err != nil { a.logger.Debug().WithError(err).Log("Unable to create snaphot") - return Err(http.StatusInternalServerError, "unable to create snapshot", "%s", err.Error()) + return Err(http.StatusInternalServerError, "", "unable to create snapshot: %s", err.Error()) } defer data.Close() @@ -253,7 +255,7 @@ func (a *api) AddProcess(c echo.Context) error { r := client.AddProcessRequest{} if err := util.ShouldBindJSON(c, &r); err != nil { - return Err(http.StatusBadRequest, "Invalid JSON", "%s", err.Error()) + return Err(http.StatusBadRequest, "", "invalid JSON: %s", err.Error()) } origin := c.Request().Header.Get("X-Cluster-Origin") @@ -267,7 +269,7 @@ func (a *api) AddProcess(c echo.Context) error { err := a.cluster.AddProcess(origin, &r.Config) if err != nil { a.logger.Debug().WithError(err).WithField("id", r.Config.ID).Log("Unable to add process") - return Err(http.StatusInternalServerError, "unable to add process", "%s", err.Error()) + return Err(http.StatusInternalServerError, "", "unable to add process: %s", err.Error()) } return c.JSON(http.StatusOK, "OK") @@ -303,7 +305,7 @@ func (a *api) RemoveProcess(c echo.Context) error { err := a.cluster.RemoveProcess(origin, pid) if err != nil { a.logger.Debug().WithError(err).WithField("id", pid).Log("Unable to remove process") - return Err(http.StatusInternalServerError, "unable to remove process", "%s", err.Error()) + return Err(http.StatusInternalServerError, "", "unable to remove process: %s", err.Error()) } return c.JSON(http.StatusOK, "OK") @@ -330,7 +332,7 @@ func (a *api) UpdateProcess(c echo.Context) error { r := client.UpdateProcessRequest{} if err := util.ShouldBindJSON(c, &r); err != nil { - return Err(http.StatusBadRequest, "Invalid JSON", "%s", err.Error()) + return Err(http.StatusBadRequest, "", "invalid JSON: %s", err.Error()) } origin := c.Request().Header.Get("X-Cluster-Origin") @@ -349,7 +351,7 @@ func (a *api) UpdateProcess(c echo.Context) error { err := a.cluster.UpdateProcess(origin, pid, &r.Config) if err != nil { a.logger.Debug().WithError(err).WithField("id", pid).Log("Unable to update process") - return Err(http.StatusInternalServerError, "unable to update process", "%s", err.Error()) + return Err(http.StatusInternalServerError, "", "unable to update process: %s", err.Error()) } return c.JSON(http.StatusOK, "OK") @@ -377,7 +379,7 @@ func (a *api) SetProcessMetadata(c echo.Context) error { r := client.SetProcessMetadataRequest{} if err := util.ShouldBindJSON(c, &r); err != nil { - return Err(http.StatusBadRequest, "Invalid JSON", "%s", err.Error()) + return Err(http.StatusBadRequest, "", "invalid JSON: %s", err.Error()) } origin := c.Request().Header.Get("X-Cluster-Origin") @@ -391,7 +393,7 @@ func (a *api) SetProcessMetadata(c echo.Context) error { err := a.cluster.SetProcessMetadata(origin, pid, key, r.Metadata) if err != nil { a.logger.Debug().WithError(err).WithField("id", pid).Log("Unable to update metadata") - return Err(http.StatusInternalServerError, "unable to update metadata", "%s", err.Error()) + return Err(http.StatusInternalServerError, "", "unable to update metadata: %s", err.Error()) } return c.JSON(http.StatusOK, "OK") @@ -415,7 +417,7 @@ func (a *api) AddIdentity(c echo.Context) error { r := client.AddIdentityRequest{} if err := util.ShouldBindJSON(c, &r); err != nil { - return Err(http.StatusBadRequest, "Invalid JSON", "%s", err.Error()) + return Err(http.StatusBadRequest, "", "invalid JSON: %s", err.Error()) } origin := c.Request().Header.Get("X-Cluster-Origin") @@ -429,7 +431,7 @@ func (a *api) AddIdentity(c echo.Context) error { err := a.cluster.AddIdentity(origin, r.Identity) if err != nil { a.logger.Debug().WithError(err).WithField("identity", r.Identity).Log("Unable to add identity") - return Err(http.StatusInternalServerError, "unable to add identity", "%s", err.Error()) + return Err(http.StatusInternalServerError, "", "unable to add identity: %s", err.Error()) } return c.JSON(http.StatusOK, "OK") @@ -454,7 +456,7 @@ func (a *api) UpdateIdentity(c echo.Context) error { r := client.UpdateIdentityRequest{} if err := util.ShouldBindJSON(c, &r); err != nil { - return Err(http.StatusBadRequest, "Invalid JSON", "%s", err.Error()) + return Err(http.StatusBadRequest, "", "invalid JSON: %s", err.Error()) } origin := c.Request().Header.Get("X-Cluster-Origin") @@ -474,7 +476,7 @@ func (a *api) UpdateIdentity(c echo.Context) error { "name": name, "identity": r.Identity, }).Log("Unable to add identity") - return Err(http.StatusInternalServerError, "unable to update identity", "%s", err.Error()) + return Err(http.StatusInternalServerError, "", "unable to update identity: %s", err.Error()) } return c.JSON(http.StatusOK, "OK") @@ -499,7 +501,7 @@ func (a *api) SetIdentityPolicies(c echo.Context) error { r := client.SetPoliciesRequest{} if err := util.ShouldBindJSON(c, &r); err != nil { - return Err(http.StatusBadRequest, "Invalid JSON", "%s", err.Error()) + return Err(http.StatusBadRequest, "", "invalid JSON: %s", err.Error()) } origin := c.Request().Header.Get("X-Cluster-Origin") @@ -513,7 +515,7 @@ func (a *api) SetIdentityPolicies(c echo.Context) error { err := a.cluster.SetPolicies(origin, name, r.Policies) if err != nil { a.logger.Debug().WithError(err).WithField("policies", r.Policies).Log("Unable to set policies") - return Err(http.StatusInternalServerError, "unable to add identity", "%s", err.Error()) + return Err(http.StatusInternalServerError, "", "unable to add identity: %s", err.Error()) } return c.JSON(http.StatusOK, "OK") @@ -545,7 +547,7 @@ func (a *api) RemoveIdentity(c echo.Context) error { err := a.cluster.RemoveIdentity(origin, name) if err != nil { a.logger.Debug().WithError(err).WithField("identity", name).Log("Unable to remove identity") - return Err(http.StatusInternalServerError, "unable to remove identity", "%s", err.Error()) + return Err(http.StatusInternalServerError, "", "unable to remove identity: %s", err.Error()) } return c.JSON(http.StatusOK, "OK") @@ -558,13 +560,25 @@ func (a *api) RemoveIdentity(c echo.Context) error { // @ID cluster-1-core-api-address // @Produce json // @Success 200 {string} string -// @Success 500 {object} Error // @Router /v1/core [get] func (a *api) CoreAPIAddress(c echo.Context) error { address, _ := a.cluster.CoreAPIAddress("") return c.JSON(http.StatusOK, address) } +// CoreConfig returns the Core config of this node +// @Summary Core config +// @Description Core config of this node +// @Tags v1.0.0 +// @ID cluster-1-core-config +// @Produce json +// @Success 200 {object} config.Config +// @Router /v1/core/config [get] +func (a *api) CoreConfig(c echo.Context) error { + config := a.cluster.CoreConfig() + return c.JSON(http.StatusOK, config) +} + // Lock tries to acquire a named lock // @Summary Acquire a named lock // @Description Acquire a named lock @@ -574,14 +588,14 @@ func (a *api) CoreAPIAddress(c echo.Context) error { // @Param data body client.LockRequest true "Lock request" // @Param X-Cluster-Origin header string false "Origin ID of request" // @Success 200 {string} string -// @Success 500 {object} Error +// @Failure 500 {object} Error // @Failure 508 {object} Error // @Router /v1/lock [post] func (a *api) Lock(c echo.Context) error { r := client.LockRequest{} if err := util.ShouldBindJSON(c, &r); err != nil { - return Err(http.StatusBadRequest, "Invalid JSON", "%s", err.Error()) + return Err(http.StatusBadRequest, "", "invalid JSON: %s", err.Error()) } origin := c.Request().Header.Get("X-Cluster-Origin") @@ -595,7 +609,7 @@ func (a *api) Lock(c echo.Context) error { err := a.cluster.CreateLock(origin, r.Name, r.ValidUntil) if err != nil { a.logger.Debug().WithError(err).WithField("name", r.Name).Log("Unable to acquire lock") - return Err(http.StatusInternalServerError, "unable to acquire lock", "%s", err.Error()) + return Err(http.StatusInternalServerError, "", "unable to acquire lock: %s", err.Error()) } return c.JSON(http.StatusOK, "OK") @@ -611,6 +625,7 @@ func (a *api) Lock(c echo.Context) error { // @Param X-Cluster-Origin header string false "Origin ID of request" // @Success 200 {string} string // @Failure 404 {object} Error +// @Failure 500 {object} Error // @Failure 508 {object} Error // @Router /v1/lock/{name} [delete] func (a *api) Unlock(c echo.Context) error { @@ -627,7 +642,7 @@ func (a *api) Unlock(c echo.Context) error { err := a.cluster.DeleteLock(origin, name) if err != nil { a.logger.Debug().WithError(err).WithField("name", name).Log("Unable to remove lock") - return Err(http.StatusInternalServerError, "unable to remove lock", "%s", err.Error()) + return Err(http.StatusInternalServerError, "", "unable to remove lock: %s", err.Error()) } return c.JSON(http.StatusOK, "OK") @@ -642,14 +657,14 @@ func (a *api) Unlock(c echo.Context) error { // @Param data body client.SetKVRequest true "Set KV request" // @Param X-Cluster-Origin header string false "Origin ID of request" // @Success 200 {string} string -// @Success 500 {object} Error +// @Failure 500 {object} Error // @Failure 508 {object} Error // @Router /v1/kv [post] func (a *api) SetKV(c echo.Context) error { r := client.SetKVRequest{} if err := util.ShouldBindJSON(c, &r); err != nil { - return Err(http.StatusBadRequest, "Invalid JSON", "%s", err.Error()) + return Err(http.StatusBadRequest, "", "invalid JSON: %s", err.Error()) } origin := c.Request().Header.Get("X-Cluster-Origin") @@ -663,7 +678,7 @@ func (a *api) SetKV(c echo.Context) error { err := a.cluster.SetKV(origin, r.Key, r.Value) if err != nil { a.logger.Debug().WithError(err).WithField("key", r.Key).Log("Unable to store value") - return Err(http.StatusInternalServerError, "unable to store value", "%s", err.Error()) + return Err(http.StatusInternalServerError, "", "unable to store value: %s", err.Error()) } return c.JSON(http.StatusOK, "OK") @@ -679,6 +694,7 @@ func (a *api) SetKV(c echo.Context) error { // @Param X-Cluster-Origin header string false "Origin ID of request" // @Success 200 {string} string // @Failure 404 {object} Error +// @Failure 500 {object} Error // @Failure 508 {object} Error // @Router /v1/kv/{key} [delete] func (a *api) UnsetKV(c echo.Context) error { @@ -694,8 +710,11 @@ func (a *api) UnsetKV(c echo.Context) error { err := a.cluster.UnsetKV(origin, key) if err != nil { + if err == fs.ErrNotExist { + return Err(http.StatusNotFound, "", "%s", err.Error()) + } a.logger.Debug().WithError(err).WithField("key", key).Log("Unable to remove key") - return Err(http.StatusInternalServerError, "unable to remove key", "%s", err.Error()) + return Err(http.StatusInternalServerError, "", "unable to remove key: %s", err.Error()) } return c.JSON(http.StatusOK, "OK") diff --git a/cluster/cluster.go b/cluster/cluster.go index 296b18af..487b7a75 100644 --- a/cluster/cluster.go +++ b/cluster/cluster.go @@ -39,6 +39,7 @@ type Cluster interface { // CoreAPIAddress returns the address of the core API of a node with // the given raft address. CoreAPIAddress(raftAddress string) (string, error) + CoreConfig() *config.Config About() (ClusterAbout, error) @@ -361,6 +362,10 @@ func (c *cluster) CoreAPIAddress(raftAddress string) (string, error) { return coreAddress, err } +func (c *cluster) CoreConfig() *config.Config { + return c.config.Clone() +} + func (c *cluster) Shutdown() error { c.logger.Info().Log("Shutting down cluster") c.shutdownLock.Lock() diff --git a/cluster/docs/ClusterAPI_docs.go b/cluster/docs/ClusterAPI_docs.go index 62336957..66f33918 100644 --- a/cluster/docs/ClusterAPI_docs.go +++ b/cluster/docs/ClusterAPI_docs.go @@ -41,11 +41,26 @@ const docTemplateClusterAPI = `{ "schema": { "type": "string" } - }, - "500": { - "description": "Internal Server Error", + } + } + } + }, + "/v1/core/config": { + "get": { + "description": "Core config of this node", + "produces": [ + "application/json" + ], + "tags": [ + "v1.0.0" + ], + "summary": "Core config", + "operationId": "cluster-1-core-config", + "responses": { + "200": { + "description": "OK", "schema": { - "$ref": "#/definitions/cluster.Error" + "$ref": "#/definitions/config.Config" } } } @@ -356,6 +371,12 @@ const docTemplateClusterAPI = `{ "$ref": "#/definitions/cluster.Error" } }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/cluster.Error" + } + }, "508": { "description": "Loop Detected", "schema": { @@ -454,6 +475,12 @@ const docTemplateClusterAPI = `{ "$ref": "#/definitions/cluster.Error" } }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/cluster.Error" + } + }, "508": { "description": "Loop Detected", "schema": { @@ -1076,6 +1103,595 @@ const docTemplateClusterAPI = `{ } } }, + "config.Config": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "api": { + "type": "object", + "properties": { + "access": { + "type": "object", + "properties": { + "http": { + "type": "object", + "properties": { + "allow": { + "type": "array", + "items": { + "type": "string" + } + }, + "block": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "https": { + "type": "object", + "properties": { + "allow": { + "type": "array", + "items": { + "type": "string" + } + }, + "block": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "auth": { + "type": "object", + "properties": { + "auth0": { + "type": "object", + "properties": { + "enable": { + "type": "boolean" + }, + "tenants": { + "type": "array", + "items": { + "$ref": "#/definitions/value.Auth0Tenant" + } + } + } + }, + "disable_localhost": { + "type": "boolean" + }, + "enable": { + "type": "boolean" + }, + "jwt": { + "type": "object", + "properties": { + "secret": { + "type": "string" + } + } + }, + "password": { + "type": "string" + }, + "username": { + "type": "string" + } + } + }, + "read_only": { + "type": "boolean" + } + } + }, + "cluster": { + "type": "object", + "properties": { + "address": { + "description": "ip:port", + "type": "string" + }, + "debug": { + "type": "boolean" + }, + "emergency_leader_timeout_sec": { + "description": "seconds", + "type": "integer", + "format": "int64" + }, + "enable": { + "type": "boolean" + }, + "node_recover_timeout_sec": { + "description": "seconds", + "type": "integer", + "format": "int64" + }, + "peers": { + "type": "array", + "items": { + "type": "string" + } + }, + "sync_interval_sec": { + "description": "seconds", + "type": "integer", + "format": "int64" + } + } + }, + "created_at": { + "description": "When this config has been persisted", + "type": "string" + }, + "db": { + "type": "object", + "properties": { + "dir": { + "type": "string" + } + } + }, + "debug": { + "type": "object", + "properties": { + "auto_max_procs": { + "type": "boolean" + }, + "force_gc": { + "description": "deprecated, use MemoryLimit instead", + "type": "integer", + "format": "int" + }, + "memory_limit_mbytes": { + "type": "integer", + "format": "int64" + }, + "profiling": { + "type": "boolean" + } + } + }, + "ffmpeg": { + "type": "object", + "properties": { + "access": { + "type": "object", + "properties": { + "input": { + "type": "object", + "properties": { + "allow": { + "type": "array", + "items": { + "type": "string" + } + }, + "block": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "output": { + "type": "object", + "properties": { + "allow": { + "type": "array", + "items": { + "type": "string" + } + }, + "block": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "binary": { + "type": "string" + }, + "log": { + "type": "object", + "properties": { + "max_history": { + "type": "integer", + "format": "int" + }, + "max_lines": { + "type": "integer", + "format": "int" + }, + "max_minimal_history": { + "type": "integer", + "format": "int" + } + } + }, + "max_processes": { + "type": "integer", + "format": "int64" + } + } + }, + "host": { + "type": "object", + "properties": { + "auto": { + "type": "boolean" + }, + "name": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "id": { + "type": "string" + }, + "log": { + "type": "object", + "properties": { + "level": { + "type": "string", + "enum": [ + "debug", + "info", + "warn", + "error", + "silent" + ] + }, + "max_lines": { + "type": "integer", + "format": "int" + }, + "topics": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "metrics": { + "type": "object", + "properties": { + "enable": { + "type": "boolean" + }, + "enable_prometheus": { + "type": "boolean" + }, + "interval_sec": { + "description": "seconds", + "type": "integer", + "format": "int64" + }, + "range_sec": { + "description": "seconds", + "type": "integer", + "format": "int64" + } + } + }, + "name": { + "type": "string" + }, + "playout": { + "type": "object", + "properties": { + "enable": { + "type": "boolean" + }, + "max_port": { + "type": "integer", + "format": "int" + }, + "min_port": { + "type": "integer", + "format": "int" + } + } + }, + "resources": { + "type": "object", + "properties": { + "max_cpu_usage": { + "description": "percent 0-100", + "type": "number" + }, + "max_memory_usage": { + "description": "percent 0-100", + "type": "number" + } + } + }, + "router": { + "type": "object", + "properties": { + "blocked_prefixes": { + "type": "array", + "items": { + "type": "string" + } + }, + "routes": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "ui_path": { + "type": "string" + } + } + }, + "rtmp": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "address_tls": { + "type": "string" + }, + "app": { + "type": "string" + }, + "enable": { + "type": "boolean" + }, + "enable_tls": { + "type": "boolean" + }, + "token": { + "description": "Deprecated, use IAM", + "type": "string" + } + } + }, + "service": { + "type": "object", + "properties": { + "enable": { + "type": "boolean" + }, + "token": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "sessions": { + "type": "object", + "properties": { + "enable": { + "type": "boolean" + }, + "ip_ignorelist": { + "type": "array", + "items": { + "type": "string" + } + }, + "max_bitrate_mbit": { + "type": "integer", + "format": "uint64" + }, + "max_sessions": { + "type": "integer", + "format": "uint64" + }, + "persist": { + "type": "boolean" + }, + "persist_interval_sec": { + "type": "integer", + "format": "int" + }, + "session_log_buffer_sec": { + "type": "integer", + "format": "int" + }, + "session_log_path_pattern": { + "type": "string" + }, + "session_timeout_sec": { + "type": "integer", + "format": "int" + } + } + }, + "srt": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "enable": { + "type": "boolean" + }, + "log": { + "type": "object", + "properties": { + "enable": { + "type": "boolean" + }, + "topics": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "passphrase": { + "type": "string" + }, + "token": { + "description": "Deprecated, use IAM", + "type": "string" + } + } + }, + "storage": { + "type": "object", + "properties": { + "cors": { + "type": "object", + "properties": { + "origins": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "disk": { + "type": "object", + "properties": { + "cache": { + "type": "object", + "properties": { + "enable": { + "type": "boolean" + }, + "max_file_size_mbytes": { + "type": "integer", + "format": "uint64" + }, + "max_size_mbytes": { + "type": "integer", + "format": "uint64" + }, + "ttl_seconds": { + "type": "integer", + "format": "int64" + }, + "types": { + "type": "object", + "properties": { + "allow": { + "type": "array", + "items": { + "type": "string" + } + }, + "block": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "dir": { + "type": "string" + }, + "max_size_mbytes": { + "type": "integer", + "format": "int64" + } + } + }, + "memory": { + "type": "object", + "properties": { + "auth": { + "description": "Deprecated, use IAM", + "type": "object", + "properties": { + "enable": { + "description": "Deprecated, use IAM", + "type": "boolean" + }, + "password": { + "description": "Deprecated, use IAM", + "type": "string" + }, + "username": { + "description": "Deprecated, use IAM", + "type": "string" + } + } + }, + "max_size_mbytes": { + "type": "integer", + "format": "int64" + }, + "purge": { + "type": "boolean" + } + } + }, + "mimetypes_file": { + "type": "string" + }, + "s3": { + "type": "array", + "items": { + "$ref": "#/definitions/value.S3Storage" + } + } + } + }, + "tls": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "auto": { + "type": "boolean" + }, + "cert_file": { + "type": "string" + }, + "email": { + "type": "string" + }, + "enable": { + "type": "boolean" + }, + "key_file": { + "type": "string" + } + } + }, + "update_check": { + "type": "boolean" + }, + "version": { + "type": "integer", + "format": "int64" + } + } + }, "identity.Auth0Tenant": { "type": "object", "properties": { @@ -1162,6 +1778,80 @@ const docTemplateClusterAPI = `{ } } } + }, + "value.Auth0Tenant": { + "type": "object", + "properties": { + "audience": { + "type": "string" + }, + "clientid": { + "type": "string" + }, + "domain": { + "type": "string" + }, + "users": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "value.S3Storage": { + "type": "object", + "properties": { + "access_key_id": { + "type": "string" + }, + "auth": { + "description": "Deprecated, use IAM", + "allOf": [ + { + "$ref": "#/definitions/value.S3StorageAuth" + } + ] + }, + "bucket": { + "type": "string" + }, + "endpoint": { + "type": "string" + }, + "mountpoint": { + "type": "string" + }, + "name": { + "type": "string" + }, + "region": { + "type": "string" + }, + "secret_access_key": { + "type": "string" + }, + "use_ssl": { + "type": "boolean" + } + } + }, + "value.S3StorageAuth": { + "type": "object", + "properties": { + "enable": { + "description": "Deprecated, use IAM", + "type": "boolean" + }, + "password": { + "description": "Deprecated, use IAM", + "type": "string" + }, + "username": { + "description": "Deprecated, use IAM", + "type": "string" + } + } } } }` diff --git a/cluster/docs/ClusterAPI_swagger.json b/cluster/docs/ClusterAPI_swagger.json index 0b559dbf..397aed46 100644 --- a/cluster/docs/ClusterAPI_swagger.json +++ b/cluster/docs/ClusterAPI_swagger.json @@ -33,11 +33,26 @@ "schema": { "type": "string" } - }, - "500": { - "description": "Internal Server Error", + } + } + } + }, + "/v1/core/config": { + "get": { + "description": "Core config of this node", + "produces": [ + "application/json" + ], + "tags": [ + "v1.0.0" + ], + "summary": "Core config", + "operationId": "cluster-1-core-config", + "responses": { + "200": { + "description": "OK", "schema": { - "$ref": "#/definitions/cluster.Error" + "$ref": "#/definitions/config.Config" } } } @@ -348,6 +363,12 @@ "$ref": "#/definitions/cluster.Error" } }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/cluster.Error" + } + }, "508": { "description": "Loop Detected", "schema": { @@ -446,6 +467,12 @@ "$ref": "#/definitions/cluster.Error" } }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/cluster.Error" + } + }, "508": { "description": "Loop Detected", "schema": { @@ -1068,6 +1095,595 @@ } } }, + "config.Config": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "api": { + "type": "object", + "properties": { + "access": { + "type": "object", + "properties": { + "http": { + "type": "object", + "properties": { + "allow": { + "type": "array", + "items": { + "type": "string" + } + }, + "block": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "https": { + "type": "object", + "properties": { + "allow": { + "type": "array", + "items": { + "type": "string" + } + }, + "block": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "auth": { + "type": "object", + "properties": { + "auth0": { + "type": "object", + "properties": { + "enable": { + "type": "boolean" + }, + "tenants": { + "type": "array", + "items": { + "$ref": "#/definitions/value.Auth0Tenant" + } + } + } + }, + "disable_localhost": { + "type": "boolean" + }, + "enable": { + "type": "boolean" + }, + "jwt": { + "type": "object", + "properties": { + "secret": { + "type": "string" + } + } + }, + "password": { + "type": "string" + }, + "username": { + "type": "string" + } + } + }, + "read_only": { + "type": "boolean" + } + } + }, + "cluster": { + "type": "object", + "properties": { + "address": { + "description": "ip:port", + "type": "string" + }, + "debug": { + "type": "boolean" + }, + "emergency_leader_timeout_sec": { + "description": "seconds", + "type": "integer", + "format": "int64" + }, + "enable": { + "type": "boolean" + }, + "node_recover_timeout_sec": { + "description": "seconds", + "type": "integer", + "format": "int64" + }, + "peers": { + "type": "array", + "items": { + "type": "string" + } + }, + "sync_interval_sec": { + "description": "seconds", + "type": "integer", + "format": "int64" + } + } + }, + "created_at": { + "description": "When this config has been persisted", + "type": "string" + }, + "db": { + "type": "object", + "properties": { + "dir": { + "type": "string" + } + } + }, + "debug": { + "type": "object", + "properties": { + "auto_max_procs": { + "type": "boolean" + }, + "force_gc": { + "description": "deprecated, use MemoryLimit instead", + "type": "integer", + "format": "int" + }, + "memory_limit_mbytes": { + "type": "integer", + "format": "int64" + }, + "profiling": { + "type": "boolean" + } + } + }, + "ffmpeg": { + "type": "object", + "properties": { + "access": { + "type": "object", + "properties": { + "input": { + "type": "object", + "properties": { + "allow": { + "type": "array", + "items": { + "type": "string" + } + }, + "block": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "output": { + "type": "object", + "properties": { + "allow": { + "type": "array", + "items": { + "type": "string" + } + }, + "block": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "binary": { + "type": "string" + }, + "log": { + "type": "object", + "properties": { + "max_history": { + "type": "integer", + "format": "int" + }, + "max_lines": { + "type": "integer", + "format": "int" + }, + "max_minimal_history": { + "type": "integer", + "format": "int" + } + } + }, + "max_processes": { + "type": "integer", + "format": "int64" + } + } + }, + "host": { + "type": "object", + "properties": { + "auto": { + "type": "boolean" + }, + "name": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "id": { + "type": "string" + }, + "log": { + "type": "object", + "properties": { + "level": { + "type": "string", + "enum": [ + "debug", + "info", + "warn", + "error", + "silent" + ] + }, + "max_lines": { + "type": "integer", + "format": "int" + }, + "topics": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "metrics": { + "type": "object", + "properties": { + "enable": { + "type": "boolean" + }, + "enable_prometheus": { + "type": "boolean" + }, + "interval_sec": { + "description": "seconds", + "type": "integer", + "format": "int64" + }, + "range_sec": { + "description": "seconds", + "type": "integer", + "format": "int64" + } + } + }, + "name": { + "type": "string" + }, + "playout": { + "type": "object", + "properties": { + "enable": { + "type": "boolean" + }, + "max_port": { + "type": "integer", + "format": "int" + }, + "min_port": { + "type": "integer", + "format": "int" + } + } + }, + "resources": { + "type": "object", + "properties": { + "max_cpu_usage": { + "description": "percent 0-100", + "type": "number" + }, + "max_memory_usage": { + "description": "percent 0-100", + "type": "number" + } + } + }, + "router": { + "type": "object", + "properties": { + "blocked_prefixes": { + "type": "array", + "items": { + "type": "string" + } + }, + "routes": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "ui_path": { + "type": "string" + } + } + }, + "rtmp": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "address_tls": { + "type": "string" + }, + "app": { + "type": "string" + }, + "enable": { + "type": "boolean" + }, + "enable_tls": { + "type": "boolean" + }, + "token": { + "description": "Deprecated, use IAM", + "type": "string" + } + } + }, + "service": { + "type": "object", + "properties": { + "enable": { + "type": "boolean" + }, + "token": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "sessions": { + "type": "object", + "properties": { + "enable": { + "type": "boolean" + }, + "ip_ignorelist": { + "type": "array", + "items": { + "type": "string" + } + }, + "max_bitrate_mbit": { + "type": "integer", + "format": "uint64" + }, + "max_sessions": { + "type": "integer", + "format": "uint64" + }, + "persist": { + "type": "boolean" + }, + "persist_interval_sec": { + "type": "integer", + "format": "int" + }, + "session_log_buffer_sec": { + "type": "integer", + "format": "int" + }, + "session_log_path_pattern": { + "type": "string" + }, + "session_timeout_sec": { + "type": "integer", + "format": "int" + } + } + }, + "srt": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "enable": { + "type": "boolean" + }, + "log": { + "type": "object", + "properties": { + "enable": { + "type": "boolean" + }, + "topics": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "passphrase": { + "type": "string" + }, + "token": { + "description": "Deprecated, use IAM", + "type": "string" + } + } + }, + "storage": { + "type": "object", + "properties": { + "cors": { + "type": "object", + "properties": { + "origins": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "disk": { + "type": "object", + "properties": { + "cache": { + "type": "object", + "properties": { + "enable": { + "type": "boolean" + }, + "max_file_size_mbytes": { + "type": "integer", + "format": "uint64" + }, + "max_size_mbytes": { + "type": "integer", + "format": "uint64" + }, + "ttl_seconds": { + "type": "integer", + "format": "int64" + }, + "types": { + "type": "object", + "properties": { + "allow": { + "type": "array", + "items": { + "type": "string" + } + }, + "block": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "dir": { + "type": "string" + }, + "max_size_mbytes": { + "type": "integer", + "format": "int64" + } + } + }, + "memory": { + "type": "object", + "properties": { + "auth": { + "description": "Deprecated, use IAM", + "type": "object", + "properties": { + "enable": { + "description": "Deprecated, use IAM", + "type": "boolean" + }, + "password": { + "description": "Deprecated, use IAM", + "type": "string" + }, + "username": { + "description": "Deprecated, use IAM", + "type": "string" + } + } + }, + "max_size_mbytes": { + "type": "integer", + "format": "int64" + }, + "purge": { + "type": "boolean" + } + } + }, + "mimetypes_file": { + "type": "string" + }, + "s3": { + "type": "array", + "items": { + "$ref": "#/definitions/value.S3Storage" + } + } + } + }, + "tls": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "auto": { + "type": "boolean" + }, + "cert_file": { + "type": "string" + }, + "email": { + "type": "string" + }, + "enable": { + "type": "boolean" + }, + "key_file": { + "type": "string" + } + } + }, + "update_check": { + "type": "boolean" + }, + "version": { + "type": "integer", + "format": "int64" + } + } + }, "identity.Auth0Tenant": { "type": "object", "properties": { @@ -1154,6 +1770,80 @@ } } } + }, + "value.Auth0Tenant": { + "type": "object", + "properties": { + "audience": { + "type": "string" + }, + "clientid": { + "type": "string" + }, + "domain": { + "type": "string" + }, + "users": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "value.S3Storage": { + "type": "object", + "properties": { + "access_key_id": { + "type": "string" + }, + "auth": { + "description": "Deprecated, use IAM", + "allOf": [ + { + "$ref": "#/definitions/value.S3StorageAuth" + } + ] + }, + "bucket": { + "type": "string" + }, + "endpoint": { + "type": "string" + }, + "mountpoint": { + "type": "string" + }, + "name": { + "type": "string" + }, + "region": { + "type": "string" + }, + "secret_access_key": { + "type": "string" + }, + "use_ssl": { + "type": "boolean" + } + } + }, + "value.S3StorageAuth": { + "type": "object", + "properties": { + "enable": { + "description": "Deprecated, use IAM", + "type": "boolean" + }, + "password": { + "description": "Deprecated, use IAM", + "type": "string" + }, + "username": { + "description": "Deprecated, use IAM", + "type": "string" + } + } } } } \ No newline at end of file diff --git a/cluster/docs/ClusterAPI_swagger.yaml b/cluster/docs/ClusterAPI_swagger.yaml index 5449f4a7..2c72e985 100644 --- a/cluster/docs/ClusterAPI_swagger.yaml +++ b/cluster/docs/ClusterAPI_swagger.yaml @@ -158,6 +158,402 @@ definitions: message: type: string type: object + config.Config: + properties: + address: + type: string + api: + properties: + access: + properties: + http: + properties: + allow: + items: + type: string + type: array + block: + items: + type: string + type: array + type: object + https: + properties: + allow: + items: + type: string + type: array + block: + items: + type: string + type: array + type: object + type: object + auth: + properties: + auth0: + properties: + enable: + type: boolean + tenants: + items: + $ref: '#/definitions/value.Auth0Tenant' + type: array + type: object + disable_localhost: + type: boolean + enable: + type: boolean + jwt: + properties: + secret: + type: string + type: object + password: + type: string + username: + type: string + type: object + read_only: + type: boolean + type: object + cluster: + properties: + address: + description: ip:port + type: string + debug: + type: boolean + emergency_leader_timeout_sec: + description: seconds + format: int64 + type: integer + enable: + type: boolean + node_recover_timeout_sec: + description: seconds + format: int64 + type: integer + peers: + items: + type: string + type: array + sync_interval_sec: + description: seconds + format: int64 + type: integer + type: object + created_at: + description: When this config has been persisted + type: string + db: + properties: + dir: + type: string + type: object + debug: + properties: + auto_max_procs: + type: boolean + force_gc: + description: deprecated, use MemoryLimit instead + format: int + type: integer + memory_limit_mbytes: + format: int64 + type: integer + profiling: + type: boolean + type: object + ffmpeg: + properties: + access: + properties: + input: + properties: + allow: + items: + type: string + type: array + block: + items: + type: string + type: array + type: object + output: + properties: + allow: + items: + type: string + type: array + block: + items: + type: string + type: array + type: object + type: object + binary: + type: string + log: + properties: + max_history: + format: int + type: integer + max_lines: + format: int + type: integer + max_minimal_history: + format: int + type: integer + type: object + max_processes: + format: int64 + type: integer + type: object + host: + properties: + auto: + type: boolean + name: + items: + type: string + type: array + type: object + id: + type: string + log: + properties: + level: + enum: + - debug + - info + - warn + - error + - silent + type: string + max_lines: + format: int + type: integer + topics: + items: + type: string + type: array + type: object + metrics: + properties: + enable: + type: boolean + enable_prometheus: + type: boolean + interval_sec: + description: seconds + format: int64 + type: integer + range_sec: + description: seconds + format: int64 + type: integer + type: object + name: + type: string + playout: + properties: + enable: + type: boolean + max_port: + format: int + type: integer + min_port: + format: int + type: integer + type: object + resources: + properties: + max_cpu_usage: + description: percent 0-100 + type: number + max_memory_usage: + description: percent 0-100 + type: number + type: object + router: + properties: + blocked_prefixes: + items: + type: string + type: array + routes: + additionalProperties: + type: string + type: object + ui_path: + type: string + type: object + rtmp: + properties: + address: + type: string + address_tls: + type: string + app: + type: string + enable: + type: boolean + enable_tls: + type: boolean + token: + description: Deprecated, use IAM + type: string + type: object + service: + properties: + enable: + type: boolean + token: + type: string + url: + type: string + type: object + sessions: + properties: + enable: + type: boolean + ip_ignorelist: + items: + type: string + type: array + max_bitrate_mbit: + format: uint64 + type: integer + max_sessions: + format: uint64 + type: integer + persist: + type: boolean + persist_interval_sec: + format: int + type: integer + session_log_buffer_sec: + format: int + type: integer + session_log_path_pattern: + type: string + session_timeout_sec: + format: int + type: integer + type: object + srt: + properties: + address: + type: string + enable: + type: boolean + log: + properties: + enable: + type: boolean + topics: + items: + type: string + type: array + type: object + passphrase: + type: string + token: + description: Deprecated, use IAM + type: string + type: object + storage: + properties: + cors: + properties: + origins: + items: + type: string + type: array + type: object + disk: + properties: + cache: + properties: + enable: + type: boolean + max_file_size_mbytes: + format: uint64 + type: integer + max_size_mbytes: + format: uint64 + type: integer + ttl_seconds: + format: int64 + type: integer + types: + properties: + allow: + items: + type: string + type: array + block: + items: + type: string + type: array + type: object + type: object + dir: + type: string + max_size_mbytes: + format: int64 + type: integer + type: object + memory: + properties: + auth: + description: Deprecated, use IAM + properties: + enable: + description: Deprecated, use IAM + type: boolean + password: + description: Deprecated, use IAM + type: string + username: + description: Deprecated, use IAM + type: string + type: object + max_size_mbytes: + format: int64 + type: integer + purge: + type: boolean + type: object + mimetypes_file: + type: string + s3: + items: + $ref: '#/definitions/value.S3Storage' + type: array + type: object + tls: + properties: + address: + type: string + auto: + type: boolean + cert_file: + type: string + email: + type: string + enable: + type: boolean + key_file: + type: string + type: object + update_check: + type: boolean + version: + format: int64 + type: integer + type: object identity.Auth0Tenant: properties: audience: @@ -215,6 +611,54 @@ definitions: type: string type: array type: object + value.Auth0Tenant: + properties: + audience: + type: string + clientid: + type: string + domain: + type: string + users: + items: + type: string + type: array + type: object + value.S3Storage: + properties: + access_key_id: + type: string + auth: + allOf: + - $ref: '#/definitions/value.S3StorageAuth' + description: Deprecated, use IAM + bucket: + type: string + endpoint: + type: string + mountpoint: + type: string + name: + type: string + region: + type: string + secret_access_key: + type: string + use_ssl: + type: boolean + type: object + value.S3StorageAuth: + properties: + enable: + description: Deprecated, use IAM + type: boolean + password: + description: Deprecated, use IAM + type: string + username: + description: Deprecated, use IAM + type: string + type: object info: contact: email: hello@datarhei.com @@ -238,13 +682,23 @@ paths: description: OK schema: type: string - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/cluster.Error' summary: Core API address and login tags: - v1.0.0 + /v1/core/config: + get: + description: Core config of this node + operationId: cluster-1-core-config + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/config.Config' + summary: Core config + tags: + - v1.0.0 /v1/iam/user: post: consumes: @@ -448,6 +902,10 @@ paths: description: Not Found schema: $ref: '#/definitions/cluster.Error' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/cluster.Error' "508": description: Loop Detected schema: @@ -513,6 +971,10 @@ paths: description: Not Found schema: $ref: '#/definitions/cluster.Error' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/cluster.Error' "508": description: Loop Detected schema: