From b128f268d9450f007fbc15dc7c1bc066c7e36b65 Mon Sep 17 00:00:00 2001 From: Coen Warmer Date: Tue, 4 Jul 2023 19:25:12 +0200 Subject: [PATCH] Have SLO routes return a 403 instead of a 400 when user has an insufficient license (#161193) --- .../observability/docs/openapi/slo/README.md | 26 +- .../docs/openapi/slo/bundled.json | 2259 +++++++++++++++++ .../docs/openapi/slo/bundled.yaml | 107 +- .../slo/components/schemas/403_response.yaml | 16 + .../paths/s@{spaceid}@api@composite_slos.yaml | 24 +- ...}@api@composite_slos@{compositesloid}.yaml | 36 +- .../slo/paths/s@{spaceid}@api@slos.yaml | 28 +- ...spaceid}@api@slos@_historical_summary.yaml | 12 +- .../paths/s@{spaceid}@api@slos@{sloid}.yaml | 38 +- ...@{spaceid}@api@slos@{sloid}@{disable}.yaml | 14 +- ...s@{spaceid}@api@slos@{sloid}@{enable}.yaml | 14 +- .../slo_details/components/header_control.tsx | 2 +- .../pages/slos/components/slo_list_item.tsx | 2 +- .../observability/server/routes/slo/route.ts | 22 +- 14 files changed, 2524 insertions(+), 76 deletions(-) create mode 100644 x-pack/plugins/observability/docs/openapi/slo/bundled.json create mode 100644 x-pack/plugins/observability/docs/openapi/slo/components/schemas/403_response.yaml diff --git a/x-pack/plugins/observability/docs/openapi/slo/README.md b/x-pack/plugins/observability/docs/openapi/slo/README.md index e128dd32a38b..440e560bf62f 100644 --- a/x-pack/plugins/observability/docs/openapi/slo/README.md +++ b/x-pack/plugins/observability/docs/openapi/slo/README.md @@ -7,28 +7,28 @@ A guide about the OpenApi specification can be found at [https://swagger.io/docs ## The `openapi/slo` folder -* `entrypoint.yaml` is the overview file which pulls together all the paths and components. -* [Paths](paths/README.md): this defines each endpoint. A path can have one operation per http method. -* [Components](components/README.md): Reusable components +- `entrypoint.yaml` is the overview file which pulls together all the paths and components. +- [Paths](paths/README.md): this defines each endpoint. A path can have one operation per http method. +- [Components](components/README.md): Reusable components ## Tools It is possible to validate the docs before bundling them with the following command in the `x-pack/plugins/observability/docs/openapi/slo` folder: - ```bash - npx swagger-cli validate entrypoint.yaml - ``` +```bash + npx swagger-cli validate entrypoint.yaml +``` Then you can generate the `bundled` files by running the following commands: - ```bash - npx @redocly/cli bundle entrypoint.yaml --output bundled.yaml --ext yaml - npx @redocly/cli bundle entrypoint.yaml --output bundled.json --ext json - ``` +```bash + npx @redocly/cli bundle entrypoint.yaml --output bundled.yaml --ext yaml + npx @redocly/cli bundle entrypoint.yaml --output bundled.json --ext json +``` After generating the json bundle ensure that it is also valid by running the following command: - ```bash - npx @redocly/cli lint bundled.json - ``` +```bash + npx @redocly/cli lint bundled.json +``` diff --git a/x-pack/plugins/observability/docs/openapi/slo/bundled.json b/x-pack/plugins/observability/docs/openapi/slo/bundled.json new file mode 100644 index 000000000000..09295ed29667 --- /dev/null +++ b/x-pack/plugins/observability/docs/openapi/slo/bundled.json @@ -0,0 +1,2259 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "SLOs", + "description": "OpenAPI schema for SLOs endpoints", + "version": "1.0", + "contact": { + "name": "Actionable Observability Team" + }, + "license": { + "name": "Elastic License 2.0", + "url": "https://www.elastic.co/licensing/elastic-license" + } + }, + "servers": [ + { + "url": "http://localhost:5601", + "description": "local" + } + ], + "security": [ + { + "basicAuth": [] + }, + { + "apiKeyAuth": [] + } + ], + "tags": [ + { + "name": "slo", + "description": "SLO APIs enable you to define, manage and track service-level objectives" + }, + { + "name": "composite slo", + "description": "Composite SLO APIs enable you to define, manage and track a group of SLOs." + } + ], + "paths": { + "/s/{spaceId}/api/observability/composite_slos": { + "post": { + "summary": "Creates a Composite SLO", + "operationId": "createCompositeSlo", + "description": "You must have `all` privileges for the **SLOs** feature in the **Observability** section of the Kibana feature privileges.\n", + "tags": [ + "composite slo" + ], + "parameters": [ + { + "$ref": "#/components/parameters/kbn_xsrf" + }, + { + "$ref": "#/components/parameters/space_id" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/create_composite_slo_request" + } + } + } + }, + "responses": { + "200": { + "description": "Successful request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/create_composite_slo_response" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + }, + "401": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "403": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403_response" + } + } + } + }, + "409": { + "description": "Conflict - The Composite SLO id already exists", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/409_response" + } + } + } + } + } + }, + "get": { + "summary": "Retrieves a paginated list of composite SLOs with summary", + "operationId": "findCompositeSlo", + "description": "You must have the `read` privileges for the **SLOs** feature in the **Observability** section of the Kibana feature privileges.\n", + "tags": [ + "composite slo" + ], + "parameters": [ + { + "$ref": "#/components/parameters/kbn_xsrf" + }, + { + "$ref": "#/components/parameters/space_id" + }, + { + "name": "page", + "in": "query", + "description": "The page number to return", + "schema": { + "type": "integer", + "default": 1 + }, + "example": 1 + }, + { + "name": "perPage", + "in": "query", + "description": "The number of SLOs to return per page", + "schema": { + "type": "integer", + "default": 25 + }, + "example": 20 + }, + { + "name": "sortBy", + "in": "query", + "description": "Sort by field", + "schema": { + "type": "string", + "enum": [ + "creationTime" + ], + "default": "creationTime" + }, + "example": "creationTime" + }, + { + "name": "sortDirection", + "in": "query", + "description": "Sort order", + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "asc" + }, + "example": "asc" + } + ], + "responses": { + "200": { + "description": "Successful request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/find_composite_slo_response" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + }, + "401": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "403": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403_response" + } + } + } + }, + "404": { + "description": "Not found response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404_response" + } + } + } + } + } + } + }, + "/s/{spaceId}/api/observability/composite_slos/{compositeSloId}": { + "get": { + "summary": "Retrieves a composite SLO", + "operationId": "getCompositeSlo", + "description": "You must have the `read` privileges for the **SLOs** feature in the **Observability** section of the Kibana feature privileges.\n", + "tags": [ + "composite slo" + ], + "parameters": [ + { + "$ref": "#/components/parameters/kbn_xsrf" + }, + { + "$ref": "#/components/parameters/space_id" + }, + { + "$ref": "#/components/parameters/composite_slo_id" + } + ], + "responses": { + "200": { + "description": "Successful request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/composite_slo_response" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + }, + "401": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "403": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403_response" + } + } + } + }, + "404": { + "description": "Not found response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404_response" + } + } + } + } + } + }, + "put": { + "summary": "Updates a composite SLO", + "operationId": "updateCompositeSlo", + "description": "You must have the `write` privileges for the **SLOs** feature in the **Observability** section of the Kibana feature privileges.\n", + "tags": [ + "composite slo" + ], + "parameters": [ + { + "$ref": "#/components/parameters/kbn_xsrf" + }, + { + "$ref": "#/components/parameters/space_id" + }, + { + "$ref": "#/components/parameters/composite_slo_id" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/update_composite_slo_request" + } + } + } + }, + "responses": { + "200": { + "description": "Successful request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/base_composite_slo_response" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + }, + "401": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "403": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403_response" + } + } + } + }, + "404": { + "description": "Not found response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404_response" + } + } + } + } + } + }, + "delete": { + "summary": "Deletes a composite SLO", + "operationId": "deleteCompositeSlo", + "description": "You must have the `write` privileges for the **SLOs** feature in the **Observability** section of the Kibana feature privileges.\n", + "tags": [ + "composite slo" + ], + "parameters": [ + { + "$ref": "#/components/parameters/kbn_xsrf" + }, + { + "$ref": "#/components/parameters/space_id" + }, + { + "$ref": "#/components/parameters/composite_slo_id" + } + ], + "responses": { + "204": { + "description": "Successful request" + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + }, + "401": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "403": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403_response" + } + } + } + }, + "404": { + "description": "Not found response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404_response" + } + } + } + } + } + } + }, + "/s/{spaceId}/api/observability/slos": { + "post": { + "summary": "Creates an SLO.", + "operationId": "createSlo", + "description": "You must have `all` privileges for the **SLOs** feature in the **Observability** section of the Kibana feature privileges.\n", + "tags": [ + "slo" + ], + "parameters": [ + { + "$ref": "#/components/parameters/kbn_xsrf" + }, + { + "$ref": "#/components/parameters/space_id" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/create_slo_request" + } + } + } + }, + "responses": { + "200": { + "description": "Successful request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/create_slo_response" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + }, + "401": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "403": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403_response" + } + } + } + }, + "409": { + "description": "Conflict - The SLO id already exists", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/409_response" + } + } + } + } + }, + "servers": [ + { + "url": "https://localhost:5601" + } + ] + }, + "get": { + "summary": "Retrieves a paginated list of SLOs", + "operationId": "findSlos", + "description": "You must have the `read` privileges for the **SLOs** feature in the **Observability** section of the Kibana feature privileges.\n", + "tags": [ + "slo" + ], + "parameters": [ + { + "$ref": "#/components/parameters/kbn_xsrf" + }, + { + "$ref": "#/components/parameters/space_id" + }, + { + "name": "name", + "in": "query", + "description": "Filter by name", + "schema": { + "type": "string" + }, + "example": "awesome-service" + }, + { + "name": "indicatorTypes", + "in": "query", + "description": "Filter by indicator type", + "schema": { + "type": "array", + "items": { + "type": "string" + } + }, + "example": [ + "sli.kql.custom" + ] + }, + { + "name": "page", + "in": "query", + "description": "The page number to return", + "schema": { + "type": "integer", + "default": 1 + }, + "example": 1 + }, + { + "name": "perPage", + "in": "query", + "description": "The number of SLOs to return per page", + "schema": { + "type": "integer", + "default": 25 + }, + "example": 20 + }, + { + "name": "sortBy", + "in": "query", + "description": "Sort by field", + "schema": { + "type": "string", + "enum": [ + "creationTime", + "indicatorType" + ], + "default": "creationTime" + }, + "example": "creationTime" + }, + { + "name": "sortDirection", + "in": "query", + "description": "Sort order", + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "asc" + }, + "example": "asc" + } + ], + "responses": { + "200": { + "description": "Successful request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/find_slo_response" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + }, + "401": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "403": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403_response" + } + } + } + }, + "404": { + "description": "Not found response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404_response" + } + } + } + } + } + } + }, + "/s/{spaceId}/api/observability/slos/{sloId}": { + "get": { + "summary": "Retrieves a SLO", + "operationId": "getSlo", + "description": "You must have the `read` privileges for the **SLOs** feature in the **Observability** section of the Kibana feature privileges.\n", + "tags": [ + "slo" + ], + "parameters": [ + { + "$ref": "#/components/parameters/kbn_xsrf" + }, + { + "$ref": "#/components/parameters/space_id" + }, + { + "$ref": "#/components/parameters/slo_id" + } + ], + "responses": { + "200": { + "description": "Successful request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/slo_response" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + }, + "401": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "403": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403_response" + } + } + } + }, + "404": { + "description": "Not found response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404_response" + } + } + } + } + } + }, + "put": { + "summary": "Updates an SLO", + "operationId": "updateSlo", + "description": "You must have the `write` privileges for the **SLOs** feature in the **Observability** section of the Kibana feature privileges.\n", + "tags": [ + "slo" + ], + "parameters": [ + { + "$ref": "#/components/parameters/kbn_xsrf" + }, + { + "$ref": "#/components/parameters/space_id" + }, + { + "$ref": "#/components/parameters/slo_id" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/update_slo_request" + } + } + } + }, + "responses": { + "200": { + "description": "Successful request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/slo_response" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + }, + "401": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "403": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403_response" + } + } + } + }, + "404": { + "description": "Not found response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404_response" + } + } + } + } + } + }, + "delete": { + "summary": "Deletes an SLO", + "operationId": "deleteSlo", + "description": "You must have the `write` privileges for the **SLOs** feature in the **Observability** section of the Kibana feature privileges.\n", + "tags": [ + "slo" + ], + "parameters": [ + { + "$ref": "#/components/parameters/kbn_xsrf" + }, + { + "$ref": "#/components/parameters/space_id" + }, + { + "$ref": "#/components/parameters/slo_id" + } + ], + "responses": { + "204": { + "description": "Successful request" + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + }, + "401": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "403": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403_response" + } + } + } + }, + "404": { + "description": "Not found response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404_response" + } + } + } + } + } + } + }, + "/s/{spaceId}/api/observability/slos/{sloId}/enable": { + "post": { + "summary": "Enables an SLO", + "operationId": "enableSlo", + "description": "You must have the `write` privileges for the **SLOs** feature in the **Observability** section of the Kibana feature privileges.\n", + "tags": [ + "slo" + ], + "parameters": [ + { + "$ref": "#/components/parameters/kbn_xsrf" + }, + { + "$ref": "#/components/parameters/space_id" + }, + { + "$ref": "#/components/parameters/slo_id" + } + ], + "responses": { + "204": { + "description": "Successful request" + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + }, + "401": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "403": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403_response" + } + } + } + }, + "404": { + "description": "Not found response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404_response" + } + } + } + } + } + } + }, + "/s/{spaceId}/api/observability/slos/{sloId}/disable": { + "post": { + "summary": "Disables an SLO", + "operationId": "disableSlo", + "description": "You must have the `write` privileges for the **SLOs** feature in the **Observability** section of the Kibana feature privileges.\n", + "tags": [ + "slo" + ], + "parameters": [ + { + "$ref": "#/components/parameters/kbn_xsrf" + }, + { + "$ref": "#/components/parameters/space_id" + }, + { + "$ref": "#/components/parameters/slo_id" + } + ], + "responses": { + "200": { + "description": "Successful request" + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + }, + "401": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "403": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403_response" + } + } + } + }, + "404": { + "description": "Not found response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404_response" + } + } + } + } + } + } + }, + "/s/{spaceId}/internal/observability/slos/_historical_summary": { + "post": { + "summary": "Retrieves the historical summary for a list of SLOs", + "operationId": "historicalSummary", + "description": "You must have the `read` privileges for the **SLOs** feature in the **Observability** section of the Kibana feature privileges.\n", + "tags": [ + "slo" + ], + "parameters": [ + { + "$ref": "#/components/parameters/kbn_xsrf" + }, + { + "$ref": "#/components/parameters/space_id" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/historical_summary_request" + } + } + } + }, + "responses": { + "200": { + "description": "Successful request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/historical_summary_response" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + }, + "401": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "403": { + "description": "Unauthorized response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403_response" + } + } + } + } + } + } + } + }, + "components": { + "securitySchemes": { + "basicAuth": { + "type": "http", + "scheme": "basic" + }, + "apiKeyAuth": { + "type": "apiKey", + "in": "header", + "name": "ApiKey" + } + }, + "parameters": { + "kbn_xsrf": { + "schema": { + "type": "string" + }, + "in": "header", + "name": "kbn-xsrf", + "description": "Cross-site request forgery protection", + "required": true + }, + "space_id": { + "in": "path", + "name": "spaceId", + "description": "An identifier for the space. If `/s/` and the identifier are omitted from the path, the default space is used.", + "required": true, + "schema": { + "type": "string", + "example": "default" + } + }, + "composite_slo_id": { + "in": "path", + "name": "compositeSloId", + "description": "An identifier for the composite slo.", + "required": true, + "schema": { + "type": "string", + "example": "9c235211-6834-11ea-a78c-6feb38a34414" + } + }, + "slo_id": { + "in": "path", + "name": "sloId", + "description": "An identifier for the slo.", + "required": true, + "schema": { + "type": "string", + "example": "9c235211-6834-11ea-a78c-6feb38a34414" + } + } + }, + "schemas": { + "time_window_rolling": { + "title": "Rolling", + "required": [ + "duration", + "isRolling" + ], + "description": "Defines properties for rolling time window", + "type": "object", + "properties": { + "duration": { + "description": "the duration formatted as {duration}{unit}", + "type": "string", + "example": "28d" + }, + "isRolling": { + "description": "Indicates a rolling time window", + "type": "boolean", + "example": true + } + } + }, + "budgeting_method": { + "title": "Budgeting method", + "type": "string", + "description": "The budgeting method to use when computing the rollup data.", + "enum": [ + "occurrences", + "timeslices" + ], + "example": "occurrences" + }, + "composite_method": { + "title": "Composite method", + "type": "string", + "description": "The composite method to use for the composite SLO.", + "enum": [ + "weightedAverage" + ], + "example": "weightedAverage" + }, + "objective": { + "title": "Objective", + "required": [ + "target" + ], + "description": "Defines properties for the SLO objective", + "type": "object", + "properties": { + "target": { + "description": "the target objective between 0 and 1 excluded", + "type": "number", + "example": 0.99 + }, + "timeslicesTarget": { + "description": "the target objective for each slice when using a timeslices budgeting method", + "type": "number", + "example": 0.995 + }, + "timeslicesWindow": { + "description": "the duration of each slice when using a timeslices budgeting method, as {duraton}{unit}", + "type": "string", + "example": "5m" + } + } + }, + "weighted_composite_sources": { + "title": "Weighted sources", + "description": "An array of source SLO to use for the weighted average composite.", + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "revision", + "weight" + ], + "properties": { + "id": { + "description": "The id of the SLO.", + "type": "string", + "example": "8853df00-ae2e-11ed-90af-09bb6422b258" + }, + "revision": { + "description": "The revision number of the SLO.", + "type": "number", + "example": 2 + }, + "weight": { + "description": "The weight to apply to this SLO.", + "type": "number", + "example": 3 + } + } + } + }, + "error_budget": { + "title": "Error budget", + "type": "object", + "properties": { + "initial": { + "type": "number", + "description": "The initial error budget, as 1 - objective", + "example": 0.02 + }, + "consumed": { + "type": "number", + "description": "The error budget consummed, as a percentage of the initial value.", + "example": 0.8 + }, + "remaining": { + "type": "number", + "description": "The error budget remaining, as a percentage of the initial value.", + "example": 0.2 + }, + "isEstimated": { + "type": "boolean", + "description": "Only for SLO defined with occurrences budgeting method and calendar aligned time window.", + "example": true + } + } + }, + "summary": { + "title": "Summary", + "type": "object", + "description": "The SLO computed data", + "properties": { + "status": { + "type": "string", + "enum": [ + "NO_DATA", + "HEALTHY", + "DEGRADING", + "VIOLATED" + ], + "example": "HEALTHY" + }, + "sliValue": { + "type": "number", + "example": 0.9836 + }, + "errorBudget": { + "$ref": "#/components/schemas/error_budget" + } + } + }, + "composite_slo_response": { + "title": "Composite SLO with summary response", + "type": "object", + "properties": { + "id": { + "description": "The identifier of the composite SLO.", + "type": "string", + "example": "8853df00-ae2e-11ed-90af-09bb6422b258" + }, + "name": { + "description": "The name of the composite SLO.", + "type": "string", + "example": "My Service SLO" + }, + "timeWindow": { + "$ref": "#/components/schemas/time_window_rolling" + }, + "budgetingMethod": { + "$ref": "#/components/schemas/budgeting_method" + }, + "compositeMethod": { + "$ref": "#/components/schemas/composite_method" + }, + "objective": { + "$ref": "#/components/schemas/objective" + }, + "sources": { + "oneOf": [ + { + "$ref": "#/components/schemas/weighted_composite_sources" + } + ] + }, + "summary": { + "$ref": "#/components/schemas/summary" + }, + "createdAt": { + "description": "The creation date", + "type": "string", + "example": "2023-01-12T10:03:19.000Z" + }, + "updatedAt": { + "description": "The last update date", + "type": "string", + "example": "2023-01-12T10:03:19.000Z" + } + } + }, + "find_composite_slo_response": { + "title": "Find composite SLO response", + "description": "A paginated response of composite SLOs matching the query.", + "type": "object", + "properties": { + "page": { + "type": "number", + "example": 1 + }, + "perPage": { + "type": "number", + "example": 25 + }, + "total": { + "type": "number", + "example": 34 + }, + "results": { + "type": "array", + "items": { + "$ref": "#/components/schemas/composite_slo_response" + } + } + } + }, + "400_response": { + "title": "Bad request", + "type": "object", + "required": [ + "statusCode", + "error", + "message" + ], + "properties": { + "statusCode": { + "type": "number", + "example": 400 + }, + "error": { + "type": "string", + "example": "Bad Request" + }, + "message": { + "type": "string", + "example": "Invalid value 'foo' supplied to: [...]" + } + } + }, + "401_response": { + "title": "Unauthorized", + "type": "object", + "required": [ + "statusCode", + "error", + "message" + ], + "properties": { + "statusCode": { + "type": "number", + "example": 401 + }, + "error": { + "type": "string", + "example": "Unauthorized" + }, + "message": { + "type": "string", + "example": "[security_exception\n\tRoot causes:\n\t\tsecurity_exception: unable to authenticate user [elastics] for REST request [/_security/_authenticate]]: unable to authenticate user [elastics] for REST request [/_security/_authenticate]" + } + } + }, + "403_response": { + "title": "Unauthorized", + "type": "object", + "required": [ + "statusCode", + "error", + "message" + ], + "properties": { + "statusCode": { + "type": "number", + "example": 403 + }, + "error": { + "type": "string", + "example": "Unauthorized" + }, + "message": { + "type": "string", + "example": "[security_exception\n\tRoot causes:\n\t\tsecurity_exception: unable to authenticate user [elastics] for REST request [/_security/_authenticate]]: unable to authenticate user [elastics] for REST request [/_security/_authenticate]" + } + } + }, + "404_response": { + "title": "Not found", + "type": "object", + "required": [ + "statusCode", + "error", + "message" + ], + "properties": { + "statusCode": { + "type": "number", + "example": 404 + }, + "error": { + "type": "string", + "example": "Not Found" + }, + "message": { + "type": "string", + "example": "SLO [3749f390-03a3-11ee-8139-c7ff60a1692d] not found" + } + } + }, + "create_composite_slo_request": { + "title": "Create composite SLO request", + "description": "The create Composite SLO API request body. The provided source SLOs must exists and their budgeting method and time window must match the one from the composite SLO.\n", + "type": "object", + "required": [ + "name", + "timeWindow", + "budgetingMethod", + "compositeMethod", + "objective", + "sources" + ], + "properties": { + "id": { + "description": "A unique identifier for the composite SLO. Must be between 8 and 36 chars", + "type": "string", + "example": "my-super-composite-slo-id" + }, + "name": { + "description": "A name for the composite SLO.", + "type": "string" + }, + "timeWindow": { + "$ref": "#/components/schemas/time_window_rolling" + }, + "budgetingMethod": { + "$ref": "#/components/schemas/budgeting_method" + }, + "compositeMethod": { + "$ref": "#/components/schemas/composite_method" + }, + "objective": { + "$ref": "#/components/schemas/objective" + }, + "sources": { + "oneOf": [ + { + "$ref": "#/components/schemas/weighted_composite_sources" + } + ] + } + } + }, + "create_composite_slo_response": { + "title": "Create composite SLO response", + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string", + "example": "8853df00-ae2e-11ed-90af-09bb6422b258" + } + } + }, + "409_response": { + "title": "Conflict", + "type": "object", + "required": [ + "statusCode", + "error", + "message" + ], + "properties": { + "statusCode": { + "type": "number", + "example": 409 + }, + "error": { + "type": "string", + "example": "Conflict" + }, + "message": { + "type": "string", + "example": "SLO [d077e940-1515-11ee-9c50-9d096392f520] already exists" + } + } + }, + "update_composite_slo_request": { + "title": "Update composite SLO request", + "description": "The update composite SLO API request body. The provided source SLOs must exists and their budgeting method and time window must match the one from the composite SLO.\n", + "type": "object", + "properties": { + "id": { + "description": "A unique identifier for the composite SLO. Must be between 8 and 36 chars", + "type": "string", + "example": "my-super-composite-slo-id" + }, + "name": { + "description": "A name for the composite SLO.", + "type": "string" + }, + "timeWindow": { + "$ref": "#/components/schemas/time_window_rolling" + }, + "budgetingMethod": { + "$ref": "#/components/schemas/budgeting_method" + }, + "compositeMethod": { + "$ref": "#/components/schemas/composite_method" + }, + "objective": { + "$ref": "#/components/schemas/objective" + }, + "sources": { + "oneOf": [ + { + "$ref": "#/components/schemas/weighted_composite_sources" + } + ] + } + } + }, + "base_composite_slo_response": { + "title": "Composite SLO response", + "type": "object", + "properties": { + "id": { + "description": "The identifier of the composite SLO.", + "type": "string", + "example": "8853df00-ae2e-11ed-90af-09bb6422b258" + }, + "name": { + "description": "The name of the composite SLO.", + "type": "string", + "example": "My Service SLO" + }, + "timeWindow": { + "$ref": "#/components/schemas/time_window_rolling" + }, + "budgetingMethod": { + "$ref": "#/components/schemas/budgeting_method" + }, + "compositeMethod": { + "$ref": "#/components/schemas/composite_method" + }, + "objective": { + "$ref": "#/components/schemas/objective" + }, + "sources": { + "oneOf": [ + { + "$ref": "#/components/schemas/weighted_composite_sources" + } + ] + }, + "createdAt": { + "description": "The creation date", + "type": "string", + "example": "2023-01-12T10:03:19.000Z" + }, + "updatedAt": { + "description": "The last update date", + "type": "string", + "example": "2023-01-12T10:03:19.000Z" + } + } + }, + "indicator_properties_custom_kql": { + "title": "Custom KQL", + "required": [ + "type", + "params" + ], + "description": "Defines properties for a custom KQL indicator type", + "type": "object", + "properties": { + "params": { + "description": "An object containing the indicator parameters.", + "type": "object", + "nullable": false, + "required": [ + "index", + "timestampField" + ], + "properties": { + "index": { + "description": "The index or index pattern to use", + "type": "string", + "example": "my-service-*" + }, + "filter": { + "description": "the KQL query to filter the documents with.", + "type": "string", + "example": "field.environment : \"production\" and service.name : \"my-service\"" + }, + "good": { + "description": "the KQL query used to define the good events.", + "type": "string", + "example": "request.latency <= 150 and request.status_code : \"2xx\"" + }, + "total": { + "description": "the KQL query used to define all events.", + "type": "string", + "example": "" + }, + "timestampField": { + "description": "The timestamp field used in the source indice.\n", + "type": "string", + "example": "timestamp" + } + } + }, + "type": { + "description": "The type of indicator.", + "type": "string", + "example": "sli.kql.custom" + } + } + }, + "indicator_properties_apm_availability": { + "title": "APM availability", + "required": [ + "type", + "params" + ], + "description": "Defines properties for the APM availability indicator type", + "type": "object", + "properties": { + "params": { + "description": "An object containing the indicator parameters.", + "type": "object", + "nullable": false, + "required": [ + "service", + "environment", + "transactionType", + "transactionName", + "index" + ], + "properties": { + "service": { + "description": "The APM service name", + "type": "string", + "example": "o11y-app" + }, + "environment": { + "description": "The APM service environment or \"*\"", + "type": "string", + "example": "production" + }, + "transactionType": { + "description": "The APM transaction type or \"*\"", + "type": "string", + "example": "request" + }, + "transactionName": { + "description": "The APM transaction name or \"*\"", + "type": "string", + "example": "GET /my/api" + }, + "filter": { + "description": "KQL query used for filtering the data", + "type": "string", + "example": "service.foo : \"bar\"" + }, + "index": { + "description": "The index used by APM metrics", + "type": "string", + "example": "metrics-apm*,apm*" + } + } + }, + "type": { + "description": "The type of indicator.", + "type": "string", + "example": "sli.apm.transactionDuration" + } + } + }, + "indicator_properties_apm_latency": { + "title": "APM latency", + "required": [ + "type", + "params" + ], + "description": "Defines properties for the APM latency indicator type", + "type": "object", + "properties": { + "params": { + "description": "An object containing the indicator parameters.", + "type": "object", + "nullable": false, + "required": [ + "service", + "environment", + "transactionType", + "transactionName", + "index", + "threshold" + ], + "properties": { + "service": { + "description": "The APM service name", + "type": "string", + "example": "o11y-app" + }, + "environment": { + "description": "The APM service environment or \"*\"", + "type": "string", + "example": "production" + }, + "transactionType": { + "description": "The APM transaction type or \"*\"", + "type": "string", + "example": "request" + }, + "transactionName": { + "description": "The APM transaction name or \"*\"", + "type": "string", + "example": "GET /my/api" + }, + "filter": { + "description": "KQL query used for filtering the data", + "type": "string", + "example": "service.foo : \"bar\"" + }, + "index": { + "description": "The index used by APM metrics", + "type": "string", + "example": "metrics-apm*,apm*" + }, + "threshold": { + "description": "The latency threshold in milliseconds", + "type": "number", + "example": 250 + } + } + }, + "type": { + "description": "The type of indicator.", + "type": "string", + "example": "sli.apm.transactionDuration" + } + } + }, + "indicator_properties_custom_metric": { + "title": "Custom metric", + "required": [ + "type", + "params" + ], + "description": "Defines properties for a custom metric indicator type", + "type": "object", + "properties": { + "params": { + "description": "An object containing the indicator parameters.", + "type": "object", + "nullable": false, + "required": [ + "index", + "timestampField", + "good", + "total" + ], + "properties": { + "index": { + "description": "The index or index pattern to use", + "type": "string", + "example": "my-service-*" + }, + "filter": { + "description": "the KQL query to filter the documents with.", + "type": "string", + "example": "field.environment : \"production\" and service.name : \"my-service\"" + }, + "timestampField": { + "description": "The timestamp field used in the source indice.\n", + "type": "string", + "example": "timestamp" + }, + "good": { + "description": "An object defining the \"good\" metrics and equation\n", + "type": "object", + "required": [ + "metrics", + "equation" + ], + "properties": { + "metrics": { + "description": "List of metrics with their name, aggregation type, and field.", + "type": "array", + "items": { + "type": "object", + "required": [ + "name", + "aggregation", + "field" + ], + "properties": { + "name": { + "description": "The name of the metric. Only valid options are A-Z", + "type": "string", + "example": "A", + "pattern": "^[A-Z]$" + }, + "aggregation": { + "description": "The aggregation type of the metric. Only valid option is \"sum\"", + "type": "string", + "example": "sum", + "enum": [ + "sum" + ] + }, + "field": { + "description": "The field of the metric.", + "type": "string", + "example": "processor.processed" + } + } + } + }, + "equation": { + "description": "The equation to calculate the \"good\" metric.", + "type": "string", + "example": "A" + } + } + }, + "total": { + "description": "An object defining the \"total\" metrics and equation\n", + "type": "object", + "required": [ + "metrics", + "equation" + ], + "properties": { + "metrics": { + "description": "List of metrics with their name, aggregation type, and field.", + "type": "array", + "items": { + "type": "object", + "required": [ + "name", + "aggregation", + "field" + ], + "properties": { + "name": { + "description": "The name of the metric. Only valid options are A-Z", + "type": "string", + "example": "A", + "pattern": "^[A-Z]$" + }, + "aggregation": { + "description": "The aggregation type of the metric. Only valid option is \"sum\"", + "type": "string", + "example": "sum", + "enum": [ + "sum" + ] + }, + "field": { + "description": "The field of the metric.", + "type": "string", + "example": "processor.processed" + } + } + } + }, + "equation": { + "description": "The equation to calculate the \"total\" metric.", + "type": "string", + "example": "A" + } + } + } + } + }, + "type": { + "description": "The type of indicator.", + "type": "string", + "example": "sli.metric.custom" + } + } + }, + "time_window_calendar_aligned": { + "title": "Calendar aligned", + "required": [ + "duration", + "isCalendar" + ], + "description": "Defines properties for calendar aligned time window", + "type": "object", + "properties": { + "duration": { + "description": "the duration formatted as {duration}{unit}, accept '1w' (weekly calendar) or '1M' (monthly calendar) only", + "type": "string", + "example": "1M" + }, + "isCalendar": { + "description": "Indicates a calendar aligned time window", + "type": "boolean", + "example": true + } + } + }, + "settings": { + "title": "Settings", + "description": "Defines properties for SLO settings.", + "type": "object", + "properties": { + "syncDelay": { + "description": "The synch delay to apply to the transform. Default 1m", + "type": "string", + "example": "5m" + }, + "frequency": { + "description": "Configure how often the transform runs, default 1m", + "type": "string", + "example": "5m" + } + } + }, + "slo_response": { + "title": "SLO response", + "type": "object", + "properties": { + "id": { + "description": "The identifier of the SLO.", + "type": "string", + "example": "8853df00-ae2e-11ed-90af-09bb6422b258" + }, + "name": { + "description": "The name of the SLO.", + "type": "string", + "example": "My Service SLO" + }, + "description": { + "description": "The description of the SLO.", + "type": "string", + "example": "My SLO description" + }, + "indicator": { + "oneOf": [ + { + "$ref": "#/components/schemas/indicator_properties_custom_kql" + }, + { + "$ref": "#/components/schemas/indicator_properties_apm_availability" + }, + { + "$ref": "#/components/schemas/indicator_properties_apm_latency" + }, + { + "$ref": "#/components/schemas/indicator_properties_custom_metric" + } + ] + }, + "timeWindow": { + "oneOf": [ + { + "$ref": "#/components/schemas/time_window_rolling" + }, + { + "$ref": "#/components/schemas/time_window_calendar_aligned" + } + ] + }, + "budgetingMethod": { + "$ref": "#/components/schemas/budgeting_method" + }, + "objective": { + "$ref": "#/components/schemas/objective" + }, + "settings": { + "$ref": "#/components/schemas/settings" + }, + "revision": { + "description": "The SLO revision", + "type": "number", + "example": 2 + }, + "summary": { + "$ref": "#/components/schemas/summary" + }, + "enabled": { + "description": "Indicate if the SLO is enabled", + "type": "boolean", + "example": true + }, + "createdAt": { + "description": "The creation date", + "type": "string", + "example": "2023-01-12T10:03:19.000Z" + }, + "updatedAt": { + "description": "The last update date", + "type": "string", + "example": "2023-01-12T10:03:19.000Z" + } + } + }, + "find_slo_response": { + "title": "Find SLO response", + "description": "A paginated response of SLOs matching the query.\n", + "type": "object", + "properties": { + "page": { + "type": "number", + "example": 1 + }, + "perPage": { + "type": "number", + "example": 25 + }, + "total": { + "type": "number", + "example": 34 + }, + "results": { + "type": "array", + "items": { + "$ref": "#/components/schemas/slo_response" + } + } + } + }, + "create_slo_request": { + "title": "Create SLO request", + "description": "The create SLO API request body varies depending on the type of indicator, time window and budgeting method.\n", + "type": "object", + "required": [ + "name", + "description", + "indicator", + "timeWindow", + "budgetingMethod", + "objective" + ], + "properties": { + "id": { + "description": "A optional and unique identifier for the SLO. Must be between 8 and 36 chars", + "type": "string", + "example": "my-super-slo-id" + }, + "name": { + "description": "A name for the SLO.", + "type": "string" + }, + "description": { + "description": "A description for the SLO.", + "type": "string" + }, + "indicator": { + "oneOf": [ + { + "$ref": "#/components/schemas/indicator_properties_custom_kql" + }, + { + "$ref": "#/components/schemas/indicator_properties_apm_availability" + }, + { + "$ref": "#/components/schemas/indicator_properties_apm_latency" + }, + { + "$ref": "#/components/schemas/indicator_properties_custom_metric" + } + ] + }, + "timeWindow": { + "oneOf": [ + { + "$ref": "#/components/schemas/time_window_rolling" + }, + { + "$ref": "#/components/schemas/time_window_calendar_aligned" + } + ] + }, + "budgetingMethod": { + "$ref": "#/components/schemas/budgeting_method" + }, + "objective": { + "$ref": "#/components/schemas/objective" + }, + "settings": { + "$ref": "#/components/schemas/settings" + } + } + }, + "create_slo_response": { + "title": "Create SLO response", + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string", + "example": "8853df00-ae2e-11ed-90af-09bb6422b258" + } + } + }, + "update_slo_request": { + "title": "Update SLO request", + "description": "The update SLO API request body varies depending on the type of indicator, time window and budgeting method. Partial update is handled.\n", + "type": "object", + "properties": { + "name": { + "description": "A name for the SLO.", + "type": "string" + }, + "description": { + "description": "A description for the SLO.", + "type": "string" + }, + "indicator": { + "oneOf": [ + { + "$ref": "#/components/schemas/indicator_properties_custom_kql" + }, + { + "$ref": "#/components/schemas/indicator_properties_apm_availability" + }, + { + "$ref": "#/components/schemas/indicator_properties_apm_latency" + }, + { + "$ref": "#/components/schemas/indicator_properties_custom_metric" + } + ] + }, + "timeWindow": { + "oneOf": [ + { + "$ref": "#/components/schemas/time_window_rolling" + }, + { + "$ref": "#/components/schemas/time_window_calendar_aligned" + } + ] + }, + "budgetingMethod": { + "$ref": "#/components/schemas/budgeting_method" + }, + "objective": { + "$ref": "#/components/schemas/objective" + }, + "settings": { + "$ref": "#/components/schemas/settings" + } + } + }, + "historical_summary_request": { + "title": "Historical summary request", + "type": "object", + "required": [ + "sloIds" + ], + "properties": { + "sloIds": { + "description": "The list of SLO identifiers to get the historical summary for", + "type": "array", + "items": { + "type": "string", + "example": "8853df00-ae2e-11ed-90af-09bb6422b258" + } + } + } + }, + "historical_summary_response": { + "title": "Historical summary response", + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "object", + "properties": { + "date": { + "type": "string", + "example": "2022-01-01T00:00:00.000Z" + }, + "status": { + "type": "string", + "enum": [ + "NO_DATA", + "HEALTHY", + "DEGRADING", + "VIOLATED" + ], + "example": "HEALTHY" + }, + "sliValue": { + "type": "number", + "example": 0.9836 + }, + "errorBudget": { + "$ref": "#/components/schemas/error_budget" + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/x-pack/plugins/observability/docs/openapi/slo/bundled.yaml b/x-pack/plugins/observability/docs/openapi/slo/bundled.yaml index 59d600a9e137..f4ef3a599138 100644 --- a/x-pack/plugins/observability/docs/openapi/slo/bundled.yaml +++ b/x-pack/plugins/observability/docs/openapi/slo/bundled.yaml @@ -8,14 +8,17 @@ info: license: name: Elastic License 2.0 url: https://www.elastic.co/licensing/elastic-license +servers: + - url: http://localhost:5601 + description: local +security: + - basicAuth: [] + - apiKeyAuth: [] tags: - name: slo description: SLO APIs enable you to define, manage and track service-level objectives - name: composite slo description: Composite SLO APIs enable you to define, manage and track a group of SLOs. -servers: - - url: http://localhost:5601 - description: local paths: /s/{spaceId}/api/observability/composite_slos: post: @@ -53,6 +56,12 @@ paths: application/json: schema: $ref: '#/components/schemas/401_response' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/403_response' '409': description: Conflict - The Composite SLO id already exists content: @@ -121,6 +130,12 @@ paths: application/json: schema: $ref: '#/components/schemas/401_response' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/403_response' '404': description: Not found response content: @@ -158,6 +173,12 @@ paths: application/json: schema: $ref: '#/components/schemas/401_response' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/403_response' '404': description: Not found response content: @@ -200,6 +221,12 @@ paths: application/json: schema: $ref: '#/components/schemas/401_response' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/403_response' '404': description: Not found response content: @@ -232,6 +259,12 @@ paths: application/json: schema: $ref: '#/components/schemas/401_response' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/403_response' '404': description: Not found response content: @@ -274,6 +307,12 @@ paths: application/json: schema: $ref: '#/components/schemas/401_response' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/403_response' '409': description: Conflict - The SLO id already exists content: @@ -360,6 +399,12 @@ paths: application/json: schema: $ref: '#/components/schemas/401_response' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/403_response' '404': description: Not found response content: @@ -397,6 +442,12 @@ paths: application/json: schema: $ref: '#/components/schemas/401_response' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/403_response' '404': description: Not found response content: @@ -439,6 +490,12 @@ paths: application/json: schema: $ref: '#/components/schemas/401_response' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/403_response' '404': description: Not found response content: @@ -471,6 +528,12 @@ paths: application/json: schema: $ref: '#/components/schemas/401_response' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/403_response' '404': description: Not found response content: @@ -504,6 +567,12 @@ paths: application/json: schema: $ref: '#/components/schemas/401_response' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/403_response' '404': description: Not found response content: @@ -537,6 +606,12 @@ paths: application/json: schema: $ref: '#/components/schemas/401_response' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/403_response' '404': description: Not found response content: @@ -579,6 +654,12 @@ paths: application/json: schema: $ref: '#/components/schemas/401_response' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/403_response' components: securitySchemes: basicAuth: @@ -817,6 +898,23 @@ components: message: type: string example: "[security_exception\n\tRoot causes:\n\t\tsecurity_exception: unable to authenticate user [elastics] for REST request [/_security/_authenticate]]: unable to authenticate user [elastics] for REST request [/_security/_authenticate]" + 403_response: + title: Unauthorized + type: object + required: + - statusCode + - error + - message + properties: + statusCode: + type: number + example: 403 + error: + type: string + example: Unauthorized + message: + type: string + example: "[security_exception\n\tRoot causes:\n\t\tsecurity_exception: unable to authenticate user [elastics] for REST request [/_security/_authenticate]]: unable to authenticate user [elastics] for REST request [/_security/_authenticate]" 404_response: title: Not found type: object @@ -1405,6 +1503,3 @@ components: example: 0.9836 errorBudget: $ref: '#/components/schemas/error_budget' -security: - - basicAuth: [] - - apiKeyAuth: [] diff --git a/x-pack/plugins/observability/docs/openapi/slo/components/schemas/403_response.yaml b/x-pack/plugins/observability/docs/openapi/slo/components/schemas/403_response.yaml new file mode 100644 index 000000000000..24fcbad202a8 --- /dev/null +++ b/x-pack/plugins/observability/docs/openapi/slo/components/schemas/403_response.yaml @@ -0,0 +1,16 @@ +title: Unauthorized +type: object +required: + - statusCode + - error + - message +properties: + statusCode: + type: number + example: 403 + error: + type: string + example: Unauthorized + message: + type: string + example: "[security_exception\n\tRoot causes:\n\t\tsecurity_exception: unable to authenticate user [elastics] for REST request [/_security/_authenticate]]: unable to authenticate user [elastics] for REST request [/_security/_authenticate]" diff --git a/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@composite_slos.yaml b/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@composite_slos.yaml index e8e3cf75decc..d77431452136 100644 --- a/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@composite_slos.yaml +++ b/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@composite_slos.yaml @@ -24,16 +24,22 @@ post: $ref: '../components/schemas/create_composite_slo_response.yaml' '400': description: Bad request - content: + content: application/json: schema: $ref: '../components/schemas/400_response.yaml' '401': description: Unauthorized response - content: + content: application/json: schema: $ref: '../components/schemas/401_response.yaml' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '../components/schemas/403_response.yaml' '409': description: Conflict - The Composite SLO id already exists content: @@ -91,19 +97,25 @@ get: $ref: '../components/schemas/find_composite_slo_response.yaml' '400': description: Bad request - content: + content: application/json: schema: $ref: '../components/schemas/400_response.yaml' '401': description: Unauthorized response - content: + content: application/json: schema: $ref: '../components/schemas/401_response.yaml' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '../components/schemas/403_response.yaml' '404': description: Not found response - content: + content: application/json: schema: - $ref: '../components/schemas/404_response.yaml' \ No newline at end of file + $ref: '../components/schemas/404_response.yaml' diff --git a/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@composite_slos@{compositesloid}.yaml b/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@composite_slos@{compositesloid}.yaml index 54b3613c7a5c..bca3976b80fc 100644 --- a/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@composite_slos@{compositesloid}.yaml +++ b/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@composite_slos@{compositesloid}.yaml @@ -19,19 +19,25 @@ get: $ref: '../components/schemas/composite_slo_response.yaml' '400': description: Bad request - content: + content: application/json: schema: $ref: '../components/schemas/400_response.yaml' '401': description: Unauthorized response - content: + content: application/json: schema: $ref: '../components/schemas/401_response.yaml' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '../components/schemas/403_response.yaml' '404': description: Not found response - content: + content: application/json: schema: $ref: '../components/schemas/404_response.yaml' @@ -63,19 +69,25 @@ put: $ref: '../components/schemas/base_composite_slo_response.yaml' '400': description: Bad request - content: + content: application/json: schema: $ref: '../components/schemas/400_response.yaml' '401': description: Unauthorized response - content: + content: application/json: schema: $ref: '../components/schemas/401_response.yaml' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '../components/schemas/403_response.yaml' '404': description: Not found response - content: + content: application/json: schema: $ref: '../components/schemas/404_response.yaml' @@ -97,19 +109,25 @@ delete: description: Successful request '400': description: Bad request - content: + content: application/json: schema: $ref: '../components/schemas/400_response.yaml' '401': description: Unauthorized response - content: + content: application/json: schema: $ref: '../components/schemas/401_response.yaml' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '../components/schemas/403_response.yaml' '404': description: Not found response - content: + content: application/json: schema: $ref: '../components/schemas/404_response.yaml' diff --git a/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos.yaml b/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos.yaml index 47fec9eee649..68c0c602448d 100644 --- a/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos.yaml +++ b/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos.yaml @@ -24,16 +24,22 @@ post: $ref: '../components/schemas/create_slo_response.yaml' '400': description: Bad request - content: + content: application/json: schema: $ref: '../components/schemas/400_response.yaml' '401': description: Unauthorized response - content: + content: application/json: schema: $ref: '../components/schemas/401_response.yaml' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '../components/schemas/403_response.yaml' '409': description: Conflict - The SLO id already exists content: @@ -65,9 +71,9 @@ get: description: Filter by indicator type schema: type: array - items: + items: type: string - example: ["sli.kql.custom"] + example: ['sli.kql.custom'] - name: page in: query description: The page number to return @@ -107,19 +113,25 @@ get: $ref: '../components/schemas/find_slo_response.yaml' '400': description: Bad request - content: + content: application/json: schema: $ref: '../components/schemas/400_response.yaml' '401': description: Unauthorized response - content: + content: application/json: schema: $ref: '../components/schemas/401_response.yaml' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '../components/schemas/403_response.yaml' '404': description: Not found response - content: + content: application/json: schema: - $ref: '../components/schemas/404_response.yaml' \ No newline at end of file + $ref: '../components/schemas/404_response.yaml' diff --git a/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@_historical_summary.yaml b/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@_historical_summary.yaml index 48ffe492a5a2..6ce99505894c 100644 --- a/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@_historical_summary.yaml +++ b/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@_historical_summary.yaml @@ -18,19 +18,25 @@ post: responses: '200': description: Successful request - content: + content: application/json: schema: $ref: '../components/schemas/historical_summary_response.yaml' '400': description: Bad request - content: + content: application/json: schema: $ref: '../components/schemas/400_response.yaml' '401': description: Unauthorized response - content: + content: application/json: schema: $ref: '../components/schemas/401_response.yaml' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '../components/schemas/403_response.yaml' diff --git a/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@{sloid}.yaml b/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@{sloid}.yaml index cf31ccb2de8b..66a5ddd7825a 100644 --- a/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@{sloid}.yaml +++ b/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@{sloid}.yaml @@ -19,19 +19,25 @@ get: $ref: '../components/schemas/slo_response.yaml' '400': description: Bad request - content: + content: application/json: schema: $ref: '../components/schemas/400_response.yaml' '401': description: Unauthorized response - content: + content: application/json: schema: $ref: '../components/schemas/401_response.yaml' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '../components/schemas/403_response.yaml' '404': description: Not found response - content: + content: application/json: schema: $ref: '../components/schemas/404_response.yaml' @@ -63,19 +69,25 @@ put: $ref: '../components/schemas/slo_response.yaml' '400': description: Bad request - content: + content: application/json: schema: $ref: '../components/schemas/400_response.yaml' '401': description: Unauthorized response - content: + content: application/json: schema: $ref: '../components/schemas/401_response.yaml' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '../components/schemas/403_response.yaml' '404': description: Not found response - content: + content: application/json: schema: $ref: '../components/schemas/404_response.yaml' @@ -97,19 +109,25 @@ delete: description: Successful request '400': description: Bad request - content: + content: application/json: schema: $ref: '../components/schemas/400_response.yaml' '401': description: Unauthorized response - content: + content: application/json: schema: $ref: '../components/schemas/401_response.yaml' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '../components/schemas/403_response.yaml' '404': description: Not found response - content: + content: application/json: schema: - $ref: '../components/schemas/404_response.yaml' \ No newline at end of file + $ref: '../components/schemas/404_response.yaml' diff --git a/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@{sloid}@{disable}.yaml b/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@{sloid}@{disable}.yaml index ace5b805cf92..4932e9cf78c3 100644 --- a/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@{sloid}@{disable}.yaml +++ b/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@{sloid}@{disable}.yaml @@ -15,19 +15,25 @@ post: description: Successful request '400': description: Bad request - content: + content: application/json: schema: $ref: '../components/schemas/400_response.yaml' '401': description: Unauthorized response - content: + content: application/json: schema: $ref: '../components/schemas/401_response.yaml' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '../components/schemas/403_response.yaml' '404': description: Not found response - content: + content: application/json: schema: - $ref: '../components/schemas/404_response.yaml' \ No newline at end of file + $ref: '../components/schemas/404_response.yaml' diff --git a/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@{sloid}@{enable}.yaml b/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@{sloid}@{enable}.yaml index d751535fe365..4ddda2bc94b6 100644 --- a/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@{sloid}@{enable}.yaml +++ b/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@{sloid}@{enable}.yaml @@ -15,19 +15,25 @@ post: description: Successful request '400': description: Bad request - content: + content: application/json: schema: $ref: '../components/schemas/400_response.yaml' '401': description: Unauthorized response - content: + content: application/json: schema: $ref: '../components/schemas/401_response.yaml' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '../components/schemas/403_response.yaml' '404': description: Not found response - content: + content: application/json: schema: - $ref: '../components/schemas/404_response.yaml' \ No newline at end of file + $ref: '../components/schemas/404_response.yaml' diff --git a/x-pack/plugins/observability/public/pages/slo_details/components/header_control.tsx b/x-pack/plugins/observability/public/pages/slo_details/components/header_control.tsx index 2d71fca18eed..6e7339852752 100644 --- a/x-pack/plugins/observability/public/pages/slo_details/components/header_control.tsx +++ b/x-pack/plugins/observability/public/pages/slo_details/components/header_control.tsx @@ -76,7 +76,7 @@ export function HeaderControl({ isLoading, slo }: Props) { params: { sloId: slo.id }, }, { - replace: true, + replace: false, } ); } diff --git a/x-pack/plugins/observability/public/pages/slos/components/slo_list_item.tsx b/x-pack/plugins/observability/public/pages/slos/components/slo_list_item.tsx index 3d9e70f68dc6..374b64b56740 100644 --- a/x-pack/plugins/observability/public/pages/slos/components/slo_list_item.tsx +++ b/x-pack/plugins/observability/public/pages/slos/components/slo_list_item.tsx @@ -106,7 +106,7 @@ export function SloListItem({ params: { sloId: slo.id }, }, { - replace: true, + replace: false, } ); }; diff --git a/x-pack/plugins/observability/server/routes/slo/route.ts b/x-pack/plugins/observability/server/routes/slo/route.ts index 52c6aa3cff0d..f41d37d4fc57 100644 --- a/x-pack/plugins/observability/server/routes/slo/route.ts +++ b/x-pack/plugins/observability/server/routes/slo/route.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { badRequest, forbidden, failedDependency } from '@hapi/boom'; +import { forbidden, failedDependency } from '@hapi/boom'; import { createSLOParamsSchema, deleteSLOParamsSchema, @@ -68,7 +68,7 @@ const createSLORoute = createObservabilityServerRoute({ const hasCorrectLicense = await isLicenseAtLeastPlatinum(context); if (!hasCorrectLicense) { - throw badRequest('Platinum license or higher is needed to make use of this feature.'); + throw forbidden('Platinum license or higher is needed to make use of this feature.'); } const esClient = (await context.core).elasticsearch.client.asCurrentUser; @@ -95,7 +95,7 @@ const updateSLORoute = createObservabilityServerRoute({ const hasCorrectLicense = await isLicenseAtLeastPlatinum(context); if (!hasCorrectLicense) { - throw badRequest('Platinum license or higher is needed to make use of this feature.'); + throw forbidden('Platinum license or higher is needed to make use of this feature.'); } const esClient = (await context.core).elasticsearch.client.asCurrentUser; @@ -127,7 +127,7 @@ const deleteSLORoute = createObservabilityServerRoute({ const hasCorrectLicense = await isLicenseAtLeastPlatinum(context); if (!hasCorrectLicense) { - throw badRequest('Platinum license or higher is needed to make use of this feature.'); + throw forbidden('Platinum license or higher is needed to make use of this feature.'); } const esClient = (await context.core).elasticsearch.client.asCurrentUser; @@ -153,7 +153,7 @@ const getSLORoute = createObservabilityServerRoute({ const hasCorrectLicense = await isLicenseAtLeastPlatinum(context); if (!hasCorrectLicense) { - throw badRequest('Platinum license or higher is needed to make use of this feature.'); + throw forbidden('Platinum license or higher is needed to make use of this feature.'); } const soClient = (await context.core).savedObjects.client; @@ -178,7 +178,7 @@ const enableSLORoute = createObservabilityServerRoute({ const hasCorrectLicense = await isLicenseAtLeastPlatinum(context); if (!hasCorrectLicense) { - throw badRequest('Platinum license or higher is needed to make use of this feature.'); + throw forbidden('Platinum license or higher is needed to make use of this feature.'); } const soClient = (await context.core).savedObjects.client; @@ -204,7 +204,7 @@ const disableSLORoute = createObservabilityServerRoute({ const hasCorrectLicense = await isLicenseAtLeastPlatinum(context); if (!hasCorrectLicense) { - throw badRequest('Platinum license or higher is needed to make use of this feature.'); + throw forbidden('Platinum license or higher is needed to make use of this feature.'); } const soClient = (await context.core).savedObjects.client; @@ -230,7 +230,7 @@ const findSLORoute = createObservabilityServerRoute({ const hasCorrectLicense = await isLicenseAtLeastPlatinum(context); if (!hasCorrectLicense) { - throw badRequest('Platinum license or higher is needed to make use of this feature.'); + throw forbidden('Platinum license or higher is needed to make use of this feature.'); } const soClient = (await context.core).savedObjects.client; @@ -255,7 +255,7 @@ const fetchHistoricalSummary = createObservabilityServerRoute({ const hasCorrectLicense = await isLicenseAtLeastPlatinum(context); if (!hasCorrectLicense) { - throw badRequest('Platinum license or higher is needed to make use of this feature.'); + throw forbidden('Platinum license or higher is needed to make use of this feature.'); } const soClient = (await context.core).savedObjects.client; @@ -317,7 +317,7 @@ const getSloBurnRates = createObservabilityServerRoute({ const hasCorrectLicense = await isLicenseAtLeastPlatinum(context); if (!hasCorrectLicense) { - throw badRequest('Platinum license or higher is needed to make use of this feature.'); + throw forbidden('Platinum license or higher is needed to make use of this feature.'); } const esClient = (await context.core).elasticsearch.client.asCurrentUser; @@ -340,7 +340,7 @@ const getPreviewData = createObservabilityServerRoute({ const hasCorrectLicense = await isLicenseAtLeastPlatinum(context); if (!hasCorrectLicense) { - throw badRequest('Platinum license or higher is needed to make use of this feature.'); + throw forbidden('Platinum license or higher is needed to make use of this feature.'); } const esClient = (await context.core).elasticsearch.client.asCurrentUser;