diff --git a/OPENAPI_DOC.yml b/OPENAPI_DOC.yml index 0df0f5b6..155e79e9 100644 --- a/OPENAPI_DOC.yml +++ b/OPENAPI_DOC.yml @@ -5,6 +5,1021 @@ info: title: rest-api version: v2 paths: + /api/engine/v2/alert_dashboards: + get: + summary: list the alert dashboards + tags: + - AlertDashboards + operationId: PlaceOS::Api::AlertDashboards_index + parameters: + - name: authority_id + in: query + description: return dashboards for a specific authority + example: authority-1234 + schema: + type: string + nullable: true + - name: q + in: query + description: returns results based on a [simple query string](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-simple-query-string-query.html) + schema: + type: string + - name: limit + in: query + description: the maximum number of results to return + example: "10000" + schema: + type: integer + format: UInt32 + - name: offset + in: query + description: deprecated, the starting offset of the result set. Used to implement + pagination + schema: + type: integer + format: UInt32 + - name: ref + in: query + description: a token for accessing the next page of results, provided in the + `Link` header + schema: + type: string + nullable: true + - name: fields + in: query + description: (Optional, comma separated array of strings) Array of fields + you wish to search. Accepts wildcard expresssions and boost relevance score + for matches for particular field using a caret ^ operator. + schema: + type: array + items: + type: string + responses: + 200: + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/PlaceOS__Model__AlertDashboard' + 409: + description: Conflict + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 401: + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 403: + description: Forbidden + 404: + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 408: + description: Request Timeout + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 400: + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError' + 422: + description: Unprocessable Entity + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError' + 406: + description: Not Acceptable + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ContentError' + 415: + description: Unsupported Media Type + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ContentError' + post: + summary: adds a new alert dashboard + tags: + - AlertDashboards + operationId: PlaceOS::Api::AlertDashboards_create + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Model__AlertDashboard' + required: true + parameters: [] + responses: + 201: + description: Created + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Model__AlertDashboard' + 409: + description: Conflict + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 401: + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 403: + description: Forbidden + 404: + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 408: + description: Request Timeout + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 400: + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError' + 422: + description: Unprocessable Entity + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError' + 406: + description: Not Acceptable + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ContentError' + 415: + description: Unsupported Media Type + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ContentError' + /api/engine/v2/alert_dashboards/{id}: + get: + summary: returns the details of an alert dashboard + tags: + - AlertDashboards + operationId: PlaceOS::Api::AlertDashboards_show + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + 200: + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Model__AlertDashboard' + 409: + description: Conflict + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 401: + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 403: + description: Forbidden + 404: + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 408: + description: Request Timeout + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 400: + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError' + 422: + description: Unprocessable Entity + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError' + 406: + description: Not Acceptable + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ContentError' + 415: + description: Unsupported Media Type + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ContentError' + put: + summary: updates an alert dashboard + tags: + - AlertDashboards + operationId: PlaceOS::Api::AlertDashboards_update + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Model__AlertDashboard' + required: true + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + 200: + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Model__AlertDashboard' + 409: + description: Conflict + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 401: + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 403: + description: Forbidden + 404: + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 408: + description: Request Timeout + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 400: + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError' + 422: + description: Unprocessable Entity + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError' + 406: + description: Not Acceptable + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ContentError' + 415: + description: Unsupported Media Type + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ContentError' + delete: + summary: removes an alert dashboard + tags: + - AlertDashboards + operationId: PlaceOS::Api::AlertDashboards_destroy + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + 202: + description: Accepted + 409: + description: Conflict + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 401: + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 403: + description: Forbidden + 404: + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 408: + description: Request Timeout + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 400: + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError' + 422: + description: Unprocessable Entity + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError' + 406: + description: Not Acceptable + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ContentError' + 415: + description: Unsupported Media Type + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ContentError' + patch: + summary: updates an alert dashboard + tags: + - AlertDashboards + operationId: PlaceOS::Api::AlertDashboards_update{2} + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Model__AlertDashboard' + required: true + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + 200: + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Model__AlertDashboard' + 409: + description: Conflict + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 401: + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 403: + description: Forbidden + 404: + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 408: + description: Request Timeout + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 400: + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError' + 422: + description: Unprocessable Entity + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError' + 406: + description: Not Acceptable + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ContentError' + 415: + description: Unsupported Media Type + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ContentError' + /api/engine/v2/alert_dashboards/{id}/alerts: + get: + summary: Get all alerts for a dashboard + tags: + - AlertDashboards + operationId: PlaceOS::Api::AlertDashboards_alerts + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + 200: + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/PlaceOS__Model__Alert' + 409: + description: Conflict + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 401: + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 403: + description: Forbidden + 404: + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 408: + description: Request Timeout + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 400: + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError' + 422: + description: Unprocessable Entity + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError' + 406: + description: Not Acceptable + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ContentError' + 415: + description: Unsupported Media Type + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ContentError' + /api/engine/v2/alerts: + get: + summary: list the alerts + tags: + - Alerts + operationId: PlaceOS::Api::Alerts_index + parameters: + - name: alert_dashboard_id + in: query + description: return alerts for a specific dashboard + example: alert_dashboard-1234 + schema: + type: string + nullable: true + - name: severity + in: query + description: filter by alert severity + example: HIGH + schema: + type: string + nullable: true + - name: alert_type + in: query + description: filter by alert type + example: THRESHOLD + schema: + type: string + nullable: true + - name: enabled + in: query + description: filter by enabled status + example: "true" + schema: + type: boolean + nullable: true + - name: q + in: query + description: returns results based on a [simple query string](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-simple-query-string-query.html) + schema: + type: string + - name: limit + in: query + description: the maximum number of results to return + example: "10000" + schema: + type: integer + format: UInt32 + - name: offset + in: query + description: deprecated, the starting offset of the result set. Used to implement + pagination + schema: + type: integer + format: UInt32 + - name: ref + in: query + description: a token for accessing the next page of results, provided in the + `Link` header + schema: + type: string + nullable: true + - name: fields + in: query + description: (Optional, comma separated array of strings) Array of fields + you wish to search. Accepts wildcard expresssions and boost relevance score + for matches for particular field using a caret ^ operator. + schema: + type: array + items: + type: string + responses: + 200: + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/PlaceOS__Model__Alert' + 409: + description: Conflict + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 401: + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 403: + description: Forbidden + 404: + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 408: + description: Request Timeout + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 400: + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError' + 422: + description: Unprocessable Entity + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError' + 406: + description: Not Acceptable + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ContentError' + 415: + description: Unsupported Media Type + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ContentError' + post: + summary: adds a new alert + tags: + - Alerts + operationId: PlaceOS::Api::Alerts_create + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Model__Alert' + required: true + parameters: [] + responses: + 201: + description: Created + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Model__Alert' + 409: + description: Conflict + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 401: + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 403: + description: Forbidden + 404: + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 408: + description: Request Timeout + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 400: + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError' + 422: + description: Unprocessable Entity + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError' + 406: + description: Not Acceptable + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ContentError' + 415: + description: Unsupported Media Type + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ContentError' + /api/engine/v2/alerts/{id}: + get: + summary: returns the details of an alert + tags: + - Alerts + operationId: PlaceOS::Api::Alerts_show + parameters: + - name: id + in: path + required: true + schema: + type: string + - name: dashboard + in: query + description: return the dashboard associated with this alert + example: "true" + schema: + type: boolean + nullable: true + responses: + 200: + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Model__Alert' + 409: + description: Conflict + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 401: + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 403: + description: Forbidden + 404: + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 408: + description: Request Timeout + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 400: + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError' + 422: + description: Unprocessable Entity + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError' + 406: + description: Not Acceptable + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ContentError' + 415: + description: Unsupported Media Type + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ContentError' + put: + summary: updates an alert + tags: + - Alerts + operationId: PlaceOS::Api::Alerts_update + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Model__Alert' + required: true + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + 200: + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Model__Alert' + 409: + description: Conflict + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 401: + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 403: + description: Forbidden + 404: + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 408: + description: Request Timeout + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 400: + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError' + 422: + description: Unprocessable Entity + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError' + 406: + description: Not Acceptable + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ContentError' + 415: + description: Unsupported Media Type + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ContentError' + delete: + summary: removes an alert + tags: + - Alerts + operationId: PlaceOS::Api::Alerts_destroy + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + 202: + description: Accepted + 409: + description: Conflict + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 401: + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 403: + description: Forbidden + 404: + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 408: + description: Request Timeout + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 400: + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError' + 422: + description: Unprocessable Entity + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError' + 406: + description: Not Acceptable + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ContentError' + 415: + description: Unsupported Media Type + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ContentError' + patch: + summary: updates an alert + tags: + - Alerts + operationId: PlaceOS::Api::Alerts_update{2} + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Model__Alert' + required: true + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + 200: + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Model__Alert' + 409: + description: Conflict + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 401: + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 403: + description: Forbidden + 404: + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 408: + description: Request Timeout + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__CommonError' + 400: + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError' + 422: + description: Unprocessable Entity + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ParameterError' + 406: + description: Not Acceptable + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ContentError' + 415: + description: Unsupported Media Type + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Api__Application__ContentError' /api/engine/v2/api_keys: get: summary: returns a list of the API keys associated with the provided domain, @@ -21486,6 +22501,195 @@ paths: $ref: '#/components/schemas/PlaceOS__Api__Application__ContentError' components: schemas: + PlaceOS__Model__AlertDashboard: + type: object + properties: + created_at: + type: integer + format: Int64 + nullable: true + updated_at: + type: integer + format: Int64 + nullable: true + name: + type: string + nullable: true + description: + type: string + nullable: true + enabled: + type: boolean + nullable: true + authority_id: + type: string + nullable: true + id: + type: string + nullable: true + PlaceOS__Model__Alert: + type: object + properties: + created_at: + type: integer + format: Int64 + nullable: true + updated_at: + type: integer + format: Int64 + nullable: true + name: + type: string + nullable: true + description: + type: string + nullable: true + enabled: + type: boolean + nullable: true + conditions: + type: object + properties: + comparisons: + type: array + items: + type: object + properties: + left: + anyOf: + - type: boolean + - type: number + format: Float64 + - type: integer + format: Int64 + - type: object + properties: + mod: + type: string + status: + type: string + keys: + type: array + items: + type: string + required: + - mod + - status + - keys + - type: string + nullable: true + operator: + type: string + enum: + - and + - equal + - exclusive_or + - greater_than + - greater_than_or_equal + - less_than + - less_than_or_equal + - not_equal + - or + nullable: true + right: + anyOf: + - type: boolean + - type: number + format: Float64 + - type: integer + format: Int64 + - type: object + properties: + mod: + type: string + status: + type: string + keys: + type: array + items: + type: string + required: + - mod + - status + - keys + - type: string + nullable: true + nullable: true + time_dependents: + type: array + items: + type: object + properties: + type: + type: string + enum: + - at + - cron + nullable: true + time: + type: integer + format: Int64 + nullable: true + cron: + type: string + nullable: true + timezone: + type: string + nullable: true + nullable: true + nullable: true + severity: + type: string + enum: + - low + - medium + - high + - critical + nullable: true + alert_type: + type: string + enum: + - threshold + - status + - custom + nullable: true + debounce_period: + type: integer + format: Int32 + nullable: true + alert_dashboard_id: + type: string + nullable: true + alert_dashboard_details: + type: object + properties: + created_at: + type: integer + format: Int64 + nullable: true + updated_at: + type: integer + format: Int64 + nullable: true + name: + type: string + nullable: true + description: + type: string + nullable: true + enabled: + type: boolean + nullable: true + authority_id: + type: string + nullable: true + id: + type: string + nullable: true + nullable: true + id: + type: string + nullable: true PlaceOS__Model__ApiKey__PublicResponse: type: object properties: diff --git a/shard.lock b/shard.lock index e340927c..421a0234 100644 --- a/shard.lock +++ b/shard.lock @@ -203,7 +203,7 @@ shards: placeos-driver: git: https://github.com/placeos/driver.git - version: 7.11.5 + version: 7.11.6 placeos-frontend-loader: git: https://github.com/placeos/frontend-loader.git @@ -215,7 +215,7 @@ shards: placeos-models: git: https://github.com/placeos/models.git - version: 9.74.0 + version: 9.75.1 placeos-resource: git: https://github.com/place-labs/resource.git diff --git a/spec/controllers/alert_dashboards_spec.cr b/spec/controllers/alert_dashboards_spec.cr new file mode 100644 index 00000000..b7f0e97a --- /dev/null +++ b/spec/controllers/alert_dashboards_spec.cr @@ -0,0 +1,58 @@ +require "../helper" + +module PlaceOS::Api + describe AlertDashboards do + Spec.test_404(AlertDashboards.base_route, model_name: Model::AlertDashboard.table_name, headers: Spec::Authentication.headers, clz: String) + + describe "index", tags: "search" do + Spec.test_base_index(Model::AlertDashboard, AlertDashboards) + end + + describe "CRUD operations", tags: "crud" do + Spec.test_crd(Model::AlertDashboard, AlertDashboards) + Spec.test_crd(Model::AlertDashboard, AlertDashboards, sys_admin: false, support: false, groups: ["management"]) + + it "allows management users to create alert dashboards" do + dashboard_data = { + "name" => "Test Dashboard", + "description" => "Test Description", + } + result = client.post( + AlertDashboards.base_route, + body: dashboard_data.to_json, + headers: Spec::Authentication.headers(sys_admin: false, support: false, groups: ["management"]) + ) + result.success?.should be_true + end + end + + describe "GET /alert_dashboards/:id/alerts" do + it "shows dashboard alerts" do + dashboard = PlaceOS::Model::Generator.alert_dashboard(name: "Test Dashboard", description: "Test Description") + dashboard.save! + dashboard_id = dashboard.id.as(String) + + alert = PlaceOS::Model::Generator.alert(name: "Test Alert", description: "Test Description", alert_dashboard_id: dashboard_id) + alert.save! + + result = client.get( + path: AlertDashboards.base_route + "#{dashboard_id}/alerts", + headers: Spec::Authentication.headers, + ) + + result.success?.should be_true + alerts = Array(Hash(String, JSON::Any)).from_json(result.body) + alerts.size.should eq 1 + alerts.first["id"].as_s.should eq alert.id + + dashboard.destroy + alert.destroy + end + end + + describe "scopes" do + Spec.test_controller_scope(AlertDashboards) + Spec.test_update_write_scope(AlertDashboards) + end + end +end diff --git a/spec/controllers/alerts_spec.cr b/spec/controllers/alerts_spec.cr new file mode 100644 index 00000000..0f25706f --- /dev/null +++ b/spec/controllers/alerts_spec.cr @@ -0,0 +1,96 @@ +require "../helper" + +module PlaceOS::Api + describe Alerts do + Spec.test_404(Alerts.base_route, model_name: Model::Alert.table_name, headers: Spec::Authentication.headers, clz: String) + + describe "index", tags: "search" do + Spec.test_base_index(Model::Alert, Alerts) + end + + describe "CRUD operations", tags: "crud" do + Spec.test_crd(Model::Alert, Alerts) + Spec.test_crd(Model::Alert, Alerts, sys_admin: false, support: false, groups: ["management"]) + + it "allows management users to create alerts" do + dashboard = PlaceOS::Model::Generator.alert_dashboard(name: "Test Dashboard", description: "Test Description") + dashboard.save! + + alert = PlaceOS::Model::Generator.alert(name: "Test Alert", description: "Test Description", alert_dashboard_id: dashboard.id) + result = client.post( + Alerts.base_route, + body: alert.to_json, + headers: Spec::Authentication.headers(sys_admin: false, support: false, groups: ["management"]) + ) + result.success?.should be_true + dashboard.destroy + end + + it "prevents creating alerts for dashboards in different authorities" do + other_authority = PlaceOS::Model::Generator.authority("other.example.com") + other_authority.save! + + dashboard = PlaceOS::Model::Generator.alert_dashboard(name: "Test Dashboard", description: "Test Description", authority_id: other_authority.id) + dashboard.save! + + alert = PlaceOS::Model::Generator.alert(name: "Test Alert", description: "Test Description", alert_dashboard_id: dashboard.id) + + result = client.post( + Alerts.base_route, + body: alert.to_json, + headers: Spec::Authentication.headers(sys_admin: false, support: false, groups: ["management"]) + ) + result.status_code.should eq 403 + + dashboard.destroy + other_authority.destroy + end + end + + describe "filtering", tags: "search" do + it "filters by severity" do + dashboard = PlaceOS::Model::Generator.alert_dashboard(name: "Test Dashboard", description: "Test Description") + dashboard.save! + + high_alert = PlaceOS::Model::Generator.alert(name: "High Alert", description: "High Priority Alert", alert_dashboard_id: dashboard.id, severity: PlaceOS::Model::Alert::Severity::HIGH) + high_alert.save! + + low_alert = PlaceOS::Model::Generator.alert(name: "Low Alert", description: "Low Priority Alert", alert_dashboard_id: dashboard.id, severity: PlaceOS::Model::Alert::Severity::LOW) + low_alert.save! + + params = HTTP::Params.encode({"severity" => "HIGH"}) + result = client.get( + "#{Alerts.base_route}?#{params}", + headers: Spec::Authentication.headers + ) + + result.success?.should be_true + alerts = Array(Hash(String, JSON::Any)).from_json(result.body) + alerts.size.should eq 1 + alerts.first["severity"].as_s.should eq "HIGH" + end + + it "filters by alert type" do + dashboard = PlaceOS::Model::Generator.alert_dashboard(name: "Test Dashboard", description: "Test Description") + dashboard.save! + + threshold_alert = PlaceOS::Model::Generator.alert(name: "Threshold Alert", description: "Threshold Alert", alert_dashboard_id: dashboard.id, alert_type: PlaceOS::Model::Alert::AlertType::THRESHOLD) + threshold_alert.save! + + status_alert = PlaceOS::Model::Generator.alert(name: "Status Alert", description: "Status Alert", alert_dashboard_id: dashboard.id, alert_type: PlaceOS::Model::Alert::AlertType::STATUS) + status_alert.save! + + params = HTTP::Params.encode({"alert_type" => "THRESHOLD"}) + result = client.get( + "#{Alerts.base_route}?#{params}", + headers: Spec::Authentication.headers + ) + + result.success?.should be_true + alerts = Array(Hash(String, JSON::Any)).from_json(result.body) + alerts.size.should eq 1 + alerts.first["alert_type"].as_s.should eq "THRESHOLD" + end + end + end +end diff --git a/src/placeos-rest-api/controllers/alert_dashboards.cr b/src/placeos-rest-api/controllers/alert_dashboards.cr new file mode 100644 index 00000000..0eb0b725 --- /dev/null +++ b/src/placeos-rest-api/controllers/alert_dashboards.cr @@ -0,0 +1,105 @@ +require "./application" + +module PlaceOS::Api + class AlertDashboards < Application + include Utils::Permissions + + base "/api/engine/v2/alert_dashboards/" + + # Scopes + ############################################################################################### + + before_action :can_read, only: [:index, :show] + before_action :can_write, only: [:create, :update, :destroy, :remove] + + ############################################################################################### + + @[AC::Route::Filter(:before_action)] + def check_authority + unless @authority = current_authority + Log.warn { {message: "authority not found", action: "authorize!", host: request.hostname} } + raise Error::Unauthorized.new "authority not found" + end + end + + getter! authority : ::PlaceOS::Model::Authority + + @[AC::Route::Filter(:before_action, except: [:index, :create])] + def find_current_alert_dashboard(id : String) + Log.context.set(alert_dashboard_id: id) + # Find will raise a 404 (not found) if there is an error + @current_alert_dashboard = ::PlaceOS::Model::AlertDashboard.find!(id) + end + + getter! current_alert_dashboard : ::PlaceOS::Model::AlertDashboard + + ############################################################################################### + + # list the alert dashboards + @[AC::Route::GET("/")] + def index( + @[AC::Param::Info(description: "return dashboards for a specific authority", example: "authority-1234")] + authority_id : String? = nil, + ) : Array(::PlaceOS::Model::AlertDashboard) + elastic = ::PlaceOS::Model::AlertDashboard.elastic + query = elastic.query(search_params) + + if authority_id + query.filter({ + "authority_id" => [authority_id], + }) + elsif !user_support? + # Limit to current authority for non-support users + query.filter({ + "authority_id" => [authority.id.as(String)], + }) + end + + query.sort(NAME_SORT_ASC) + paginate_results(elastic, query) + end + + # returns the details of an alert dashboard + @[AC::Route::GET("/:id")] + def show : ::PlaceOS::Model::AlertDashboard + dashboard = current_alert_dashboard + dashboard + end + + # updates an alert dashboard + @[AC::Route::PATCH("/:id", body: :dashboard)] + @[AC::Route::PUT("/:id", body: :dashboard)] + def update(dashboard : ::PlaceOS::Model::AlertDashboard) : ::PlaceOS::Model::AlertDashboard + current = current_alert_dashboard + current.assign_attributes(dashboard) + raise Error::ModelValidation.new(current.errors) unless current.save + current + end + + # adds a new alert dashboard + @[AC::Route::POST("/", body: :dashboard, status_code: HTTP::Status::CREATED)] + def create(dashboard : ::PlaceOS::Model::AlertDashboard) : ::PlaceOS::Model::AlertDashboard + # Set authority_id if not provided + if !user_support? || dashboard.authority_id.presence.nil? + dashboard.authority_id = authority.id + end + + raise Error::ModelValidation.new(dashboard.errors) unless dashboard.save + dashboard + end + + # removes an alert dashboard + @[AC::Route::DELETE("/:id", status_code: HTTP::Status::ACCEPTED)] + def destroy : Nil + current_alert_dashboard.destroy + end + + # Get all alerts for a dashboard + @[AC::Route::GET("/:id/alerts")] + def alerts : Array(::PlaceOS::Model::Alert) + alerts = current_alert_dashboard.alerts.to_a + set_collection_headers(alerts.size, ::PlaceOS::Model::Alert.table_name) + alerts + end + end +end diff --git a/src/placeos-rest-api/controllers/alerts.cr b/src/placeos-rest-api/controllers/alerts.cr new file mode 100644 index 00000000..fc7ef9c0 --- /dev/null +++ b/src/placeos-rest-api/controllers/alerts.cr @@ -0,0 +1,128 @@ +require "./application" + +module PlaceOS::Api + class Alerts < Application + include Utils::Permissions + + base "/api/engine/v2/alerts/" + + # Scopes + ############################################################################################### + + before_action :can_read, only: [:index, :show] + before_action :can_write, only: [:create, :update, :destroy, :remove] + + ############################################################################################### + + @[AC::Route::Filter(:before_action, except: [:index, :create])] + def find_current_alert(id : String) + Log.context.set(alert_id: id) + # Find will raise a 404 (not found) if there is an error + @current_alert = ::PlaceOS::Model::Alert.find!(id) + end + + getter! current_alert : ::PlaceOS::Model::Alert + + # extend the Alert model to include dashboard details + class ::PlaceOS::Model::Alert + @[JSON::Field(key: "alert_dashboard_details")] + property alert_dashboard_details : ::PlaceOS::Model::AlertDashboard? = nil + end + + ############################################################################################### + + # list the alerts + @[AC::Route::GET("/")] + def index( + @[AC::Param::Info(description: "return alerts for a specific dashboard", example: "alert_dashboard-1234")] + alert_dashboard_id : String? = nil, + @[AC::Param::Info(description: "filter by alert severity", example: "HIGH")] + severity : String? = nil, + @[AC::Param::Info(description: "filter by alert type", example: "THRESHOLD")] + alert_type : String? = nil, + @[AC::Param::Info(description: "filter by enabled status", example: "true")] + enabled : Bool? = nil, + ) : Array(::PlaceOS::Model::Alert) + elastic = ::PlaceOS::Model::Alert.elastic + query = elastic.query(search_params) + + if adi = alert_dashboard_id + query.filter({ + "alert_dashboard_id" => [adi], + }) + elsif !user_support? + # Limit to current authority's dashboards for non-support users + auth = current_authority.as(::PlaceOS::Model::Authority) + dashboard_ids = ::PlaceOS::Model::AlertDashboard.where(authority_id: auth.id).select(:id).map(&.id.as(String)) + query.filter({ + "alert_dashboard_id" => dashboard_ids, + }) + end + + if sev = severity + query.filter({ + "severity" => [sev.downcase], + }) + end + + if at = alert_type + query.filter({ + "alert_type" => [at.downcase], + }) + end + + if enb = enabled + query.filter({ + "enabled" => [enb], + }) + end + + p! query + query.sort(NAME_SORT_ASC) + paginate_results(elastic, query) + end + + # returns the details of an alert + @[AC::Route::GET("/:id")] + def show( + @[AC::Param::Info(name: "dashboard", description: "return the dashboard associated with this alert", example: "true")] + include_dashboard : Bool? = nil, + ) : ::PlaceOS::Model::Alert + alert = current_alert + alert.alert_dashboard_details = alert.alert_dashboard if include_dashboard + alert + end + + # updates an alert + @[AC::Route::PATCH("/:id", body: :alert)] + @[AC::Route::PUT("/:id", body: :alert)] + def update(alert : ::PlaceOS::Model::Alert) : ::PlaceOS::Model::Alert + current = current_alert + current.assign_attributes(alert) + raise Error::ModelValidation.new(current.errors) unless current.save + current + end + + # adds a new alert + @[AC::Route::POST("/", body: :alert, status_code: HTTP::Status::CREATED)] + def create(alert : ::PlaceOS::Model::Alert) : ::PlaceOS::Model::Alert + # Validate that the dashboard belongs to the current authority if not support user + if alert.alert_dashboard_id && !user_support? + dashboard = ::PlaceOS::Model::AlertDashboard.find!(alert.alert_dashboard_id.as(String)) + auth = current_authority.as(::PlaceOS::Model::Authority) + unless dashboard.authority_id == auth.id + raise Error::Forbidden.new("Cannot create alert for dashboard in different authority") + end + end + + raise Error::ModelValidation.new(alert.errors) unless alert.save + alert + end + + # removes an alert + @[AC::Route::DELETE("/:id", status_code: HTTP::Status::ACCEPTED)] + def destroy : Nil + current_alert.destroy + end + end +end