From b0ba7b0db9a03e011764b9036e6322b06e94374c Mon Sep 17 00:00:00 2001 From: Mahendra Paipuri Date: Sun, 5 Jul 2026 12:46:03 +0200 Subject: [PATCH 1/2] refactor: Misc improvements and fixes for API server * Apply CORS headers for middleware as well. Until now, CORS headers are applied only for the requests that pass thru middleware. So, when header checks fail in middleware, CORS headers are missing in responses and hence browsers do not treat those responses correctly. Now CORS headers are applied to the middleware as well * Generate OAPI spec 3 for swagger docs. Need to replace upstream modules for Swagger UI to work correctly in our case. Add health endpoint to Swagger spec. Move API swagger docs folder out of http folder into api folder to be more consistent * Fix health endpoint in deployment docs Closes #548 Signed-off-by: Mahendra Paipuri --- .golangci.yml | 7 + Makefile | 4 +- Makefile.common | 4 +- go.mod | 43 +- go.sum | 98 +- pkg/api/cli/cli.go | 54 + pkg/api/docs/docs.go | 2161 +++++++++++++++++++++++++++++ pkg/api/docs/swagger.json | 2139 ++++++++++++++++++++++++++++ pkg/api/docs/swagger.yaml | 1701 +++++++++++++++++++++++ pkg/api/http/docs/docs.go | 1874 ------------------------- pkg/api/http/docs/swagger.json | 1853 ------------------------- pkg/api/http/docs/swagger.yaml | 1547 --------------------- pkg/api/http/middleware.go | 8 +- pkg/api/http/middleware_test.go | 16 +- pkg/api/http/server.go | 110 +- pkg/api/models/models.go | 30 +- website/.gitignore | 3 + website/docs/deployments/guide.md | 2 +- website/docusaurus.config.ts | 4 +- website/yarn.lock | 13 +- 20 files changed, 6218 insertions(+), 5453 deletions(-) create mode 100644 pkg/api/docs/docs.go create mode 100644 pkg/api/docs/swagger.json create mode 100644 pkg/api/docs/swagger.yaml delete mode 100644 pkg/api/http/docs/docs.go delete mode 100644 pkg/api/http/docs/swagger.json delete mode 100644 pkg/api/http/docs/swagger.yaml diff --git a/.golangci.yml b/.golangci.yml index 5cb5bf8d..0b9981b7 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -58,6 +58,7 @@ linters: replace-allow-list: - github.com/grafana/pyroscope/ebpf - github.com/go-openapi/testify/v2/assert/yaml + - github.com/swaggo/http-swagger/v2 exclusions: generated: lax presets: @@ -79,6 +80,11 @@ linters: - unqueryvet # text: "(G705: XSS via taint analysis|G704: SSRF via taint analysis|G703: Path traversal via taint analysis|G702: Command injection via taint analysis|G306: Expect WriteFile permissions to be 0600 or less|G120: Parsing form data without limiting request body size can allow memory exhaustion (use http.MaxBytesReader)|net/http/httptest.NewRequest must not be called. use net/http/httptest.NewRequestWithContext)" path: scripts/mock_servers + - linters: + - exhaustive + - intrange + - nilnil + path: website paths: - third_party$ - builtin$ @@ -95,3 +101,4 @@ formatters: - third_party$ - builtin$ - examples$ + - website$ diff --git a/Makefile b/Makefile index b4532f91..b2cb2252 100644 --- a/Makefile +++ b/Makefile @@ -29,8 +29,8 @@ CGO_APPS ?= 0 RELEASE_BUILD ?= 0 # Swagger docs -SWAGGER_DIR ?= pkg/api/http -SWAGGER_MAIN ?= server.go +SWAGGER_DIR ?= pkg/api +SWAGGER_MAIN ?= cli/cli.go include Makefile.common diff --git a/Makefile.common b/Makefile.common index d6f5263f..e785e73d 100644 --- a/Makefile.common +++ b/Makefile.common @@ -219,7 +219,7 @@ common-build: promu swag bpf ifeq ($(RELEASE_BUILD), 0) ifeq ($(CGO_APPS), 1) @echo ">> updating swagger docs" - $(SWAG) init -d $(SWAGGER_DIR) -g $(SWAGGER_MAIN) -o $(SWAGGER_DIR)/docs --pd --quiet + $(SWAG) init -d $(SWAGGER_DIR) -g $(SWAGGER_MAIN) -o $(SWAGGER_DIR)/docs --pd --v3.1 --quiet $(SWAG) fmt -d $(SWAGGER_DIR) -g $(SWAGGER_MAIN) endif @echo ">> building test binaries" @@ -369,7 +369,7 @@ swag: $(SWAG) $(SWAG): ifeq ($(RELEASE_BUILD), 0) ifeq ($(CGO_APPS), 1) - $(GO) install github.com/swaggo/swag/cmd/swag@v1.16.3 + $(GO) install github.com/swaggo/swag/v2/cmd/swag@2.0.0-rc5 endif endif diff --git a/go.mod b/go.mod index 4a5b4cc4..fdb9734e 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/stmcginnis/gofish v0.22.0 github.com/stretchr/testify v1.11.1 github.com/swaggo/http-swagger/v2 v2.0.2 - github.com/swaggo/swag v1.16.6 + github.com/swaggo/swag/v2 v2.0.0-rc5 github.com/wneessen/go-fileperm v0.2.1 github.com/zeebo/xxh3 v1.1.0 golang.org/x/crypto v0.53.0 @@ -57,22 +57,21 @@ require ( github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/go-logfmt/logfmt v0.6.1 // indirect github.com/go-logr/logr v1.4.3 // indirect - github.com/go-openapi/jsonpointer v0.23.1 // indirect - github.com/go-openapi/jsonreference v0.21.5 // indirect - github.com/go-openapi/spec v0.22.4 // indirect - github.com/go-openapi/swag v0.25.5 // indirect - github.com/go-openapi/swag/cmdutils v0.25.5 // indirect - github.com/go-openapi/swag/conv v0.25.5 // indirect - github.com/go-openapi/swag/fileutils v0.25.5 // indirect - github.com/go-openapi/swag/jsonname v0.26.0 // indirect - github.com/go-openapi/swag/jsonutils v0.25.5 // indirect - github.com/go-openapi/swag/loading v0.25.5 // indirect - github.com/go-openapi/swag/mangling v0.25.5 // indirect - github.com/go-openapi/swag/netutils v0.25.5 // indirect - github.com/go-openapi/swag/stringutils v0.25.5 // indirect - github.com/go-openapi/swag/typeutils v0.25.5 // indirect - github.com/go-openapi/swag/yamlutils v0.25.5 // indirect - github.com/go-openapi/testify/v2 v2.5.1 // indirect + github.com/go-openapi/jsonpointer v0.24.0 // indirect + github.com/go-openapi/jsonreference v0.21.6 // indirect + github.com/go-openapi/spec v0.22.6 // indirect + github.com/go-openapi/swag v0.27.0 // indirect + github.com/go-openapi/swag/cmdutils v0.27.0 // indirect + github.com/go-openapi/swag/conv v0.27.0 // indirect + github.com/go-openapi/swag/fileutils v0.27.0 // indirect + github.com/go-openapi/swag/jsonname v0.26.1 // indirect + github.com/go-openapi/swag/jsonutils v0.27.0 // indirect + github.com/go-openapi/swag/loading v0.27.0 // indirect + github.com/go-openapi/swag/mangling v0.27.0 // indirect + github.com/go-openapi/swag/netutils v0.27.0 // indirect + github.com/go-openapi/swag/stringutils v0.27.0 // indirect + github.com/go-openapi/swag/typeutils v0.27.0 // indirect + github.com/go-openapi/swag/yamlutils v0.27.0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/golang-jwt/jwt/v5 v5.3.1 // indirect github.com/google/gnostic v0.7.1 // indirect @@ -104,21 +103,21 @@ require ( github.com/samber/lo v1.53.0 // indirect github.com/sirupsen/logrus v1.9.4 // indirect github.com/spf13/pflag v1.0.10 // indirect - github.com/swaggo/files/v2 v2.0.0 // indirect + github.com/sv-tools/openapi v0.4.0 // indirect + github.com/swaggo/files/v2 v2.0.3-0.20251121144713-2d164417a56b // indirect github.com/ulikunitz/xz v0.5.15 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/mod v0.36.0 // indirect - golang.org/x/net v0.55.0 // indirect + golang.org/x/net v0.56.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect golang.org/x/sync v0.21.0 // indirect golang.org/x/term v0.44.0 // indirect golang.org/x/text v0.38.0 // indirect golang.org/x/time v0.15.0 // indirect - golang.org/x/tools v0.45.0 // indirect + golang.org/x/tools v0.47.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect @@ -135,3 +134,5 @@ require ( replace github.com/grafana/pyroscope/ebpf => github.com/ceems-dev/pyroscope/ebpf v0.4.12-0.20260703124214-043c38d9bd02 replace github.com/go-openapi/testify/v2/assert/yaml => github.com/go-openapi/testify/enable/yaml/v2 v2.5.1 + +replace github.com/swaggo/http-swagger/v2 => github.com/ceems-dev/http-swagger/v2 v2.1.0 diff --git a/go.sum b/go.sum index 89433791..c747a68f 100644 --- a/go.sum +++ b/go.sum @@ -12,6 +12,8 @@ github.com/avvmoto/buf-readerat v0.0.0-20171115124131-a17c8cb89270 h1:JIxGEMs4E5 github.com/avvmoto/buf-readerat v0.0.0-20171115124131-a17c8cb89270/go.mod h1:2XtVRGCw/HthOLxU0Qw6o6jSJrcEoOb2OCCl8gQYvGw= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/ceems-dev/http-swagger/v2 v2.1.0 h1:h5Fldq/RIGfFG6MRGLGEtUeoK1nqwAHvpEqd2ElAq/c= +github.com/ceems-dev/http-swagger/v2 v2.1.0/go.mod h1:eyD8wOULz3WWBYrQdGqjjHaG8VvMwr1Rn2eDhiBGg1Y= github.com/ceems-dev/perf-utils v0.0.0-20250716113832-99ba71e88ef4 h1:mchfmIweUjhXxH/LER0/NvqzkjIhCINfmlBYJH5lJXw= github.com/ceems-dev/perf-utils v0.0.0-20250716113832-99ba71e88ef4/go.mod h1:6yFz1mwaJvVpwXLJW3oS82o2oe0oSVXuKA0gi9FBrSY= github.com/ceems-dev/pyroscope/ebpf v0.4.12-0.20260703124214-043c38d9bd02 h1:IEZCDXcMoJbNwpGCtm4dHepsVE1U2HGPVbJx5W7dY1k= @@ -46,42 +48,42 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-openapi/jsonpointer v0.23.1 h1:1HBACs7XIwR2RcmItfdSFlALhGbe6S92p0ry4d1GWg4= -github.com/go-openapi/jsonpointer v0.23.1/go.mod h1:iWRmZTrGn7XwYhtPt/fvdSFj1OfNBngqRT2UG3BxSqY= -github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe+pJyVWRdiE= -github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZLcfifd1Q+iKKOUxExw= -github.com/go-openapi/spec v0.22.4 h1:4pxGjipMKu0FzFiu/DPwN3CTBRlVM2yLf/YTWorYfDQ= -github.com/go-openapi/spec v0.22.4/go.mod h1:WQ6Ai0VPWMZgMT4XySjlRIE6GP1bGQOtEThn3gcWLtQ= -github.com/go-openapi/swag v0.25.5 h1:pNkwbUEeGwMtcgxDr+2GBPAk4kT+kJ+AaB+TMKAg+TU= -github.com/go-openapi/swag v0.25.5/go.mod h1:B3RT6l8q7X803JRxa2e59tHOiZlX1t8viplOcs9CwTA= -github.com/go-openapi/swag/cmdutils v0.25.5 h1:yh5hHrpgsw4NwM9KAEtaDTXILYzdXh/I8Whhx9hKj7c= -github.com/go-openapi/swag/cmdutils v0.25.5/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= -github.com/go-openapi/swag/conv v0.25.5 h1:wAXBYEXJjoKwE5+vc9YHhpQOFj2JYBMF2DUi+tGu97g= -github.com/go-openapi/swag/conv v0.25.5/go.mod h1:CuJ1eWvh1c4ORKx7unQnFGyvBbNlRKbnRyAvDvzWA4k= -github.com/go-openapi/swag/fileutils v0.25.5 h1:B6JTdOcs2c0dBIs9HnkyTW+5gC+8NIhVBUwERkFhMWk= -github.com/go-openapi/swag/fileutils v0.25.5/go.mod h1:V3cT9UdMQIaH4WiTrUc9EPtVA4txS0TOmRURmhGF4kc= -github.com/go-openapi/swag/jsonname v0.26.0 h1:gV1NFX9M8avo0YSpmWogqfQISigCmpaiNci8cGECU5w= -github.com/go-openapi/swag/jsonname v0.26.0/go.mod h1:urBBR8bZNoDYGr653ynhIx+gTeIz0ARZxHkAPktJK2M= -github.com/go-openapi/swag/jsonutils v0.25.5 h1:XUZF8awQr75MXeC+/iaw5usY/iM7nXPDwdG3Jbl9vYo= -github.com/go-openapi/swag/jsonutils v0.25.5/go.mod h1:48FXUaz8YsDAA9s5AnaUvAmry1UcLcNVWUjY42XkrN4= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5 h1:SX6sE4FrGb4sEnnxbFL/25yZBb5Hcg1inLeErd86Y1U= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5/go.mod h1:/2KvOTrKWjVA5Xli3DZWdMCZDzz3uV/T7bXwrKWPquo= -github.com/go-openapi/swag/loading v0.25.5 h1:odQ/umlIZ1ZVRteI6ckSrvP6e2w9UTF5qgNdemJHjuU= -github.com/go-openapi/swag/loading v0.25.5/go.mod h1:I8A8RaaQ4DApxhPSWLNYWh9NvmX2YKMoB9nwvv6oW6g= -github.com/go-openapi/swag/mangling v0.25.5 h1:hyrnvbQRS7vKePQPHHDso+k6CGn5ZBs5232UqWZmJZw= -github.com/go-openapi/swag/mangling v0.25.5/go.mod h1:6hadXM/o312N/h98RwByLg088U61TPGiltQn71Iw0NY= -github.com/go-openapi/swag/netutils v0.25.5 h1:LZq2Xc2QI8+7838elRAaPCeqJnHODfSyOa7ZGfxDKlU= -github.com/go-openapi/swag/netutils v0.25.5/go.mod h1:lHbtmj4m57APG/8H7ZcMMSWzNqIQcu0RFiXrPUara14= -github.com/go-openapi/swag/stringutils v0.25.5 h1:NVkoDOA8YBgtAR/zvCx5rhJKtZF3IzXcDdwOsYzrB6M= -github.com/go-openapi/swag/stringutils v0.25.5/go.mod h1:PKK8EZdu4QJq8iezt17HM8RXnLAzY7gW0O1KKarrZII= -github.com/go-openapi/swag/typeutils v0.25.5 h1:EFJ+PCga2HfHGdo8s8VJXEVbeXRCYwzzr9u4rJk7L7E= -github.com/go-openapi/swag/typeutils v0.25.5/go.mod h1:itmFmScAYE1bSD8C4rS0W+0InZUBrB2xSPbWt6DLGuc= -github.com/go-openapi/swag/yamlutils v0.25.5 h1:kASCIS+oIeoc55j28T4o8KwlV2S4ZLPT6G0iq2SSbVQ= -github.com/go-openapi/swag/yamlutils v0.25.5/go.mod h1:Gek1/SjjfbYvM+Iq4QGwa/2lEXde9n2j4a3wI3pNuOQ= -github.com/go-openapi/testify/enable/yaml/v2 v2.4.0 h1:7SgOMTvJkM8yWrQlU8Jm18VeDPuAvB/xWrdxFJkoFag= -github.com/go-openapi/testify/enable/yaml/v2 v2.4.0/go.mod h1:14iV8jyyQlinc9StD7w1xVPW3CO3q1Gj04Jy//Kw4VM= -github.com/go-openapi/testify/v2 v2.5.1 h1:TMdhCaw8fUNraVSf3Omoob1dO/AzBfhtFAPW0an6sBo= -github.com/go-openapi/testify/v2 v2.5.1/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw= +github.com/go-openapi/jsonpointer v0.24.0 h1:AA6mCjHYHmZ+1RU2Js089EaOK/iwXXNwQsTgnsTha2M= +github.com/go-openapi/jsonpointer v0.24.0/go.mod h1:Z3rw7dWu1p9IgitXCFamSlA5lmDiklEB6vkaxcNZW5Y= +github.com/go-openapi/jsonreference v0.21.6 h1:NZ5nGfnaM1n4I43Xjm1e5/M2GjOwQwndQz22uhxwD+Y= +github.com/go-openapi/jsonreference v0.21.6/go.mod h1:xzbgtQ3ZbWxvET3AxdzCJlJt6vkovbf+IfSPJjD0tUY= +github.com/go-openapi/spec v0.22.6 h1:Tyy1pLaNCM8GBCFLoGYLonjJi6zykqyLCjXLc19ZPic= +github.com/go-openapi/spec v0.22.6/go.mod h1:HZvTHat+iH0PALQRWhrqIHtU/PEqxqd89fu0MxGlMeM= +github.com/go-openapi/swag v0.27.0 h1:8ecSuZlh4NXc3GsmAOqECIYqDTApCWaMe3gO4gjJNEE= +github.com/go-openapi/swag v0.27.0/go.mod h1:Kkgz9Ht0+ul9/aVdFmc9xSyPzUwf/aFF5KiFPBXfSY0= +github.com/go-openapi/swag/cmdutils v0.27.0 h1:aIKiqhB29AaP+7xm8/CPg3uOpeHx2SUp6TvMpu/a31Y= +github.com/go-openapi/swag/cmdutils v0.27.0/go.mod h1:Sm1MVFMkF6guJJ+pQqHnQA3N0j9qALV3NxzDSv6bETM= +github.com/go-openapi/swag/conv v0.27.0 h1:EKOH4feXrvdo8DbSsXSAqRT8fz1epEnS5O2IfXUOzE8= +github.com/go-openapi/swag/conv v0.27.0/go.mod h1:pfiv0uKQTbaGApk8Zs/lZV3uSjmSpa2FO1y183YngN8= +github.com/go-openapi/swag/fileutils v0.27.0 h1:ib5jMUqGq5tY1EyO4inlrabsaeDAleFU+XD1FXQcgp8= +github.com/go-openapi/swag/fileutils v0.27.0/go.mod h1:VvJFZLTZS0AI854gEQz5tk7dBESdLjiNUMSZ/th2ry8= +github.com/go-openapi/swag/jsonname v0.26.1 h1:VReupaV6WxlAsCn0e4DUfgV6bPmINnPpyJDLqSfNPcE= +github.com/go-openapi/swag/jsonname v0.26.1/go.mod h1:OvdW6BoWoj33pTfi7x9vFrgmT+fk7aw0BRwvCE0YOuc= +github.com/go-openapi/swag/jsonutils v0.27.0 h1:VYtd9jEQYeU4j8q5vdn5KWotF4vKywhGdMBrALtAsfE= +github.com/go-openapi/swag/jsonutils v0.27.0/go.mod h1:U7pb8AGuwhok3RDicHeHwSG4L3PXSq6PAL98Aon632g= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.27.0 h1:+d7C7Ur/SsGg/UZ9G0JEovnfRqtMNZCJQGKc2h/ojoE= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.27.0/go.mod h1:mofwUWx70wvskwESqRJ//k/9kURmCgyJl5m5Ppoh5kY= +github.com/go-openapi/swag/loading v0.27.0 h1:s8DA9aPEdFH6OluHUYUn3DnIuoTdyWs9RwffXBUfyeI= +github.com/go-openapi/swag/loading v0.27.0/go.mod h1:VOz+Jg6UGGywcmRvYsI4fvtp+bd7NfioseGEPleYdA4= +github.com/go-openapi/swag/mangling v0.27.0 h1:rpPJuqQHa6z2pDiP3iIpXOyNXlSs9cQCxnJSAxzdfOc= +github.com/go-openapi/swag/mangling v0.27.0/go.mod h1:jtBE2+V+3pILxOR7Vgce+Cwp6A2PgZbvVqfNntbVs0w= +github.com/go-openapi/swag/netutils v0.27.0 h1:lEUG+hHvPvLggB3A8snFk0IRKNf9uC0YKc+7WYqvAF8= +github.com/go-openapi/swag/netutils v0.27.0/go.mod h1:J+WYyFMLtvtCGqa6jLv+YNUmIKI3ZRQRrvfNDMoQoEQ= +github.com/go-openapi/swag/stringutils v0.27.0 h1:Of7w/HljWsNZvuxsUAnw3n+hCOyI6HLJOxW2kQRAxio= +github.com/go-openapi/swag/stringutils v0.27.0/go.mod h1:lzRN95CxXmA03XcDWHLOb6nOMcxCqR5rGY0lOgsfRoM= +github.com/go-openapi/swag/typeutils v0.27.0 h1:aCf4MSGo8NLwZP8Q6t32DWLJSvl/WwNqgmEG+xJ6v2o= +github.com/go-openapi/swag/typeutils v0.27.0/go.mod h1:Srm0xFNRZ1Y+vCxJclo5qzx8aj+1pAKda/YfFPrG0dQ= +github.com/go-openapi/swag/yamlutils v0.27.0 h1:bQ6eAMil5X9tdcf7dMn4t15alzG6jddnrKPuKa/zxKM= +github.com/go-openapi/swag/yamlutils v0.27.0/go.mod h1:yRfIo7qqVkmJRQjX8exjA3AfcI8rH1KDNPsTparoCv4= +github.com/go-openapi/testify/enable/yaml/v2 v2.6.0 h1:gGHwAJ0R/5jU8BEGDbfRNR3hL68dAVi84WuOApp29B0= +github.com/go-openapi/testify/enable/yaml/v2 v2.6.0/go.mod h1:tY+St1SGq4NFl0QIqdTY4aEdbChAHxhyB77XQi9iJCo= +github.com/go-openapi/testify/v2 v2.6.0 h1:5PKH2HE7YJ/LuRPQGvSxBRlFXNQhSetBLlGAgUEu3ug= +github.com/go-openapi/testify/v2 v2.6.0/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw= github.com/go-quicktest/qt v1.101.1-0.20240301121107-c6c8733fa1e6 h1:teYtXy9B7y5lHTp8V9KPxpYRAVA7dozigQcMiBust1s= github.com/go-quicktest/qt v1.101.1-0.20240301121107-c6c8733fa1e6/go.mod h1:p4lGIVX+8Wa6ZPNDvqcxq36XpUDLh42FLetFU7odllI= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= @@ -211,12 +213,12 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/swaggo/files/v2 v2.0.0 h1:hmAt8Dkynw7Ssz46F6pn8ok6YmGZqHSVLZ+HQM7i0kw= -github.com/swaggo/files/v2 v2.0.0/go.mod h1:24kk2Y9NYEJ5lHuCra6iVwkMjIekMCaFq/0JQj66kyM= -github.com/swaggo/http-swagger/v2 v2.0.2 h1:FKCdLsl+sFCx60KFsyM0rDarwiUSZ8DqbfSyIKC9OBg= -github.com/swaggo/http-swagger/v2 v2.0.2/go.mod h1:r7/GBkAWIfK6E/OLnE8fXnviHiDeAHmgIyooa4xm3AQ= -github.com/swaggo/swag v1.16.6 h1:qBNcx53ZaX+M5dxVyTrgQ0PJ/ACK+NzhwcbieTt+9yI= -github.com/swaggo/swag v1.16.6/go.mod h1:ngP2etMK5a0P3QBizic5MEwpRmluJZPHjXcMoj4Xesg= +github.com/sv-tools/openapi v0.4.0 h1:UhD9DVnGox1hfTePNclpUzUFgos57FvzT2jmcAuTOJ4= +github.com/sv-tools/openapi v0.4.0/go.mod h1:kD/dG+KP0+Fom1r6nvcj/ORtLus8d8enXT6dyRZDirE= +github.com/swaggo/files/v2 v2.0.3-0.20251121144713-2d164417a56b h1:z2KeAJrxwN7S1KnPh+t3KlWjaMGmPYVUOXu4fIALCQo= +github.com/swaggo/files/v2 v2.0.3-0.20251121144713-2d164417a56b/go.mod h1:TVqetIzZsO9OhHX1Am9sRf9LdrFZqoK49N37KON/jr0= +github.com/swaggo/swag/v2 v2.0.0-rc5 h1:fK7d6ET9rrEsdB8IyuwXREWMcyQN3N7gawGFbbrjgHk= +github.com/swaggo/swag/v2 v2.0.0-rc5/go.mod h1:kCL8Fu4Zl8d5tB2Bgj96b8wRowwrwk175bZHXfuGVFI= github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY= github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/wneessen/go-fileperm v0.2.1 h1:VNZT41b8HJDY5zUw4TbwPtfU1DuxZ3lcGH4dXlaZKis= @@ -253,10 +255,10 @@ go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto= golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= -golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= -golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= -golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= -golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= +golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= +golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= +golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= +golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= @@ -270,8 +272,8 @@ golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE= golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= -golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= -golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= +golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q= +golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk= diff --git a/pkg/api/cli/cli.go b/pkg/api/cli/cli.go index 5e68461a..4e8c9701 100644 --- a/pkg/api/cli/cli.go +++ b/pkg/api/cli/cli.go @@ -83,6 +83,60 @@ func NewCEEMSServer() (*CEEMSServer, error) { } // Main is the entry point of the `ceems_server` command. +// +// @title CEEMS API +// @version 1.0 +// @description OpenAPI specification (OAS) for the CEEMS REST API. +// @description +// @description See the Interactive Docs to try CEEMS API methods without writing code, and get +// @description the complete schema of resources exposed by the API. +// @description +// @description If basic auth is enabled, all the endpoints require authentication. +// @description +// @description All the endpoints, except `health`, `swagger`, `debug` and `demo`, +// @description must send a user-agent header. +// @description +// @description A demo instance of CEEMS API server is provided for the users to test. This +// @description instance is running at `https://ceems-demo.myaddr.tools:6443` and it is the +// @description default server that will serve the requests originating from current OAS client. +// @description +// @description Some of the valid users for this demo instance are: +// @description - arnold +// @description - betty +// @description - edna +// @description - gazoo +// @description - wilma +// @description +// @description Every request must contain a `X-Grafana-User` header with one of the usernames +// @description above as the value to the header. This is how CEEMS API server recognise the user. +// @description +// @description Some of the valid projects for this demo instance are: +// @description - bedrock +// @description - cornerstone +// @description +// @description Demo instance have CORS enabled to allow cross-domain communication from the browser. +// @description All responses have a wildcard same-origin which makes them completely public and +// @description accessible to everyone, including any code on any site. +// @description +// @description To test admin resources, users can use `admin` as `X-Grafana-User`. +// @description +// @description Timestamps must be specified in milliseconds, unless otherwise specified. +// +// @contact.name Mahendra Paipuri +// @contact.url https://github.com/ceems-dev/ceems/issues +// @contact.email mahendra.paipuri@gmail.com +// +// @license.name GPL-3.0 license +// @license.url https://www.gnu.org/licenses/gpl-3.0.en.html +// +// @securityDefinitions.basic BasicAuth +// +// @servers.url https://ceems-demo.myaddr.tools:6443/api/v1 +// @servers.description Test CEEMS API server URL. +// +// @externalDocs.url https://ceems-dev.github.io/ceems/ +// +// @x-logo {"url": "https://raw.githubusercontent.com/ceems-dev/ceems/refs/heads/main/website/static/img/logo.png", "altText": "CEEMS logo"} func (b *CEEMSServer) Main() error { // CLI vars var ( diff --git a/pkg/api/docs/docs.go b/pkg/api/docs/docs.go new file mode 100644 index 00000000..a490b25a --- /dev/null +++ b/pkg/api/docs/docs.go @@ -0,0 +1,2161 @@ +// Code generated by swaggo/swag. DO NOT EDIT. + +package docs + +import "github.com/swaggo/swag/v2" + +const docTemplate = `{ + "schemes": {{ marshal .Schemes }}, + "components": { + "schemas": { + "http.Response-any": { + "properties": { + "data": { + "items": {}, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + }, + "error": { + "type": "string", + "x-nullable": true, + "x-omitempty": true + }, + "errorType": { + "$ref": "#/components/schemas/http.errorType" + }, + "status": { + "type": "string" + }, + "warnings": { + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + } + }, + "type": "object" + }, + "http.Response-models_Cluster": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/models.Cluster" + }, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + }, + "error": { + "type": "string", + "x-nullable": true, + "x-omitempty": true + }, + "errorType": { + "$ref": "#/components/schemas/http.errorType" + }, + "status": { + "type": "string" + }, + "warnings": { + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + } + }, + "type": "object" + }, + "http.Response-models_Project": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/models.Project" + }, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + }, + "error": { + "type": "string", + "x-nullable": true, + "x-omitempty": true + }, + "errorType": { + "$ref": "#/components/schemas/http.errorType" + }, + "status": { + "type": "string" + }, + "warnings": { + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + } + }, + "type": "object" + }, + "http.Response-models_Stat": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/models.Stat" + }, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + }, + "error": { + "type": "string", + "x-nullable": true, + "x-omitempty": true + }, + "errorType": { + "$ref": "#/components/schemas/http.errorType" + }, + "status": { + "type": "string" + }, + "warnings": { + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + } + }, + "type": "object" + }, + "http.Response-models_Unit": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/models.Unit" + }, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + }, + "error": { + "type": "string", + "x-nullable": true, + "x-omitempty": true + }, + "errorType": { + "$ref": "#/components/schemas/http.errorType" + }, + "status": { + "type": "string" + }, + "warnings": { + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + } + }, + "type": "object" + }, + "http.Response-models_Usage": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/models.Usage" + }, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + }, + "error": { + "type": "string", + "x-nullable": true, + "x-omitempty": true + }, + "errorType": { + "$ref": "#/components/schemas/http.errorType" + }, + "status": { + "type": "string" + }, + "warnings": { + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + } + }, + "type": "object" + }, + "http.Response-models_User": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/models.User" + }, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + }, + "error": { + "type": "string", + "x-nullable": true, + "x-omitempty": true + }, + "errorType": { + "$ref": "#/components/schemas/http.errorType" + }, + "status": { + "type": "string" + }, + "warnings": { + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + } + }, + "type": "object" + }, + "http.errorType": { + "enum": [ + "", + "unauthorized", + "forbidden", + "timeout", + "canceled", + "execution", + "bad_data", + "internal", + "unavailable", + "not_found", + "not_acceptable" + ], + "type": "string", + "x-nullable": true, + "x-omitempty": true + }, + "models.Cluster": { + "properties": { + "id": { + "type": "string" + }, + "manager": { + "type": "string" + } + }, + "type": "object" + }, + "models.Project": { + "properties": { + "cluster_id": { + "description": "Identifier of the resource manager that owns project. It is used to differentiate multiple clusters of same resource manager.", + "example": "slurm-0", + "type": "string" + }, + "name": { + "description": "Name of the project", + "example": "prj1", + "type": "string" + }, + "resource_manager": { + "description": "Name of the resource manager that owns project. Eg slurm, openstack, kubernetes, etc", + "example": "slurm", + "type": "string" + }, + "tags": { + "description": "List of meta data tags of the project", + "example": [ + "tag1", + "tag2" + ], + "items": {}, + "type": "array", + "uniqueItems": false + }, + "uid": { + "description": "Unique identifier of the project provided by cluster", + "example": "1000", + "type": "string" + }, + "users": { + "description": "List of users of the project", + "example": [ + "usr1", + "usr2" + ], + "items": {}, + "type": "array", + "uniqueItems": false + } + }, + "type": "object" + }, + "models.Stat": { + "properties": { + "cluster_id": { + "description": "Identifier of the resource manager that owns compute unit. It is used to differentiate multiple clusters of same resource manager.", + "example": "slurm-0", + "type": "string" + }, + "num_active_units": { + "description": "Number of active units that are in running state", + "example": 800, + "type": "integer" + }, + "num_inactive_units": { + "description": "Number of inactive units that are in terminated/cancelled/error state", + "example": 200, + "type": "integer" + }, + "num_projects": { + "description": "Number of projects", + "example": 200, + "type": "integer" + }, + "num_units": { + "description": "Number of active and terminated units", + "example": 1000, + "type": "integer" + }, + "num_users": { + "description": "Number of users", + "example": 500, + "type": "integer" + }, + "resource_manager": { + "description": "Name of the resource manager that owns project. Eg slurm, openstack, kubernetes, etc", + "example": "slurm", + "type": "string" + } + }, + "type": "object" + }, + "models.Unit": { + "properties": { + "allocation": { + "additionalProperties": { + "type": "number" + }, + "description": "Allocation map of unit. Only string and int64 values are supported in map", + "example": { + "cpus": 1, + "gpus": 1, + "mem": 10 + }, + "type": "object" + }, + "avg_cpu_mem_usage": { + "additionalProperties": { + "type": "number" + }, + "description": "Average CPU memory usage(s) during lifetime of unit", + "example": { + "global": 45.26 + }, + "type": "object" + }, + "avg_cpu_usage": { + "additionalProperties": { + "type": "number" + }, + "description": "Average CPU usage(s) during lifetime of unit", + "example": { + "global": 70.12 + }, + "type": "object" + }, + "avg_gpu_mem_usage": { + "additionalProperties": { + "type": "number" + }, + "description": "Average GPU memory usage(s) during lifetime of unit", + "example": { + "global": 45.26 + }, + "type": "object" + }, + "avg_gpu_usage": { + "additionalProperties": { + "type": "number" + }, + "description": "Average GPU usage(s) during lifetime of unit", + "example": { + "global": 70.12 + }, + "type": "object" + }, + "cluster_id": { + "description": "Identifier of the resource manager that owns compute unit. It is used to differentiate multiple clusters of same resource manager.", + "example": "slurm-0", + "type": "string" + }, + "created_at": { + "description": "Creation time", + "example": "2023-02-21T15:48:20+0100", + "type": "string" + }, + "created_at_ts": { + "description": "Creation timestamp", + "example": 1676990900000, + "type": "integer" + }, + "elapsed": { + "description": "Human readable total elapsed time string", + "example": "2-00:10:20", + "type": "string" + }, + "ended_at": { + "description": "End time", + "example": "Unknown", + "type": "string" + }, + "ended_at_ts": { + "description": "End timestamp", + "example": 0, + "type": "integer" + }, + "groupname": { + "description": "User group", + "example": "grp1", + "type": "string" + }, + "name": { + "description": "Name of compute unit", + "example": "my-slurm-job", + "type": "string" + }, + "project": { + "description": "Account in batch systems, Tenant in Openstack, Namespace in k8s", + "example": "prj1", + "type": "string" + }, + "resource_manager": { + "description": "Name of the resource manager that owns compute unit. Eg slurm, openstack, kubernetes, etc", + "example": "slurm", + "type": "string" + }, + "started_at": { + "description": "Start time", + "example": "2023-02-21T15:49:06+0100", + "type": "string" + }, + "started_at_ts": { + "description": "Start timestamp", + "example": 1676990946000, + "type": "integer" + }, + "state": { + "description": "Current state of unit", + "example": "RUNNING", + "type": "string" + }, + "tags": { + "additionalProperties": { + "type": "string" + }, + "description": "A map to store generic info. String and int64 are valid value types of map", + "example": { + "gid": "1000", + "uid": "1000", + "workdir": "/home/user" + }, + "type": "object" + }, + "total_cpu_emissions_gms": { + "additionalProperties": { + "type": "number" + }, + "description": "Total CPU emissions from source(s) in grams during lifetime of unit", + "example": { + "emaps_total": 3.09, + "owid_total": 5.22 + }, + "type": "object" + }, + "total_cpu_energy_usage_kwh": { + "additionalProperties": { + "type": "number" + }, + "description": "Total CPU energy usage(s) in kWh during lifetime of unit", + "example": { + "total": 0.73 + }, + "type": "object" + }, + "total_egress_stats": { + "additionalProperties": { + "type": "number" + }, + "description": "Total Outgress statistics of unit", + "example": { + "bytes_total": 454342323, + "packets_total": 23232323 + }, + "type": "object" + }, + "total_gpu_emissions_gms": { + "additionalProperties": { + "type": "number" + }, + "description": "Total GPU emissions from source(s) in grams during lifetime of unit", + "example": { + "emaps_total": 12.09, + "owid_total": 15.22 + }, + "type": "object" + }, + "total_gpu_energy_usage_kwh": { + "additionalProperties": { + "type": "number" + }, + "description": "Total GPU energy usage(s) in kWh during lifetime of unit", + "example": { + "total": 5.39 + }, + "type": "object" + }, + "total_ingress_stats": { + "additionalProperties": { + "type": "number" + }, + "description": "Total Ingress statistics of unit", + "example": { + "bytes_total": 8503405, + "packets_total": 43423 + }, + "type": "object" + }, + "total_io_read_stats": { + "additionalProperties": { + "type": "number" + }, + "description": "Total IO read statistics during lifetime of unit", + "example": { + "bytes_total": 245000000, + "requests_total": 49423 + }, + "type": "object" + }, + "total_io_write_stats": { + "additionalProperties": { + "type": "number" + }, + "description": "Total IO write statistics during lifetime of unit", + "example": { + "bytes_total": 12000000, + "requests_total": 13923 + }, + "type": "object" + }, + "total_time_seconds": { + "additionalProperties": { + "type": "number" + }, + "description": "Different types of times in seconds consumed by the unit. This map contains at minimum ` + "`" + `walltime` + "`" + `, ` + "`" + `alloc_cputime` + "`" + `, ` + "`" + `alloc_cpumemtime` + "`" + `, ` + "`" + `alloc_gputime` + "`" + ` and ` + "`" + `alloc_gpumem_time` + "`" + ` keys.", + "example": { + "alloc_cpumemtime": 1000, + "alloc_cputime": 100, + "alloc_gpumemtime": 100, + "alloc_gputime": 100, + "walltime": 100 + }, + "type": "object" + }, + "username": { + "description": "Username", + "example": "usr1", + "type": "string" + }, + "uuid": { + "description": "Unique identifier of unit. It can be Job ID for batch jobs, UUID for pods in k8s or VMs in Openstack", + "example": "193048", + "type": "string" + } + }, + "type": "object" + }, + "models.Usage": { + "properties": { + "avg_cpu_mem_usage": { + "additionalProperties": { + "type": "number" + }, + "description": "Average CPU memory usage(s) during lifetime of project", + "example": { + "global": 45.26 + }, + "type": "object" + }, + "avg_cpu_usage": { + "additionalProperties": { + "type": "number" + }, + "description": "Average CPU usage(s) during lifetime of project", + "example": { + "global": 70.12 + }, + "type": "object" + }, + "avg_gpu_mem_usage": { + "additionalProperties": { + "type": "number" + }, + "description": "Average GPU memory usage(s) during lifetime of project", + "example": { + "global": 45.26 + }, + "type": "object" + }, + "avg_gpu_usage": { + "additionalProperties": { + "type": "number" + }, + "description": "Average GPU usage(s) during lifetime of project", + "example": { + "global": 70.12 + }, + "type": "object" + }, + "cluster_id": { + "description": "Identifier of the resource manager that owns compute unit. It is used to differentiate multiple clusters of same resource manager.", + "example": "slurm-0", + "type": "string" + }, + "groupname": { + "description": "User group", + "example": "grp1", + "type": "string" + }, + "num_units": { + "description": "Number of consumed units", + "example": 145, + "type": "integer" + }, + "project": { + "description": "Account in batch systems, Tenant in Openstack, Namespace in k8s", + "example": "prj1", + "type": "string" + }, + "resource_manager": { + "description": "Name of the resource manager that owns project. Eg slurm, openstack, kubernetes, etc", + "example": "slurm", + "type": "string" + }, + "total_cpu_emissions_gms": { + "additionalProperties": { + "type": "number" + }, + "description": "Total CPU emissions from source(s) in grams during lifetime of project", + "example": { + "emaps_total": 3.09, + "owid_total": 5.22 + }, + "type": "object" + }, + "total_cpu_energy_usage_kwh": { + "additionalProperties": { + "type": "number" + }, + "description": "Total CPU energy usage(s) in kWh during lifetime of project", + "example": { + "total": 0.73 + }, + "type": "object" + }, + "total_egress_stats": { + "additionalProperties": { + "type": "number" + }, + "description": "Total Egress statistics of unit", + "example": { + "bytes_total": 454342323, + "packets_total": 23232323 + }, + "type": "object" + }, + "total_gpu_emissions_gms": { + "additionalProperties": { + "type": "number" + }, + "description": "Total GPU emissions from source(s) in grams during lifetime of project", + "example": { + "emaps_total": 12.09, + "owid_total": 15.22 + }, + "type": "object" + }, + "total_gpu_energy_usage_kwh": { + "additionalProperties": { + "type": "number" + }, + "description": "Total GPU energy usage(s) in kWh during lifetime of project", + "example": { + "total": 5.39 + }, + "type": "object" + }, + "total_ingress_stats": { + "additionalProperties": { + "type": "number" + }, + "description": "Total Ingress statistics of unit", + "example": { + "bytes_total": 8503405, + "packets_total": 43423 + }, + "type": "object" + }, + "total_io_read_stats": { + "additionalProperties": { + "type": "number" + }, + "description": "Total IO read statistics during lifetime of unit", + "example": { + "bytes_total": 245000000, + "requests_total": 49423 + }, + "type": "object" + }, + "total_io_write_stats": { + "additionalProperties": { + "type": "number" + }, + "description": "Total IO write statistics during lifetime of unit", + "example": { + "bytes_total": 12000000, + "requests_total": 13923 + }, + "type": "object" + }, + "total_time_seconds": { + "additionalProperties": { + "type": "number" + }, + "description": "Different times in seconds consumed by the unit. This map must contain ` + "`" + `walltime` + "`" + `, ` + "`" + `alloc_cputime` + "`" + `, ` + "`" + `alloc_cpumemtime` + "`" + `, ` + "`" + `alloc_gputime` + "`" + ` and ` + "`" + `alloc_gpumem_time` + "`" + ` keys.", + "example": { + "alloc_cpumemtime": 1000, + "alloc_cputime": 100, + "alloc_gpumemtime": 100, + "alloc_gputime": 100, + "walltime": 100 + }, + "type": "object" + }, + "username": { + "description": "Username", + "example": "usr1", + "type": "string" + } + }, + "type": "object" + }, + "models.User": { + "properties": { + "cluster_id": { + "description": "Identifier of the resource manager that owns user. It is used to differentiate multiple clusters of same resource manager.", + "example": "slurm-0", + "type": "string" + }, + "name": { + "description": "Name of the user", + "example": "usr1", + "type": "string" + }, + "projects": { + "description": "List of projects of the user", + "example": [ + "prj1", + "prj2" + ], + "items": {}, + "type": "array", + "uniqueItems": false + }, + "resource_manager": { + "description": "Name of the resource manager that owns user. Eg slurm, openstack, kubernetes, etc", + "example": "slurm", + "type": "string" + }, + "tags": { + "description": "List of meta data tags of the user", + "example": [ + "tag1", + "tag2" + ], + "items": {}, + "type": "array", + "uniqueItems": false + }, + "uid": { + "description": "Unique identifier of the user provided by cluster", + "example": "1000", + "type": "string" + } + }, + "type": "object" + } + }, + "securitySchemes": { + "BasicAuth": { + "scheme": "basic", + "type": "http" + } + } + }, + "info": { + "contact": { + "email": "mahendra.paipuri@gmail.com", + "name": "Mahendra Paipuri", + "url": "https://github.com/ceems-dev/ceems/issues" + }, + "description": "{{escape .Description}}", + "license": { + "name": "GPL-3.0 license", + "url": "https://www.gnu.org/licenses/gpl-3.0.en.html" + }, + "title": "{{.Title}}", + "version": "{{.Version}}", + "x-logo": { + "altText": "CEEMS logo", + "url": "https://raw.githubusercontent.com/ceems-dev/ceems/refs/heads/main/website/static/img/logo.png" + } + }, + "externalDocs": { + "description": "", + "url": "https://ceems-dev.github.io/ceems/" + }, + "paths": { + "/clusters/admin": { + "get": { + "description": "This endpoint will list all the cluster IDs in the CEEMS DB. The\ncurrent user is always identified by the header ` + "`" + `X-Grafana-User` + "`" + ` in\nthe request.\n\nThis will list all the cluster IDs in the DB. This is primarily\nused to verify the CEEMS load balancer's backend IDs that should match\nwith cluster IDs.\n", + "parameters": [ + { + "description": "Current user name", + "in": "header", + "name": "X-Grafana-User", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-models_Cluster" + } + } + }, + "description": "OK" + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Forbidden" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Internal Server Error" + } + }, + "security": [ + { + "BasicAuth": [] + } + ], + "summary": "List clusters", + "tags": [ + "clusters" + ] + } + }, + "/demo/{resource}": { + "get": { + "description": "This endpoint returns sample response for units and usage models. This\nendpoint do not require the setting of ` + "`" + `X-Grafana-User` + "`" + ` header as it\nonly returns mock data for each request. This can be used to introspect\nthe response models for different resources.\n\nThe endpoint requires a path parameter ` + "`" + `resource` + "`" + ` which takes either:\n- ` + "`" + `units` + "`" + ` which returns a mock units response\n- ` + "`" + `usage` + "`" + ` which returns a mock usage response.\n\nThe mock data is generated randomly for each request and there is\nno guarantee that the data has logical sense.", + "parameters": [ + { + "description": "Whether to return mock units or usage data", + "in": "path", + "name": "resource", + "required": true, + "schema": { + "enum": [ + "units", + "usage" + ], + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/http.Response-models_Unit" + }, + { + "$ref": "#/components/schemas/http.Response-models_Usage" + } + ] + } + } + }, + "description": "OK" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Demo Units/Usage endpoints", + "tags": [ + "demo" + ] + } + }, + "/health": { + "get": { + "description": "This health endpoint can be used to check on the health of the API server\nin containerised and Kubernetes environments.\n\nThis endpoint does not need any user header. However, if basic auth\nis enabled, authentication header must be provided to get status.", + "responses": { + "200": { + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "description": "OK" + }, + "401": { + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized" + }, + "503": { + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "description": "KO" + } + }, + "security": [ + { + "BasicAuth": [] + } + ], + "servers": [ + { + "description": "Test CEEMS API server URL for health, swagger and debug endpoints only.", + "url": "https://ceems-demo.myaddr.tools:6443" + } + ], + "summary": "Health check endpoint for API server.", + "tags": [ + "health" + ] + } + }, + "/projects": { + "get": { + "description": "This endpoint will show details of the queried project of current user. The\ncurrent user is always identified by the header ` + "`" + `X-Grafana-User` + "`" + ` in\nthe request.\n\nThe details include list of users in that project. If current user\nattempts to query a project that they are not part of, empty response\nwill be returned\n", + "parameters": [ + { + "description": "Current user name", + "in": "header", + "name": "X-Grafana-User", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Project", + "in": "query", + "name": "project", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "Cluster ID", + "in": "query", + "name": "cluster_id", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-models_Project" + } + } + }, + "description": "OK" + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Internal Server Error" + } + }, + "security": [ + { + "BasicAuth": [] + } + ], + "summary": "Show project details", + "tags": [ + "projects" + ] + } + }, + "/projects/admin": { + "get": { + "description": "This endpoint will show details of the queried project. The\ncurrent user is always identified by the header ` + "`" + `X-Grafana-User` + "`" + ` in\nthe request.\n\nThe user who is making the request must be in the list of admin users\nconfigured for the server.\n\nThe details include list of users in that project. If current user\nattempts to query a project that they are not part of, empty response\nwill be returned\n", + "parameters": [ + { + "description": "Current user name", + "in": "header", + "name": "X-Grafana-User", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Project", + "in": "query", + "name": "project", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "Cluster ID", + "in": "query", + "name": "cluster_id", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-models_Project" + } + } + }, + "description": "OK" + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Forbidden" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Internal Server Error" + } + }, + "security": [ + { + "BasicAuth": [] + } + ], + "summary": "Admin endpoint to fetch project details", + "tags": [ + "projects" + ] + } + }, + "/stats/{mode}/admin": { + "get": { + "description": "This admin endpoint will return the quick stats of _queried_ cluster. The\ncurrent user is always identified by the header ` + "`" + `X-Grafana-User` + "`" + ` in\nthe request.\n\nThe user who is making the request must be in the list of admin users\nconfigured for the server.\n\nA path parameter ` + "`" + `mode` + "`" + ` is required to return the kind of usage statistics.\nCurrently, two modes of statistics are supported:\n- ` + "`" + `current` + "`" + `: In this mode the usage between two time periods is returned\nbased on ` + "`" + `from` + "`" + ` and ` + "`" + `to` + "`" + ` query parameters.\n- ` + "`" + `global` + "`" + `: In this mode the _total_ usage statistics are returned. For\ninstance, if the retention period of the DB is set to 2 years, usage\nstatistics of last 2 years will be returned.\n\nThe statistics include current number of active users, projects, jobs, _etc_.\n\nIf ` + "`" + `to` + "`" + ` query parameter is not provided, current time will be used. If ` + "`" + `from` + "`" + `\nquery parameter is not used, a default query window of 24 hours will be used.\nIt means if ` + "`" + `to` + "`" + ` is provided, ` + "`" + `from` + "`" + ` will be calculated as ` + "`" + `to` + "`" + ` - 24hrs.\n", + "parameters": [ + { + "description": "Current user name", + "in": "header", + "name": "X-Grafana-User", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Whether to get quick stats within a period or global", + "in": "path", + "name": "mode", + "required": true, + "schema": { + "enum": [ + "current", + "global" + ], + "type": "string" + } + }, + { + "description": "cluster ID", + "in": "query", + "name": "cluster_id", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "From timestamp", + "in": "query", + "name": "from", + "schema": { + "type": "string" + } + }, + { + "description": "To timestamp", + "in": "query", + "name": "to", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-models_Stat" + } + } + }, + "description": "OK" + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Forbidden" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Internal Server Error" + } + }, + "security": [ + { + "BasicAuth": [] + } + ], + "summary": "Admin Stats", + "tags": [ + "stats" + ] + } + }, + "/units": { + "get": { + "description": "This user endpoint will fetch compute units of the current user. The\ncurrent user is always identified by the header ` + "`" + `X-Grafana-User` + "`" + ` in\nthe request.\n\nIf multiple query parameters are passed, for instance, ` + "`" + `?uuid=\u003cuuid\u003e\u0026project=\u003cproject\u003e` + "`" + `,\nthe intersection of query parameters are used to fetch compute units rather than\nthe union. That means if the compute unit's ` + "`" + `uuid` + "`" + ` does not belong to the queried\nproject, null response will be returned.\n\nIn order to return the running compute units as well, use the query parameter ` + "`" + `running` + "`" + `.\n\nIf ` + "`" + `to` + "`" + ` query parameter is not provided, current time will be used. If ` + "`" + `from` + "`" + `\nquery parameter is not used, a default query window of 24 hours will be used.\nIt means if ` + "`" + `to` + "`" + ` is provided, ` + "`" + `from` + "`" + ` will be calculated as ` + "`" + `to` + "`" + ` - 24hrs. If query\nparameter ` + "`" + `timezone` + "`" + ` is provided, the unit's created, start and end time strings\nwill be presented in that time zone.\n\nTo limit the number of fields in the response, use ` + "`" + `field` + "`" + ` query parameter. By default, all\nfields will be included in the response if they are _non-empty_.", + "parameters": [ + { + "description": "Current user name", + "in": "header", + "name": "X-Grafana-User", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Cluster ID", + "in": "query", + "name": "cluster_id", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "Unit UUID", + "in": "query", + "name": "uuid", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "Project", + "in": "query", + "name": "project", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "Whether to fetch running units", + "in": "query", + "name": "running", + "schema": { + "type": "boolean" + } + }, + { + "description": "From timestamp", + "in": "query", + "name": "from", + "schema": { + "type": "string" + } + }, + { + "description": "To timestamp", + "in": "query", + "name": "to", + "schema": { + "type": "string" + } + }, + { + "description": "Time zone in IANA format", + "in": "query", + "name": "timezone", + "schema": { + "type": "string" + } + }, + { + "description": "Fields to return in response", + "in": "query", + "name": "field", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-models_Unit" + } + } + }, + "description": "OK" + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Forbidden" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Internal Server Error" + } + }, + "security": [ + { + "BasicAuth": [] + } + ], + "summary": "User endpoint for fetching compute units", + "tags": [ + "units" + ] + } + }, + "/units/admin": { + "get": { + "description": "This admin endpoint will fetch compute units of _any_ user, compute unit and/or project. The\ncurrent user is always identified by the header ` + "`" + `X-Grafana-User` + "`" + ` in\nthe request.\n\nThe user who is making the request must be in the list of admin users\nconfigured for the server.\n\nIf multiple query parameters are passed, for instance, ` + "`" + `?uuid=\u003cuuid\u003e\u0026user=\u003cuser\u003e` + "`" + `,\nthe intersection of query parameters are used to fetch compute units rather than\nthe union. That means if the compute unit's ` + "`" + `uuid` + "`" + ` does not belong to the queried\nuser, null response will be returned.\n\nIn order to return the running compute units as well, use the query parameter ` + "`" + `running` + "`" + `.\n\nIf ` + "`" + `to` + "`" + ` query parameter is not provided, current time will be used. If ` + "`" + `from` + "`" + `\nquery parameter is not used, a default query window of 24 hours will be used.\nIt means if ` + "`" + `to` + "`" + ` is provided, ` + "`" + `from` + "`" + ` will be calculated as ` + "`" + `to` + "`" + ` - 24hrs. If query\nparameter ` + "`" + `timezone` + "`" + ` is provided, the unit's created, start and end time strings\nwill be presented in that time zone.\n\nTo limit the number of fields in the response, use ` + "`" + `field` + "`" + ` query parameter. By default, all\nfields will be included in the response if they are _non-empty_.", + "parameters": [ + { + "description": "Current user name", + "in": "header", + "name": "X-Grafana-User", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Cluster ID", + "in": "query", + "name": "cluster_id", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "Unit UUID", + "in": "query", + "name": "uuid", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "Project", + "in": "query", + "name": "project", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "User name", + "in": "query", + "name": "user", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "Whether to fetch running units", + "in": "query", + "name": "running", + "schema": { + "type": "boolean" + } + }, + { + "description": "From timestamp", + "in": "query", + "name": "from", + "schema": { + "type": "string" + } + }, + { + "description": "To timestamp", + "in": "query", + "name": "to", + "schema": { + "type": "string" + } + }, + { + "description": "Time zone in IANA format", + "in": "query", + "name": "timezone", + "schema": { + "type": "string" + } + }, + { + "description": "Fields to return in response", + "in": "query", + "name": "field", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-models_Unit" + } + } + }, + "description": "OK" + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Forbidden" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Internal Server Error" + } + }, + "security": [ + { + "BasicAuth": [] + } + ], + "summary": "Admin endpoint for fetching compute units.", + "tags": [ + "units" + ] + } + }, + "/units/verify": { + "get": { + "description": "This endpoint will check if the current user is the owner of the\nqueried UUIDs. The current user is always identified by the header ` + "`" + `X-Grafana-User` + "`" + ` in\nthe request.\n\nA response of 200 means that the current user is the owner of the queried UUIDs.\nAny other response code should be treated as the current user not being the owner\nof the queried units.\n\nThe ownership check passes if any of the following conditions are ` + "`" + `true` + "`" + `:\n- If the current user is the _direct_ owner of the compute unit.\n- If the current user belongs to the same account/project/namespace as\nthe compute unit. This means the users belonging to the same project can\naccess each others compute units.\n- If the current user has admin role\n\nThe above checks must pass for **all** the queried units.\nIf the check does not pass for at least one queried unit, a response 403 will be\nreturned.\n\nAny 500 response codes should be treated as failed check as well.", + "parameters": [ + { + "description": "Current user name", + "in": "header", + "name": "X-Grafana-User", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Unit UUID", + "in": "query", + "name": "uuid", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "Cluster ID", + "in": "query", + "name": "cluster_id", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "OK" + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Forbidden" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Internal Server Error" + } + }, + "security": [ + { + "BasicAuth": [] + } + ], + "summary": "Verify unit ownership", + "tags": [ + "units" + ] + } + }, + "/usage/{mode}": { + "get": { + "description": "This endpoint will return the usage statistics current user. The\ncurrent user is always identified by the header ` + "`" + `X-Grafana-User` + "`" + ` in\nthe request.\n\nA path parameter ` + "`" + `mode` + "`" + ` is required to return the kind of usage statistics.\nCurrently, two modes of statistics are supported:\n- ` + "`" + `current` + "`" + `: In this mode the usage between two time periods is returned\nbased on ` + "`" + `from` + "`" + ` and ` + "`" + `to` + "`" + ` query parameters.\n- ` + "`" + `global` + "`" + `: In this mode the _total_ usage statistics are returned. For\ninstance, if the retention period of the DB is set to 2 years, usage\nstatistics of last 2 years will be returned.\n\nThe statistics can be limited to certain projects by passing ` + "`" + `project` + "`" + ` query,\nparameter.\n\nIf ` + "`" + `to` + "`" + ` query parameter is not provided, current time will be used. If ` + "`" + `from` + "`" + `\nquery parameter is not used, a default query window of 24 hours will be used.\nIt means if ` + "`" + `to` + "`" + ` is provided, ` + "`" + `from` + "`" + ` will be calculated as ` + "`" + `to` + "`" + ` - 24hrs.\n\nTo limit the number of fields in the response, use ` + "`" + `field` + "`" + ` query parameter. By default, all\nfields will be included in the response if they are _non-empty_.\n\nThe ` + "`" + `current` + "`" + ` usage mode can be slow query depending the requested\nwindow interval. This is mostly due to the fact that the CEEMS DB\nuses custom JSON types to store metric data and usage statistics\nneeds to aggregate metrics over these JSON types using custom aggregate\nfunctions which can be slow.\n\nTherefore the query results are cached for 15 min to avoid load on server.\nURL string is used as the cache key. Thus, the query parameters\n` + "`" + `from` + "`" + ` and ` + "`" + `to` + "`" + ` are rounded to the nearest timestamp that are\nmultiple of 900 sec (15 min). The first query will make a DB query and\ncache results and subsequent queries, for a given user and same URL\nquery parameters, will return the same cached result until the cache\nis invalidated after 15 min.", + "parameters": [ + { + "description": "Current user name", + "in": "header", + "name": "X-Grafana-User", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Whether to get usage stats within a period or global", + "in": "path", + "name": "mode", + "required": true, + "schema": { + "enum": [ + "current", + "global" + ], + "type": "string" + } + }, + { + "description": "cluster ID", + "in": "query", + "name": "cluster_id", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "Project", + "in": "query", + "name": "project", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "From timestamp", + "in": "query", + "name": "from", + "schema": { + "type": "string" + } + }, + { + "description": "To timestamp", + "in": "query", + "name": "to", + "schema": { + "type": "string" + } + }, + { + "description": "Fields to return in response", + "in": "query", + "name": "field", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-models_Usage" + } + } + }, + "description": "OK" + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Internal Server Error" + } + }, + "security": [ + { + "BasicAuth": [] + } + ], + "summary": "Usage statistics", + "tags": [ + "usage" + ] + } + }, + "/usage/{mode}/admin": { + "get": { + "description": "This admin endpoint will return the usage statistics of _queried_ user. The\ncurrent user is always identified by the header ` + "`" + `X-Grafana-User` + "`" + ` in\nthe request.\n\nThe user who is making the request must be in the list of admin users\nconfigured for the server.\n\nA path parameter ` + "`" + `mode` + "`" + ` is required to return the kind of usage statistics.\nCurrently, two modes of statistics are supported:\n- ` + "`" + `current` + "`" + `: In this mode the usage between two time periods is returned\nbased on ` + "`" + `from` + "`" + ` and ` + "`" + `to` + "`" + ` query parameters.\n- ` + "`" + `global` + "`" + `: In this mode the _total_ usage statistics are returned. For\ninstance, if the retention period of the DB is set to 2 years, usage\nstatistics of last 2 years will be returned.\n\nThe statistics can be limited to certain projects by passing ` + "`" + `project` + "`" + ` query,\nparameter.\n\nIf ` + "`" + `to` + "`" + ` query parameter is not provided, current time will be used. If ` + "`" + `from` + "`" + `\nquery parameter is not used, a default query window of 24 hours will be used.\nIt means if ` + "`" + `to` + "`" + ` is provided, ` + "`" + `from` + "`" + ` will be calculated as ` + "`" + `to` + "`" + ` - 24hrs.\n\nTo limit the number of fields in the response, use ` + "`" + `field` + "`" + ` query parameter. By default, all\nfields will be included in the response if they are _non-empty_.\n\nThe ` + "`" + `current` + "`" + ` usage mode can be slow query depending the requested\nwindow interval. This is mostly due to the fact that the CEEMS DB\nuses custom JSON types to store metric data and usage statistics\nneeds to aggregate metrics over these JSON types using custom aggregate\nfunctions which can be slow.\n\nTherefore the query results are cached for 15 min to avoid load on server.\nURL string is used as the cache key. Thus, the query parameters\n` + "`" + `from` + "`" + ` and ` + "`" + `to` + "`" + ` are rounded to the nearest timestamp that are\nmultiple of 900 sec (15 min). The first query will make a DB query and\ncache results and subsequent queries, for a given user and same URL\nquery parameters, will return the same cached result until the cache\nis invalidated after 15 min.", + "parameters": [ + { + "description": "Current user name", + "in": "header", + "name": "X-Grafana-User", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Whether to get usage stats within a period or global", + "in": "path", + "name": "mode", + "required": true, + "schema": { + "enum": [ + "current", + "global" + ], + "type": "string" + } + }, + { + "description": "cluster ID", + "in": "query", + "name": "cluster_id", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "Project", + "in": "query", + "name": "project", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Username", + "in": "query", + "name": "user", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "From timestamp", + "in": "query", + "name": "from", + "schema": { + "type": "string" + } + }, + { + "description": "To timestamp", + "in": "query", + "name": "to", + "schema": { + "type": "string" + } + }, + { + "description": "Fields to return in response", + "in": "query", + "name": "field", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-models_Usage" + } + } + }, + "description": "OK" + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Forbidden" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Internal Server Error" + } + }, + "security": [ + { + "BasicAuth": [] + } + ], + "summary": "Admin Usage statistics", + "tags": [ + "usage" + ] + } + }, + "/users": { + "get": { + "description": "This endpoint will show details of the current user. The\ncurrent user is always identified by the header ` + "`" + `X-Grafana-User` + "`" + ` in\nthe request.\n\nThe details include list of projects that user is currently a part of.\n", + "parameters": [ + { + "description": "Current user name", + "in": "header", + "name": "X-Grafana-User", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Cluster ID", + "in": "query", + "name": "cluster_id", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-models_User" + } + } + }, + "description": "OK" + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Internal Server Error" + } + }, + "security": [ + { + "BasicAuth": [] + } + ], + "summary": "Show user details", + "tags": [ + "users" + ] + } + }, + "/users/admin": { + "get": { + "description": "This endpoint will show details of the queried user(s). The\ncurrent user is always identified by the header ` + "`" + `X-Grafana-User` + "`" + ` in\nthe request.\n\nThe user who is making the request must be in the list of admin users\nconfigured for the server.\n\nWhen the query parameter ` + "`" + `user` + "`" + ` is empty, all users will be returned\nin the response.\n\nThe details include list of projects that user is currently a part of.\n\nWhen query parameter ` + "`" + `role` + "`" + ` is set to ` + "`" + `admin` + "`" + `, only admin users will\nwill be returned. The ` + "`" + `tags` + "`" + ` values indicates the source of admin user.\n", + "parameters": [ + { + "description": "Current user name", + "in": "header", + "name": "X-Grafana-User", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "User name", + "in": "query", + "name": "user", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "Cluster ID", + "in": "query", + "name": "cluster_id", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "User role", + "in": "query", + "name": "role", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-models_User" + } + } + }, + "description": "OK" + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Forbidden" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Internal Server Error" + } + }, + "security": [ + { + "BasicAuth": [] + } + ], + "summary": "Admin endpoint for fetching user details of _any_ user.", + "tags": [ + "users" + ] + } + } + }, + "openapi": "3.1.0", + "servers": [ + { + "description": "Test CEEMS API server URL.", + "url": "https://ceems-demo.myaddr.tools:6443/api/v1" + } + ] +}` + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = &swag.Spec{ + Version: "1.0", + Title: "CEEMS API", + Description: "OpenAPI specification (OAS) for the CEEMS REST API.\n\nSee the Interactive Docs to try CEEMS API methods without writing code, and get\nthe complete schema of resources exposed by the API.\n\nIf basic auth is enabled, all the endpoints require authentication.\n\nAll the endpoints, except `health`, `swagger`, `debug` and `demo`,\nmust send a user-agent header.\n\nA demo instance of CEEMS API server is provided for the users to test. This\ninstance is running at `https://ceems-demo.myaddr.tools:6443` and it is the\ndefault server that will serve the requests originating from current OAS client.\n\nSome of the valid users for this demo instance are:\n- arnold\n- betty\n- edna\n- gazoo\n- wilma\n\nEvery request must contain a `X-Grafana-User` header with one of the usernames\nabove as the value to the header. This is how CEEMS API server recognise the user.\n\nSome of the valid projects for this demo instance are:\n- bedrock\n- cornerstone\n\nDemo instance have CORS enabled to allow cross-domain communication from the browser.\nAll responses have a wildcard same-origin which makes them completely public and\naccessible to everyone, including any code on any site.\n\nTo test admin resources, users can use `admin` as `X-Grafana-User`.\n\nTimestamps must be specified in milliseconds, unless otherwise specified.", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, + LeftDelim: "{{", + RightDelim: "}}", +} + +func init() { + swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) +} diff --git a/pkg/api/docs/swagger.json b/pkg/api/docs/swagger.json new file mode 100644 index 00000000..3e878720 --- /dev/null +++ b/pkg/api/docs/swagger.json @@ -0,0 +1,2139 @@ +{ + "components": { + "schemas": { + "http.Response-any": { + "properties": { + "data": { + "items": {}, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + }, + "error": { + "type": "string", + "x-nullable": true, + "x-omitempty": true + }, + "errorType": { + "$ref": "#/components/schemas/http.errorType" + }, + "status": { + "type": "string" + }, + "warnings": { + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + } + }, + "type": "object" + }, + "http.Response-models_Cluster": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/models.Cluster" + }, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + }, + "error": { + "type": "string", + "x-nullable": true, + "x-omitempty": true + }, + "errorType": { + "$ref": "#/components/schemas/http.errorType" + }, + "status": { + "type": "string" + }, + "warnings": { + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + } + }, + "type": "object" + }, + "http.Response-models_Project": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/models.Project" + }, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + }, + "error": { + "type": "string", + "x-nullable": true, + "x-omitempty": true + }, + "errorType": { + "$ref": "#/components/schemas/http.errorType" + }, + "status": { + "type": "string" + }, + "warnings": { + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + } + }, + "type": "object" + }, + "http.Response-models_Stat": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/models.Stat" + }, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + }, + "error": { + "type": "string", + "x-nullable": true, + "x-omitempty": true + }, + "errorType": { + "$ref": "#/components/schemas/http.errorType" + }, + "status": { + "type": "string" + }, + "warnings": { + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + } + }, + "type": "object" + }, + "http.Response-models_Unit": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/models.Unit" + }, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + }, + "error": { + "type": "string", + "x-nullable": true, + "x-omitempty": true + }, + "errorType": { + "$ref": "#/components/schemas/http.errorType" + }, + "status": { + "type": "string" + }, + "warnings": { + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + } + }, + "type": "object" + }, + "http.Response-models_Usage": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/models.Usage" + }, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + }, + "error": { + "type": "string", + "x-nullable": true, + "x-omitempty": true + }, + "errorType": { + "$ref": "#/components/schemas/http.errorType" + }, + "status": { + "type": "string" + }, + "warnings": { + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + } + }, + "type": "object" + }, + "http.Response-models_User": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/models.User" + }, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + }, + "error": { + "type": "string", + "x-nullable": true, + "x-omitempty": true + }, + "errorType": { + "$ref": "#/components/schemas/http.errorType" + }, + "status": { + "type": "string" + }, + "warnings": { + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": false, + "x-nullable": true, + "x-omitempty": true + } + }, + "type": "object" + }, + "http.errorType": { + "enum": [ + "", + "unauthorized", + "forbidden", + "timeout", + "canceled", + "execution", + "bad_data", + "internal", + "unavailable", + "not_found", + "not_acceptable" + ], + "type": "string", + "x-nullable": true, + "x-omitempty": true + }, + "models.Cluster": { + "properties": { + "id": { + "type": "string" + }, + "manager": { + "type": "string" + } + }, + "type": "object" + }, + "models.Project": { + "properties": { + "cluster_id": { + "description": "Identifier of the resource manager that owns project. It is used to differentiate multiple clusters of same resource manager.", + "example": "slurm-0", + "type": "string" + }, + "name": { + "description": "Name of the project", + "example": "prj1", + "type": "string" + }, + "resource_manager": { + "description": "Name of the resource manager that owns project. Eg slurm, openstack, kubernetes, etc", + "example": "slurm", + "type": "string" + }, + "tags": { + "description": "List of meta data tags of the project", + "example": [ + "tag1", + "tag2" + ], + "items": {}, + "type": "array", + "uniqueItems": false + }, + "uid": { + "description": "Unique identifier of the project provided by cluster", + "example": "1000", + "type": "string" + }, + "users": { + "description": "List of users of the project", + "example": [ + "usr1", + "usr2" + ], + "items": {}, + "type": "array", + "uniqueItems": false + } + }, + "type": "object" + }, + "models.Stat": { + "properties": { + "cluster_id": { + "description": "Identifier of the resource manager that owns compute unit. It is used to differentiate multiple clusters of same resource manager.", + "example": "slurm-0", + "type": "string" + }, + "num_active_units": { + "description": "Number of active units that are in running state", + "example": 800, + "type": "integer" + }, + "num_inactive_units": { + "description": "Number of inactive units that are in terminated/cancelled/error state", + "example": 200, + "type": "integer" + }, + "num_projects": { + "description": "Number of projects", + "example": 200, + "type": "integer" + }, + "num_units": { + "description": "Number of active and terminated units", + "example": 1000, + "type": "integer" + }, + "num_users": { + "description": "Number of users", + "example": 500, + "type": "integer" + }, + "resource_manager": { + "description": "Name of the resource manager that owns project. Eg slurm, openstack, kubernetes, etc", + "example": "slurm", + "type": "string" + } + }, + "type": "object" + }, + "models.Unit": { + "properties": { + "allocation": { + "additionalProperties": { + "type": "number" + }, + "description": "Allocation map of unit. Only string and int64 values are supported in map", + "example": { + "cpus": 1, + "gpus": 1, + "mem": 10 + }, + "type": "object" + }, + "avg_cpu_mem_usage": { + "additionalProperties": { + "type": "number" + }, + "description": "Average CPU memory usage(s) during lifetime of unit", + "example": { + "global": 45.26 + }, + "type": "object" + }, + "avg_cpu_usage": { + "additionalProperties": { + "type": "number" + }, + "description": "Average CPU usage(s) during lifetime of unit", + "example": { + "global": 70.12 + }, + "type": "object" + }, + "avg_gpu_mem_usage": { + "additionalProperties": { + "type": "number" + }, + "description": "Average GPU memory usage(s) during lifetime of unit", + "example": { + "global": 45.26 + }, + "type": "object" + }, + "avg_gpu_usage": { + "additionalProperties": { + "type": "number" + }, + "description": "Average GPU usage(s) during lifetime of unit", + "example": { + "global": 70.12 + }, + "type": "object" + }, + "cluster_id": { + "description": "Identifier of the resource manager that owns compute unit. It is used to differentiate multiple clusters of same resource manager.", + "example": "slurm-0", + "type": "string" + }, + "created_at": { + "description": "Creation time", + "example": "2023-02-21T15:48:20+0100", + "type": "string" + }, + "created_at_ts": { + "description": "Creation timestamp", + "example": 1676990900000, + "type": "integer" + }, + "elapsed": { + "description": "Human readable total elapsed time string", + "example": "2-00:10:20", + "type": "string" + }, + "ended_at": { + "description": "End time", + "example": "Unknown", + "type": "string" + }, + "ended_at_ts": { + "description": "End timestamp", + "example": 0, + "type": "integer" + }, + "groupname": { + "description": "User group", + "example": "grp1", + "type": "string" + }, + "name": { + "description": "Name of compute unit", + "example": "my-slurm-job", + "type": "string" + }, + "project": { + "description": "Account in batch systems, Tenant in Openstack, Namespace in k8s", + "example": "prj1", + "type": "string" + }, + "resource_manager": { + "description": "Name of the resource manager that owns compute unit. Eg slurm, openstack, kubernetes, etc", + "example": "slurm", + "type": "string" + }, + "started_at": { + "description": "Start time", + "example": "2023-02-21T15:49:06+0100", + "type": "string" + }, + "started_at_ts": { + "description": "Start timestamp", + "example": 1676990946000, + "type": "integer" + }, + "state": { + "description": "Current state of unit", + "example": "RUNNING", + "type": "string" + }, + "tags": { + "additionalProperties": { + "type": "string" + }, + "description": "A map to store generic info. String and int64 are valid value types of map", + "example": { + "gid": "1000", + "uid": "1000", + "workdir": "/home/user" + }, + "type": "object" + }, + "total_cpu_emissions_gms": { + "additionalProperties": { + "type": "number" + }, + "description": "Total CPU emissions from source(s) in grams during lifetime of unit", + "example": { + "emaps_total": 3.09, + "owid_total": 5.22 + }, + "type": "object" + }, + "total_cpu_energy_usage_kwh": { + "additionalProperties": { + "type": "number" + }, + "description": "Total CPU energy usage(s) in kWh during lifetime of unit", + "example": { + "total": 0.73 + }, + "type": "object" + }, + "total_egress_stats": { + "additionalProperties": { + "type": "number" + }, + "description": "Total Outgress statistics of unit", + "example": { + "bytes_total": 454342323, + "packets_total": 23232323 + }, + "type": "object" + }, + "total_gpu_emissions_gms": { + "additionalProperties": { + "type": "number" + }, + "description": "Total GPU emissions from source(s) in grams during lifetime of unit", + "example": { + "emaps_total": 12.09, + "owid_total": 15.22 + }, + "type": "object" + }, + "total_gpu_energy_usage_kwh": { + "additionalProperties": { + "type": "number" + }, + "description": "Total GPU energy usage(s) in kWh during lifetime of unit", + "example": { + "total": 5.39 + }, + "type": "object" + }, + "total_ingress_stats": { + "additionalProperties": { + "type": "number" + }, + "description": "Total Ingress statistics of unit", + "example": { + "bytes_total": 8503405, + "packets_total": 43423 + }, + "type": "object" + }, + "total_io_read_stats": { + "additionalProperties": { + "type": "number" + }, + "description": "Total IO read statistics during lifetime of unit", + "example": { + "bytes_total": 245000000, + "requests_total": 49423 + }, + "type": "object" + }, + "total_io_write_stats": { + "additionalProperties": { + "type": "number" + }, + "description": "Total IO write statistics during lifetime of unit", + "example": { + "bytes_total": 12000000, + "requests_total": 13923 + }, + "type": "object" + }, + "total_time_seconds": { + "additionalProperties": { + "type": "number" + }, + "description": "Different types of times in seconds consumed by the unit. This map contains at minimum `walltime`, `alloc_cputime`, `alloc_cpumemtime`, `alloc_gputime` and `alloc_gpumem_time` keys.", + "example": { + "alloc_cpumemtime": 1000, + "alloc_cputime": 100, + "alloc_gpumemtime": 100, + "alloc_gputime": 100, + "walltime": 100 + }, + "type": "object" + }, + "username": { + "description": "Username", + "example": "usr1", + "type": "string" + }, + "uuid": { + "description": "Unique identifier of unit. It can be Job ID for batch jobs, UUID for pods in k8s or VMs in Openstack", + "example": "193048", + "type": "string" + } + }, + "type": "object" + }, + "models.Usage": { + "properties": { + "avg_cpu_mem_usage": { + "additionalProperties": { + "type": "number" + }, + "description": "Average CPU memory usage(s) during lifetime of project", + "example": { + "global": 45.26 + }, + "type": "object" + }, + "avg_cpu_usage": { + "additionalProperties": { + "type": "number" + }, + "description": "Average CPU usage(s) during lifetime of project", + "example": { + "global": 70.12 + }, + "type": "object" + }, + "avg_gpu_mem_usage": { + "additionalProperties": { + "type": "number" + }, + "description": "Average GPU memory usage(s) during lifetime of project", + "example": { + "global": 45.26 + }, + "type": "object" + }, + "avg_gpu_usage": { + "additionalProperties": { + "type": "number" + }, + "description": "Average GPU usage(s) during lifetime of project", + "example": { + "global": 70.12 + }, + "type": "object" + }, + "cluster_id": { + "description": "Identifier of the resource manager that owns compute unit. It is used to differentiate multiple clusters of same resource manager.", + "example": "slurm-0", + "type": "string" + }, + "groupname": { + "description": "User group", + "example": "grp1", + "type": "string" + }, + "num_units": { + "description": "Number of consumed units", + "example": 145, + "type": "integer" + }, + "project": { + "description": "Account in batch systems, Tenant in Openstack, Namespace in k8s", + "example": "prj1", + "type": "string" + }, + "resource_manager": { + "description": "Name of the resource manager that owns project. Eg slurm, openstack, kubernetes, etc", + "example": "slurm", + "type": "string" + }, + "total_cpu_emissions_gms": { + "additionalProperties": { + "type": "number" + }, + "description": "Total CPU emissions from source(s) in grams during lifetime of project", + "example": { + "emaps_total": 3.09, + "owid_total": 5.22 + }, + "type": "object" + }, + "total_cpu_energy_usage_kwh": { + "additionalProperties": { + "type": "number" + }, + "description": "Total CPU energy usage(s) in kWh during lifetime of project", + "example": { + "total": 0.73 + }, + "type": "object" + }, + "total_egress_stats": { + "additionalProperties": { + "type": "number" + }, + "description": "Total Egress statistics of unit", + "example": { + "bytes_total": 454342323, + "packets_total": 23232323 + }, + "type": "object" + }, + "total_gpu_emissions_gms": { + "additionalProperties": { + "type": "number" + }, + "description": "Total GPU emissions from source(s) in grams during lifetime of project", + "example": { + "emaps_total": 12.09, + "owid_total": 15.22 + }, + "type": "object" + }, + "total_gpu_energy_usage_kwh": { + "additionalProperties": { + "type": "number" + }, + "description": "Total GPU energy usage(s) in kWh during lifetime of project", + "example": { + "total": 5.39 + }, + "type": "object" + }, + "total_ingress_stats": { + "additionalProperties": { + "type": "number" + }, + "description": "Total Ingress statistics of unit", + "example": { + "bytes_total": 8503405, + "packets_total": 43423 + }, + "type": "object" + }, + "total_io_read_stats": { + "additionalProperties": { + "type": "number" + }, + "description": "Total IO read statistics during lifetime of unit", + "example": { + "bytes_total": 245000000, + "requests_total": 49423 + }, + "type": "object" + }, + "total_io_write_stats": { + "additionalProperties": { + "type": "number" + }, + "description": "Total IO write statistics during lifetime of unit", + "example": { + "bytes_total": 12000000, + "requests_total": 13923 + }, + "type": "object" + }, + "total_time_seconds": { + "additionalProperties": { + "type": "number" + }, + "description": "Different times in seconds consumed by the unit. This map must contain `walltime`, `alloc_cputime`, `alloc_cpumemtime`, `alloc_gputime` and `alloc_gpumem_time` keys.", + "example": { + "alloc_cpumemtime": 1000, + "alloc_cputime": 100, + "alloc_gpumemtime": 100, + "alloc_gputime": 100, + "walltime": 100 + }, + "type": "object" + }, + "username": { + "description": "Username", + "example": "usr1", + "type": "string" + } + }, + "type": "object" + }, + "models.User": { + "properties": { + "cluster_id": { + "description": "Identifier of the resource manager that owns user. It is used to differentiate multiple clusters of same resource manager.", + "example": "slurm-0", + "type": "string" + }, + "name": { + "description": "Name of the user", + "example": "usr1", + "type": "string" + }, + "projects": { + "description": "List of projects of the user", + "example": [ + "prj1", + "prj2" + ], + "items": {}, + "type": "array", + "uniqueItems": false + }, + "resource_manager": { + "description": "Name of the resource manager that owns user. Eg slurm, openstack, kubernetes, etc", + "example": "slurm", + "type": "string" + }, + "tags": { + "description": "List of meta data tags of the user", + "example": [ + "tag1", + "tag2" + ], + "items": {}, + "type": "array", + "uniqueItems": false + }, + "uid": { + "description": "Unique identifier of the user provided by cluster", + "example": "1000", + "type": "string" + } + }, + "type": "object" + } + }, + "securitySchemes": { + "BasicAuth": { + "scheme": "basic", + "type": "http" + } + } + }, + "info": { + "contact": { + "email": "mahendra.paipuri@gmail.com", + "name": "Mahendra Paipuri", + "url": "https://github.com/ceems-dev/ceems/issues" + }, + "description": "OpenAPI specification (OAS) for the CEEMS REST API.\n\nSee the Interactive Docs to try CEEMS API methods without writing code, and get\nthe complete schema of resources exposed by the API.\n\nIf basic auth is enabled, all the endpoints require authentication.\n\nAll the endpoints, except `health`, `swagger`, `debug` and `demo`,\nmust send a user-agent header.\n\nA demo instance of CEEMS API server is provided for the users to test. This\ninstance is running at `https://ceems-demo.myaddr.tools:6443` and it is the\ndefault server that will serve the requests originating from current OAS client.\n\nSome of the valid users for this demo instance are:\n- arnold\n- betty\n- edna\n- gazoo\n- wilma\n\nEvery request must contain a `X-Grafana-User` header with one of the usernames\nabove as the value to the header. This is how CEEMS API server recognise the user.\n\nSome of the valid projects for this demo instance are:\n- bedrock\n- cornerstone\n\nDemo instance have CORS enabled to allow cross-domain communication from the browser.\nAll responses have a wildcard same-origin which makes them completely public and\naccessible to everyone, including any code on any site.\n\nTo test admin resources, users can use `admin` as `X-Grafana-User`.\n\nTimestamps must be specified in milliseconds, unless otherwise specified.", + "license": { + "name": "GPL-3.0 license", + "url": "https://www.gnu.org/licenses/gpl-3.0.en.html" + }, + "title": "CEEMS API", + "version": "1.0", + "x-logo": { + "altText": "CEEMS logo", + "url": "https://raw.githubusercontent.com/ceems-dev/ceems/refs/heads/main/website/static/img/logo.png" + } + }, + "externalDocs": { + "description": "", + "url": "https://ceems-dev.github.io/ceems/" + }, + "paths": { + "/clusters/admin": { + "get": { + "description": "This endpoint will list all the cluster IDs in the CEEMS DB. The\ncurrent user is always identified by the header `X-Grafana-User` in\nthe request.\n\nThis will list all the cluster IDs in the DB. This is primarily\nused to verify the CEEMS load balancer's backend IDs that should match\nwith cluster IDs.\n", + "parameters": [ + { + "description": "Current user name", + "in": "header", + "name": "X-Grafana-User", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-models_Cluster" + } + } + }, + "description": "OK" + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Forbidden" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Internal Server Error" + } + }, + "security": [ + { + "BasicAuth": [] + } + ], + "summary": "List clusters", + "tags": [ + "clusters" + ] + } + }, + "/demo/{resource}": { + "get": { + "description": "This endpoint returns sample response for units and usage models. This\nendpoint do not require the setting of `X-Grafana-User` header as it\nonly returns mock data for each request. This can be used to introspect\nthe response models for different resources.\n\nThe endpoint requires a path parameter `resource` which takes either:\n- `units` which returns a mock units response\n- `usage` which returns a mock usage response.\n\nThe mock data is generated randomly for each request and there is\nno guarantee that the data has logical sense.", + "parameters": [ + { + "description": "Whether to return mock units or usage data", + "in": "path", + "name": "resource", + "required": true, + "schema": { + "enum": [ + "units", + "usage" + ], + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/http.Response-models_Unit" + }, + { + "$ref": "#/components/schemas/http.Response-models_Usage" + } + ] + } + } + }, + "description": "OK" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Demo Units/Usage endpoints", + "tags": [ + "demo" + ] + } + }, + "/health": { + "get": { + "description": "This health endpoint can be used to check on the health of the API server\nin containerised and Kubernetes environments.\n\nThis endpoint does not need any user header. However, if basic auth\nis enabled, authentication header must be provided to get status.", + "responses": { + "200": { + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "description": "OK" + }, + "401": { + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized" + }, + "503": { + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "description": "KO" + } + }, + "security": [ + { + "BasicAuth": [] + } + ], + "servers": [ + { + "description": "Test CEEMS API server URL for health, swagger and debug endpoints only.", + "url": "https://ceems-demo.myaddr.tools:6443" + } + ], + "summary": "Health check endpoint for API server.", + "tags": [ + "health" + ] + } + }, + "/projects": { + "get": { + "description": "This endpoint will show details of the queried project of current user. The\ncurrent user is always identified by the header `X-Grafana-User` in\nthe request.\n\nThe details include list of users in that project. If current user\nattempts to query a project that they are not part of, empty response\nwill be returned\n", + "parameters": [ + { + "description": "Current user name", + "in": "header", + "name": "X-Grafana-User", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Project", + "in": "query", + "name": "project", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "Cluster ID", + "in": "query", + "name": "cluster_id", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-models_Project" + } + } + }, + "description": "OK" + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Internal Server Error" + } + }, + "security": [ + { + "BasicAuth": [] + } + ], + "summary": "Show project details", + "tags": [ + "projects" + ] + } + }, + "/projects/admin": { + "get": { + "description": "This endpoint will show details of the queried project. The\ncurrent user is always identified by the header `X-Grafana-User` in\nthe request.\n\nThe user who is making the request must be in the list of admin users\nconfigured for the server.\n\nThe details include list of users in that project. If current user\nattempts to query a project that they are not part of, empty response\nwill be returned\n", + "parameters": [ + { + "description": "Current user name", + "in": "header", + "name": "X-Grafana-User", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Project", + "in": "query", + "name": "project", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "Cluster ID", + "in": "query", + "name": "cluster_id", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-models_Project" + } + } + }, + "description": "OK" + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Forbidden" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Internal Server Error" + } + }, + "security": [ + { + "BasicAuth": [] + } + ], + "summary": "Admin endpoint to fetch project details", + "tags": [ + "projects" + ] + } + }, + "/stats/{mode}/admin": { + "get": { + "description": "This admin endpoint will return the quick stats of _queried_ cluster. The\ncurrent user is always identified by the header `X-Grafana-User` in\nthe request.\n\nThe user who is making the request must be in the list of admin users\nconfigured for the server.\n\nA path parameter `mode` is required to return the kind of usage statistics.\nCurrently, two modes of statistics are supported:\n- `current`: In this mode the usage between two time periods is returned\nbased on `from` and `to` query parameters.\n- `global`: In this mode the _total_ usage statistics are returned. For\ninstance, if the retention period of the DB is set to 2 years, usage\nstatistics of last 2 years will be returned.\n\nThe statistics include current number of active users, projects, jobs, _etc_.\n\nIf `to` query parameter is not provided, current time will be used. If `from`\nquery parameter is not used, a default query window of 24 hours will be used.\nIt means if `to` is provided, `from` will be calculated as `to` - 24hrs.\n", + "parameters": [ + { + "description": "Current user name", + "in": "header", + "name": "X-Grafana-User", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Whether to get quick stats within a period or global", + "in": "path", + "name": "mode", + "required": true, + "schema": { + "enum": [ + "current", + "global" + ], + "type": "string" + } + }, + { + "description": "cluster ID", + "in": "query", + "name": "cluster_id", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "From timestamp", + "in": "query", + "name": "from", + "schema": { + "type": "string" + } + }, + { + "description": "To timestamp", + "in": "query", + "name": "to", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-models_Stat" + } + } + }, + "description": "OK" + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Forbidden" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Internal Server Error" + } + }, + "security": [ + { + "BasicAuth": [] + } + ], + "summary": "Admin Stats", + "tags": [ + "stats" + ] + } + }, + "/units": { + "get": { + "description": "This user endpoint will fetch compute units of the current user. The\ncurrent user is always identified by the header `X-Grafana-User` in\nthe request.\n\nIf multiple query parameters are passed, for instance, `?uuid=\u003cuuid\u003e\u0026project=\u003cproject\u003e`,\nthe intersection of query parameters are used to fetch compute units rather than\nthe union. That means if the compute unit's `uuid` does not belong to the queried\nproject, null response will be returned.\n\nIn order to return the running compute units as well, use the query parameter `running`.\n\nIf `to` query parameter is not provided, current time will be used. If `from`\nquery parameter is not used, a default query window of 24 hours will be used.\nIt means if `to` is provided, `from` will be calculated as `to` - 24hrs. If query\nparameter `timezone` is provided, the unit's created, start and end time strings\nwill be presented in that time zone.\n\nTo limit the number of fields in the response, use `field` query parameter. By default, all\nfields will be included in the response if they are _non-empty_.", + "parameters": [ + { + "description": "Current user name", + "in": "header", + "name": "X-Grafana-User", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Cluster ID", + "in": "query", + "name": "cluster_id", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "Unit UUID", + "in": "query", + "name": "uuid", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "Project", + "in": "query", + "name": "project", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "Whether to fetch running units", + "in": "query", + "name": "running", + "schema": { + "type": "boolean" + } + }, + { + "description": "From timestamp", + "in": "query", + "name": "from", + "schema": { + "type": "string" + } + }, + { + "description": "To timestamp", + "in": "query", + "name": "to", + "schema": { + "type": "string" + } + }, + { + "description": "Time zone in IANA format", + "in": "query", + "name": "timezone", + "schema": { + "type": "string" + } + }, + { + "description": "Fields to return in response", + "in": "query", + "name": "field", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-models_Unit" + } + } + }, + "description": "OK" + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Forbidden" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Internal Server Error" + } + }, + "security": [ + { + "BasicAuth": [] + } + ], + "summary": "User endpoint for fetching compute units", + "tags": [ + "units" + ] + } + }, + "/units/admin": { + "get": { + "description": "This admin endpoint will fetch compute units of _any_ user, compute unit and/or project. The\ncurrent user is always identified by the header `X-Grafana-User` in\nthe request.\n\nThe user who is making the request must be in the list of admin users\nconfigured for the server.\n\nIf multiple query parameters are passed, for instance, `?uuid=\u003cuuid\u003e\u0026user=\u003cuser\u003e`,\nthe intersection of query parameters are used to fetch compute units rather than\nthe union. That means if the compute unit's `uuid` does not belong to the queried\nuser, null response will be returned.\n\nIn order to return the running compute units as well, use the query parameter `running`.\n\nIf `to` query parameter is not provided, current time will be used. If `from`\nquery parameter is not used, a default query window of 24 hours will be used.\nIt means if `to` is provided, `from` will be calculated as `to` - 24hrs. If query\nparameter `timezone` is provided, the unit's created, start and end time strings\nwill be presented in that time zone.\n\nTo limit the number of fields in the response, use `field` query parameter. By default, all\nfields will be included in the response if they are _non-empty_.", + "parameters": [ + { + "description": "Current user name", + "in": "header", + "name": "X-Grafana-User", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Cluster ID", + "in": "query", + "name": "cluster_id", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "Unit UUID", + "in": "query", + "name": "uuid", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "Project", + "in": "query", + "name": "project", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "User name", + "in": "query", + "name": "user", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "Whether to fetch running units", + "in": "query", + "name": "running", + "schema": { + "type": "boolean" + } + }, + { + "description": "From timestamp", + "in": "query", + "name": "from", + "schema": { + "type": "string" + } + }, + { + "description": "To timestamp", + "in": "query", + "name": "to", + "schema": { + "type": "string" + } + }, + { + "description": "Time zone in IANA format", + "in": "query", + "name": "timezone", + "schema": { + "type": "string" + } + }, + { + "description": "Fields to return in response", + "in": "query", + "name": "field", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-models_Unit" + } + } + }, + "description": "OK" + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Forbidden" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Internal Server Error" + } + }, + "security": [ + { + "BasicAuth": [] + } + ], + "summary": "Admin endpoint for fetching compute units.", + "tags": [ + "units" + ] + } + }, + "/units/verify": { + "get": { + "description": "This endpoint will check if the current user is the owner of the\nqueried UUIDs. The current user is always identified by the header `X-Grafana-User` in\nthe request.\n\nA response of 200 means that the current user is the owner of the queried UUIDs.\nAny other response code should be treated as the current user not being the owner\nof the queried units.\n\nThe ownership check passes if any of the following conditions are `true`:\n- If the current user is the _direct_ owner of the compute unit.\n- If the current user belongs to the same account/project/namespace as\nthe compute unit. This means the users belonging to the same project can\naccess each others compute units.\n- If the current user has admin role\n\nThe above checks must pass for **all** the queried units.\nIf the check does not pass for at least one queried unit, a response 403 will be\nreturned.\n\nAny 500 response codes should be treated as failed check as well.", + "parameters": [ + { + "description": "Current user name", + "in": "header", + "name": "X-Grafana-User", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Unit UUID", + "in": "query", + "name": "uuid", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "Cluster ID", + "in": "query", + "name": "cluster_id", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "OK" + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Forbidden" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Internal Server Error" + } + }, + "security": [ + { + "BasicAuth": [] + } + ], + "summary": "Verify unit ownership", + "tags": [ + "units" + ] + } + }, + "/usage/{mode}": { + "get": { + "description": "This endpoint will return the usage statistics current user. The\ncurrent user is always identified by the header `X-Grafana-User` in\nthe request.\n\nA path parameter `mode` is required to return the kind of usage statistics.\nCurrently, two modes of statistics are supported:\n- `current`: In this mode the usage between two time periods is returned\nbased on `from` and `to` query parameters.\n- `global`: In this mode the _total_ usage statistics are returned. For\ninstance, if the retention period of the DB is set to 2 years, usage\nstatistics of last 2 years will be returned.\n\nThe statistics can be limited to certain projects by passing `project` query,\nparameter.\n\nIf `to` query parameter is not provided, current time will be used. If `from`\nquery parameter is not used, a default query window of 24 hours will be used.\nIt means if `to` is provided, `from` will be calculated as `to` - 24hrs.\n\nTo limit the number of fields in the response, use `field` query parameter. By default, all\nfields will be included in the response if they are _non-empty_.\n\nThe `current` usage mode can be slow query depending the requested\nwindow interval. This is mostly due to the fact that the CEEMS DB\nuses custom JSON types to store metric data and usage statistics\nneeds to aggregate metrics over these JSON types using custom aggregate\nfunctions which can be slow.\n\nTherefore the query results are cached for 15 min to avoid load on server.\nURL string is used as the cache key. Thus, the query parameters\n`from` and `to` are rounded to the nearest timestamp that are\nmultiple of 900 sec (15 min). The first query will make a DB query and\ncache results and subsequent queries, for a given user and same URL\nquery parameters, will return the same cached result until the cache\nis invalidated after 15 min.", + "parameters": [ + { + "description": "Current user name", + "in": "header", + "name": "X-Grafana-User", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Whether to get usage stats within a period or global", + "in": "path", + "name": "mode", + "required": true, + "schema": { + "enum": [ + "current", + "global" + ], + "type": "string" + } + }, + { + "description": "cluster ID", + "in": "query", + "name": "cluster_id", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "Project", + "in": "query", + "name": "project", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "From timestamp", + "in": "query", + "name": "from", + "schema": { + "type": "string" + } + }, + { + "description": "To timestamp", + "in": "query", + "name": "to", + "schema": { + "type": "string" + } + }, + { + "description": "Fields to return in response", + "in": "query", + "name": "field", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-models_Usage" + } + } + }, + "description": "OK" + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Internal Server Error" + } + }, + "security": [ + { + "BasicAuth": [] + } + ], + "summary": "Usage statistics", + "tags": [ + "usage" + ] + } + }, + "/usage/{mode}/admin": { + "get": { + "description": "This admin endpoint will return the usage statistics of _queried_ user. The\ncurrent user is always identified by the header `X-Grafana-User` in\nthe request.\n\nThe user who is making the request must be in the list of admin users\nconfigured for the server.\n\nA path parameter `mode` is required to return the kind of usage statistics.\nCurrently, two modes of statistics are supported:\n- `current`: In this mode the usage between two time periods is returned\nbased on `from` and `to` query parameters.\n- `global`: In this mode the _total_ usage statistics are returned. For\ninstance, if the retention period of the DB is set to 2 years, usage\nstatistics of last 2 years will be returned.\n\nThe statistics can be limited to certain projects by passing `project` query,\nparameter.\n\nIf `to` query parameter is not provided, current time will be used. If `from`\nquery parameter is not used, a default query window of 24 hours will be used.\nIt means if `to` is provided, `from` will be calculated as `to` - 24hrs.\n\nTo limit the number of fields in the response, use `field` query parameter. By default, all\nfields will be included in the response if they are _non-empty_.\n\nThe `current` usage mode can be slow query depending the requested\nwindow interval. This is mostly due to the fact that the CEEMS DB\nuses custom JSON types to store metric data and usage statistics\nneeds to aggregate metrics over these JSON types using custom aggregate\nfunctions which can be slow.\n\nTherefore the query results are cached for 15 min to avoid load on server.\nURL string is used as the cache key. Thus, the query parameters\n`from` and `to` are rounded to the nearest timestamp that are\nmultiple of 900 sec (15 min). The first query will make a DB query and\ncache results and subsequent queries, for a given user and same URL\nquery parameters, will return the same cached result until the cache\nis invalidated after 15 min.", + "parameters": [ + { + "description": "Current user name", + "in": "header", + "name": "X-Grafana-User", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Whether to get usage stats within a period or global", + "in": "path", + "name": "mode", + "required": true, + "schema": { + "enum": [ + "current", + "global" + ], + "type": "string" + } + }, + { + "description": "cluster ID", + "in": "query", + "name": "cluster_id", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "Project", + "in": "query", + "name": "project", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Username", + "in": "query", + "name": "user", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "From timestamp", + "in": "query", + "name": "from", + "schema": { + "type": "string" + } + }, + { + "description": "To timestamp", + "in": "query", + "name": "to", + "schema": { + "type": "string" + } + }, + { + "description": "Fields to return in response", + "in": "query", + "name": "field", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-models_Usage" + } + } + }, + "description": "OK" + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Forbidden" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Internal Server Error" + } + }, + "security": [ + { + "BasicAuth": [] + } + ], + "summary": "Admin Usage statistics", + "tags": [ + "usage" + ] + } + }, + "/users": { + "get": { + "description": "This endpoint will show details of the current user. The\ncurrent user is always identified by the header `X-Grafana-User` in\nthe request.\n\nThe details include list of projects that user is currently a part of.\n", + "parameters": [ + { + "description": "Current user name", + "in": "header", + "name": "X-Grafana-User", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Cluster ID", + "in": "query", + "name": "cluster_id", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-models_User" + } + } + }, + "description": "OK" + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Internal Server Error" + } + }, + "security": [ + { + "BasicAuth": [] + } + ], + "summary": "Show user details", + "tags": [ + "users" + ] + } + }, + "/users/admin": { + "get": { + "description": "This endpoint will show details of the queried user(s). The\ncurrent user is always identified by the header `X-Grafana-User` in\nthe request.\n\nThe user who is making the request must be in the list of admin users\nconfigured for the server.\n\nWhen the query parameter `user` is empty, all users will be returned\nin the response.\n\nThe details include list of projects that user is currently a part of.\n\nWhen query parameter `role` is set to `admin`, only admin users will\nwill be returned. The `tags` values indicates the source of admin user.\n", + "parameters": [ + { + "description": "Current user name", + "in": "header", + "name": "X-Grafana-User", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "User name", + "in": "query", + "name": "user", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "Cluster ID", + "in": "query", + "name": "cluster_id", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "style": "form" + }, + { + "description": "User role", + "in": "query", + "name": "role", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-models_User" + } + } + }, + "description": "OK" + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Forbidden" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/http.Response-any" + } + } + }, + "description": "Internal Server Error" + } + }, + "security": [ + { + "BasicAuth": [] + } + ], + "summary": "Admin endpoint for fetching user details of _any_ user.", + "tags": [ + "users" + ] + } + } + }, + "openapi": "3.1.0", + "servers": [ + { + "description": "Test CEEMS API server URL.", + "url": "https://ceems-demo.myaddr.tools:6443/api/v1" + } + ] +} \ No newline at end of file diff --git a/pkg/api/docs/swagger.yaml b/pkg/api/docs/swagger.yaml new file mode 100644 index 00000000..261b51d3 --- /dev/null +++ b/pkg/api/docs/swagger.yaml @@ -0,0 +1,1701 @@ +components: + schemas: + http.Response-any: + properties: + data: + items: {} + type: array + uniqueItems: false + x-nullable: true + x-omitempty: true + error: + type: string + x-nullable: true + x-omitempty: true + errorType: + $ref: '#/components/schemas/http.errorType' + status: + type: string + warnings: + items: + type: string + type: array + uniqueItems: false + x-nullable: true + x-omitempty: true + type: object + http.Response-models_Cluster: + properties: + data: + items: + $ref: '#/components/schemas/models.Cluster' + type: array + uniqueItems: false + x-nullable: true + x-omitempty: true + error: + type: string + x-nullable: true + x-omitempty: true + errorType: + $ref: '#/components/schemas/http.errorType' + status: + type: string + warnings: + items: + type: string + type: array + uniqueItems: false + x-nullable: true + x-omitempty: true + type: object + http.Response-models_Project: + properties: + data: + items: + $ref: '#/components/schemas/models.Project' + type: array + uniqueItems: false + x-nullable: true + x-omitempty: true + error: + type: string + x-nullable: true + x-omitempty: true + errorType: + $ref: '#/components/schemas/http.errorType' + status: + type: string + warnings: + items: + type: string + type: array + uniqueItems: false + x-nullable: true + x-omitempty: true + type: object + http.Response-models_Stat: + properties: + data: + items: + $ref: '#/components/schemas/models.Stat' + type: array + uniqueItems: false + x-nullable: true + x-omitempty: true + error: + type: string + x-nullable: true + x-omitempty: true + errorType: + $ref: '#/components/schemas/http.errorType' + status: + type: string + warnings: + items: + type: string + type: array + uniqueItems: false + x-nullable: true + x-omitempty: true + type: object + http.Response-models_Unit: + properties: + data: + items: + $ref: '#/components/schemas/models.Unit' + type: array + uniqueItems: false + x-nullable: true + x-omitempty: true + error: + type: string + x-nullable: true + x-omitempty: true + errorType: + $ref: '#/components/schemas/http.errorType' + status: + type: string + warnings: + items: + type: string + type: array + uniqueItems: false + x-nullable: true + x-omitempty: true + type: object + http.Response-models_Usage: + properties: + data: + items: + $ref: '#/components/schemas/models.Usage' + type: array + uniqueItems: false + x-nullable: true + x-omitempty: true + error: + type: string + x-nullable: true + x-omitempty: true + errorType: + $ref: '#/components/schemas/http.errorType' + status: + type: string + warnings: + items: + type: string + type: array + uniqueItems: false + x-nullable: true + x-omitempty: true + type: object + http.Response-models_User: + properties: + data: + items: + $ref: '#/components/schemas/models.User' + type: array + uniqueItems: false + x-nullable: true + x-omitempty: true + error: + type: string + x-nullable: true + x-omitempty: true + errorType: + $ref: '#/components/schemas/http.errorType' + status: + type: string + warnings: + items: + type: string + type: array + uniqueItems: false + x-nullable: true + x-omitempty: true + type: object + http.errorType: + enum: + - "" + - unauthorized + - forbidden + - timeout + - canceled + - execution + - bad_data + - internal + - unavailable + - not_found + - not_acceptable + type: string + x-nullable: true + x-omitempty: true + models.Cluster: + properties: + id: + type: string + manager: + type: string + type: object + models.Project: + properties: + cluster_id: + description: Identifier of the resource manager that owns project. It is + used to differentiate multiple clusters of same resource manager. + example: slurm-0 + type: string + name: + description: Name of the project + example: prj1 + type: string + resource_manager: + description: Name of the resource manager that owns project. Eg slurm, openstack, + kubernetes, etc + example: slurm + type: string + tags: + description: List of meta data tags of the project + example: + - tag1 + - tag2 + items: {} + type: array + uniqueItems: false + uid: + description: Unique identifier of the project provided by cluster + example: "1000" + type: string + users: + description: List of users of the project + example: + - usr1 + - usr2 + items: {} + type: array + uniqueItems: false + type: object + models.Stat: + properties: + cluster_id: + description: Identifier of the resource manager that owns compute unit. + It is used to differentiate multiple clusters of same resource manager. + example: slurm-0 + type: string + num_active_units: + description: Number of active units that are in running state + example: 800 + type: integer + num_inactive_units: + description: Number of inactive units that are in terminated/cancelled/error + state + example: 200 + type: integer + num_projects: + description: Number of projects + example: 200 + type: integer + num_units: + description: Number of active and terminated units + example: 1000 + type: integer + num_users: + description: Number of users + example: 500 + type: integer + resource_manager: + description: Name of the resource manager that owns project. Eg slurm, openstack, + kubernetes, etc + example: slurm + type: string + type: object + models.Unit: + properties: + allocation: + additionalProperties: + type: number + description: Allocation map of unit. Only string and int64 values are supported + in map + example: + cpus: 1 + gpus: 1 + mem: 10 + type: object + avg_cpu_mem_usage: + additionalProperties: + type: number + description: Average CPU memory usage(s) during lifetime of unit + example: + global: 45.26 + type: object + avg_cpu_usage: + additionalProperties: + type: number + description: Average CPU usage(s) during lifetime of unit + example: + global: 70.12 + type: object + avg_gpu_mem_usage: + additionalProperties: + type: number + description: Average GPU memory usage(s) during lifetime of unit + example: + global: 45.26 + type: object + avg_gpu_usage: + additionalProperties: + type: number + description: Average GPU usage(s) during lifetime of unit + example: + global: 70.12 + type: object + cluster_id: + description: Identifier of the resource manager that owns compute unit. + It is used to differentiate multiple clusters of same resource manager. + example: slurm-0 + type: string + created_at: + description: Creation time + example: 2023-02-21T15:48:20+0100 + type: string + created_at_ts: + description: Creation timestamp + example: 1676990900000 + type: integer + elapsed: + description: Human readable total elapsed time string + example: 2-00:10:20 + type: string + ended_at: + description: End time + example: Unknown + type: string + ended_at_ts: + description: End timestamp + example: 0 + type: integer + groupname: + description: User group + example: grp1 + type: string + name: + description: Name of compute unit + example: my-slurm-job + type: string + project: + description: Account in batch systems, Tenant in Openstack, Namespace in + k8s + example: prj1 + type: string + resource_manager: + description: Name of the resource manager that owns compute unit. Eg slurm, + openstack, kubernetes, etc + example: slurm + type: string + started_at: + description: Start time + example: 2023-02-21T15:49:06+0100 + type: string + started_at_ts: + description: Start timestamp + example: 1676990946000 + type: integer + state: + description: Current state of unit + example: RUNNING + type: string + tags: + additionalProperties: + type: string + description: A map to store generic info. String and int64 are valid value + types of map + example: + gid: "1000" + uid: "1000" + workdir: /home/user + type: object + total_cpu_emissions_gms: + additionalProperties: + type: number + description: Total CPU emissions from source(s) in grams during lifetime + of unit + example: + emaps_total: 3.09 + owid_total: 5.22 + type: object + total_cpu_energy_usage_kwh: + additionalProperties: + type: number + description: Total CPU energy usage(s) in kWh during lifetime of unit + example: + total: 0.73 + type: object + total_egress_stats: + additionalProperties: + type: number + description: Total Outgress statistics of unit + example: + bytes_total: 454342323 + packets_total: 23232323 + type: object + total_gpu_emissions_gms: + additionalProperties: + type: number + description: Total GPU emissions from source(s) in grams during lifetime + of unit + example: + emaps_total: 12.09 + owid_total: 15.22 + type: object + total_gpu_energy_usage_kwh: + additionalProperties: + type: number + description: Total GPU energy usage(s) in kWh during lifetime of unit + example: + total: 5.39 + type: object + total_ingress_stats: + additionalProperties: + type: number + description: Total Ingress statistics of unit + example: + bytes_total: 8503405 + packets_total: 43423 + type: object + total_io_read_stats: + additionalProperties: + type: number + description: Total IO read statistics during lifetime of unit + example: + bytes_total: 245000000 + requests_total: 49423 + type: object + total_io_write_stats: + additionalProperties: + type: number + description: Total IO write statistics during lifetime of unit + example: + bytes_total: 12000000 + requests_total: 13923 + type: object + total_time_seconds: + additionalProperties: + type: number + description: Different types of times in seconds consumed by the unit. This + map contains at minimum `walltime`, `alloc_cputime`, `alloc_cpumemtime`, + `alloc_gputime` and `alloc_gpumem_time` keys. + example: + alloc_cpumemtime: 1000 + alloc_cputime: 100 + alloc_gpumemtime: 100 + alloc_gputime: 100 + walltime: 100 + type: object + username: + description: Username + example: usr1 + type: string + uuid: + description: Unique identifier of unit. It can be Job ID for batch jobs, + UUID for pods in k8s or VMs in Openstack + example: "193048" + type: string + type: object + models.Usage: + properties: + avg_cpu_mem_usage: + additionalProperties: + type: number + description: Average CPU memory usage(s) during lifetime of project + example: + global: 45.26 + type: object + avg_cpu_usage: + additionalProperties: + type: number + description: Average CPU usage(s) during lifetime of project + example: + global: 70.12 + type: object + avg_gpu_mem_usage: + additionalProperties: + type: number + description: Average GPU memory usage(s) during lifetime of project + example: + global: 45.26 + type: object + avg_gpu_usage: + additionalProperties: + type: number + description: Average GPU usage(s) during lifetime of project + example: + global: 70.12 + type: object + cluster_id: + description: Identifier of the resource manager that owns compute unit. + It is used to differentiate multiple clusters of same resource manager. + example: slurm-0 + type: string + groupname: + description: User group + example: grp1 + type: string + num_units: + description: Number of consumed units + example: 145 + type: integer + project: + description: Account in batch systems, Tenant in Openstack, Namespace in + k8s + example: prj1 + type: string + resource_manager: + description: Name of the resource manager that owns project. Eg slurm, openstack, + kubernetes, etc + example: slurm + type: string + total_cpu_emissions_gms: + additionalProperties: + type: number + description: Total CPU emissions from source(s) in grams during lifetime + of project + example: + emaps_total: 3.09 + owid_total: 5.22 + type: object + total_cpu_energy_usage_kwh: + additionalProperties: + type: number + description: Total CPU energy usage(s) in kWh during lifetime of project + example: + total: 0.73 + type: object + total_egress_stats: + additionalProperties: + type: number + description: Total Egress statistics of unit + example: + bytes_total: 454342323 + packets_total: 23232323 + type: object + total_gpu_emissions_gms: + additionalProperties: + type: number + description: Total GPU emissions from source(s) in grams during lifetime + of project + example: + emaps_total: 12.09 + owid_total: 15.22 + type: object + total_gpu_energy_usage_kwh: + additionalProperties: + type: number + description: Total GPU energy usage(s) in kWh during lifetime of project + example: + total: 5.39 + type: object + total_ingress_stats: + additionalProperties: + type: number + description: Total Ingress statistics of unit + example: + bytes_total: 8503405 + packets_total: 43423 + type: object + total_io_read_stats: + additionalProperties: + type: number + description: Total IO read statistics during lifetime of unit + example: + bytes_total: 245000000 + requests_total: 49423 + type: object + total_io_write_stats: + additionalProperties: + type: number + description: Total IO write statistics during lifetime of unit + example: + bytes_total: 12000000 + requests_total: 13923 + type: object + total_time_seconds: + additionalProperties: + type: number + description: Different times in seconds consumed by the unit. This map must + contain `walltime`, `alloc_cputime`, `alloc_cpumemtime`, `alloc_gputime` + and `alloc_gpumem_time` keys. + example: + alloc_cpumemtime: 1000 + alloc_cputime: 100 + alloc_gpumemtime: 100 + alloc_gputime: 100 + walltime: 100 + type: object + username: + description: Username + example: usr1 + type: string + type: object + models.User: + properties: + cluster_id: + description: Identifier of the resource manager that owns user. It is used + to differentiate multiple clusters of same resource manager. + example: slurm-0 + type: string + name: + description: Name of the user + example: usr1 + type: string + projects: + description: List of projects of the user + example: + - prj1 + - prj2 + items: {} + type: array + uniqueItems: false + resource_manager: + description: Name of the resource manager that owns user. Eg slurm, openstack, + kubernetes, etc + example: slurm + type: string + tags: + description: List of meta data tags of the user + example: + - tag1 + - tag2 + items: {} + type: array + uniqueItems: false + uid: + description: Unique identifier of the user provided by cluster + example: "1000" + type: string + type: object + securitySchemes: + BasicAuth: + scheme: basic + type: http +externalDocs: + description: "" + url: https://ceems-dev.github.io/ceems/ +info: + contact: + email: mahendra.paipuri@gmail.com + name: Mahendra Paipuri + url: https://github.com/ceems-dev/ceems/issues + description: |- + OpenAPI specification (OAS) for the CEEMS REST API. + + See the Interactive Docs to try CEEMS API methods without writing code, and get + the complete schema of resources exposed by the API. + + If basic auth is enabled, all the endpoints require authentication. + + All the endpoints, except `health`, `swagger`, `debug` and `demo`, + must send a user-agent header. + + A demo instance of CEEMS API server is provided for the users to test. This + instance is running at `https://ceems-demo.myaddr.tools:6443` and it is the + default server that will serve the requests originating from current OAS client. + + Some of the valid users for this demo instance are: + - arnold + - betty + - edna + - gazoo + - wilma + + Every request must contain a `X-Grafana-User` header with one of the usernames + above as the value to the header. This is how CEEMS API server recognise the user. + + Some of the valid projects for this demo instance are: + - bedrock + - cornerstone + + Demo instance have CORS enabled to allow cross-domain communication from the browser. + All responses have a wildcard same-origin which makes them completely public and + accessible to everyone, including any code on any site. + + To test admin resources, users can use `admin` as `X-Grafana-User`. + + Timestamps must be specified in milliseconds, unless otherwise specified. + license: + name: GPL-3.0 license + url: https://www.gnu.org/licenses/gpl-3.0.en.html + title: CEEMS API + version: "1.0" + x-logo: + altText: CEEMS logo + url: https://raw.githubusercontent.com/ceems-dev/ceems/refs/heads/main/website/static/img/logo.png +openapi: 3.1.0 +paths: + /clusters/admin: + get: + description: | + This endpoint will list all the cluster IDs in the CEEMS DB. The + current user is always identified by the header `X-Grafana-User` in + the request. + + This will list all the cluster IDs in the DB. This is primarily + used to verify the CEEMS load balancer's backend IDs that should match + with cluster IDs. + parameters: + - description: Current user name + in: header + name: X-Grafana-User + required: true + schema: + type: string + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-models_Cluster' + description: OK + "401": + content: + application/json: + schema: + type: string + description: Unauthorized + "403": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-any' + description: Forbidden + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-any' + description: Internal Server Error + security: + - BasicAuth: [] + summary: List clusters + tags: + - clusters + /demo/{resource}: + get: + description: |- + This endpoint returns sample response for units and usage models. This + endpoint do not require the setting of `X-Grafana-User` header as it + only returns mock data for each request. This can be used to introspect + the response models for different resources. + + The endpoint requires a path parameter `resource` which takes either: + - `units` which returns a mock units response + - `usage` which returns a mock usage response. + + The mock data is generated randomly for each request and there is + no guarantee that the data has logical sense. + parameters: + - description: Whether to return mock units or usage data + in: path + name: resource + required: true + schema: + enum: + - units + - usage + type: string + responses: + "200": + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/http.Response-models_Unit' + - $ref: '#/components/schemas/http.Response-models_Usage' + description: OK + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-any' + description: Internal Server Error + summary: Demo Units/Usage endpoints + tags: + - demo + /health: + get: + description: |- + This health endpoint can be used to check on the health of the API server + in containerised and Kubernetes environments. + + This endpoint does not need any user header. However, if basic auth + is enabled, authentication header must be provided to get status. + responses: + "200": + content: + text/plain: + schema: + type: string + description: OK + "401": + content: + text/plain: + schema: + type: string + description: Unauthorized + "503": + content: + text/plain: + schema: + type: string + description: KO + security: + - BasicAuth: [] + servers: + - description: Test CEEMS API server URL for health, swagger and debug endpoints + only. + url: https://ceems-demo.myaddr.tools:6443 + summary: Health check endpoint for API server. + tags: + - health + /projects: + get: + description: | + This endpoint will show details of the queried project of current user. The + current user is always identified by the header `X-Grafana-User` in + the request. + + The details include list of users in that project. If current user + attempts to query a project that they are not part of, empty response + will be returned + parameters: + - description: Current user name + in: header + name: X-Grafana-User + required: true + schema: + type: string + - description: Project + in: query + name: project + schema: + items: + type: string + type: array + style: form + - description: Cluster ID + in: query + name: cluster_id + schema: + items: + type: string + type: array + style: form + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-models_Project' + description: OK + "401": + content: + application/json: + schema: + type: string + description: Unauthorized + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-any' + description: Internal Server Error + security: + - BasicAuth: [] + summary: Show project details + tags: + - projects + /projects/admin: + get: + description: | + This endpoint will show details of the queried project. The + current user is always identified by the header `X-Grafana-User` in + the request. + + The user who is making the request must be in the list of admin users + configured for the server. + + The details include list of users in that project. If current user + attempts to query a project that they are not part of, empty response + will be returned + parameters: + - description: Current user name + in: header + name: X-Grafana-User + required: true + schema: + type: string + - description: Project + in: query + name: project + schema: + items: + type: string + type: array + style: form + - description: Cluster ID + in: query + name: cluster_id + schema: + items: + type: string + type: array + style: form + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-models_Project' + description: OK + "401": + content: + application/json: + schema: + type: string + description: Unauthorized + "403": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-any' + description: Forbidden + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-any' + description: Internal Server Error + security: + - BasicAuth: [] + summary: Admin endpoint to fetch project details + tags: + - projects + /stats/{mode}/admin: + get: + description: | + This admin endpoint will return the quick stats of _queried_ cluster. The + current user is always identified by the header `X-Grafana-User` in + the request. + + The user who is making the request must be in the list of admin users + configured for the server. + + A path parameter `mode` is required to return the kind of usage statistics. + Currently, two modes of statistics are supported: + - `current`: In this mode the usage between two time periods is returned + based on `from` and `to` query parameters. + - `global`: In this mode the _total_ usage statistics are returned. For + instance, if the retention period of the DB is set to 2 years, usage + statistics of last 2 years will be returned. + + The statistics include current number of active users, projects, jobs, _etc_. + + If `to` query parameter is not provided, current time will be used. If `from` + query parameter is not used, a default query window of 24 hours will be used. + It means if `to` is provided, `from` will be calculated as `to` - 24hrs. + parameters: + - description: Current user name + in: header + name: X-Grafana-User + required: true + schema: + type: string + - description: Whether to get quick stats within a period or global + in: path + name: mode + required: true + schema: + enum: + - current + - global + type: string + - description: cluster ID + in: query + name: cluster_id + schema: + items: + type: string + type: array + style: form + - description: From timestamp + in: query + name: from + schema: + type: string + - description: To timestamp + in: query + name: to + schema: + type: string + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-models_Stat' + description: OK + "401": + content: + application/json: + schema: + type: string + description: Unauthorized + "403": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-any' + description: Forbidden + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-any' + description: Internal Server Error + security: + - BasicAuth: [] + summary: Admin Stats + tags: + - stats + /units: + get: + description: |- + This user endpoint will fetch compute units of the current user. The + current user is always identified by the header `X-Grafana-User` in + the request. + + If multiple query parameters are passed, for instance, `?uuid=&project=`, + the intersection of query parameters are used to fetch compute units rather than + the union. That means if the compute unit's `uuid` does not belong to the queried + project, null response will be returned. + + In order to return the running compute units as well, use the query parameter `running`. + + If `to` query parameter is not provided, current time will be used. If `from` + query parameter is not used, a default query window of 24 hours will be used. + It means if `to` is provided, `from` will be calculated as `to` - 24hrs. If query + parameter `timezone` is provided, the unit's created, start and end time strings + will be presented in that time zone. + + To limit the number of fields in the response, use `field` query parameter. By default, all + fields will be included in the response if they are _non-empty_. + parameters: + - description: Current user name + in: header + name: X-Grafana-User + required: true + schema: + type: string + - description: Cluster ID + in: query + name: cluster_id + schema: + items: + type: string + type: array + style: form + - description: Unit UUID + in: query + name: uuid + schema: + items: + type: string + type: array + style: form + - description: Project + in: query + name: project + schema: + items: + type: string + type: array + style: form + - description: Whether to fetch running units + in: query + name: running + schema: + type: boolean + - description: From timestamp + in: query + name: from + schema: + type: string + - description: To timestamp + in: query + name: to + schema: + type: string + - description: Time zone in IANA format + in: query + name: timezone + schema: + type: string + - description: Fields to return in response + in: query + name: field + schema: + items: + type: string + type: array + style: form + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-models_Unit' + description: OK + "401": + content: + application/json: + schema: + type: string + description: Unauthorized + "403": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-any' + description: Forbidden + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-any' + description: Internal Server Error + security: + - BasicAuth: [] + summary: User endpoint for fetching compute units + tags: + - units + /units/admin: + get: + description: |- + This admin endpoint will fetch compute units of _any_ user, compute unit and/or project. The + current user is always identified by the header `X-Grafana-User` in + the request. + + The user who is making the request must be in the list of admin users + configured for the server. + + If multiple query parameters are passed, for instance, `?uuid=&user=`, + the intersection of query parameters are used to fetch compute units rather than + the union. That means if the compute unit's `uuid` does not belong to the queried + user, null response will be returned. + + In order to return the running compute units as well, use the query parameter `running`. + + If `to` query parameter is not provided, current time will be used. If `from` + query parameter is not used, a default query window of 24 hours will be used. + It means if `to` is provided, `from` will be calculated as `to` - 24hrs. If query + parameter `timezone` is provided, the unit's created, start and end time strings + will be presented in that time zone. + + To limit the number of fields in the response, use `field` query parameter. By default, all + fields will be included in the response if they are _non-empty_. + parameters: + - description: Current user name + in: header + name: X-Grafana-User + required: true + schema: + type: string + - description: Cluster ID + in: query + name: cluster_id + schema: + items: + type: string + type: array + style: form + - description: Unit UUID + in: query + name: uuid + schema: + items: + type: string + type: array + style: form + - description: Project + in: query + name: project + schema: + items: + type: string + type: array + style: form + - description: User name + in: query + name: user + schema: + items: + type: string + type: array + style: form + - description: Whether to fetch running units + in: query + name: running + schema: + type: boolean + - description: From timestamp + in: query + name: from + schema: + type: string + - description: To timestamp + in: query + name: to + schema: + type: string + - description: Time zone in IANA format + in: query + name: timezone + schema: + type: string + - description: Fields to return in response + in: query + name: field + schema: + items: + type: string + type: array + style: form + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-models_Unit' + description: OK + "401": + content: + application/json: + schema: + type: string + description: Unauthorized + "403": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-any' + description: Forbidden + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-any' + description: Internal Server Error + security: + - BasicAuth: [] + summary: Admin endpoint for fetching compute units. + tags: + - units + /units/verify: + get: + description: |- + This endpoint will check if the current user is the owner of the + queried UUIDs. The current user is always identified by the header `X-Grafana-User` in + the request. + + A response of 200 means that the current user is the owner of the queried UUIDs. + Any other response code should be treated as the current user not being the owner + of the queried units. + + The ownership check passes if any of the following conditions are `true`: + - If the current user is the _direct_ owner of the compute unit. + - If the current user belongs to the same account/project/namespace as + the compute unit. This means the users belonging to the same project can + access each others compute units. + - If the current user has admin role + + The above checks must pass for **all** the queried units. + If the check does not pass for at least one queried unit, a response 403 will be + returned. + + Any 500 response codes should be treated as failed check as well. + parameters: + - description: Current user name + in: header + name: X-Grafana-User + required: true + schema: + type: string + - description: Unit UUID + in: query + name: uuid + schema: + items: + type: string + type: array + style: form + - description: Cluster ID + in: query + name: cluster_id + schema: + items: + type: string + type: array + style: form + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-any' + description: OK + "401": + content: + application/json: + schema: + type: string + description: Unauthorized + "403": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-any' + description: Forbidden + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-any' + description: Internal Server Error + security: + - BasicAuth: [] + summary: Verify unit ownership + tags: + - units + /usage/{mode}: + get: + description: |- + This endpoint will return the usage statistics current user. The + current user is always identified by the header `X-Grafana-User` in + the request. + + A path parameter `mode` is required to return the kind of usage statistics. + Currently, two modes of statistics are supported: + - `current`: In this mode the usage between two time periods is returned + based on `from` and `to` query parameters. + - `global`: In this mode the _total_ usage statistics are returned. For + instance, if the retention period of the DB is set to 2 years, usage + statistics of last 2 years will be returned. + + The statistics can be limited to certain projects by passing `project` query, + parameter. + + If `to` query parameter is not provided, current time will be used. If `from` + query parameter is not used, a default query window of 24 hours will be used. + It means if `to` is provided, `from` will be calculated as `to` - 24hrs. + + To limit the number of fields in the response, use `field` query parameter. By default, all + fields will be included in the response if they are _non-empty_. + + The `current` usage mode can be slow query depending the requested + window interval. This is mostly due to the fact that the CEEMS DB + uses custom JSON types to store metric data and usage statistics + needs to aggregate metrics over these JSON types using custom aggregate + functions which can be slow. + + Therefore the query results are cached for 15 min to avoid load on server. + URL string is used as the cache key. Thus, the query parameters + `from` and `to` are rounded to the nearest timestamp that are + multiple of 900 sec (15 min). The first query will make a DB query and + cache results and subsequent queries, for a given user and same URL + query parameters, will return the same cached result until the cache + is invalidated after 15 min. + parameters: + - description: Current user name + in: header + name: X-Grafana-User + required: true + schema: + type: string + - description: Whether to get usage stats within a period or global + in: path + name: mode + required: true + schema: + enum: + - current + - global + type: string + - description: cluster ID + in: query + name: cluster_id + schema: + items: + type: string + type: array + style: form + - description: Project + in: query + name: project + schema: + items: + type: string + type: array + style: form + - description: From timestamp + in: query + name: from + schema: + type: string + - description: To timestamp + in: query + name: to + schema: + type: string + - description: Fields to return in response + in: query + name: field + schema: + items: + type: string + type: array + style: form + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-models_Usage' + description: OK + "401": + content: + application/json: + schema: + type: string + description: Unauthorized + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-any' + description: Internal Server Error + security: + - BasicAuth: [] + summary: Usage statistics + tags: + - usage + /usage/{mode}/admin: + get: + description: |- + This admin endpoint will return the usage statistics of _queried_ user. The + current user is always identified by the header `X-Grafana-User` in + the request. + + The user who is making the request must be in the list of admin users + configured for the server. + + A path parameter `mode` is required to return the kind of usage statistics. + Currently, two modes of statistics are supported: + - `current`: In this mode the usage between two time periods is returned + based on `from` and `to` query parameters. + - `global`: In this mode the _total_ usage statistics are returned. For + instance, if the retention period of the DB is set to 2 years, usage + statistics of last 2 years will be returned. + + The statistics can be limited to certain projects by passing `project` query, + parameter. + + If `to` query parameter is not provided, current time will be used. If `from` + query parameter is not used, a default query window of 24 hours will be used. + It means if `to` is provided, `from` will be calculated as `to` - 24hrs. + + To limit the number of fields in the response, use `field` query parameter. By default, all + fields will be included in the response if they are _non-empty_. + + The `current` usage mode can be slow query depending the requested + window interval. This is mostly due to the fact that the CEEMS DB + uses custom JSON types to store metric data and usage statistics + needs to aggregate metrics over these JSON types using custom aggregate + functions which can be slow. + + Therefore the query results are cached for 15 min to avoid load on server. + URL string is used as the cache key. Thus, the query parameters + `from` and `to` are rounded to the nearest timestamp that are + multiple of 900 sec (15 min). The first query will make a DB query and + cache results and subsequent queries, for a given user and same URL + query parameters, will return the same cached result until the cache + is invalidated after 15 min. + parameters: + - description: Current user name + in: header + name: X-Grafana-User + required: true + schema: + type: string + - description: Whether to get usage stats within a period or global + in: path + name: mode + required: true + schema: + enum: + - current + - global + type: string + - description: cluster ID + in: query + name: cluster_id + schema: + items: + type: string + type: array + style: form + - description: Project + in: query + name: project + schema: + items: + type: string + type: array + - description: Username + in: query + name: user + schema: + items: + type: string + type: array + style: form + - description: From timestamp + in: query + name: from + schema: + type: string + - description: To timestamp + in: query + name: to + schema: + type: string + - description: Fields to return in response + in: query + name: field + schema: + items: + type: string + type: array + style: form + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-models_Usage' + description: OK + "401": + content: + application/json: + schema: + type: string + description: Unauthorized + "403": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-any' + description: Forbidden + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-any' + description: Internal Server Error + security: + - BasicAuth: [] + summary: Admin Usage statistics + tags: + - usage + /users: + get: + description: | + This endpoint will show details of the current user. The + current user is always identified by the header `X-Grafana-User` in + the request. + + The details include list of projects that user is currently a part of. + parameters: + - description: Current user name + in: header + name: X-Grafana-User + required: true + schema: + type: string + - description: Cluster ID + in: query + name: cluster_id + schema: + items: + type: string + type: array + style: form + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-models_User' + description: OK + "401": + content: + application/json: + schema: + type: string + description: Unauthorized + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-any' + description: Internal Server Error + security: + - BasicAuth: [] + summary: Show user details + tags: + - users + /users/admin: + get: + description: | + This endpoint will show details of the queried user(s). The + current user is always identified by the header `X-Grafana-User` in + the request. + + The user who is making the request must be in the list of admin users + configured for the server. + + When the query parameter `user` is empty, all users will be returned + in the response. + + The details include list of projects that user is currently a part of. + + When query parameter `role` is set to `admin`, only admin users will + will be returned. The `tags` values indicates the source of admin user. + parameters: + - description: Current user name + in: header + name: X-Grafana-User + required: true + schema: + type: string + - description: User name + in: query + name: user + schema: + items: + type: string + type: array + style: form + - description: Cluster ID + in: query + name: cluster_id + schema: + items: + type: string + type: array + style: form + - description: User role + in: query + name: role + schema: + type: string + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-models_User' + description: OK + "401": + content: + application/json: + schema: + type: string + description: Unauthorized + "403": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-any' + description: Forbidden + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/http.Response-any' + description: Internal Server Error + security: + - BasicAuth: [] + summary: Admin endpoint for fetching user details of _any_ user. + tags: + - users +servers: +- description: Test CEEMS API server URL. + url: https://ceems-demo.myaddr.tools:6443/api/v1 diff --git a/pkg/api/http/docs/docs.go b/pkg/api/http/docs/docs.go deleted file mode 100644 index 40ae6d6e..00000000 --- a/pkg/api/http/docs/docs.go +++ /dev/null @@ -1,1874 +0,0 @@ -// Package docs Code generated by swaggo/swag. DO NOT EDIT -package docs - -import "github.com/swaggo/swag" - -const docTemplate = `{ - "schemes": {{ marshal .Schemes }}, - "swagger": "2.0", - "info": { - "description": "{{escape .Description}}", - "title": "{{.Title}}", - "contact": { - "name": "Mahendra Paipuri", - "url": "https://github.com/ceems-dev/ceems/issues", - "email": "mahendra.paipuri@gmail.com" - }, - "license": { - "name": "GPL-3.0 license", - "url": "https://www.gnu.org/licenses/gpl-3.0.en.html" - }, - "version": "{{.Version}}", - "x-logo": { - "altText": "CEEMS logo", - "url": "https://raw.githubusercontent.com/ceems-dev/ceems/refs/heads/main/website/static/img/logo.png" - } - }, - "host": "{{.Host}}", - "basePath": "{{.BasePath}}", - "paths": { - "/clusters/admin": { - "get": { - "security": [ - { - "BasicAuth": [] - } - ], - "description": "This endpoint will list all the cluster IDs in the CEEMS DB. The\ncurrent user is always identified by the header ` + "`" + `X-Grafana-User` + "`" + ` in\nthe request.\n\nThis will list all the cluster IDs in the DB. This is primarily\nused to verify the CEEMS load balancer's backend IDs that should match\nwith cluster IDs.\n", - "produces": [ - "application/json" - ], - "tags": [ - "clusters" - ], - "summary": "List clusters", - "parameters": [ - { - "type": "string", - "description": "Current user name", - "name": "X-Grafana-User", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/http.Response-models_Cluster" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - } - } - } - }, - "/demo/{resource}": { - "get": { - "description": "This endpoint returns sample response for units and usage models. This\nendpoint do not require the setting of ` + "`" + `X-Grafana-User` + "`" + ` header as it\nonly returns mock data for each request. This can be used to introspect\nthe response models for different resources.\n\nThe endpoint requires a path parameter ` + "`" + `resource` + "`" + ` which takes either:\n- ` + "`" + `units` + "`" + ` which returns a mock units response\n- ` + "`" + `usage` + "`" + ` which returns a mock usage response.\n\nThe mock data is generated randomly for each request and there is\nno guarantee that the data has logical sense.", - "produces": [ - "application/json" - ], - "tags": [ - "demo" - ], - "summary": "Demo Units/Usage endpoints", - "parameters": [ - { - "enum": [ - "units", - "usage" - ], - "type": "string", - "description": "Whether to return mock units or usage data", - "name": "resource", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/http.Response-models_Usage" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - } - } - } - }, - "/projects": { - "get": { - "security": [ - { - "BasicAuth": [] - } - ], - "description": "This endpoint will show details of the queried project of current user. The\ncurrent user is always identified by the header ` + "`" + `X-Grafana-User` + "`" + ` in\nthe request.\n\nThe details include list of users in that project. If current user\nattempts to query a project that they are not part of, empty response\nwill be returned\n", - "produces": [ - "application/json" - ], - "tags": [ - "projects" - ], - "summary": "Show project details", - "parameters": [ - { - "type": "string", - "description": "Current user name", - "name": "X-Grafana-User", - "in": "header", - "required": true - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Project", - "name": "project", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Cluster ID", - "name": "cluster_id", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/http.Response-models_Project" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - } - } - } - }, - "/projects/admin": { - "get": { - "security": [ - { - "BasicAuth": [] - } - ], - "description": "This endpoint will show details of the queried project. The\ncurrent user is always identified by the header ` + "`" + `X-Grafana-User` + "`" + ` in\nthe request.\n\nThe user who is making the request must be in the list of admin users\nconfigured for the server.\n\nThe details include list of users in that project. If current user\nattempts to query a project that they are not part of, empty response\nwill be returned\n", - "produces": [ - "application/json" - ], - "tags": [ - "projects" - ], - "summary": "Admin endpoint to fetch project details", - "parameters": [ - { - "type": "string", - "description": "Current user name", - "name": "X-Grafana-User", - "in": "header", - "required": true - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Project", - "name": "project", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Cluster ID", - "name": "cluster_id", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/http.Response-models_Project" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - } - } - } - }, - "/stats/{mode}/admin": { - "get": { - "security": [ - { - "BasicAuth": [] - } - ], - "description": "This admin endpoint will return the quick stats of _queried_ cluster. The\ncurrent user is always identified by the header ` + "`" + `X-Grafana-User` + "`" + ` in\nthe request.\n\nThe user who is making the request must be in the list of admin users\nconfigured for the server.\n\nA path parameter ` + "`" + `mode` + "`" + ` is required to return the kind of usage statistics.\nCurrently, two modes of statistics are supported:\n- ` + "`" + `current` + "`" + `: In this mode the usage between two time periods is returned\nbased on ` + "`" + `from` + "`" + ` and ` + "`" + `to` + "`" + ` query parameters.\n- ` + "`" + `global` + "`" + `: In this mode the _total_ usage statistics are returned. For\ninstance, if the retention period of the DB is set to 2 years, usage\nstatistics of last 2 years will be returned.\n\nThe statistics include current number of active users, projects, jobs, _etc_.\n\nIf ` + "`" + `to` + "`" + ` query parameter is not provided, current time will be used. If ` + "`" + `from` + "`" + `\nquery parameter is not used, a default query window of 24 hours will be used.\nIt means if ` + "`" + `to` + "`" + ` is provided, ` + "`" + `from` + "`" + ` will be calculated as ` + "`" + `to` + "`" + ` - 24hrs.\n", - "produces": [ - "application/json" - ], - "tags": [ - "stats" - ], - "summary": "Admin Stats", - "parameters": [ - { - "type": "string", - "description": "Current user name", - "name": "X-Grafana-User", - "in": "header", - "required": true - }, - { - "enum": [ - "current", - "global" - ], - "type": "string", - "description": "Whether to get quick stats within a period or global", - "name": "mode", - "in": "path", - "required": true - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "cluster ID", - "name": "cluster_id", - "in": "query" - }, - { - "type": "string", - "description": "From timestamp", - "name": "from", - "in": "query" - }, - { - "type": "string", - "description": "To timestamp", - "name": "to", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/http.Response-models_Stat" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "403": { - "description": "Forbidden", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - } - } - } - }, - "/units": { - "get": { - "security": [ - { - "BasicAuth": [] - } - ], - "description": "This user endpoint will fetch compute units of the current user. The\ncurrent user is always identified by the header ` + "`" + `X-Grafana-User` + "`" + ` in\nthe request.\n\nIf multiple query parameters are passed, for instance, ` + "`" + `?uuid=\u003cuuid\u003e\u0026project=\u003cproject\u003e` + "`" + `,\nthe intersection of query parameters are used to fetch compute units rather than\nthe union. That means if the compute unit's ` + "`" + `uuid` + "`" + ` does not belong to the queried\nproject, null response will be returned.\n\nIn order to return the running compute units as well, use the query parameter ` + "`" + `running` + "`" + `.\n\nIf ` + "`" + `to` + "`" + ` query parameter is not provided, current time will be used. If ` + "`" + `from` + "`" + `\nquery parameter is not used, a default query window of 24 hours will be used.\nIt means if ` + "`" + `to` + "`" + ` is provided, ` + "`" + `from` + "`" + ` will be calculated as ` + "`" + `to` + "`" + ` - 24hrs. If query\nparameter ` + "`" + `timezone` + "`" + ` is provided, the unit's created, start and end time strings\nwill be presented in that time zone.\n\nTo limit the number of fields in the response, use ` + "`" + `field` + "`" + ` query parameter. By default, all\nfields will be included in the response if they are _non-empty_.", - "produces": [ - "application/json" - ], - "tags": [ - "units" - ], - "summary": "User endpoint for fetching compute units", - "parameters": [ - { - "type": "string", - "description": "Current user name", - "name": "X-Grafana-User", - "in": "header", - "required": true - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Cluster ID", - "name": "cluster_id", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Unit UUID", - "name": "uuid", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Project", - "name": "project", - "in": "query" - }, - { - "type": "boolean", - "description": "Whether to fetch running units", - "name": "running", - "in": "query" - }, - { - "type": "string", - "description": "From timestamp", - "name": "from", - "in": "query" - }, - { - "type": "string", - "description": "To timestamp", - "name": "to", - "in": "query" - }, - { - "type": "string", - "description": "Time zone in IANA format", - "name": "timezone", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Fields to return in response", - "name": "field", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/http.Response-models_Unit" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "403": { - "description": "Forbidden", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - } - } - } - }, - "/units/admin": { - "get": { - "security": [ - { - "BasicAuth": [] - } - ], - "description": "This admin endpoint will fetch compute units of _any_ user, compute unit and/or project. The\ncurrent user is always identified by the header ` + "`" + `X-Grafana-User` + "`" + ` in\nthe request.\n\nThe user who is making the request must be in the list of admin users\nconfigured for the server.\n\nIf multiple query parameters are passed, for instance, ` + "`" + `?uuid=\u003cuuid\u003e\u0026user=\u003cuser\u003e` + "`" + `,\nthe intersection of query parameters are used to fetch compute units rather than\nthe union. That means if the compute unit's ` + "`" + `uuid` + "`" + ` does not belong to the queried\nuser, null response will be returned.\n\nIn order to return the running compute units as well, use the query parameter ` + "`" + `running` + "`" + `.\n\nIf ` + "`" + `to` + "`" + ` query parameter is not provided, current time will be used. If ` + "`" + `from` + "`" + `\nquery parameter is not used, a default query window of 24 hours will be used.\nIt means if ` + "`" + `to` + "`" + ` is provided, ` + "`" + `from` + "`" + ` will be calculated as ` + "`" + `to` + "`" + ` - 24hrs. If query\nparameter ` + "`" + `timezone` + "`" + ` is provided, the unit's created, start and end time strings\nwill be presented in that time zone.\n\nTo limit the number of fields in the response, use ` + "`" + `field` + "`" + ` query parameter. By default, all\nfields will be included in the response if they are _non-empty_.", - "produces": [ - "application/json" - ], - "tags": [ - "units" - ], - "summary": "Admin endpoint for fetching compute units.", - "parameters": [ - { - "type": "string", - "description": "Current user name", - "name": "X-Grafana-User", - "in": "header", - "required": true - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Cluster ID", - "name": "cluster_id", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Unit UUID", - "name": "uuid", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Project", - "name": "project", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "User name", - "name": "user", - "in": "query" - }, - { - "type": "boolean", - "description": "Whether to fetch running units", - "name": "running", - "in": "query" - }, - { - "type": "string", - "description": "From timestamp", - "name": "from", - "in": "query" - }, - { - "type": "string", - "description": "To timestamp", - "name": "to", - "in": "query" - }, - { - "type": "string", - "description": "Time zone in IANA format", - "name": "timezone", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Fields to return in response", - "name": "field", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/http.Response-models_Unit" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "403": { - "description": "Forbidden", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - } - } - } - }, - "/units/verify": { - "get": { - "security": [ - { - "BasicAuth": [] - } - ], - "description": "This endpoint will check if the current user is the owner of the\nqueried UUIDs. The current user is always identified by the header ` + "`" + `X-Grafana-User` + "`" + ` in\nthe request.\n\nA response of 200 means that the current user is the owner of the queried UUIDs.\nAny other response code should be treated as the current user not being the owner\nof the queried units.\n\nThe ownership check passes if any of the following conditions are ` + "`" + `true` + "`" + `:\n- If the current user is the _direct_ owner of the compute unit.\n- If the current user belongs to the same account/project/namespace as\nthe compute unit. This means the users belonging to the same project can\naccess each others compute units.\n- If the current user has admin role\n\nThe above checks must pass for **all** the queried units.\nIf the check does not pass for at least one queried unit, a response 403 will be\nreturned.\n\nAny 500 response codes should be treated as failed check as well.", - "produces": [ - "application/json" - ], - "tags": [ - "units" - ], - "summary": "Verify unit ownership", - "parameters": [ - { - "type": "string", - "description": "Current user name", - "name": "X-Grafana-User", - "in": "header", - "required": true - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Unit UUID", - "name": "uuid", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Cluster ID", - "name": "cluster_id", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "403": { - "description": "Forbidden", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - } - } - } - }, - "/usage/{mode}": { - "get": { - "security": [ - { - "BasicAuth": [] - } - ], - "description": "This endpoint will return the usage statistics current user. The\ncurrent user is always identified by the header ` + "`" + `X-Grafana-User` + "`" + ` in\nthe request.\n\nA path parameter ` + "`" + `mode` + "`" + ` is required to return the kind of usage statistics.\nCurrently, two modes of statistics are supported:\n- ` + "`" + `current` + "`" + `: In this mode the usage between two time periods is returned\nbased on ` + "`" + `from` + "`" + ` and ` + "`" + `to` + "`" + ` query parameters.\n- ` + "`" + `global` + "`" + `: In this mode the _total_ usage statistics are returned. For\ninstance, if the retention period of the DB is set to 2 years, usage\nstatistics of last 2 years will be returned.\n\nThe statistics can be limited to certain projects by passing ` + "`" + `project` + "`" + ` query,\nparameter.\n\nIf ` + "`" + `to` + "`" + ` query parameter is not provided, current time will be used. If ` + "`" + `from` + "`" + `\nquery parameter is not used, a default query window of 24 hours will be used.\nIt means if ` + "`" + `to` + "`" + ` is provided, ` + "`" + `from` + "`" + ` will be calculated as ` + "`" + `to` + "`" + ` - 24hrs.\n\nTo limit the number of fields in the response, use ` + "`" + `field` + "`" + ` query parameter. By default, all\nfields will be included in the response if they are _non-empty_.\n\nThe ` + "`" + `current` + "`" + ` usage mode can be slow query depending the requested\nwindow interval. This is mostly due to the fact that the CEEMS DB\nuses custom JSON types to store metric data and usage statistics\nneeds to aggregate metrics over these JSON types using custom aggregate\nfunctions which can be slow.\n\nTherefore the query results are cached for 15 min to avoid load on server.\nURL string is used as the cache key. Thus, the query parameters\n` + "`" + `from` + "`" + ` and ` + "`" + `to` + "`" + ` are rounded to the nearest timestamp that are\nmultiple of 900 sec (15 min). The first query will make a DB query and\ncache results and subsequent queries, for a given user and same URL\nquery parameters, will return the same cached result until the cache\nis invalidated after 15 min.", - "produces": [ - "application/json" - ], - "tags": [ - "usage" - ], - "summary": "Usage statistics", - "parameters": [ - { - "type": "string", - "description": "Current user name", - "name": "X-Grafana-User", - "in": "header", - "required": true - }, - { - "enum": [ - "current", - "global" - ], - "type": "string", - "description": "Whether to get usage stats within a period or global", - "name": "mode", - "in": "path", - "required": true - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "cluster ID", - "name": "cluster_id", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Project", - "name": "project", - "in": "query" - }, - { - "type": "string", - "description": "From timestamp", - "name": "from", - "in": "query" - }, - { - "type": "string", - "description": "To timestamp", - "name": "to", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Fields to return in response", - "name": "field", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/http.Response-models_Usage" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - } - } - } - }, - "/usage/{mode}/admin": { - "get": { - "security": [ - { - "BasicAuth": [] - } - ], - "description": "This admin endpoint will return the usage statistics of _queried_ user. The\ncurrent user is always identified by the header ` + "`" + `X-Grafana-User` + "`" + ` in\nthe request.\n\nThe user who is making the request must be in the list of admin users\nconfigured for the server.\n\nA path parameter ` + "`" + `mode` + "`" + ` is required to return the kind of usage statistics.\nCurrently, two modes of statistics are supported:\n- ` + "`" + `current` + "`" + `: In this mode the usage between two time periods is returned\nbased on ` + "`" + `from` + "`" + ` and ` + "`" + `to` + "`" + ` query parameters.\n- ` + "`" + `global` + "`" + `: In this mode the _total_ usage statistics are returned. For\ninstance, if the retention period of the DB is set to 2 years, usage\nstatistics of last 2 years will be returned.\n\nThe statistics can be limited to certain projects by passing ` + "`" + `project` + "`" + ` query,\nparameter.\n\nIf ` + "`" + `to` + "`" + ` query parameter is not provided, current time will be used. If ` + "`" + `from` + "`" + `\nquery parameter is not used, a default query window of 24 hours will be used.\nIt means if ` + "`" + `to` + "`" + ` is provided, ` + "`" + `from` + "`" + ` will be calculated as ` + "`" + `to` + "`" + ` - 24hrs.\n\nTo limit the number of fields in the response, use ` + "`" + `field` + "`" + ` query parameter. By default, all\nfields will be included in the response if they are _non-empty_.\n\nThe ` + "`" + `current` + "`" + ` usage mode can be slow query depending the requested\nwindow interval. This is mostly due to the fact that the CEEMS DB\nuses custom JSON types to store metric data and usage statistics\nneeds to aggregate metrics over these JSON types using custom aggregate\nfunctions which can be slow.\n\nTherefore the query results are cached for 15 min to avoid load on server.\nURL string is used as the cache key. Thus, the query parameters\n` + "`" + `from` + "`" + ` and ` + "`" + `to` + "`" + ` are rounded to the nearest timestamp that are\nmultiple of 900 sec (15 min). The first query will make a DB query and\ncache results and subsequent queries, for a given user and same URL\nquery parameters, will return the same cached result until the cache\nis invalidated after 15 min.", - "produces": [ - "application/json" - ], - "tags": [ - "usage" - ], - "summary": "Admin Usage statistics", - "parameters": [ - { - "type": "string", - "description": "Current user name", - "name": "X-Grafana-User", - "in": "header", - "required": true - }, - { - "enum": [ - "current", - "global" - ], - "type": "string", - "description": "Whether to get usage stats within a period or global", - "name": "mode", - "in": "path", - "required": true - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "cluster ID", - "name": "cluster_id", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "csv", - "description": "Project", - "name": "project", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Username", - "name": "user", - "in": "query" - }, - { - "type": "string", - "description": "From timestamp", - "name": "from", - "in": "query" - }, - { - "type": "string", - "description": "To timestamp", - "name": "to", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Fields to return in response", - "name": "field", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/http.Response-models_Usage" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "403": { - "description": "Forbidden", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - } - } - } - }, - "/users": { - "get": { - "security": [ - { - "BasicAuth": [] - } - ], - "description": "This endpoint will show details of the current user. The\ncurrent user is always identified by the header ` + "`" + `X-Grafana-User` + "`" + ` in\nthe request.\n\nThe details include list of projects that user is currently a part of.\n", - "produces": [ - "application/json" - ], - "tags": [ - "users" - ], - "summary": "Show user details", - "parameters": [ - { - "type": "string", - "description": "Current user name", - "name": "X-Grafana-User", - "in": "header", - "required": true - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Cluster ID", - "name": "cluster_id", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/http.Response-models_User" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - } - } - } - }, - "/users/admin": { - "get": { - "security": [ - { - "BasicAuth": [] - } - ], - "description": "This endpoint will show details of the queried user(s). The\ncurrent user is always identified by the header ` + "`" + `X-Grafana-User` + "`" + ` in\nthe request.\n\nThe user who is making the request must be in the list of admin users\nconfigured for the server.\n\nWhen the query parameter ` + "`" + `user` + "`" + ` is empty, all users will be returned\nin the response.\n\nThe details include list of projects that user is currently a part of.\n\nWhen query parameter ` + "`" + `role` + "`" + ` is set to ` + "`" + `admin` + "`" + `, only admin users will\nwill be returned. The ` + "`" + `tags` + "`" + ` values indicates the source of admin user.\n", - "produces": [ - "application/json" - ], - "tags": [ - "users" - ], - "summary": "Admin endpoint for fetching user details of _any_ user.", - "parameters": [ - { - "type": "string", - "description": "Current user name", - "name": "X-Grafana-User", - "in": "header", - "required": true - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "User name", - "name": "user", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Cluster ID", - "name": "cluster_id", - "in": "query" - }, - { - "type": "string", - "description": "User role", - "name": "role", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/http.Response-models_User" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - } - } - } - } - }, - "definitions": { - "http.Response-any": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": {}, - "x-nullable": true, - "x-omitempty": true - }, - "error": { - "type": "string", - "x-nullable": true, - "x-omitempty": true - }, - "errorType": { - "allOf": [ - { - "$ref": "#/definitions/http.errorType" - } - ], - "x-nullable": true, - "x-omitempty": true - }, - "status": { - "type": "string" - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - }, - "x-nullable": true, - "x-omitempty": true - } - } - }, - "http.Response-models_Cluster": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/definitions/models.Cluster" - }, - "x-nullable": true, - "x-omitempty": true - }, - "error": { - "type": "string", - "x-nullable": true, - "x-omitempty": true - }, - "errorType": { - "allOf": [ - { - "$ref": "#/definitions/http.errorType" - } - ], - "x-nullable": true, - "x-omitempty": true - }, - "status": { - "type": "string" - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - }, - "x-nullable": true, - "x-omitempty": true - } - } - }, - "http.Response-models_Project": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/definitions/models.Project" - }, - "x-nullable": true, - "x-omitempty": true - }, - "error": { - "type": "string", - "x-nullable": true, - "x-omitempty": true - }, - "errorType": { - "allOf": [ - { - "$ref": "#/definitions/http.errorType" - } - ], - "x-nullable": true, - "x-omitempty": true - }, - "status": { - "type": "string" - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - }, - "x-nullable": true, - "x-omitempty": true - } - } - }, - "http.Response-models_Stat": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/definitions/models.Stat" - }, - "x-nullable": true, - "x-omitempty": true - }, - "error": { - "type": "string", - "x-nullable": true, - "x-omitempty": true - }, - "errorType": { - "allOf": [ - { - "$ref": "#/definitions/http.errorType" - } - ], - "x-nullable": true, - "x-omitempty": true - }, - "status": { - "type": "string" - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - }, - "x-nullable": true, - "x-omitempty": true - } - } - }, - "http.Response-models_Unit": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/definitions/models.Unit" - }, - "x-nullable": true, - "x-omitempty": true - }, - "error": { - "type": "string", - "x-nullable": true, - "x-omitempty": true - }, - "errorType": { - "allOf": [ - { - "$ref": "#/definitions/http.errorType" - } - ], - "x-nullable": true, - "x-omitempty": true - }, - "status": { - "type": "string" - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - }, - "x-nullable": true, - "x-omitempty": true - } - } - }, - "http.Response-models_Usage": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/definitions/models.Usage" - }, - "x-nullable": true, - "x-omitempty": true - }, - "error": { - "type": "string", - "x-nullable": true, - "x-omitempty": true - }, - "errorType": { - "allOf": [ - { - "$ref": "#/definitions/http.errorType" - } - ], - "x-nullable": true, - "x-omitempty": true - }, - "status": { - "type": "string" - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - }, - "x-nullable": true, - "x-omitempty": true - } - } - }, - "http.Response-models_User": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/definitions/models.User" - }, - "x-nullable": true, - "x-omitempty": true - }, - "error": { - "type": "string", - "x-nullable": true, - "x-omitempty": true - }, - "errorType": { - "allOf": [ - { - "$ref": "#/definitions/http.errorType" - } - ], - "x-nullable": true, - "x-omitempty": true - }, - "status": { - "type": "string" - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - }, - "x-nullable": true, - "x-omitempty": true - } - } - }, - "http.errorType": { - "type": "string", - "enum": [ - "", - "unauthorized", - "forbidden", - "timeout", - "canceled", - "execution", - "bad_data", - "internal", - "unavailable", - "not_found", - "not_acceptable" - ], - "x-enum-varnames": [ - "ErrorNone", - "ErrorUnauthorized", - "ErrorForbidden", - "ErrorTimeout", - "ErrorCanceled", - "ErrorExec", - "ErrorBadData", - "ErrorInternal", - "ErrorUnavailable", - "ErrorNotFound", - "ErrorNotAcceptable" - ] - }, - "models.Cluster": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "manager": { - "type": "string" - } - } - }, - "models.Project": { - "type": "object", - "properties": { - "cluster_id": { - "description": "Identifier of the resource manager that owns project. It is used to differentiate multiple clusters of same resource manager.", - "type": "string", - "example": "slurm-0" - }, - "name": { - "description": "Name of the project", - "type": "string", - "example": "prj1" - }, - "resource_manager": { - "description": "Name of the resource manager that owns project. Eg slurm, openstack, kubernetes, etc", - "type": "string", - "example": "slurm" - }, - "tags": { - "description": "List of meta data tags of the project", - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "tag1", - "tag2" - ] - }, - "uid": { - "description": "Unique identifier of the project provided by cluster", - "type": "string", - "example": "1000" - }, - "users": { - "description": "List of users of the project", - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "usr1", - "usr2" - ] - } - } - }, - "models.Stat": { - "type": "object", - "properties": { - "cluster_id": { - "description": "Identifier of the resource manager that owns compute unit. It is used to differentiate multiple clusters of same resource manager.", - "type": "string", - "example": "slurm-0" - }, - "num_active_units": { - "description": "Number of active units that are in running state", - "type": "integer", - "example": 800 - }, - "num_inactive_units": { - "description": "Number of inactive units that are in terminated/cancelled/error state", - "type": "integer", - "example": 200 - }, - "num_projects": { - "description": "Number of projects", - "type": "integer", - "example": 200 - }, - "num_units": { - "description": "Number of active and terminated units", - "type": "integer", - "example": 1000 - }, - "num_users": { - "description": "Number of users", - "type": "integer", - "example": 500 - }, - "resource_manager": { - "description": "Name of the resource manager that owns project. Eg slurm, openstack, kubernetes, etc", - "type": "string", - "example": "slurm" - } - } - }, - "models.Unit": { - "type": "object", - "properties": { - "allocation": { - "description": "Allocation map of unit. Only string and int64 values are supported in map", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "cpus": 1, - "gpus": 1, - "mem": 10 - } - }, - "avg_cpu_mem_usage": { - "description": "Average CPU memory usage(s) during lifetime of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "global": 45.26 - } - }, - "avg_cpu_usage": { - "description": "Average CPU usage(s) during lifetime of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "global": 70.12 - } - }, - "avg_gpu_mem_usage": { - "description": "Average GPU memory usage(s) during lifetime of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "global": 45.26 - } - }, - "avg_gpu_usage": { - "description": "Average GPU usage(s) during lifetime of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "global": 70.12 - } - }, - "cluster_id": { - "description": "Identifier of the resource manager that owns compute unit. It is used to differentiate multiple clusters of same resource manager.", - "type": "string", - "example": "slurm-0" - }, - "created_at": { - "description": "Creation time", - "type": "string", - "example": "2023-02-21T15:48:20+0100" - }, - "created_at_ts": { - "description": "Creation timestamp", - "type": "integer", - "example": 1676990900000 - }, - "elapsed": { - "description": "Human readable total elapsed time string", - "type": "string", - "example": "2-00:10:20" - }, - "ended_at": { - "description": "End time", - "type": "string", - "example": "Unknown" - }, - "ended_at_ts": { - "description": "End timestamp", - "type": "integer", - "example": 0 - }, - "groupname": { - "description": "User group", - "type": "string", - "example": "grp1" - }, - "name": { - "description": "Name of compute unit", - "type": "string", - "example": "my-slurm-job" - }, - "project": { - "description": "Account in batch systems, Tenant in Openstack, Namespace in k8s", - "type": "string", - "example": "prj1" - }, - "resource_manager": { - "description": "Name of the resource manager that owns compute unit. Eg slurm, openstack, kubernetes, etc", - "type": "string", - "example": "slurm" - }, - "started_at": { - "description": "Start time", - "type": "string", - "example": "2023-02-21T15:49:06+0100" - }, - "started_at_ts": { - "description": "Start timestamp", - "type": "integer", - "example": 1676990946000 - }, - "state": { - "description": "Current state of unit", - "type": "string", - "example": "RUNNING" - }, - "tags": { - "description": "A map to store generic info. String and int64 are valid value types of map", - "type": "object", - "additionalProperties": { - "type": "string" - }, - "example": { - "gid": "1000", - "uid": "1000", - "workdir": "/home/user" - } - }, - "total_cpu_emissions_gms": { - "description": "Total CPU emissions from source(s) in grams during lifetime of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "emaps_total": 3.09, - "owid_total": 5.22 - } - }, - "total_cpu_energy_usage_kwh": { - "description": "Total CPU energy usage(s) in kWh during lifetime of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "total": 0.73 - } - }, - "total_egress_stats": { - "description": "Total Outgress statistics of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "bytes_total": 454342323, - "packets_total": 23232323 - } - }, - "total_gpu_emissions_gms": { - "description": "Total GPU emissions from source(s) in grams during lifetime of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "emaps_total": 12.09, - "owid_total": 15.22 - } - }, - "total_gpu_energy_usage_kwh": { - "description": "Total GPU energy usage(s) in kWh during lifetime of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "total": 5.39 - } - }, - "total_ingress_stats": { - "description": "Total Ingress statistics of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "bytes_total": 8503405, - "packets_total": 43423 - } - }, - "total_io_read_stats": { - "description": "Total IO read statistics during lifetime of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "bytes_total": 245000000, - "requests_total": 49423 - } - }, - "total_io_write_stats": { - "description": "Total IO write statistics during lifetime of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "bytes_total": 12000000, - "requests_total": 13923 - } - }, - "total_time_seconds": { - "description": "Different types of times in seconds consumed by the unit. This map contains at minimum ` + "`" + `walltime` + "`" + `, ` + "`" + `alloc_cputime` + "`" + `, ` + "`" + `alloc_cpumemtime` + "`" + `, ` + "`" + `alloc_gputime` + "`" + ` and ` + "`" + `alloc_gpumem_time` + "`" + ` keys.", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "alloc_cpumemtime": 1000, - "alloc_cputime": 100, - "alloc_gpumemtime": 100, - "alloc_gputime": 100, - "walltime": 100 - } - }, - "username": { - "description": "Username", - "type": "string", - "example": "usr1" - }, - "uuid": { - "description": "Unique identifier of unit. It can be Job ID for batch jobs, UUID for pods in k8s or VMs in Openstack", - "type": "string", - "example": "193048" - } - } - }, - "models.Usage": { - "type": "object", - "properties": { - "avg_cpu_mem_usage": { - "description": "Average CPU memory usage(s) during lifetime of project", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "global": 45.26 - } - }, - "avg_cpu_usage": { - "description": "Average CPU usage(s) during lifetime of project", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "global": 70.12 - } - }, - "avg_gpu_mem_usage": { - "description": "Average GPU memory usage(s) during lifetime of project", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "global": 45.26 - } - }, - "avg_gpu_usage": { - "description": "Average GPU usage(s) during lifetime of project", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "global": 70.12 - } - }, - "cluster_id": { - "description": "Identifier of the resource manager that owns compute unit. It is used to differentiate multiple clusters of same resource manager.", - "type": "string", - "example": "slurm-0" - }, - "groupname": { - "description": "User group", - "type": "string", - "example": "grp1" - }, - "num_units": { - "description": "Number of consumed units", - "type": "integer", - "example": 145 - }, - "project": { - "description": "Account in batch systems, Tenant in Openstack, Namespace in k8s", - "type": "string", - "example": "prj1" - }, - "resource_manager": { - "description": "Name of the resource manager that owns project. Eg slurm, openstack, kubernetes, etc", - "type": "string", - "example": "slurm" - }, - "total_cpu_emissions_gms": { - "description": "Total CPU emissions from source(s) in grams during lifetime of project", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "emaps_total": 3.09, - "owid_total": 5.22 - } - }, - "total_cpu_energy_usage_kwh": { - "description": "Total CPU energy usage(s) in kWh during lifetime of project", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "total": 0.73 - } - }, - "total_egress_stats": { - "description": "Total Egress statistics of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "bytes_total": 454342323, - "packets_total": 23232323 - } - }, - "total_gpu_emissions_gms": { - "description": "Total GPU emissions from source(s) in grams during lifetime of project", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "emaps_total": 12.09, - "owid_total": 15.22 - } - }, - "total_gpu_energy_usage_kwh": { - "description": "Total GPU energy usage(s) in kWh during lifetime of project", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "total": 5.39 - } - }, - "total_ingress_stats": { - "description": "Total Ingress statistics of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "bytes_total": 8503405, - "packets_total": 43423 - } - }, - "total_io_read_stats": { - "description": "Total IO read statistics during lifetime of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "bytes_total": 245000000, - "requests_total": 49423 - } - }, - "total_io_write_stats": { - "description": "Total IO write statistics during lifetime of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "bytes_total": 12000000, - "requests_total": 13923 - } - }, - "total_time_seconds": { - "description": "Different times in seconds consumed by the unit. This map must contain ` + "`" + `walltime` + "`" + `, ` + "`" + `alloc_cputime` + "`" + `, ` + "`" + `alloc_cpumemtime` + "`" + `, ` + "`" + `alloc_gputime` + "`" + ` and ` + "`" + `alloc_gpumem_time` + "`" + ` keys.", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "alloc_cpumemtime": 1000, - "alloc_cputime": 100, - "alloc_gpumemtime": 100, - "alloc_gputime": 100, - "walltime": 100 - } - }, - "username": { - "description": "Username", - "type": "string", - "example": "usr1" - } - } - }, - "models.User": { - "type": "object", - "properties": { - "cluster_id": { - "description": "Identifier of the resource manager that owns user. It is used to differentiate multiple clusters of same resource manager.", - "type": "string", - "example": "slurm-0" - }, - "name": { - "description": "Name of the user", - "type": "string", - "example": "usr1" - }, - "projects": { - "description": "List of projects of the user", - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "prj1", - "prj2" - ] - }, - "resource_manager": { - "description": "Name of the resource manager that owns user. Eg slurm, openstack, kubernetes, etc", - "type": "string", - "example": "slurm" - }, - "tags": { - "description": "List of meta data tags of the user", - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "tag1", - "tag2" - ] - }, - "uid": { - "description": "Unique identifier of the user provided by cluster", - "type": "string", - "example": "1000" - } - } - } - }, - "securityDefinitions": { - "BasicAuth": { - "type": "basic" - } - }, - "externalDocs": { - "url": "https://ceems-dev.github.io/ceems/" - } -}` - -// SwaggerInfo holds exported Swagger Info so clients can modify it -var SwaggerInfo = &swag.Spec{ - Version: "1.0", - Host: "ceems-demo.myaddr.tools:6443", - BasePath: "/api/v1", - Schemes: []string{"https"}, - Title: "CEEMS API", - Description: "OpenAPI specification (OAS) for the CEEMS REST API.\n\nSee the Interactive Docs to try CEEMS API methods without writing code, and get\nthe complete schema of resources exposed by the API.\n\nIf basic auth is enabled, all the endpoints require authentication.\n\nAll the endpoints, except `health`, `swagger`, `debug` and `demo`,\nmust send a user-agent header.\n\nA demo instance of CEEMS API server is provided for the users to test. This\ninstance is running at `https://ceems-demo.myaddr.tools:6443` and it is the\ndefault server that will serve the requests originating from current OAS client.\n\nSome of the valid users for this demo instance are:\n- arnold\n- betty\n- edna\n- gazoo\n- wilma\n\nEvery request must contain a `X-Grafana-User` header with one of the usernames\nabove as the value to the header. This is how CEEMS API server recognise the user.\n\nSome of the valid projects for this demo instance are:\n- bedrock\n- cornerstone\n\nDemo instance have CORS enabled to allow cross-domain communication from the browser.\nAll responses have a wildcard same-origin which makes them completely public and\naccessible to everyone, including any code on any site.\n\nTo test admin resources, users can use `admin` as `X-Grafana-User`.\n\nTimestamps must be specified in milliseconds, unless otherwise specified.", - InfoInstanceName: "swagger", - SwaggerTemplate: docTemplate, - LeftDelim: "{{", - RightDelim: "}}", -} - -func init() { - swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) -} diff --git a/pkg/api/http/docs/swagger.json b/pkg/api/http/docs/swagger.json deleted file mode 100644 index da6ccd5a..00000000 --- a/pkg/api/http/docs/swagger.json +++ /dev/null @@ -1,1853 +0,0 @@ -{ - "schemes": [ - "https" - ], - "swagger": "2.0", - "info": { - "description": "OpenAPI specification (OAS) for the CEEMS REST API.\n\nSee the Interactive Docs to try CEEMS API methods without writing code, and get\nthe complete schema of resources exposed by the API.\n\nIf basic auth is enabled, all the endpoints require authentication.\n\nAll the endpoints, except `health`, `swagger`, `debug` and `demo`,\nmust send a user-agent header.\n\nA demo instance of CEEMS API server is provided for the users to test. This\ninstance is running at `https://ceems-demo.myaddr.tools:6443` and it is the\ndefault server that will serve the requests originating from current OAS client.\n\nSome of the valid users for this demo instance are:\n- arnold\n- betty\n- edna\n- gazoo\n- wilma\n\nEvery request must contain a `X-Grafana-User` header with one of the usernames\nabove as the value to the header. This is how CEEMS API server recognise the user.\n\nSome of the valid projects for this demo instance are:\n- bedrock\n- cornerstone\n\nDemo instance have CORS enabled to allow cross-domain communication from the browser.\nAll responses have a wildcard same-origin which makes them completely public and\naccessible to everyone, including any code on any site.\n\nTo test admin resources, users can use `admin` as `X-Grafana-User`.\n\nTimestamps must be specified in milliseconds, unless otherwise specified.", - "title": "CEEMS API", - "contact": { - "name": "Mahendra Paipuri", - "url": "https://github.com/ceems-dev/ceems/issues", - "email": "mahendra.paipuri@gmail.com" - }, - "license": { - "name": "GPL-3.0 license", - "url": "https://www.gnu.org/licenses/gpl-3.0.en.html" - }, - "version": "1.0", - "x-logo": { - "altText": "CEEMS logo", - "url": "https://raw.githubusercontent.com/ceems-dev/ceems/refs/heads/main/website/static/img/logo.png" - } - }, - "host": "ceems-demo.myaddr.tools:6443", - "basePath": "/api/v1", - "paths": { - "/clusters/admin": { - "get": { - "security": [ - { - "BasicAuth": [] - } - ], - "description": "This endpoint will list all the cluster IDs in the CEEMS DB. The\ncurrent user is always identified by the header `X-Grafana-User` in\nthe request.\n\nThis will list all the cluster IDs in the DB. This is primarily\nused to verify the CEEMS load balancer's backend IDs that should match\nwith cluster IDs.\n", - "produces": [ - "application/json" - ], - "tags": [ - "clusters" - ], - "summary": "List clusters", - "parameters": [ - { - "type": "string", - "description": "Current user name", - "name": "X-Grafana-User", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/http.Response-models_Cluster" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - } - } - } - }, - "/demo/{resource}": { - "get": { - "description": "This endpoint returns sample response for units and usage models. This\nendpoint do not require the setting of `X-Grafana-User` header as it\nonly returns mock data for each request. This can be used to introspect\nthe response models for different resources.\n\nThe endpoint requires a path parameter `resource` which takes either:\n- `units` which returns a mock units response\n- `usage` which returns a mock usage response.\n\nThe mock data is generated randomly for each request and there is\nno guarantee that the data has logical sense.", - "produces": [ - "application/json" - ], - "tags": [ - "demo" - ], - "summary": "Demo Units/Usage endpoints", - "parameters": [ - { - "enum": [ - "units", - "usage" - ], - "type": "string", - "description": "Whether to return mock units or usage data", - "name": "resource", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/http.Response-models_Usage" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - } - } - } - }, - "/projects": { - "get": { - "security": [ - { - "BasicAuth": [] - } - ], - "description": "This endpoint will show details of the queried project of current user. The\ncurrent user is always identified by the header `X-Grafana-User` in\nthe request.\n\nThe details include list of users in that project. If current user\nattempts to query a project that they are not part of, empty response\nwill be returned\n", - "produces": [ - "application/json" - ], - "tags": [ - "projects" - ], - "summary": "Show project details", - "parameters": [ - { - "type": "string", - "description": "Current user name", - "name": "X-Grafana-User", - "in": "header", - "required": true - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Project", - "name": "project", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Cluster ID", - "name": "cluster_id", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/http.Response-models_Project" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - } - } - } - }, - "/projects/admin": { - "get": { - "security": [ - { - "BasicAuth": [] - } - ], - "description": "This endpoint will show details of the queried project. The\ncurrent user is always identified by the header `X-Grafana-User` in\nthe request.\n\nThe user who is making the request must be in the list of admin users\nconfigured for the server.\n\nThe details include list of users in that project. If current user\nattempts to query a project that they are not part of, empty response\nwill be returned\n", - "produces": [ - "application/json" - ], - "tags": [ - "projects" - ], - "summary": "Admin endpoint to fetch project details", - "parameters": [ - { - "type": "string", - "description": "Current user name", - "name": "X-Grafana-User", - "in": "header", - "required": true - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Project", - "name": "project", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Cluster ID", - "name": "cluster_id", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/http.Response-models_Project" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - } - } - } - }, - "/stats/{mode}/admin": { - "get": { - "security": [ - { - "BasicAuth": [] - } - ], - "description": "This admin endpoint will return the quick stats of _queried_ cluster. The\ncurrent user is always identified by the header `X-Grafana-User` in\nthe request.\n\nThe user who is making the request must be in the list of admin users\nconfigured for the server.\n\nA path parameter `mode` is required to return the kind of usage statistics.\nCurrently, two modes of statistics are supported:\n- `current`: In this mode the usage between two time periods is returned\nbased on `from` and `to` query parameters.\n- `global`: In this mode the _total_ usage statistics are returned. For\ninstance, if the retention period of the DB is set to 2 years, usage\nstatistics of last 2 years will be returned.\n\nThe statistics include current number of active users, projects, jobs, _etc_.\n\nIf `to` query parameter is not provided, current time will be used. If `from`\nquery parameter is not used, a default query window of 24 hours will be used.\nIt means if `to` is provided, `from` will be calculated as `to` - 24hrs.\n", - "produces": [ - "application/json" - ], - "tags": [ - "stats" - ], - "summary": "Admin Stats", - "parameters": [ - { - "type": "string", - "description": "Current user name", - "name": "X-Grafana-User", - "in": "header", - "required": true - }, - { - "enum": [ - "current", - "global" - ], - "type": "string", - "description": "Whether to get quick stats within a period or global", - "name": "mode", - "in": "path", - "required": true - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "cluster ID", - "name": "cluster_id", - "in": "query" - }, - { - "type": "string", - "description": "From timestamp", - "name": "from", - "in": "query" - }, - { - "type": "string", - "description": "To timestamp", - "name": "to", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/http.Response-models_Stat" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "403": { - "description": "Forbidden", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - } - } - } - }, - "/units": { - "get": { - "security": [ - { - "BasicAuth": [] - } - ], - "description": "This user endpoint will fetch compute units of the current user. The\ncurrent user is always identified by the header `X-Grafana-User` in\nthe request.\n\nIf multiple query parameters are passed, for instance, `?uuid=\u003cuuid\u003e\u0026project=\u003cproject\u003e`,\nthe intersection of query parameters are used to fetch compute units rather than\nthe union. That means if the compute unit's `uuid` does not belong to the queried\nproject, null response will be returned.\n\nIn order to return the running compute units as well, use the query parameter `running`.\n\nIf `to` query parameter is not provided, current time will be used. If `from`\nquery parameter is not used, a default query window of 24 hours will be used.\nIt means if `to` is provided, `from` will be calculated as `to` - 24hrs. If query\nparameter `timezone` is provided, the unit's created, start and end time strings\nwill be presented in that time zone.\n\nTo limit the number of fields in the response, use `field` query parameter. By default, all\nfields will be included in the response if they are _non-empty_.", - "produces": [ - "application/json" - ], - "tags": [ - "units" - ], - "summary": "User endpoint for fetching compute units", - "parameters": [ - { - "type": "string", - "description": "Current user name", - "name": "X-Grafana-User", - "in": "header", - "required": true - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Cluster ID", - "name": "cluster_id", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Unit UUID", - "name": "uuid", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Project", - "name": "project", - "in": "query" - }, - { - "type": "boolean", - "description": "Whether to fetch running units", - "name": "running", - "in": "query" - }, - { - "type": "string", - "description": "From timestamp", - "name": "from", - "in": "query" - }, - { - "type": "string", - "description": "To timestamp", - "name": "to", - "in": "query" - }, - { - "type": "string", - "description": "Time zone in IANA format", - "name": "timezone", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Fields to return in response", - "name": "field", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/http.Response-models_Unit" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "403": { - "description": "Forbidden", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - } - } - } - }, - "/units/admin": { - "get": { - "security": [ - { - "BasicAuth": [] - } - ], - "description": "This admin endpoint will fetch compute units of _any_ user, compute unit and/or project. The\ncurrent user is always identified by the header `X-Grafana-User` in\nthe request.\n\nThe user who is making the request must be in the list of admin users\nconfigured for the server.\n\nIf multiple query parameters are passed, for instance, `?uuid=\u003cuuid\u003e\u0026user=\u003cuser\u003e`,\nthe intersection of query parameters are used to fetch compute units rather than\nthe union. That means if the compute unit's `uuid` does not belong to the queried\nuser, null response will be returned.\n\nIn order to return the running compute units as well, use the query parameter `running`.\n\nIf `to` query parameter is not provided, current time will be used. If `from`\nquery parameter is not used, a default query window of 24 hours will be used.\nIt means if `to` is provided, `from` will be calculated as `to` - 24hrs. If query\nparameter `timezone` is provided, the unit's created, start and end time strings\nwill be presented in that time zone.\n\nTo limit the number of fields in the response, use `field` query parameter. By default, all\nfields will be included in the response if they are _non-empty_.", - "produces": [ - "application/json" - ], - "tags": [ - "units" - ], - "summary": "Admin endpoint for fetching compute units.", - "parameters": [ - { - "type": "string", - "description": "Current user name", - "name": "X-Grafana-User", - "in": "header", - "required": true - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Cluster ID", - "name": "cluster_id", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Unit UUID", - "name": "uuid", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Project", - "name": "project", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "User name", - "name": "user", - "in": "query" - }, - { - "type": "boolean", - "description": "Whether to fetch running units", - "name": "running", - "in": "query" - }, - { - "type": "string", - "description": "From timestamp", - "name": "from", - "in": "query" - }, - { - "type": "string", - "description": "To timestamp", - "name": "to", - "in": "query" - }, - { - "type": "string", - "description": "Time zone in IANA format", - "name": "timezone", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Fields to return in response", - "name": "field", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/http.Response-models_Unit" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "403": { - "description": "Forbidden", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - } - } - } - }, - "/units/verify": { - "get": { - "security": [ - { - "BasicAuth": [] - } - ], - "description": "This endpoint will check if the current user is the owner of the\nqueried UUIDs. The current user is always identified by the header `X-Grafana-User` in\nthe request.\n\nA response of 200 means that the current user is the owner of the queried UUIDs.\nAny other response code should be treated as the current user not being the owner\nof the queried units.\n\nThe ownership check passes if any of the following conditions are `true`:\n- If the current user is the _direct_ owner of the compute unit.\n- If the current user belongs to the same account/project/namespace as\nthe compute unit. This means the users belonging to the same project can\naccess each others compute units.\n- If the current user has admin role\n\nThe above checks must pass for **all** the queried units.\nIf the check does not pass for at least one queried unit, a response 403 will be\nreturned.\n\nAny 500 response codes should be treated as failed check as well.", - "produces": [ - "application/json" - ], - "tags": [ - "units" - ], - "summary": "Verify unit ownership", - "parameters": [ - { - "type": "string", - "description": "Current user name", - "name": "X-Grafana-User", - "in": "header", - "required": true - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Unit UUID", - "name": "uuid", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Cluster ID", - "name": "cluster_id", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "403": { - "description": "Forbidden", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - } - } - } - }, - "/usage/{mode}": { - "get": { - "security": [ - { - "BasicAuth": [] - } - ], - "description": "This endpoint will return the usage statistics current user. The\ncurrent user is always identified by the header `X-Grafana-User` in\nthe request.\n\nA path parameter `mode` is required to return the kind of usage statistics.\nCurrently, two modes of statistics are supported:\n- `current`: In this mode the usage between two time periods is returned\nbased on `from` and `to` query parameters.\n- `global`: In this mode the _total_ usage statistics are returned. For\ninstance, if the retention period of the DB is set to 2 years, usage\nstatistics of last 2 years will be returned.\n\nThe statistics can be limited to certain projects by passing `project` query,\nparameter.\n\nIf `to` query parameter is not provided, current time will be used. If `from`\nquery parameter is not used, a default query window of 24 hours will be used.\nIt means if `to` is provided, `from` will be calculated as `to` - 24hrs.\n\nTo limit the number of fields in the response, use `field` query parameter. By default, all\nfields will be included in the response if they are _non-empty_.\n\nThe `current` usage mode can be slow query depending the requested\nwindow interval. This is mostly due to the fact that the CEEMS DB\nuses custom JSON types to store metric data and usage statistics\nneeds to aggregate metrics over these JSON types using custom aggregate\nfunctions which can be slow.\n\nTherefore the query results are cached for 15 min to avoid load on server.\nURL string is used as the cache key. Thus, the query parameters\n`from` and `to` are rounded to the nearest timestamp that are\nmultiple of 900 sec (15 min). The first query will make a DB query and\ncache results and subsequent queries, for a given user and same URL\nquery parameters, will return the same cached result until the cache\nis invalidated after 15 min.", - "produces": [ - "application/json" - ], - "tags": [ - "usage" - ], - "summary": "Usage statistics", - "parameters": [ - { - "type": "string", - "description": "Current user name", - "name": "X-Grafana-User", - "in": "header", - "required": true - }, - { - "enum": [ - "current", - "global" - ], - "type": "string", - "description": "Whether to get usage stats within a period or global", - "name": "mode", - "in": "path", - "required": true - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "cluster ID", - "name": "cluster_id", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Project", - "name": "project", - "in": "query" - }, - { - "type": "string", - "description": "From timestamp", - "name": "from", - "in": "query" - }, - { - "type": "string", - "description": "To timestamp", - "name": "to", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Fields to return in response", - "name": "field", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/http.Response-models_Usage" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - } - } - } - }, - "/usage/{mode}/admin": { - "get": { - "security": [ - { - "BasicAuth": [] - } - ], - "description": "This admin endpoint will return the usage statistics of _queried_ user. The\ncurrent user is always identified by the header `X-Grafana-User` in\nthe request.\n\nThe user who is making the request must be in the list of admin users\nconfigured for the server.\n\nA path parameter `mode` is required to return the kind of usage statistics.\nCurrently, two modes of statistics are supported:\n- `current`: In this mode the usage between two time periods is returned\nbased on `from` and `to` query parameters.\n- `global`: In this mode the _total_ usage statistics are returned. For\ninstance, if the retention period of the DB is set to 2 years, usage\nstatistics of last 2 years will be returned.\n\nThe statistics can be limited to certain projects by passing `project` query,\nparameter.\n\nIf `to` query parameter is not provided, current time will be used. If `from`\nquery parameter is not used, a default query window of 24 hours will be used.\nIt means if `to` is provided, `from` will be calculated as `to` - 24hrs.\n\nTo limit the number of fields in the response, use `field` query parameter. By default, all\nfields will be included in the response if they are _non-empty_.\n\nThe `current` usage mode can be slow query depending the requested\nwindow interval. This is mostly due to the fact that the CEEMS DB\nuses custom JSON types to store metric data and usage statistics\nneeds to aggregate metrics over these JSON types using custom aggregate\nfunctions which can be slow.\n\nTherefore the query results are cached for 15 min to avoid load on server.\nURL string is used as the cache key. Thus, the query parameters\n`from` and `to` are rounded to the nearest timestamp that are\nmultiple of 900 sec (15 min). The first query will make a DB query and\ncache results and subsequent queries, for a given user and same URL\nquery parameters, will return the same cached result until the cache\nis invalidated after 15 min.", - "produces": [ - "application/json" - ], - "tags": [ - "usage" - ], - "summary": "Admin Usage statistics", - "parameters": [ - { - "type": "string", - "description": "Current user name", - "name": "X-Grafana-User", - "in": "header", - "required": true - }, - { - "enum": [ - "current", - "global" - ], - "type": "string", - "description": "Whether to get usage stats within a period or global", - "name": "mode", - "in": "path", - "required": true - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "cluster ID", - "name": "cluster_id", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "csv", - "description": "Project", - "name": "project", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Username", - "name": "user", - "in": "query" - }, - { - "type": "string", - "description": "From timestamp", - "name": "from", - "in": "query" - }, - { - "type": "string", - "description": "To timestamp", - "name": "to", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Fields to return in response", - "name": "field", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/http.Response-models_Usage" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "403": { - "description": "Forbidden", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - } - } - } - }, - "/users": { - "get": { - "security": [ - { - "BasicAuth": [] - } - ], - "description": "This endpoint will show details of the current user. The\ncurrent user is always identified by the header `X-Grafana-User` in\nthe request.\n\nThe details include list of projects that user is currently a part of.\n", - "produces": [ - "application/json" - ], - "tags": [ - "users" - ], - "summary": "Show user details", - "parameters": [ - { - "type": "string", - "description": "Current user name", - "name": "X-Grafana-User", - "in": "header", - "required": true - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Cluster ID", - "name": "cluster_id", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/http.Response-models_User" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - } - } - } - }, - "/users/admin": { - "get": { - "security": [ - { - "BasicAuth": [] - } - ], - "description": "This endpoint will show details of the queried user(s). The\ncurrent user is always identified by the header `X-Grafana-User` in\nthe request.\n\nThe user who is making the request must be in the list of admin users\nconfigured for the server.\n\nWhen the query parameter `user` is empty, all users will be returned\nin the response.\n\nThe details include list of projects that user is currently a part of.\n\nWhen query parameter `role` is set to `admin`, only admin users will\nwill be returned. The `tags` values indicates the source of admin user.\n", - "produces": [ - "application/json" - ], - "tags": [ - "users" - ], - "summary": "Admin endpoint for fetching user details of _any_ user.", - "parameters": [ - { - "type": "string", - "description": "Current user name", - "name": "X-Grafana-User", - "in": "header", - "required": true - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "User name", - "name": "user", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "Cluster ID", - "name": "cluster_id", - "in": "query" - }, - { - "type": "string", - "description": "User role", - "name": "role", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/http.Response-models_User" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/http.Response-any" - } - } - } - } - } - }, - "definitions": { - "http.Response-any": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": {}, - "x-nullable": true, - "x-omitempty": true - }, - "error": { - "type": "string", - "x-nullable": true, - "x-omitempty": true - }, - "errorType": { - "allOf": [ - { - "$ref": "#/definitions/http.errorType" - } - ], - "x-nullable": true, - "x-omitempty": true - }, - "status": { - "type": "string" - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - }, - "x-nullable": true, - "x-omitempty": true - } - } - }, - "http.Response-models_Cluster": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/definitions/models.Cluster" - }, - "x-nullable": true, - "x-omitempty": true - }, - "error": { - "type": "string", - "x-nullable": true, - "x-omitempty": true - }, - "errorType": { - "allOf": [ - { - "$ref": "#/definitions/http.errorType" - } - ], - "x-nullable": true, - "x-omitempty": true - }, - "status": { - "type": "string" - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - }, - "x-nullable": true, - "x-omitempty": true - } - } - }, - "http.Response-models_Project": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/definitions/models.Project" - }, - "x-nullable": true, - "x-omitempty": true - }, - "error": { - "type": "string", - "x-nullable": true, - "x-omitempty": true - }, - "errorType": { - "allOf": [ - { - "$ref": "#/definitions/http.errorType" - } - ], - "x-nullable": true, - "x-omitempty": true - }, - "status": { - "type": "string" - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - }, - "x-nullable": true, - "x-omitempty": true - } - } - }, - "http.Response-models_Stat": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/definitions/models.Stat" - }, - "x-nullable": true, - "x-omitempty": true - }, - "error": { - "type": "string", - "x-nullable": true, - "x-omitempty": true - }, - "errorType": { - "allOf": [ - { - "$ref": "#/definitions/http.errorType" - } - ], - "x-nullable": true, - "x-omitempty": true - }, - "status": { - "type": "string" - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - }, - "x-nullable": true, - "x-omitempty": true - } - } - }, - "http.Response-models_Unit": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/definitions/models.Unit" - }, - "x-nullable": true, - "x-omitempty": true - }, - "error": { - "type": "string", - "x-nullable": true, - "x-omitempty": true - }, - "errorType": { - "allOf": [ - { - "$ref": "#/definitions/http.errorType" - } - ], - "x-nullable": true, - "x-omitempty": true - }, - "status": { - "type": "string" - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - }, - "x-nullable": true, - "x-omitempty": true - } - } - }, - "http.Response-models_Usage": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/definitions/models.Usage" - }, - "x-nullable": true, - "x-omitempty": true - }, - "error": { - "type": "string", - "x-nullable": true, - "x-omitempty": true - }, - "errorType": { - "allOf": [ - { - "$ref": "#/definitions/http.errorType" - } - ], - "x-nullable": true, - "x-omitempty": true - }, - "status": { - "type": "string" - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - }, - "x-nullable": true, - "x-omitempty": true - } - } - }, - "http.Response-models_User": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/definitions/models.User" - }, - "x-nullable": true, - "x-omitempty": true - }, - "error": { - "type": "string", - "x-nullable": true, - "x-omitempty": true - }, - "errorType": { - "allOf": [ - { - "$ref": "#/definitions/http.errorType" - } - ], - "x-nullable": true, - "x-omitempty": true - }, - "status": { - "type": "string" - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - }, - "x-nullable": true, - "x-omitempty": true - } - } - }, - "http.errorType": { - "type": "string", - "enum": [ - "", - "unauthorized", - "forbidden", - "timeout", - "canceled", - "execution", - "bad_data", - "internal", - "unavailable", - "not_found", - "not_acceptable" - ], - "x-enum-varnames": [ - "ErrorNone", - "ErrorUnauthorized", - "ErrorForbidden", - "ErrorTimeout", - "ErrorCanceled", - "ErrorExec", - "ErrorBadData", - "ErrorInternal", - "ErrorUnavailable", - "ErrorNotFound", - "ErrorNotAcceptable" - ] - }, - "models.Cluster": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "manager": { - "type": "string" - } - } - }, - "models.Project": { - "type": "object", - "properties": { - "cluster_id": { - "description": "Identifier of the resource manager that owns project. It is used to differentiate multiple clusters of same resource manager.", - "type": "string", - "example": "slurm-0" - }, - "name": { - "description": "Name of the project", - "type": "string", - "example": "prj1" - }, - "resource_manager": { - "description": "Name of the resource manager that owns project. Eg slurm, openstack, kubernetes, etc", - "type": "string", - "example": "slurm" - }, - "tags": { - "description": "List of meta data tags of the project", - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "tag1", - "tag2" - ] - }, - "uid": { - "description": "Unique identifier of the project provided by cluster", - "type": "string", - "example": "1000" - }, - "users": { - "description": "List of users of the project", - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "usr1", - "usr2" - ] - } - } - }, - "models.Stat": { - "type": "object", - "properties": { - "cluster_id": { - "description": "Identifier of the resource manager that owns compute unit. It is used to differentiate multiple clusters of same resource manager.", - "type": "string", - "example": "slurm-0" - }, - "num_active_units": { - "description": "Number of active units that are in running state", - "type": "integer", - "example": 800 - }, - "num_inactive_units": { - "description": "Number of inactive units that are in terminated/cancelled/error state", - "type": "integer", - "example": 200 - }, - "num_projects": { - "description": "Number of projects", - "type": "integer", - "example": 200 - }, - "num_units": { - "description": "Number of active and terminated units", - "type": "integer", - "example": 1000 - }, - "num_users": { - "description": "Number of users", - "type": "integer", - "example": 500 - }, - "resource_manager": { - "description": "Name of the resource manager that owns project. Eg slurm, openstack, kubernetes, etc", - "type": "string", - "example": "slurm" - } - } - }, - "models.Unit": { - "type": "object", - "properties": { - "allocation": { - "description": "Allocation map of unit. Only string and int64 values are supported in map", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "cpus": 1, - "gpus": 1, - "mem": 10 - } - }, - "avg_cpu_mem_usage": { - "description": "Average CPU memory usage(s) during lifetime of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "global": 45.26 - } - }, - "avg_cpu_usage": { - "description": "Average CPU usage(s) during lifetime of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "global": 70.12 - } - }, - "avg_gpu_mem_usage": { - "description": "Average GPU memory usage(s) during lifetime of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "global": 45.26 - } - }, - "avg_gpu_usage": { - "description": "Average GPU usage(s) during lifetime of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "global": 70.12 - } - }, - "cluster_id": { - "description": "Identifier of the resource manager that owns compute unit. It is used to differentiate multiple clusters of same resource manager.", - "type": "string", - "example": "slurm-0" - }, - "created_at": { - "description": "Creation time", - "type": "string", - "example": "2023-02-21T15:48:20+0100" - }, - "created_at_ts": { - "description": "Creation timestamp", - "type": "integer", - "example": 1676990900000 - }, - "elapsed": { - "description": "Human readable total elapsed time string", - "type": "string", - "example": "2-00:10:20" - }, - "ended_at": { - "description": "End time", - "type": "string", - "example": "Unknown" - }, - "ended_at_ts": { - "description": "End timestamp", - "type": "integer", - "example": 0 - }, - "groupname": { - "description": "User group", - "type": "string", - "example": "grp1" - }, - "name": { - "description": "Name of compute unit", - "type": "string", - "example": "my-slurm-job" - }, - "project": { - "description": "Account in batch systems, Tenant in Openstack, Namespace in k8s", - "type": "string", - "example": "prj1" - }, - "resource_manager": { - "description": "Name of the resource manager that owns compute unit. Eg slurm, openstack, kubernetes, etc", - "type": "string", - "example": "slurm" - }, - "started_at": { - "description": "Start time", - "type": "string", - "example": "2023-02-21T15:49:06+0100" - }, - "started_at_ts": { - "description": "Start timestamp", - "type": "integer", - "example": 1676990946000 - }, - "state": { - "description": "Current state of unit", - "type": "string", - "example": "RUNNING" - }, - "tags": { - "description": "A map to store generic info. String and int64 are valid value types of map", - "type": "object", - "additionalProperties": { - "type": "string" - }, - "example": { - "gid": "1000", - "uid": "1000", - "workdir": "/home/user" - } - }, - "total_cpu_emissions_gms": { - "description": "Total CPU emissions from source(s) in grams during lifetime of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "emaps_total": 3.09, - "owid_total": 5.22 - } - }, - "total_cpu_energy_usage_kwh": { - "description": "Total CPU energy usage(s) in kWh during lifetime of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "total": 0.73 - } - }, - "total_egress_stats": { - "description": "Total Outgress statistics of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "bytes_total": 454342323, - "packets_total": 23232323 - } - }, - "total_gpu_emissions_gms": { - "description": "Total GPU emissions from source(s) in grams during lifetime of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "emaps_total": 12.09, - "owid_total": 15.22 - } - }, - "total_gpu_energy_usage_kwh": { - "description": "Total GPU energy usage(s) in kWh during lifetime of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "total": 5.39 - } - }, - "total_ingress_stats": { - "description": "Total Ingress statistics of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "bytes_total": 8503405, - "packets_total": 43423 - } - }, - "total_io_read_stats": { - "description": "Total IO read statistics during lifetime of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "bytes_total": 245000000, - "requests_total": 49423 - } - }, - "total_io_write_stats": { - "description": "Total IO write statistics during lifetime of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "bytes_total": 12000000, - "requests_total": 13923 - } - }, - "total_time_seconds": { - "description": "Different types of times in seconds consumed by the unit. This map contains at minimum `walltime`, `alloc_cputime`, `alloc_cpumemtime`, `alloc_gputime` and `alloc_gpumem_time` keys.", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "alloc_cpumemtime": 1000, - "alloc_cputime": 100, - "alloc_gpumemtime": 100, - "alloc_gputime": 100, - "walltime": 100 - } - }, - "username": { - "description": "Username", - "type": "string", - "example": "usr1" - }, - "uuid": { - "description": "Unique identifier of unit. It can be Job ID for batch jobs, UUID for pods in k8s or VMs in Openstack", - "type": "string", - "example": "193048" - } - } - }, - "models.Usage": { - "type": "object", - "properties": { - "avg_cpu_mem_usage": { - "description": "Average CPU memory usage(s) during lifetime of project", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "global": 45.26 - } - }, - "avg_cpu_usage": { - "description": "Average CPU usage(s) during lifetime of project", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "global": 70.12 - } - }, - "avg_gpu_mem_usage": { - "description": "Average GPU memory usage(s) during lifetime of project", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "global": 45.26 - } - }, - "avg_gpu_usage": { - "description": "Average GPU usage(s) during lifetime of project", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "global": 70.12 - } - }, - "cluster_id": { - "description": "Identifier of the resource manager that owns compute unit. It is used to differentiate multiple clusters of same resource manager.", - "type": "string", - "example": "slurm-0" - }, - "groupname": { - "description": "User group", - "type": "string", - "example": "grp1" - }, - "num_units": { - "description": "Number of consumed units", - "type": "integer", - "example": 145 - }, - "project": { - "description": "Account in batch systems, Tenant in Openstack, Namespace in k8s", - "type": "string", - "example": "prj1" - }, - "resource_manager": { - "description": "Name of the resource manager that owns project. Eg slurm, openstack, kubernetes, etc", - "type": "string", - "example": "slurm" - }, - "total_cpu_emissions_gms": { - "description": "Total CPU emissions from source(s) in grams during lifetime of project", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "emaps_total": 3.09, - "owid_total": 5.22 - } - }, - "total_cpu_energy_usage_kwh": { - "description": "Total CPU energy usage(s) in kWh during lifetime of project", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "total": 0.73 - } - }, - "total_egress_stats": { - "description": "Total Egress statistics of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "bytes_total": 454342323, - "packets_total": 23232323 - } - }, - "total_gpu_emissions_gms": { - "description": "Total GPU emissions from source(s) in grams during lifetime of project", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "emaps_total": 12.09, - "owid_total": 15.22 - } - }, - "total_gpu_energy_usage_kwh": { - "description": "Total GPU energy usage(s) in kWh during lifetime of project", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "total": 5.39 - } - }, - "total_ingress_stats": { - "description": "Total Ingress statistics of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "bytes_total": 8503405, - "packets_total": 43423 - } - }, - "total_io_read_stats": { - "description": "Total IO read statistics during lifetime of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "bytes_total": 245000000, - "requests_total": 49423 - } - }, - "total_io_write_stats": { - "description": "Total IO write statistics during lifetime of unit", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "bytes_total": 12000000, - "requests_total": 13923 - } - }, - "total_time_seconds": { - "description": "Different times in seconds consumed by the unit. This map must contain `walltime`, `alloc_cputime`, `alloc_cpumemtime`, `alloc_gputime` and `alloc_gpumem_time` keys.", - "type": "object", - "additionalProperties": { - "type": "number" - }, - "example": { - "alloc_cpumemtime": 1000, - "alloc_cputime": 100, - "alloc_gpumemtime": 100, - "alloc_gputime": 100, - "walltime": 100 - } - }, - "username": { - "description": "Username", - "type": "string", - "example": "usr1" - } - } - }, - "models.User": { - "type": "object", - "properties": { - "cluster_id": { - "description": "Identifier of the resource manager that owns user. It is used to differentiate multiple clusters of same resource manager.", - "type": "string", - "example": "slurm-0" - }, - "name": { - "description": "Name of the user", - "type": "string", - "example": "usr1" - }, - "projects": { - "description": "List of projects of the user", - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "prj1", - "prj2" - ] - }, - "resource_manager": { - "description": "Name of the resource manager that owns user. Eg slurm, openstack, kubernetes, etc", - "type": "string", - "example": "slurm" - }, - "tags": { - "description": "List of meta data tags of the user", - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "tag1", - "tag2" - ] - }, - "uid": { - "description": "Unique identifier of the user provided by cluster", - "type": "string", - "example": "1000" - } - } - } - }, - "securityDefinitions": { - "BasicAuth": { - "type": "basic" - } - }, - "externalDocs": { - "url": "https://ceems-dev.github.io/ceems/" - } -} \ No newline at end of file diff --git a/pkg/api/http/docs/swagger.yaml b/pkg/api/http/docs/swagger.yaml deleted file mode 100644 index 97f1af8c..00000000 --- a/pkg/api/http/docs/swagger.yaml +++ /dev/null @@ -1,1547 +0,0 @@ -basePath: /api/v1 -definitions: - http.Response-any: - properties: - data: - items: {} - type: array - x-nullable: true - x-omitempty: true - error: - type: string - x-nullable: true - x-omitempty: true - errorType: - allOf: - - $ref: '#/definitions/http.errorType' - x-nullable: true - x-omitempty: true - status: - type: string - warnings: - items: - type: string - type: array - x-nullable: true - x-omitempty: true - type: object - http.Response-models_Cluster: - properties: - data: - items: - $ref: '#/definitions/models.Cluster' - type: array - x-nullable: true - x-omitempty: true - error: - type: string - x-nullable: true - x-omitempty: true - errorType: - allOf: - - $ref: '#/definitions/http.errorType' - x-nullable: true - x-omitempty: true - status: - type: string - warnings: - items: - type: string - type: array - x-nullable: true - x-omitempty: true - type: object - http.Response-models_Project: - properties: - data: - items: - $ref: '#/definitions/models.Project' - type: array - x-nullable: true - x-omitempty: true - error: - type: string - x-nullable: true - x-omitempty: true - errorType: - allOf: - - $ref: '#/definitions/http.errorType' - x-nullable: true - x-omitempty: true - status: - type: string - warnings: - items: - type: string - type: array - x-nullable: true - x-omitempty: true - type: object - http.Response-models_Stat: - properties: - data: - items: - $ref: '#/definitions/models.Stat' - type: array - x-nullable: true - x-omitempty: true - error: - type: string - x-nullable: true - x-omitempty: true - errorType: - allOf: - - $ref: '#/definitions/http.errorType' - x-nullable: true - x-omitempty: true - status: - type: string - warnings: - items: - type: string - type: array - x-nullable: true - x-omitempty: true - type: object - http.Response-models_Unit: - properties: - data: - items: - $ref: '#/definitions/models.Unit' - type: array - x-nullable: true - x-omitempty: true - error: - type: string - x-nullable: true - x-omitempty: true - errorType: - allOf: - - $ref: '#/definitions/http.errorType' - x-nullable: true - x-omitempty: true - status: - type: string - warnings: - items: - type: string - type: array - x-nullable: true - x-omitempty: true - type: object - http.Response-models_Usage: - properties: - data: - items: - $ref: '#/definitions/models.Usage' - type: array - x-nullable: true - x-omitempty: true - error: - type: string - x-nullable: true - x-omitempty: true - errorType: - allOf: - - $ref: '#/definitions/http.errorType' - x-nullable: true - x-omitempty: true - status: - type: string - warnings: - items: - type: string - type: array - x-nullable: true - x-omitempty: true - type: object - http.Response-models_User: - properties: - data: - items: - $ref: '#/definitions/models.User' - type: array - x-nullable: true - x-omitempty: true - error: - type: string - x-nullable: true - x-omitempty: true - errorType: - allOf: - - $ref: '#/definitions/http.errorType' - x-nullable: true - x-omitempty: true - status: - type: string - warnings: - items: - type: string - type: array - x-nullable: true - x-omitempty: true - type: object - http.errorType: - enum: - - "" - - unauthorized - - forbidden - - timeout - - canceled - - execution - - bad_data - - internal - - unavailable - - not_found - - not_acceptable - type: string - x-enum-varnames: - - ErrorNone - - ErrorUnauthorized - - ErrorForbidden - - ErrorTimeout - - ErrorCanceled - - ErrorExec - - ErrorBadData - - ErrorInternal - - ErrorUnavailable - - ErrorNotFound - - ErrorNotAcceptable - models.Cluster: - properties: - id: - type: string - manager: - type: string - type: object - models.Project: - properties: - cluster_id: - description: Identifier of the resource manager that owns project. It is used - to differentiate multiple clusters of same resource manager. - example: slurm-0 - type: string - name: - description: Name of the project - example: prj1 - type: string - resource_manager: - description: Name of the resource manager that owns project. Eg slurm, openstack, - kubernetes, etc - example: slurm - type: string - tags: - description: List of meta data tags of the project - example: - - tag1 - - tag2 - items: - type: string - type: array - uid: - description: Unique identifier of the project provided by cluster - example: "1000" - type: string - users: - description: List of users of the project - example: - - usr1 - - usr2 - items: - type: string - type: array - type: object - models.Stat: - properties: - cluster_id: - description: Identifier of the resource manager that owns compute unit. It - is used to differentiate multiple clusters of same resource manager. - example: slurm-0 - type: string - num_active_units: - description: Number of active units that are in running state - example: 800 - type: integer - num_inactive_units: - description: Number of inactive units that are in terminated/cancelled/error - state - example: 200 - type: integer - num_projects: - description: Number of projects - example: 200 - type: integer - num_units: - description: Number of active and terminated units - example: 1000 - type: integer - num_users: - description: Number of users - example: 500 - type: integer - resource_manager: - description: Name of the resource manager that owns project. Eg slurm, openstack, - kubernetes, etc - example: slurm - type: string - type: object - models.Unit: - properties: - allocation: - additionalProperties: - type: number - description: Allocation map of unit. Only string and int64 values are supported - in map - example: - cpus: 1 - gpus: 1 - mem: 10 - type: object - avg_cpu_mem_usage: - additionalProperties: - type: number - description: Average CPU memory usage(s) during lifetime of unit - example: - global: 45.26 - type: object - avg_cpu_usage: - additionalProperties: - type: number - description: Average CPU usage(s) during lifetime of unit - example: - global: 70.12 - type: object - avg_gpu_mem_usage: - additionalProperties: - type: number - description: Average GPU memory usage(s) during lifetime of unit - example: - global: 45.26 - type: object - avg_gpu_usage: - additionalProperties: - type: number - description: Average GPU usage(s) during lifetime of unit - example: - global: 70.12 - type: object - cluster_id: - description: Identifier of the resource manager that owns compute unit. It - is used to differentiate multiple clusters of same resource manager. - example: slurm-0 - type: string - created_at: - description: Creation time - example: 2023-02-21T15:48:20+0100 - type: string - created_at_ts: - description: Creation timestamp - example: 1676990900000 - type: integer - elapsed: - description: Human readable total elapsed time string - example: 2-00:10:20 - type: string - ended_at: - description: End time - example: Unknown - type: string - ended_at_ts: - description: End timestamp - example: 0 - type: integer - groupname: - description: User group - example: grp1 - type: string - name: - description: Name of compute unit - example: my-slurm-job - type: string - project: - description: Account in batch systems, Tenant in Openstack, Namespace in k8s - example: prj1 - type: string - resource_manager: - description: Name of the resource manager that owns compute unit. Eg slurm, - openstack, kubernetes, etc - example: slurm - type: string - started_at: - description: Start time - example: 2023-02-21T15:49:06+0100 - type: string - started_at_ts: - description: Start timestamp - example: 1676990946000 - type: integer - state: - description: Current state of unit - example: RUNNING - type: string - tags: - additionalProperties: - type: string - description: A map to store generic info. String and int64 are valid value - types of map - example: - gid: "1000" - uid: "1000" - workdir: /home/user - type: object - total_cpu_emissions_gms: - additionalProperties: - type: number - description: Total CPU emissions from source(s) in grams during lifetime of - unit - example: - emaps_total: 3.09 - owid_total: 5.22 - type: object - total_cpu_energy_usage_kwh: - additionalProperties: - type: number - description: Total CPU energy usage(s) in kWh during lifetime of unit - example: - total: 0.73 - type: object - total_egress_stats: - additionalProperties: - type: number - description: Total Outgress statistics of unit - example: - bytes_total: 454342323 - packets_total: 23232323 - type: object - total_gpu_emissions_gms: - additionalProperties: - type: number - description: Total GPU emissions from source(s) in grams during lifetime of - unit - example: - emaps_total: 12.09 - owid_total: 15.22 - type: object - total_gpu_energy_usage_kwh: - additionalProperties: - type: number - description: Total GPU energy usage(s) in kWh during lifetime of unit - example: - total: 5.39 - type: object - total_ingress_stats: - additionalProperties: - type: number - description: Total Ingress statistics of unit - example: - bytes_total: 8503405 - packets_total: 43423 - type: object - total_io_read_stats: - additionalProperties: - type: number - description: Total IO read statistics during lifetime of unit - example: - bytes_total: 245000000 - requests_total: 49423 - type: object - total_io_write_stats: - additionalProperties: - type: number - description: Total IO write statistics during lifetime of unit - example: - bytes_total: 12000000 - requests_total: 13923 - type: object - total_time_seconds: - additionalProperties: - type: number - description: Different types of times in seconds consumed by the unit. This - map contains at minimum `walltime`, `alloc_cputime`, `alloc_cpumemtime`, - `alloc_gputime` and `alloc_gpumem_time` keys. - example: - alloc_cpumemtime: 1000 - alloc_cputime: 100 - alloc_gpumemtime: 100 - alloc_gputime: 100 - walltime: 100 - type: object - username: - description: Username - example: usr1 - type: string - uuid: - description: Unique identifier of unit. It can be Job ID for batch jobs, UUID - for pods in k8s or VMs in Openstack - example: "193048" - type: string - type: object - models.Usage: - properties: - avg_cpu_mem_usage: - additionalProperties: - type: number - description: Average CPU memory usage(s) during lifetime of project - example: - global: 45.26 - type: object - avg_cpu_usage: - additionalProperties: - type: number - description: Average CPU usage(s) during lifetime of project - example: - global: 70.12 - type: object - avg_gpu_mem_usage: - additionalProperties: - type: number - description: Average GPU memory usage(s) during lifetime of project - example: - global: 45.26 - type: object - avg_gpu_usage: - additionalProperties: - type: number - description: Average GPU usage(s) during lifetime of project - example: - global: 70.12 - type: object - cluster_id: - description: Identifier of the resource manager that owns compute unit. It - is used to differentiate multiple clusters of same resource manager. - example: slurm-0 - type: string - groupname: - description: User group - example: grp1 - type: string - num_units: - description: Number of consumed units - example: 145 - type: integer - project: - description: Account in batch systems, Tenant in Openstack, Namespace in k8s - example: prj1 - type: string - resource_manager: - description: Name of the resource manager that owns project. Eg slurm, openstack, - kubernetes, etc - example: slurm - type: string - total_cpu_emissions_gms: - additionalProperties: - type: number - description: Total CPU emissions from source(s) in grams during lifetime of - project - example: - emaps_total: 3.09 - owid_total: 5.22 - type: object - total_cpu_energy_usage_kwh: - additionalProperties: - type: number - description: Total CPU energy usage(s) in kWh during lifetime of project - example: - total: 0.73 - type: object - total_egress_stats: - additionalProperties: - type: number - description: Total Egress statistics of unit - example: - bytes_total: 454342323 - packets_total: 23232323 - type: object - total_gpu_emissions_gms: - additionalProperties: - type: number - description: Total GPU emissions from source(s) in grams during lifetime of - project - example: - emaps_total: 12.09 - owid_total: 15.22 - type: object - total_gpu_energy_usage_kwh: - additionalProperties: - type: number - description: Total GPU energy usage(s) in kWh during lifetime of project - example: - total: 5.39 - type: object - total_ingress_stats: - additionalProperties: - type: number - description: Total Ingress statistics of unit - example: - bytes_total: 8503405 - packets_total: 43423 - type: object - total_io_read_stats: - additionalProperties: - type: number - description: Total IO read statistics during lifetime of unit - example: - bytes_total: 245000000 - requests_total: 49423 - type: object - total_io_write_stats: - additionalProperties: - type: number - description: Total IO write statistics during lifetime of unit - example: - bytes_total: 12000000 - requests_total: 13923 - type: object - total_time_seconds: - additionalProperties: - type: number - description: Different times in seconds consumed by the unit. This map must - contain `walltime`, `alloc_cputime`, `alloc_cpumemtime`, `alloc_gputime` - and `alloc_gpumem_time` keys. - example: - alloc_cpumemtime: 1000 - alloc_cputime: 100 - alloc_gpumemtime: 100 - alloc_gputime: 100 - walltime: 100 - type: object - username: - description: Username - example: usr1 - type: string - type: object - models.User: - properties: - cluster_id: - description: Identifier of the resource manager that owns user. It is used - to differentiate multiple clusters of same resource manager. - example: slurm-0 - type: string - name: - description: Name of the user - example: usr1 - type: string - projects: - description: List of projects of the user - example: - - prj1 - - prj2 - items: - type: string - type: array - resource_manager: - description: Name of the resource manager that owns user. Eg slurm, openstack, - kubernetes, etc - example: slurm - type: string - tags: - description: List of meta data tags of the user - example: - - tag1 - - tag2 - items: - type: string - type: array - uid: - description: Unique identifier of the user provided by cluster - example: "1000" - type: string - type: object -externalDocs: - url: https://ceems-dev.github.io/ceems/ -host: ceems-demo.myaddr.tools:6443 -info: - contact: - email: mahendra.paipuri@gmail.com - name: Mahendra Paipuri - url: https://github.com/ceems-dev/ceems/issues - description: |- - OpenAPI specification (OAS) for the CEEMS REST API. - - See the Interactive Docs to try CEEMS API methods without writing code, and get - the complete schema of resources exposed by the API. - - If basic auth is enabled, all the endpoints require authentication. - - All the endpoints, except `health`, `swagger`, `debug` and `demo`, - must send a user-agent header. - - A demo instance of CEEMS API server is provided for the users to test. This - instance is running at `https://ceems-demo.myaddr.tools:6443` and it is the - default server that will serve the requests originating from current OAS client. - - Some of the valid users for this demo instance are: - - arnold - - betty - - edna - - gazoo - - wilma - - Every request must contain a `X-Grafana-User` header with one of the usernames - above as the value to the header. This is how CEEMS API server recognise the user. - - Some of the valid projects for this demo instance are: - - bedrock - - cornerstone - - Demo instance have CORS enabled to allow cross-domain communication from the browser. - All responses have a wildcard same-origin which makes them completely public and - accessible to everyone, including any code on any site. - - To test admin resources, users can use `admin` as `X-Grafana-User`. - - Timestamps must be specified in milliseconds, unless otherwise specified. - license: - name: GPL-3.0 license - url: https://www.gnu.org/licenses/gpl-3.0.en.html - title: CEEMS API - version: "1.0" - x-logo: - altText: CEEMS logo - url: https://raw.githubusercontent.com/ceems-dev/ceems/refs/heads/main/website/static/img/logo.png -paths: - /clusters/admin: - get: - description: | - This endpoint will list all the cluster IDs in the CEEMS DB. The - current user is always identified by the header `X-Grafana-User` in - the request. - - This will list all the cluster IDs in the DB. This is primarily - used to verify the CEEMS load balancer's backend IDs that should match - with cluster IDs. - parameters: - - description: Current user name - in: header - name: X-Grafana-User - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/http.Response-models_Cluster' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/http.Response-any' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/http.Response-any' - security: - - BasicAuth: [] - summary: List clusters - tags: - - clusters - /demo/{resource}: - get: - description: |- - This endpoint returns sample response for units and usage models. This - endpoint do not require the setting of `X-Grafana-User` header as it - only returns mock data for each request. This can be used to introspect - the response models for different resources. - - The endpoint requires a path parameter `resource` which takes either: - - `units` which returns a mock units response - - `usage` which returns a mock usage response. - - The mock data is generated randomly for each request and there is - no guarantee that the data has logical sense. - parameters: - - description: Whether to return mock units or usage data - enum: - - units - - usage - in: path - name: resource - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/http.Response-models_Usage' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/http.Response-any' - summary: Demo Units/Usage endpoints - tags: - - demo - /projects: - get: - description: | - This endpoint will show details of the queried project of current user. The - current user is always identified by the header `X-Grafana-User` in - the request. - - The details include list of users in that project. If current user - attempts to query a project that they are not part of, empty response - will be returned - parameters: - - description: Current user name - in: header - name: X-Grafana-User - required: true - type: string - - collectionFormat: multi - description: Project - in: query - items: - type: string - name: project - type: array - - collectionFormat: multi - description: Cluster ID - in: query - items: - type: string - name: cluster_id - type: array - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/http.Response-models_Project' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/http.Response-any' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/http.Response-any' - security: - - BasicAuth: [] - summary: Show project details - tags: - - projects - /projects/admin: - get: - description: | - This endpoint will show details of the queried project. The - current user is always identified by the header `X-Grafana-User` in - the request. - - The user who is making the request must be in the list of admin users - configured for the server. - - The details include list of users in that project. If current user - attempts to query a project that they are not part of, empty response - will be returned - parameters: - - description: Current user name - in: header - name: X-Grafana-User - required: true - type: string - - collectionFormat: multi - description: Project - in: query - items: - type: string - name: project - type: array - - collectionFormat: multi - description: Cluster ID - in: query - items: - type: string - name: cluster_id - type: array - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/http.Response-models_Project' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/http.Response-any' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/http.Response-any' - security: - - BasicAuth: [] - summary: Admin endpoint to fetch project details - tags: - - projects - /stats/{mode}/admin: - get: - description: | - This admin endpoint will return the quick stats of _queried_ cluster. The - current user is always identified by the header `X-Grafana-User` in - the request. - - The user who is making the request must be in the list of admin users - configured for the server. - - A path parameter `mode` is required to return the kind of usage statistics. - Currently, two modes of statistics are supported: - - `current`: In this mode the usage between two time periods is returned - based on `from` and `to` query parameters. - - `global`: In this mode the _total_ usage statistics are returned. For - instance, if the retention period of the DB is set to 2 years, usage - statistics of last 2 years will be returned. - - The statistics include current number of active users, projects, jobs, _etc_. - - If `to` query parameter is not provided, current time will be used. If `from` - query parameter is not used, a default query window of 24 hours will be used. - It means if `to` is provided, `from` will be calculated as `to` - 24hrs. - parameters: - - description: Current user name - in: header - name: X-Grafana-User - required: true - type: string - - description: Whether to get quick stats within a period or global - enum: - - current - - global - in: path - name: mode - required: true - type: string - - collectionFormat: multi - description: cluster ID - in: query - items: - type: string - name: cluster_id - type: array - - description: From timestamp - in: query - name: from - type: string - - description: To timestamp - in: query - name: to - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/http.Response-models_Stat' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/http.Response-any' - "403": - description: Forbidden - schema: - $ref: '#/definitions/http.Response-any' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/http.Response-any' - security: - - BasicAuth: [] - summary: Admin Stats - tags: - - stats - /units: - get: - description: |- - This user endpoint will fetch compute units of the current user. The - current user is always identified by the header `X-Grafana-User` in - the request. - - If multiple query parameters are passed, for instance, `?uuid=&project=`, - the intersection of query parameters are used to fetch compute units rather than - the union. That means if the compute unit's `uuid` does not belong to the queried - project, null response will be returned. - - In order to return the running compute units as well, use the query parameter `running`. - - If `to` query parameter is not provided, current time will be used. If `from` - query parameter is not used, a default query window of 24 hours will be used. - It means if `to` is provided, `from` will be calculated as `to` - 24hrs. If query - parameter `timezone` is provided, the unit's created, start and end time strings - will be presented in that time zone. - - To limit the number of fields in the response, use `field` query parameter. By default, all - fields will be included in the response if they are _non-empty_. - parameters: - - description: Current user name - in: header - name: X-Grafana-User - required: true - type: string - - collectionFormat: multi - description: Cluster ID - in: query - items: - type: string - name: cluster_id - type: array - - collectionFormat: multi - description: Unit UUID - in: query - items: - type: string - name: uuid - type: array - - collectionFormat: multi - description: Project - in: query - items: - type: string - name: project - type: array - - description: Whether to fetch running units - in: query - name: running - type: boolean - - description: From timestamp - in: query - name: from - type: string - - description: To timestamp - in: query - name: to - type: string - - description: Time zone in IANA format - in: query - name: timezone - type: string - - collectionFormat: multi - description: Fields to return in response - in: query - items: - type: string - name: field - type: array - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/http.Response-models_Unit' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/http.Response-any' - "403": - description: Forbidden - schema: - $ref: '#/definitions/http.Response-any' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/http.Response-any' - security: - - BasicAuth: [] - summary: User endpoint for fetching compute units - tags: - - units - /units/admin: - get: - description: |- - This admin endpoint will fetch compute units of _any_ user, compute unit and/or project. The - current user is always identified by the header `X-Grafana-User` in - the request. - - The user who is making the request must be in the list of admin users - configured for the server. - - If multiple query parameters are passed, for instance, `?uuid=&user=`, - the intersection of query parameters are used to fetch compute units rather than - the union. That means if the compute unit's `uuid` does not belong to the queried - user, null response will be returned. - - In order to return the running compute units as well, use the query parameter `running`. - - If `to` query parameter is not provided, current time will be used. If `from` - query parameter is not used, a default query window of 24 hours will be used. - It means if `to` is provided, `from` will be calculated as `to` - 24hrs. If query - parameter `timezone` is provided, the unit's created, start and end time strings - will be presented in that time zone. - - To limit the number of fields in the response, use `field` query parameter. By default, all - fields will be included in the response if they are _non-empty_. - parameters: - - description: Current user name - in: header - name: X-Grafana-User - required: true - type: string - - collectionFormat: multi - description: Cluster ID - in: query - items: - type: string - name: cluster_id - type: array - - collectionFormat: multi - description: Unit UUID - in: query - items: - type: string - name: uuid - type: array - - collectionFormat: multi - description: Project - in: query - items: - type: string - name: project - type: array - - collectionFormat: multi - description: User name - in: query - items: - type: string - name: user - type: array - - description: Whether to fetch running units - in: query - name: running - type: boolean - - description: From timestamp - in: query - name: from - type: string - - description: To timestamp - in: query - name: to - type: string - - description: Time zone in IANA format - in: query - name: timezone - type: string - - collectionFormat: multi - description: Fields to return in response - in: query - items: - type: string - name: field - type: array - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/http.Response-models_Unit' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/http.Response-any' - "403": - description: Forbidden - schema: - $ref: '#/definitions/http.Response-any' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/http.Response-any' - security: - - BasicAuth: [] - summary: Admin endpoint for fetching compute units. - tags: - - units - /units/verify: - get: - description: |- - This endpoint will check if the current user is the owner of the - queried UUIDs. The current user is always identified by the header `X-Grafana-User` in - the request. - - A response of 200 means that the current user is the owner of the queried UUIDs. - Any other response code should be treated as the current user not being the owner - of the queried units. - - The ownership check passes if any of the following conditions are `true`: - - If the current user is the _direct_ owner of the compute unit. - - If the current user belongs to the same account/project/namespace as - the compute unit. This means the users belonging to the same project can - access each others compute units. - - If the current user has admin role - - The above checks must pass for **all** the queried units. - If the check does not pass for at least one queried unit, a response 403 will be - returned. - - Any 500 response codes should be treated as failed check as well. - parameters: - - description: Current user name - in: header - name: X-Grafana-User - required: true - type: string - - collectionFormat: multi - description: Unit UUID - in: query - items: - type: string - name: uuid - type: array - - collectionFormat: multi - description: Cluster ID - in: query - items: - type: string - name: cluster_id - type: array - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/http.Response-any' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/http.Response-any' - "403": - description: Forbidden - schema: - $ref: '#/definitions/http.Response-any' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/http.Response-any' - security: - - BasicAuth: [] - summary: Verify unit ownership - tags: - - units - /usage/{mode}: - get: - description: |- - This endpoint will return the usage statistics current user. The - current user is always identified by the header `X-Grafana-User` in - the request. - - A path parameter `mode` is required to return the kind of usage statistics. - Currently, two modes of statistics are supported: - - `current`: In this mode the usage between two time periods is returned - based on `from` and `to` query parameters. - - `global`: In this mode the _total_ usage statistics are returned. For - instance, if the retention period of the DB is set to 2 years, usage - statistics of last 2 years will be returned. - - The statistics can be limited to certain projects by passing `project` query, - parameter. - - If `to` query parameter is not provided, current time will be used. If `from` - query parameter is not used, a default query window of 24 hours will be used. - It means if `to` is provided, `from` will be calculated as `to` - 24hrs. - - To limit the number of fields in the response, use `field` query parameter. By default, all - fields will be included in the response if they are _non-empty_. - - The `current` usage mode can be slow query depending the requested - window interval. This is mostly due to the fact that the CEEMS DB - uses custom JSON types to store metric data and usage statistics - needs to aggregate metrics over these JSON types using custom aggregate - functions which can be slow. - - Therefore the query results are cached for 15 min to avoid load on server. - URL string is used as the cache key. Thus, the query parameters - `from` and `to` are rounded to the nearest timestamp that are - multiple of 900 sec (15 min). The first query will make a DB query and - cache results and subsequent queries, for a given user and same URL - query parameters, will return the same cached result until the cache - is invalidated after 15 min. - parameters: - - description: Current user name - in: header - name: X-Grafana-User - required: true - type: string - - description: Whether to get usage stats within a period or global - enum: - - current - - global - in: path - name: mode - required: true - type: string - - collectionFormat: multi - description: cluster ID - in: query - items: - type: string - name: cluster_id - type: array - - collectionFormat: multi - description: Project - in: query - items: - type: string - name: project - type: array - - description: From timestamp - in: query - name: from - type: string - - description: To timestamp - in: query - name: to - type: string - - collectionFormat: multi - description: Fields to return in response - in: query - items: - type: string - name: field - type: array - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/http.Response-models_Usage' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/http.Response-any' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/http.Response-any' - security: - - BasicAuth: [] - summary: Usage statistics - tags: - - usage - /usage/{mode}/admin: - get: - description: |- - This admin endpoint will return the usage statistics of _queried_ user. The - current user is always identified by the header `X-Grafana-User` in - the request. - - The user who is making the request must be in the list of admin users - configured for the server. - - A path parameter `mode` is required to return the kind of usage statistics. - Currently, two modes of statistics are supported: - - `current`: In this mode the usage between two time periods is returned - based on `from` and `to` query parameters. - - `global`: In this mode the _total_ usage statistics are returned. For - instance, if the retention period of the DB is set to 2 years, usage - statistics of last 2 years will be returned. - - The statistics can be limited to certain projects by passing `project` query, - parameter. - - If `to` query parameter is not provided, current time will be used. If `from` - query parameter is not used, a default query window of 24 hours will be used. - It means if `to` is provided, `from` will be calculated as `to` - 24hrs. - - To limit the number of fields in the response, use `field` query parameter. By default, all - fields will be included in the response if they are _non-empty_. - - The `current` usage mode can be slow query depending the requested - window interval. This is mostly due to the fact that the CEEMS DB - uses custom JSON types to store metric data and usage statistics - needs to aggregate metrics over these JSON types using custom aggregate - functions which can be slow. - - Therefore the query results are cached for 15 min to avoid load on server. - URL string is used as the cache key. Thus, the query parameters - `from` and `to` are rounded to the nearest timestamp that are - multiple of 900 sec (15 min). The first query will make a DB query and - cache results and subsequent queries, for a given user and same URL - query parameters, will return the same cached result until the cache - is invalidated after 15 min. - parameters: - - description: Current user name - in: header - name: X-Grafana-User - required: true - type: string - - description: Whether to get usage stats within a period or global - enum: - - current - - global - in: path - name: mode - required: true - type: string - - collectionFormat: multi - description: cluster ID - in: query - items: - type: string - name: cluster_id - type: array - - collectionFormat: csv - description: Project - in: query - items: - type: string - name: project - type: array - - collectionFormat: multi - description: Username - in: query - items: - type: string - name: user - type: array - - description: From timestamp - in: query - name: from - type: string - - description: To timestamp - in: query - name: to - type: string - - collectionFormat: multi - description: Fields to return in response - in: query - items: - type: string - name: field - type: array - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/http.Response-models_Usage' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/http.Response-any' - "403": - description: Forbidden - schema: - $ref: '#/definitions/http.Response-any' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/http.Response-any' - security: - - BasicAuth: [] - summary: Admin Usage statistics - tags: - - usage - /users: - get: - description: | - This endpoint will show details of the current user. The - current user is always identified by the header `X-Grafana-User` in - the request. - - The details include list of projects that user is currently a part of. - parameters: - - description: Current user name - in: header - name: X-Grafana-User - required: true - type: string - - collectionFormat: multi - description: Cluster ID - in: query - items: - type: string - name: cluster_id - type: array - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/http.Response-models_User' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/http.Response-any' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/http.Response-any' - security: - - BasicAuth: [] - summary: Show user details - tags: - - users - /users/admin: - get: - description: | - This endpoint will show details of the queried user(s). The - current user is always identified by the header `X-Grafana-User` in - the request. - - The user who is making the request must be in the list of admin users - configured for the server. - - When the query parameter `user` is empty, all users will be returned - in the response. - - The details include list of projects that user is currently a part of. - - When query parameter `role` is set to `admin`, only admin users will - will be returned. The `tags` values indicates the source of admin user. - parameters: - - description: Current user name - in: header - name: X-Grafana-User - required: true - type: string - - collectionFormat: multi - description: User name - in: query - items: - type: string - name: user - type: array - - collectionFormat: multi - description: Cluster ID - in: query - items: - type: string - name: cluster_id - type: array - - description: User role - in: query - name: role - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/http.Response-models_User' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/http.Response-any' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/http.Response-any' - security: - - BasicAuth: [] - summary: Admin endpoint for fetching user details of _any_ user. - tags: - - users -schemes: -- https -securityDefinitions: - BasicAuth: - type: basic -swagger: "2.0" diff --git a/pkg/api/http/middleware.go b/pkg/api/http/middleware.go index 63c07d7e..76c6870b 100644 --- a/pkg/api/http/middleware.go +++ b/pkg/api/http/middleware.go @@ -22,12 +22,13 @@ type authenticationMiddleware struct { logger *slog.Logger whitelistedURLs *regexp.Regexp db *sql.DB + cors *cors headers []string adminUsers func(context.Context, *sql.DB) ([]string, error) } // newAuthenticationMiddleware returns a new instance authenticationMiddleware. -func newAuthenticationMiddleware(routePrefix string, headers []string, db *sql.DB, logger *slog.Logger) (*authenticationMiddleware, error) { +func newAuthenticationMiddleware(routePrefix string, headers []string, db *sql.DB, cors *cors, logger *slog.Logger) (*authenticationMiddleware, error) { // Playground: https://regex101.com/r/lkmsWz/3 urlsRegex, err := regexp.Compile( fmt.Sprintf("^(?:(%s)?)/(swagger|debug|health|demo)(.*)", strings.TrimSuffix(routePrefix, "/")), @@ -45,6 +46,7 @@ func newAuthenticationMiddleware(routePrefix string, headers []string, db *sql.D logger: logger, whitelistedURLs: urlsRegex, db: db, + cors: cors, headers: headers, adminUsers: AdminUserNames, }, nil @@ -52,7 +54,7 @@ func newAuthenticationMiddleware(routePrefix string, headers []string, db *sql.D // Middleware function, which will be called for each request. func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + return http.HandlerFunc(amw.cors.wrap(func(w http.ResponseWriter, r *http.Request) { var loggedUser string var admUsers []string @@ -129,7 +131,7 @@ func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler end: // Pass down the request to the next middleware (or final handler) next.ServeHTTP(w, r) - }) + })) } // getAuthenticatedUserFromHeader looks different headers for the presence of value diff --git a/pkg/api/http/middleware_test.go b/pkg/api/http/middleware_test.go index 1e1b623c..12dcdc08 100644 --- a/pkg/api/http/middleware_test.go +++ b/pkg/api/http/middleware_test.go @@ -7,6 +7,7 @@ import ( "database/sql" "net/http" "net/http/httptest" + "regexp" "testing" "github.com/ceems-dev/ceems/pkg/api/base" @@ -19,7 +20,11 @@ func mockAdminUsers(_ context.Context, _ *sql.DB) ([]string, error) { } func setupMiddleware() (http.Handler, error) { - amw, err := newAuthenticationMiddleware("/api/v1", []string{base.GrafanaUserHeader}, nil, noOpLogger) + // Setup CORS + cors := newCORS(regexp.MustCompile("^(?:.*)$"), []string{"X-Grafana-User"}) + + // Setup middileware + amw, err := newAuthenticationMiddleware("/api/v1", []string{base.GrafanaUserHeader}, nil, cors, noOpLogger) if err != nil { return nil, err } @@ -35,16 +40,19 @@ func setupMiddleware() (http.Handler, error) { } func TestNewMiddleware(t *testing.T) { + // Setup CORS + cors := newCORS(regexp.MustCompile("^(?:.*)$"), []string{"X-Grafana-User"}) + // Valid route prefix - _, err := newAuthenticationMiddleware("/api/v1", []string{base.GrafanaUserHeader}, nil, noOpLogger) + _, err := newAuthenticationMiddleware("/api/v1", []string{base.GrafanaUserHeader}, nil, cors, noOpLogger) require.NoError(t, err) // Invald route prefix - _, err = newAuthenticationMiddleware("/(?!\\/)", []string{base.GrafanaUserHeader}, nil, noOpLogger) + _, err = newAuthenticationMiddleware("/(?!\\/)", []string{base.GrafanaUserHeader}, nil, cors, noOpLogger) require.Error(t, err) // No user headers - _, err = newAuthenticationMiddleware("/api/v1", nil, nil, noOpLogger) + _, err = newAuthenticationMiddleware("/api/v1", nil, nil, cors, noOpLogger) require.Error(t, err) } diff --git a/pkg/api/http/server.go b/pkg/api/http/server.go index 8ed5994c..a98eeddb 100644 --- a/pkg/api/http/server.go +++ b/pkg/api/http/server.go @@ -27,7 +27,7 @@ import ( "github.com/ceems-dev/ceems/internal/common" "github.com/ceems-dev/ceems/pkg/api/base" "github.com/ceems-dev/ceems/pkg/api/db" - "github.com/ceems-dev/ceems/pkg/api/http/docs" + "github.com/ceems-dev/ceems/pkg/api/docs" "github.com/ceems-dev/ceems/pkg/api/models" "github.com/ceems-dev/ceems/pkg/sqlite3" "github.com/go-chi/httprate" @@ -299,7 +299,7 @@ func New(c *Config) (*CEEMSServer, error) { } // Add a middleware that verifies headers and pass them in requests - amw, err := newAuthenticationMiddleware(routePrefix, c.Web.UserHeaderNames, server.db, c.Logger) + amw, err := newAuthenticationMiddleware(routePrefix, c.Web.UserHeaderNames, server.db, cors, c.Logger) if err != nil { return nil, fmt.Errorf("failed to create middleware: %w", err) } @@ -322,66 +322,10 @@ func New(c *Config) (*CEEMSServer, error) { return server, nil } -// Start launches CEEMS HTTP server godoc -// -// @title CEEMS API -// @version 1.0 -// @description OpenAPI specification (OAS) for the CEEMS REST API. -// @description -// @description See the Interactive Docs to try CEEMS API methods without writing code, and get -// @description the complete schema of resources exposed by the API. -// @description -// @description If basic auth is enabled, all the endpoints require authentication. -// @description -// @description All the endpoints, except `health`, `swagger`, `debug` and `demo`, -// @description must send a user-agent header. -// @description -// @description A demo instance of CEEMS API server is provided for the users to test. This -// @description instance is running at `https://ceems-demo.myaddr.tools:6443` and it is the -// @description default server that will serve the requests originating from current OAS client. -// @description -// @description Some of the valid users for this demo instance are: -// @description - arnold -// @description - betty -// @description - edna -// @description - gazoo -// @description - wilma -// @description -// @description Every request must contain a `X-Grafana-User` header with one of the usernames -// @description above as the value to the header. This is how CEEMS API server recognise the user. -// @description -// @description Some of the valid projects for this demo instance are: -// @description - bedrock -// @description - cornerstone -// @description -// @description Demo instance have CORS enabled to allow cross-domain communication from the browser. -// @description All responses have a wildcard same-origin which makes them completely public and -// @description accessible to everyone, including any code on any site. -// @description -// @description To test admin resources, users can use `admin` as `X-Grafana-User`. -// @description -// @description Timestamps must be specified in milliseconds, unless otherwise specified. -// -// @contact.name Mahendra Paipuri -// @contact.url https://github.com/ceems-dev/ceems/issues -// @contact.email mahendra.paipuri@gmail.com -// -// @license.name GPL-3.0 license -// @license.url https://www.gnu.org/licenses/gpl-3.0.en.html -// -// @securityDefinitions.basic BasicAuth -// -// @host ceems-demo.myaddr.tools:6443 -// @BasePath /api/v1 -// -// @schemes https -// -// @externalDocs.url https://ceems-dev.github.io/ceems/ -// -// @x-logo {"url": "https://raw.githubusercontent.com/ceems-dev/ceems/refs/heads/main/website/static/img/logo.png", "altText": "CEEMS logo"} +// Start launches CEEMS HTTP server godoc. func (s *CEEMSServer) Start(_ context.Context) error { // Set swagger info - docs.SwaggerInfo.BasePath = "/api/" + base.APIVersion + // docs.SwaggerInfo.BasePath = "/api/" + base.APIVersion docs.SwaggerInfo.Schemes = []string{"http", "https"} docs.SwaggerInfo.Host = s.server.Addr @@ -466,7 +410,26 @@ func (s *CEEMSServer) setWriteDeadline(deadline time.Duration, w http.ResponseWr } } -// Check status of server. +// Health check godoc +// +// @Summary Health check endpoint for API server. +// @Description This health endpoint can be used to check on the health of the API server +// @Description in containerised and Kubernetes environments. +// @Description +// @Description This endpoint does not need any user header. However, if basic auth +// @Description is enabled, authentication header must be provided to get status. +// @servers.url https://ceems-demo.myaddr.tools:6443 +// @servers.description Test CEEMS API server URL for health, swagger and debug endpoints only. +// @Security BasicAuth +// @Tags health +// @Produce plain +// @Success 200 {string} string "OK" +// @Failure 401 {string} string "Unauthorized" +// @Failure 503 {string} string "KO" +// @Router /health [get] +// +// GET /health +// Get health status of the server. func (s *CEEMSServer) health(w http.ResponseWriter, r *http.Request) { if !s.healthCheck(r.Context(), s.db, s.logger) { w.Header().Set("X-Content-Type-Options", "nosniff") @@ -849,7 +812,7 @@ queryUnits: // @Param timezone query string false "Time zone in IANA format" // @Param field query []string false "Fields to return in response" collectionFormat(multi) // @Success 200 {object} Response[models.Unit] -// @Failure 401 {object} Response[any] +// @Failure 401 {string} string "Unauthorized" // @Failure 403 {object} Response[any] // @Failure 500 {object} Response[any] // @Router /units/admin [get] @@ -902,7 +865,7 @@ func (s *CEEMSServer) unitsAdmin(w http.ResponseWriter, r *http.Request) { // @Param timezone query string false "Time zone in IANA format" // @Param field query []string false "Fields to return in response" collectionFormat(multi) // @Success 200 {object} Response[models.Unit] -// @Failure 401 {object} Response[any] +// @Failure 401 {string} string "Unauthorized" // @Failure 403 {object} Response[any] // @Failure 500 {object} Response[any] // @Router /units [get] @@ -953,7 +916,7 @@ func (s *CEEMSServer) units(w http.ResponseWriter, r *http.Request) { // @Param uuid query []string false "Unit UUID" collectionFormat(multi) // @Param cluster_id query []string false "Cluster ID" collectionFormat(multi) // @Success 200 {object} Response[any] -// @Failure 401 {object} Response[any] +// @Failure 401 {string} string "Unauthorized" // @Failure 403 {object} Response[any] // @Failure 500 {object} Response[any] // @Router /units/verify [get] @@ -1016,7 +979,8 @@ func (s *CEEMSServer) verifyUnitsOwnership(w http.ResponseWriter, r *http.Reques // @Produce json // @Param X-Grafana-User header string true "Current user name" // @Success 200 {object} Response[models.Cluster] -// @Failure 401 {object} Response[any] +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {object} Response[any] // @Failure 500 {object} Response[any] // @Router /clusters/admin [get] // @@ -1172,7 +1136,7 @@ func (s *CEEMSServer) usersQuerier(users []string, w http.ResponseWriter, r *htt // @Param X-Grafana-User header string true "Current user name" // @Param cluster_id query []string false "Cluster ID" collectionFormat(multi) // @Success 200 {object} Response[models.User] -// @Failure 401 {object} Response[any] +// @Failure 401 {string} string "Unauthorized" // @Failure 500 {object} Response[any] // @Router /users [get] // @@ -1218,7 +1182,8 @@ func (s *CEEMSServer) users(w http.ResponseWriter, r *http.Request) { // @Param cluster_id query []string false "Cluster ID" collectionFormat(multi) // @Param role query string false "User role" // @Success 200 {object} Response[models.User] -// @Failure 401 {object} Response[any] +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {object} Response[any] // @Failure 500 {object} Response[any] // @Router /users/admin [get] // @@ -1322,7 +1287,7 @@ func (s *CEEMSServer) projectsQuerier(users []string, w http.ResponseWriter, r * // @Param project query []string false "Project" collectionFormat(multi) // @Param cluster_id query []string false "Cluster ID" collectionFormat(multi) // @Success 200 {object} Response[models.Project] -// @Failure 401 {object} Response[any] +// @Failure 401 {string} string "Unauthorized" // @Failure 500 {object} Response[any] // @Router /projects [get] // @@ -1363,7 +1328,8 @@ func (s *CEEMSServer) projects(w http.ResponseWriter, r *http.Request) { // @Param project query []string false "Project" collectionFormat(multi) // @Param cluster_id query []string false "Cluster ID" collectionFormat(multi) // @Success 200 {object} Response[models.Project] -// @Failure 401 {object} Response[any] +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {object} Response[any] // @Failure 500 {object} Response[any] // @Router /projects/admin [get] // @@ -1730,7 +1696,7 @@ func (s *CEEMSServer) globalUsage(users []string, queriedFields []string, w http // @Param to query string false "To timestamp" // @Param field query []string false "Fields to return in response" collectionFormat(multi) // @Success 200 {object} Response[models.Usage] -// @Failure 401 {object} Response[any] +// @Failure 401 {string} string "Unauthorized" // @Failure 500 {object} Response[any] // @Router /usage/{mode} [get] // @@ -1832,7 +1798,7 @@ func (s *CEEMSServer) usage(w http.ResponseWriter, r *http.Request) { // @Param to query string false "To timestamp" // @Param field query []string false "Fields to return in response" collectionFormat(multi) // @Success 200 {object} Response[models.Usage] -// @Failure 401 {object} Response[any] +// @Failure 401 {string} string "Unauthorized" // @Failure 403 {object} Response[any] // @Failure 500 {object} Response[any] // @Router /usage/{mode}/admin [get] @@ -2039,7 +2005,7 @@ func (s *CEEMSServer) globalStats(users []string, w http.ResponseWriter, r *http // @Param from query string false "From timestamp" // @Param to query string false "To timestamp" // @Success 200 {object} Response[models.Stat] -// @Failure 401 {object} Response[any] +// @Failure 401 {string} string "Unauthorized" // @Failure 403 {object} Response[any] // @Failure 500 {object} Response[any] // @Router /stats/{mode}/admin [get] diff --git a/pkg/api/models/models.go b/pkg/api/models/models.go index 9229c542..830dc93f 100644 --- a/pkg/api/models/models.go +++ b/pkg/api/models/models.go @@ -145,13 +145,13 @@ func (s Stat) TagMap(keyTag string, valueTag string) map[string]string { // Project is the container for a given account/tenant/namespace of cluster. type Project struct { ID int64 `example:"1" json:"-" sql:"id" sqlitetype:"integer not null primary key"` - UID string `example:"1000" json:"uid,omitempty" sql:"uid" sqlitetype:"text"` // Unique identifier of the project provided by cluster - ClusterID string `example:"slurm-0" json:"cluster_id" sql:"cluster_id" sqlitetype:"text"` // Identifier of the resource manager that owns project. It is used to differentiate multiple clusters of same resource manager. - ResourceManager string `example:"slurm" json:"resource_manager" sql:"resource_manager" sqlitetype:"text"` // Name of the resource manager that owns project. Eg slurm, openstack, kubernetes, etc - Name string `example:"prj1" json:"name" sql:"name" sqlitetype:"text"` // Name of the project - Users List `example:"usr1,usr2" json:"users" sql:"users" sqlitetype:"text" swaggertype:"array,string"` // List of users of the project - Tags List `example:"tag1,tag2" json:"tags,omitempty" sql:"tags" sqlitetype:"text" swaggertype:"array,string"` // List of meta data tags of the project - LastUpdatedAt string `json:"-" sql:"last_updated_at" sqlitetype:"text"` // Last Updated time + UID string `example:"1000" json:"uid,omitempty" sql:"uid" sqlitetype:"text"` // Unique identifier of the project provided by cluster + ClusterID string `example:"slurm-0" json:"cluster_id" sql:"cluster_id" sqlitetype:"text"` // Identifier of the resource manager that owns project. It is used to differentiate multiple clusters of same resource manager. + ResourceManager string `example:"slurm" json:"resource_manager" sql:"resource_manager" sqlitetype:"text"` // Name of the resource manager that owns project. Eg slurm, openstack, kubernetes, etc + Name string `example:"prj1" json:"name" sql:"name" sqlitetype:"text"` // Name of the project + Users List `example:"usr1,usr2" json:"users" sql:"users" sqlitetype:"text"` // List of users of the project + Tags List `example:"tag1,tag2" json:"tags,omitempty" sql:"tags" sqlitetype:"text"` // List of meta data tags of the project + LastUpdatedAt string `json:"-" sql:"last_updated_at" sqlitetype:"text"` // Last Updated time } // TableName returns the table which admin users list is stored into. @@ -172,14 +172,14 @@ func (p Project) TagMap(keyTag string, valueTag string) map[string]string { // User is the container for a given user of cluster. type User struct { - ID int64 `example:"1" json:"-" sql:"id" sqlitetype:"integer not null primary key"` - UID string `example:"1000" json:"uid,omitempty" sql:"uid" sqlitetype:"text"` // Unique identifier of the user provided by cluster - ClusterID string `example:"slurm-0" json:"cluster_id" sql:"cluster_id" sqlitetype:"text"` // Identifier of the resource manager that owns user. It is used to differentiate multiple clusters of same resource manager. - ResourceManager string `example:"slurm" json:"resource_manager,omitempty" sql:"resource_manager" sqlitetype:"text"` // Name of the resource manager that owns user. Eg slurm, openstack, kubernetes, etc - Name string `example:"usr1" json:"name" sql:"name" sqlitetype:"text"` // Name of the user - Projects List `example:"prj1,prj2" json:"projects,omitempty" sql:"projects" sqlitetype:"text" swaggertype:"array,string"` // List of projects of the user - Tags List `example:"tag1,tag2" json:"tags,omitempty" sql:"tags" sqlitetype:"text" swaggertype:"array,string"` // List of meta data tags of the user - LastUpdatedAt string `json:"-" sql:"last_updated_at" sqlitetype:"text"` // Last Updated time + ID int64 `example:"1" json:"-" sql:"id" sqlitetype:"integer not null primary key"` + UID string `example:"1000" json:"uid,omitempty" sql:"uid" sqlitetype:"text"` // Unique identifier of the user provided by cluster + ClusterID string `example:"slurm-0" json:"cluster_id" sql:"cluster_id" sqlitetype:"text"` // Identifier of the resource manager that owns user. It is used to differentiate multiple clusters of same resource manager. + ResourceManager string `example:"slurm" json:"resource_manager" sql:"resource_manager" sqlitetype:"text"` // Name of the resource manager that owns user. Eg slurm, openstack, kubernetes, etc + Name string `example:"usr1" json:"name" sql:"name" sqlitetype:"text"` // Name of the user + Projects List `example:"prj1,prj2" json:"projects" sql:"projects" sqlitetype:"text"` // List of projects of the user + Tags List `example:"tag1,tag2" json:"tags,omitempty" sql:"tags" sqlitetype:"text"` // List of meta data tags of the user + LastUpdatedAt string `json:"-" sql:"last_updated_at" sqlitetype:"text"` // Last Updated time } // TableName returns the table which admin users list is stored into. diff --git a/website/.gitignore b/website/.gitignore index 540fc077..f2853b06 100644 --- a/website/.gitignore +++ b/website/.gitignore @@ -10,6 +10,9 @@ docs/api/*.mdx docs/api/*.ts docs/api/*.json +docs/api/schemas/*.mdx +docs/api/schemas/*.ts +docs/api/schemas/*.json # Misc .DS_Store diff --git a/website/docs/deployments/guide.md b/website/docs/deployments/guide.md index 571f3f70..7dac9786 100644 --- a/website/docs/deployments/guide.md +++ b/website/docs/deployments/guide.md @@ -614,7 +614,7 @@ systemctl start ceems_api_server.service ``` Once the API server has started, we can check for its health by hitting endpoint -`http://localhost:9020/api/v1/health` assuming we are on the host where API server +`http://localhost:9020/health` assuming we are on the host where API server has been deployed. Once the Prometheus and CEEMS API server are up and running, we can configure Grafana diff --git a/website/docusaurus.config.ts b/website/docusaurus.config.ts index 04e6900f..c6bbb95b 100644 --- a/website/docusaurus.config.ts +++ b/website/docusaurus.config.ts @@ -122,14 +122,14 @@ const config: Config = { docsPluginId: "classic", // configured for preset-classic config: { ceems: { - specPath: "../pkg/api/http/docs/swagger.yaml", + specPath: "../pkg/api/docs/swagger.yaml", outputDir: "docs/api", sidebarOptions: { groupPathsBy: "tag", categoryLinkSource: "tag", }, template: "api.mustache", // Customize API MDX with mustache template - // showSchemas: true, + showSchemas: true, markdownGenerators: { createApiPageMD: myCustomApiMdGenerator }, // customize MDX with markdown generator } satisfies OpenApiPlugin.Options, } diff --git a/website/yarn.lock b/website/yarn.lock index c35d3c25..585668c9 100644 --- a/website/yarn.lock +++ b/website/yarn.lock @@ -4246,15 +4246,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001646, caniuse-lite@^1.0.30001669, caniuse-lite@^1.0.30001702, caniuse-lite@^1.0.30001718: - version "1.0.30001734" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001734.tgz" - integrity sha512-uhE1Ye5vgqju6OI71HTQqcBCZrvHugk0MjLak7Q+HfoBgoq5Bi+5YnwjP4fjDgrtYr/l8MVRBvzz9dPD4KyK0A== - -caniuse-lite@^1.0.30001759: - version "1.0.30001769" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz#1ad91594fad7dc233777c2781879ab5409f7d9c2" - integrity sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001646, caniuse-lite@^1.0.30001669, caniuse-lite@^1.0.30001702, caniuse-lite@^1.0.30001718, caniuse-lite@^1.0.30001759: + version "1.0.30001800" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001800.tgz" + integrity sha512-MMHtuAz9Ys840zAY5F4k6fV5GaivZ9sPk+nz0mY+GYVzRBnYkN0mpqkSR92oWRQ19yQWo4HvBV/FnC16AJX8MA== ccount@^2.0.0: version "2.0.1" From 32eccff082daaa2fdf0b354c357353ad377706d4 Mon Sep 17 00:00:00 2001 From: Mahendra Paipuri Date: Sun, 5 Jul 2026 13:12:19 +0200 Subject: [PATCH 2/2] Fix version of swag in Makefile Signed-off-by: Mahendra Paipuri --- Makefile.common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.common b/Makefile.common index e785e73d..e2a180ad 100644 --- a/Makefile.common +++ b/Makefile.common @@ -369,7 +369,7 @@ swag: $(SWAG) $(SWAG): ifeq ($(RELEASE_BUILD), 0) ifeq ($(CGO_APPS), 1) - $(GO) install github.com/swaggo/swag/v2/cmd/swag@2.0.0-rc5 + $(GO) install github.com/swaggo/swag/v2/cmd/swag@v2.0.0-rc5 endif endif