From a43a13b39050de41fd24e11d16a3a280af088527 Mon Sep 17 00:00:00 2001 From: Bruno Sakoto Date: Thu, 7 Oct 2021 09:11:48 -0400 Subject: Finalize design and modeling documentation Issue-ID: CPS-447 Signed-off-by: Bruno Sakoto Change-Id: I58181dd7018319c46d465c78b8299c3f316f455e --- .../cps-data-updated-event-schema-v1.json | 87 +++++++ docs/_static/openapi/swagger/openapi.yml | 255 ++++++++++++++++++ .../cps-temporal-postman-collection.json | 288 +++++++++++++++++++++ docs/content/design.rst | 36 ++- docs/content/modeling.rst | 32 ++- 5 files changed, 691 insertions(+), 7 deletions(-) create mode 100644 docs/_static/event-schema/cps-data-updated-event-schema-v1.json create mode 100644 docs/_static/openapi/swagger/openapi.yml create mode 100644 docs/_static/postman-collections/cps-temporal-postman-collection.json (limited to 'docs') diff --git a/docs/_static/event-schema/cps-data-updated-event-schema-v1.json b/docs/_static/event-schema/cps-data-updated-event-schema-v1.json new file mode 100644 index 0000000..2057955 --- /dev/null +++ b/docs/_static/event-schema/cps-data-updated-event-schema-v1.json @@ -0,0 +1,87 @@ +{ + + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$id": "urn:cps:org.onap.cps:data-updated-event-schema:v1", + + "$ref": "#/definitions/CpsDataUpdatedEvent", + + "definitions": { + + "CpsDataUpdatedEvent": { + "description": "The payload for CPS data updated event.", + "type": "object", + "properties": { + "schema": { + "description": "The schema, including its version, that this event adheres to. E.g. 'urn:cps:org.onap.cps:data-updated-event-schema:v99'.", + "type": "string", + "format": "uri" + }, + "id": { + "description": "The unique id identifying the event for the specified source. Producer must ensure that source + id is unique for each distinct event.", + "type": "string" + }, + "source": { + "description": "The source of the event. Producer must ensure that source + id is unique for each distinct event.", + "type": "string", + "format": "uri" + }, + "type": { + "description": "The type of the event.", + "type": "string" + }, + "content": { + "$ref": "#/definitions/Content" + } + }, + "required": [ + "schema", + "id", + "source", + "type", + "content" + ], + "additionalProperties": false + }, + + "Content": { + "description": "The event content.", + "type": "object", + "properties": { + "observedTimestamp": { + "description": "The timestamp when the data has been observed. The expected format is 'yyyy-MM-dd'T'HH:mm:ss.SSSZ'. Ex: '2020-12-01T00:00:00.000+0000' ", + "type": "string" + }, + "dataspaceName": { + "description": "The name of CPS Core dataspace the data belongs to.", + "type": "string" + }, + "schemaSetName": { + "description": "The name of CPS Core schema set the data adheres to.", + "type": "string" + }, + "anchorName": { + "description": "The name of CPS Core anchor the data is attached to.", + "type": "string" + }, + "data": { + "$ref": "#/definitions/Data" + } + }, + "required": [ + "observedTimestamp", + "dataspaceName", + "schemaSetName", + "anchorName", + "data" + ], + "additionalProperties": false + }, + + "Data": { + "description": "Data as json object.", + "type": "object" + } + + } + +} \ No newline at end of file diff --git a/docs/_static/openapi/swagger/openapi.yml b/docs/_static/openapi/swagger/openapi.yml new file mode 100644 index 0000000..991d807 --- /dev/null +++ b/docs/_static/openapi/swagger/openapi.yml @@ -0,0 +1,255 @@ +# ============LICENSE_START======================================================= +# Copyright (c) 2021 Bell Canada. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# ============LICENSE_END========================================================= + +openapi: 3.0.1 +info: + title: ONAP Open API v3 Configuration Persistence Service - Temporal + description: CPS-Temporal is time-series database for network data + version: 1.0.0 + contact: + name: ONAP + url: 'https://onap.readthedocs.io' + email: onap-discuss@lists.onap.org + license: + name: Apache 2.0 + url: 'http://www.apache.org/licenses/LICENSE-2.0' + x-planned-retirement-date: '202212' + x-component: Modeling +servers: + - url: '/cps-temporal/api' +tags: + - name: cps-temporal-query + description: CPS Temporal Query +paths: + '/v1/dataspaces/{dataspace-name}/anchors/{anchor-name}/history': + get: + description: 'Read the data for the specified anchor based on filter criteria provided in query parameters' + tags: + - cps-temporal-query + summary: Get anchor data by name + operationId: getAnchorDataByName + parameters: + - $ref: '#/components/parameters/dataspaceName' + - name: anchor-name + in: path + description: Anchor Name + required: true + schema: + type: string + - $ref: '#/components/parameters/observedTimestampAfter' + - $ref: '#/components/parameters/simplePayloadFilter' + - $ref: '#/components/parameters/pointInTime' + - $ref: '#/components/parameters/pageNumber' + - $ref: '#/components/parameters/pageLimit' + - $ref: '#/components/parameters/sort' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/AnchorHistory' + example: + nextRecordsLink: /v1/dataspace/my-dataspace/anchors/my-anchor/history?pageLimit=20&pageNumber=2 + previousRecordsLink: /v1/dataspace/my-dataspace/anchors/my-anchor/history?pageLimit=20&pageNumber=0 + records: + - timestamp: '2021-03-21T00:00:00.000-0000' + dataspace: my-dataspace + schemaSet: my-schema-set + anchor: my-anchor + data: + status: UP + + + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '/v1/dataspaces/{dataspace-name}/anchors/history': + get: + description: 'Read anchors data based on filter criteria provided in query parameters' + tags: + - cps-temporal-query + summary: Get anchors data based on filter criteria + operationId: getAnchorsDataByFilter + parameters: + - $ref: '#/components/parameters/dataspaceName' + - name: schema-set-name + in: query + description: Schema-set name + required: true + schema: + type: string + - $ref: '#/components/parameters/observedTimestampAfter' + - $ref: '#/components/parameters/simplePayloadFilter' + - $ref: '#/components/parameters/pointInTime' + - $ref: '#/components/parameters/pageNumber' + - $ref: '#/components/parameters/pageLimit' + - $ref: '#/components/parameters/sort' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/AnchorHistory' + example: + nextRecordsLink: /v1/dataspace/my-dataspace/anchors/history?pageLimit=20&pageNumber=2 + previousRecordsLink: /v1/dataspace/my-dataspace/anchors/history?pageLimit=20&pageNumber=0 + records: + - timestamp: '2021-03-21T00:00:00.000-0000' + dataspace: my-dataspace + schemaSet: my-schema-set + anchor: my-anchor + data: + status: UP + + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' +components: + parameters: + dataspaceName: + name: dataspace-name + in: path + description: Dataspace Name + required: true + schema: + type: string + observedTimestampAfter: + name: observedTimestampAfter + in: query + description: Fetch data with observed timestamp after
Format - 'yyyy-MM-ddTHH:mm:ss.SSSZ' + required: false + schema: + type: string + example: '2021-03-21T00:00:00.000-0000' + simplePayloadFilter: + name: simplePayloadFilter + in: query + description: Payload filter + required: false + schema: + type: string + pointInTime: + name: pointInTime + in: query + description: Consider data modified before
Format - 'yyyy-MM-ddTHH:mm:ss.SSSZ' + required: false + schema: + type: string + example: '2021-03-21T00:00:00.000-0000' + pageLimit: + in: query + name: pageLimit + required: false + schema: + type: integer + minimum: 0 + default: 1000 + description: The numbers of items to return + pageNumber: + name: pageNumber + in: query + description: Page number + required: false + schema: + type: integer + minimum: 0 + default: 0 + sort: + in: query + name: sort + required: false + schema: + type: string + default: observed_timestamp:desc + description: "Sort by timestamp in 'asc' or 'desc' order. Supported values:
observed_timestamp:desc
anchor:asc,observed_timestamp:desc" + responses: + BadRequest: + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + Unauthorized: + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + Forbidden: + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + schemas: + AnchorDetails: + type: object + title: AnchorDetails + properties: + observedTimestamp: + type: string + example: '2021-03-21T00:00:00.000-0000' + dataspace: + type: string + example: 'my-dataspace' + schemaSet: + type: string + example: 'my-schema-set' + anchor: + type: string + example: 'my-anchor' + data: + type: object + example: { "status" : "UP" } + AnchorHistory: + type: object + title: AnchorHistory + properties: + nextRecordsLink: + type: string + example: /v1/dataspace/dataspace-name/anchors/history?pageLimit=20&pageNumber=2 + previousRecordsLink: + type: string + example: /v1/dataspace/dataspace-name/anchors/history?pageLimit=20&pageNumber=0 + records: + type: array + items: + $ref: '#/components/schemas/AnchorDetails' + required: + - records + ErrorMessage: + type: object + title: Error + properties: + status: + type: string + example: 400 + message: + type: string + example: Data could not be fetched + details: + type: string + example: "after parameter should have datetime value in ISO format yyyy-MM-ddTHH:mm:ss.SSSZ" diff --git a/docs/_static/postman-collections/cps-temporal-postman-collection.json b/docs/_static/postman-collections/cps-temporal-postman-collection.json new file mode 100644 index 0000000..cd23d16 --- /dev/null +++ b/docs/_static/postman-collections/cps-temporal-postman-collection.json @@ -0,0 +1,288 @@ +{ + "info": { + "_postman_id": "9ef134f9-0f80-4a1c-92af-51da658c228b", + "name": "CPS Temporal", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "Actuator", + "item": [ + { + "name": "Get Health", + "protocolProfileBehavior": { + "disableCookies": true + }, + "request": { + "auth": { + "type": "noauth" + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{temporal-host}}:{{temporal-management-port}}/manage/health", + "protocol": "{{protocol}}", + "host": [ + "{{temporal-host}}" + ], + "port": "{{temporal-management-port}}", + "path": [ + "manage", + "health" + ] + } + }, + "response": [] + }, + { + "name": "Get Metrics", + "protocolProfileBehavior": { + "disableCookies": true + }, + "request": { + "auth": { + "type": "noauth" + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{temporal-host}}:{{temporal-management-port}}/manage/prometheus", + "protocol": "{{protocol}}", + "host": [ + "{{temporal-host}}" + ], + "port": "{{temporal-management-port}}", + "path": [ + "manage", + "prometheus" + ] + } + }, + "response": [] + }, + { + "name": "Get Info", + "protocolProfileBehavior": { + "disableCookies": true + }, + "request": { + "auth": { + "type": "noauth" + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{temporal-host}}:{{temporal-management-port}}/manage/info", + "protocol": "{{protocol}}", + "host": [ + "{{temporal-host}}" + ], + "port": "{{temporal-management-port}}", + "path": [ + "manage", + "info" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Specifications", + "item": [ + { + "name": "Swagger UI", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{temporal-host}}:{{temporal-port}}/swagger-ui.html", + "protocol": "{{protocol}}", + "host": [ + "{{temporal-host}}" + ], + "port": "{{temporal-port}}", + "path": [ + "swagger-ui.html" + ] + } + }, + "response": [] + }, + { + "name": "Open API", + "request": { + "auth": { + "type": "noauth" + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{temporal-host}}:{{temporal-port}}/swagger/openapi.yml", + "protocol": "{{protocol}}", + "host": [ + "{{temporal-host}}" + ], + "port": "{{temporal-port}}", + "path": [ + "swagger", + "openapi.yml" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Data", + "item": [ + { + "name": "Get Anchor Data", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{temporal-host}}:{{temporal-port}}/cps-temporal/api/v1/dataspaces/{{dataspace-name}}/anchors/{{anchor-name}}/history", + "protocol": "{{protocol}}", + "host": [ + "{{temporal-host}}" + ], + "port": "{{temporal-port}}", + "path": [ + "cps-temporal", + "api", + "v1", + "dataspaces", + "{{dataspace-name}}", + "anchors", + "{{anchor-name}}", + "history" + ], + "query": [ + { + "key": "sort", + "value": "observed_timestamp:desc,anchor:asc", + "disabled": true + }, + { + "key": "observedTimestampAfter", + "value": "2021-08-01T00:00:00.000-0000", + "disabled": true + }, + { + "key": "pointInTime", + "value": "2021-08-17T14:35:00.000-0400", + "disabled": true + }, + { + "key": "pageNumber", + "value": "0", + "disabled": true + }, + { + "key": "pageLimit", + "value": "1", + "disabled": true + } + ] + } + }, + "response": [] + }, + { + "name": "Get Schema Set Data", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{temporal-host}}:{{temporal-port}}/cps-temporal/api/v1/dataspaces/{{dataspace-name}}/anchors/history?schema-set-name={{schema-set-name}}", + "protocol": "{{protocol}}", + "host": [ + "{{temporal-host}}" + ], + "port": "{{temporal-port}}", + "path": [ + "cps-temporal", + "api", + "v1", + "dataspaces", + "{{dataspace-name}}", + "anchors", + "history" + ], + "query": [ + { + "key": "schema-set-name", + "value": "{{schema-set-name}}" + }, + { + "key": "sort", + "value": "observed_timestamp:desc,anchor:asc", + "disabled": true + }, + { + "key": "observedTimestampAfter", + "value": "2021-08-01T00:00:00.000%2B0100", + "disabled": true + }, + { + "key": "pointInTime", + "value": "2021-08-17T14:35:00.000-0400", + "disabled": true + }, + { + "key": "pageNumber", + "value": "0", + "disabled": true + }, + { + "key": "pageLimit", + "value": "1", + "disabled": true + } + ] + } + }, + "response": [] + } + ] + } + ], + "auth": { + "type": "basic", + "basic": [ + { + "key": "password", + "value": "{{temporal-password}}", + "type": "string" + }, + { + "key": "username", + "value": "{{temporal-username}}", + "type": "string" + } + ] + }, + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] +} \ No newline at end of file diff --git a/docs/content/design.rst b/docs/content/design.rst index 7a6590d..c414e6d 100644 --- a/docs/content/design.rst +++ b/docs/content/design.rst @@ -8,13 +8,37 @@ CPS Temporal Design =================== -.. warning:: Draft +Exposed APIs +============ -* REST API +CPS Temporal is providing a REST HTTP API to query historical CPS data. +Its OPEN API Specification can be found either: - * Specification - * Postman Collection +* In :download:`openapi.yml <../_static/openapi/swagger/openapi.yml>` + file +* At ``https://:/swagger/openapi.yml`` + endpoint available on CPS Temporal running instance -* Event Schema +Swagger UI is also available at: - * Json Schema +* ``https://:/swagger-ui.html`` + +And following Postman collection can be used to send requests to any running +instance: + +* :download:`CPS Temporal Postman Collection <../_static/postman-collections/cps-temporal-postman-collection.json>` + +Event Integration +================= + +CPS Core and CPS Temporal are integrated with an event driven architecture. +Integration between these two components is event notification based. + +For each data modification handled by CPS Core, + +* CPS Core is publishing, to a dedicated Kafka topic, an event representing + the data configuration or state. +* CPS Temporal is listening to the same topic for the event and is responsible + to keep track of all data over time. + +Refer to :doc:`modeling` for more details on the event structure. diff --git a/docs/content/modeling.rst b/docs/content/modeling.rst index b8bf91e..8871a81 100644 --- a/docs/content/modeling.rst +++ b/docs/content/modeling.rst @@ -8,4 +8,34 @@ CPS Temporal Modeling ===================== -.. warning:: Draft +Event Structure +=============== + +Data manipulated by both CPS Core and CPS Temporal to represent a Data Updated +Event is a JSON structure that is defined by following Json Schema: + +* :download:`cps-data-updated-event-schema.json <../_static/event-schema/cps-data-updated-event-schema-v1.json>` + +And following is an example of an event compliant with this schema: + +.. code:: json + + { + "schema": "urn:cps:org.onap.cps:data-updated-event-schema:v1", + "id": "38aa6cc6-264d-4ede-b534-18f5c1f403ea", + "source": "urn:cps:org.onap.cps", + "type": "org.onap.cps.data-updated-event", + "content": { + "observedTimestamp": "2021-06-09T13:00:00.123-0400", + "dataspaceName": "my-dataspace", + "schemaSetName": "my-schema-set", + "anchorName": "my-anchor", + "data": { + "interface": { + "name": "itf-1", + "status": "up" + } + } + } + } + -- cgit 1.2.3-korg