From 68060afc32f8140d42ce0358b6016bc2e5b0e151 Mon Sep 17 00:00:00 2001 From: Jack Ding Date: Thu, 7 Nov 2024 16:58:42 -0500 Subject: [PATCH] add v2 swagger Signed-off-by: Jack Ding --- .gitignore | 3 +- v2/README.md | 266 ++++++++++++++++++++++++++++++++++++++++++++++++ v2/server.go | 47 +++++++-- v2/swagger.json | 148 ++++++++------------------- 4 files changed, 346 insertions(+), 118 deletions(-) create mode 100644 v2/README.md diff --git a/.gitignore b/.gitignore index 77ab3be..2fc8f1a 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,5 @@ cover.out pub.json sub.json -.idea \ No newline at end of file +.idea +.cache diff --git a/v2/README.md b/v2/README.md new file mode 100644 index 0000000..fd18d7a --- /dev/null +++ b/v2/README.md @@ -0,0 +1,266 @@ +# Rest API +[![go-doc](https://godoc.org/github.com/redhat-cne/rest-api?status.svg)](https://godoc.org/github.com/redhat-cne/rest-api) +[![Go Report Card](https://goreportcard.com/badge/github.com/redhat-cne/rest-api)](https://goreportcard.com/report/github.com/redhat-cne/rest-api) +[![LICENSE](https://img.shields.io/github/license/redhat-cne/rest-api.svg)](https://github.com/redhat-cne/rest-api/blob/main/LICENSE) + +Available Routes + +```html + +POST /api/ocloudNotifications/v2/subscriptions +GET /api/ocloudNotifications/v2/subscriptions +GET /api/ocloudNotifications/v2/subscriptions/{subscription_id} +DELETE /api/ocloudNotifications/v2/subscriptions/{subscription_id} +GET api/ocloudnotifications/v2/{resource_address}/CurrentState +GET /api/ocloudNotifications/v2/health +GET /api/ocloudNotifications/v2/publishers +DELETE /api/ocloudNotifications/v2/subscriptions +``` + +## Pub/Sub Rest API + +Rest API spec . + +### Version: 1.0.0 + + +### /publishers/ + +#### POST +##### Summary + +Creates a new publisher. + +##### Description + +If publisher creation is success(or if already exists), publisher will be returned with Created (201). + +##### Parameters + +| Name | Located in | Description | Required | Schema | +| ---- | ---------- | ----------- | -------- | ---- | +| publisher | body | publisher to add to the list of pub | [PubSub](#pubsub) | + +##### Responses + +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 201 | publisher/subscription data model | [PubSub](#pubsub) | +| 400 | Error Bad Request | object | + +### /subscriptions/ + +#### POST +##### Summary + +Creates a new subscription. + +##### Description + +If subscription creation is success(or if already exists), subscription will be returned with Created (201). + +##### Parameters + +| Name | Located in | Description | Required | Schema | +| ---- | ---------- | ----------- | -------- | ---- | +| subscription | body | subscription to add to the list of subscriptions | yes | [PubSub](#pubsub) | + +##### Responses + +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 201 | publisher/subscription data model | [PubSub](#pubsub) | +| 400 | Error Bad Request | object | + + + +### /create/event/ + +#### POST +##### Summary + +Creates a new event. + +##### Description + +If publisher is present for the event, then event creation is success and be returned with Accepted (202). + +##### Parameters + +| Name | Located in | Description | Required | Schema | +| ---- | ---------- | ----------- | -------- | ---- | +| event | body | event along with publisher id | Yes | [Event](#event) | + +##### Responses + +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 202 | Accepted | object | +| 400 | Error Bad Request | object | + +### /subscriptions/status/{subscriptionid} + +#### PUT +##### Summary + +Creates a new status ping request. + +##### Description + +If a subscription is present for the request, then status request is success and be returned with Accepted (202). + +##### Parameters + +| Name | Located in | Description | Required | Schema | +| ---- | ---------- | ----------- | -------- | ---- | +| subscriptionid | request | subscription id | Yes | | + +##### Responses + +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 202 | Accepted | object | +| 400 | Error Bad Request | object | + +### Models + +#### Data + +Data ... cloud native events' data Json payload is as follows, +```json + +{ +"version": "v1.0", +"values": [{ +"resource": "/cluster/node/ptp", +"dataType": "notification", +"valueType": "enumeration", +"value": "ACQUIRING-SYNC" +}, { +"resource": "/cluster/node/clock", +"dataType": "metric", +"valueType": "decimal64.3", +"value": 100.3 +}] +} +``` + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| values | [ [DataValue](#datavalue) ] | | Yes | +| version | string | | Yes | + +#### DataType + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| DataType | string | | Yes | + +#### DataValue + +DataValue Json payload is as follows, +```json + +{ +"resource": "/cluster/node/ptp", +"dataType": "notification", +"valueType": "enumeration", +"value": "ACQUIRING-SYNC" +} +``` + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| dataType | [DataType](#datatype) | | yes | +| resource | string | | yes | +| value | object | | yes | +| valueType | [ValueType](#valuetype) | | yes | + +#### Event + +Event Json payload is as follows, +```json + +{ +"id": "5ce55d17-9234-4fee-a589-d0f10cb32b8e", +"type": "event.synchronization-state-chang", +"time": "2021-02-05T17:31:00Z", +"data": { +"version": "v1.0", +"values": [{ +"resource": "/cluster/node/ptp", +"dataType": "notification", +"valueType": "enumeration", +"value": "ACQUIRING-SYNC" +}, { +"resource": "/cluster/node/clock", +"dataType": "metric", +"valueType": "decimal64.3", +"value": 100.3 +}] +} +} +``` +Event request model + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| data | [Data](#data) | | yes | +| dataContentType | string | DataContentType - the Data content type +required | yes | +| dataSchema | [URI](#uri) | | No | +| id | string | ID of the event; must be non-empty and unique within the scope of the producer. +required | yes | +| time | [Timestamp](#timestamp) | | yes | +| type | string | Type - The type of the occurrence which has happened. +required | yes | + +#### PubSub +PubSub Json request payload is as follows, +```json + +{ +"id": "789be75d-7ac3-472e-bbbc-6d62878aad4a", +"endpointUri": "http://localhost:9090/ack/event", +"uriLocation": "}", +"resource": "/east-edge-10/vdu3/o-ran-sync/sync-group/sync-status/sync-state" +} +``` +PubSub request model + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| endpointUri | [URI](#uri) | | yes | +| resource | string | Resource - The type of the Resource. +required | yes | + + +#### Timestamp + +Timestamp wraps time.Time to normalize the time layout to RFC3339. It is +intended to enforce compliance with the Cloud Native events spec for their +definition of Timestamp. Custom marshal methods are implemented to ensure +the outbound Timestamp is a string in the RFC3339 layout. + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| Timestamp | object | Timestamp wraps time.Time to normalize the time layout to RFC3339. It is intended to enforce compliance with the Cloud Native events spec for their definition of Timestamp. Custom marshal methods are implemented to ensure the outbound Timestamp is a string in the RFC3339 layout. | | + +#### URI + +URI is a wrapper to url.URL. It is intended to enforce compliance with +the Cloud Native Events spec for their definition of URI. Custom +marshal methods are implemented to ensure the outbound URI object +is a flat string. + + +#### ValueType + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| ValueType | ENUM | ENUMERATION,DECIMAL | yes | + + +## Collecting metrics with Prometheus +Cloud native events rest API comes with following metrics collectors . +1. Number of events published by the rest api. +2. Number of active subscriptions. +3. Number of active publishers. + +[Metrics details ](docs/metrics.md) diff --git a/v2/server.go b/v2/server.go index fc459be..e5e5020 100644 --- a/v2/server.go +++ b/v2/server.go @@ -20,8 +20,8 @@ // // Schemes: http, https // Host: localhost:8089 -// basePath: /api/ocloudNotifications/v1 -// Version: 1.0.0 +// BasePath: /api/ocloudNotifications/v2 +// Version: 2.0.0 // Contact: Aneesh Puttur // // Consumes: @@ -44,7 +44,6 @@ import ( "github.com/gorilla/mux" "github.com/redhat-cne/sdk-go/pkg/channel" "github.com/redhat-cne/sdk-go/pkg/event" - "github.com/redhat-cne/sdk-go/pkg/pubsub" "github.com/redhat-cne/sdk-go/pkg/types" pubsubv1 "github.com/redhat-cne/sdk-go/v1/pubsub" subscriberApi "github.com/redhat-cne/sdk-go/v1/subscriber" @@ -95,10 +94,32 @@ type Server struct { } // publisher/subscription data model +// SubscriptionInfo defines data types used for subscription. +type SubscriptionInfo struct { //nolint:deadcode,unused + // Identifier for the created subscription resource. + // +required + ID string `json:"SubscriptionId" omit:"empty"` + // A URI describing the call back address. + // +required + EndPointURI string `json:"EndpointUri" example:"http://localhost:8080/resourcestatus/ptp" omit:"empty"` + // A URI describing the publisher/subscription get link. + URILocation string `json:"UriLocation" omit:"empty"` + // The resource address specifies the Event Producer with a hierarchical path. + // Format /{clusterName}/{siteName}(/optional/hierarchy/..)/{nodeName}/{(/optional/hierarchy)/resource} + // +required + Resource string `json:"ResourceAddress" example:"/east-edge-10/vdu3/o-ran-sync/sync-group/sync-status/sync-state"` +} + // swagger:response pubSubResp type swaggPubSubRes struct { //nolint:deadcode,unused // in:body - Body pubsub.PubSub + Body SubscriptionInfo +} + +// swagger:response publishers +type swaggPubSubResList struct { //nolint:deadcode,unused + // in:body + Body []SubscriptionInfo } // PubSub request model @@ -243,7 +264,7 @@ func (s *Server) Start() { api.HandleFunc("/subscriptions", s.createSubscription).Methods(http.MethodPost) //createPublisher create publisher and send it to a channel that is shared by middleware to process - // swagger:operation POST /publishers/ publishers createPublisher + // internal:operation POST /publishers/ publishers createPublisher // --- // summary: Creates a new publisher. // description: If publisher creation is success(or if already exists), publisher will be returned with Created (201). @@ -252,7 +273,7 @@ func (s *Server) Start() { // description: publisher to add to the list of publishers // in: body // schema: - // "$ref": "#/definitions/PubSub" + // "$ref": "#/definitions/SubscriptionInfo" // responses: // "201": // "$ref": "#/responses/pubSubResp" @@ -265,18 +286,23 @@ func (s *Server) Start() { See note below. 404 Subscription resources are not available (not created). */ + // swagger:route GET /subscriptions + // Get a list of subscription object(s) and their associated properties. + // responses: + // 200: Returns the subscription resources and their associated properties that already exist. + // 400: Bad request by the client. api.HandleFunc("/subscriptions", s.getSubscriptions).Methods(http.MethodGet) //publishers create publisher and send it to a channel that is shared by middleware to process // swagger:operation GET /publishers/ publishers getPublishers // --- // summary: Get publishers. - // description: If publisher creation is success(or if already exists), publisher will be returned with Created (201). + // description: Returns a list of publisher details for the cluster node. // parameters: // responses: // "200": // "$ref": "#/responses/publishers" // "404": - // "$ref": "#/responses/notFound" + // "$ref": "#/responses/notFoundReq" api.HandleFunc("/publishers", s.getPublishers).Methods(http.MethodGet) // 200 and 404 api.HandleFunc("/subscriptions/{subscriptionid}", s.getSubscriptionByID).Methods(http.MethodGet) @@ -289,7 +315,8 @@ func (s *Server) Start() { api.HandleFunc("/publishers", s.deleteAllPublishers).Methods(http.MethodDelete) //pingForSubscribedEventStatus pings for event status if the publisher has capability to push event on demand - // swagger:operation POST /subscriptions/status subscriptions pingForSubscribedEventStatus + // this API is internal + // operation POST /subscriptions/status subscriptions pingForSubscribedEventStatus // --- // summary: Get status of publishing events. // description: If publisher status ping is success, call will be returned with status accepted. @@ -313,7 +340,7 @@ func (s *Server) Start() { api.HandleFunc("/log", s.logEvent).Methods(http.MethodPost) //publishEvent create event and send it to a channel that is shared by middleware to process - // swagger:operation POST /create/event/ event publishEvent + // this API is internal // --- // summary: Creates a new event. // description: If publisher is present for the event, then event creation is success and be returned with Accepted (202). diff --git a/v2/swagger.json b/v2/swagger.json index e4337c9..4b25498 100644 --- a/v2/swagger.json +++ b/v2/swagger.json @@ -17,42 +17,14 @@ "name": "Aneesh Puttur", "email": "aputtur@redhat.com" }, - "version": "1.0.0" + "version": "2.0.0" }, "host": "localhost:8089", - "basePath": "/api/ocloudNotifications/v1", + "basePath": "/api/ocloudNotifications/v2", "paths": { - "/create/event/": { - "post": { - "description": "If publisher is present for the event, then event creation is success and be returned with Accepted (202).", - "tags": [ - "event" - ], - "summary": "Creates a new event.", - "operationId": "publishEvent", - "parameters": [ - { - "description": "event along with publisher id", - "name": "event", - "in": "body", - "schema": { - "$ref": "#/definitions/Event" - } - } - ], - "responses": { - "202": { - "$ref": "#/responses/acceptedReq" - }, - "400": { - "$ref": "#/responses/badReq" - } - } - } - }, "/publishers/": { "get": { - "description": "If publisher creation is success(or if already exists), publisher will be returned with Created (201).", + "description": "Returns a list of publisher details for the cluster node.", "tags": [ "publishers" ], @@ -63,33 +35,7 @@ "$ref": "#/responses/publishers" }, "404": { - "$ref": "#/responses/notFound" - } - } - }, - "post": { - "description": "If publisher creation is success(or if already exists), publisher will be returned with Created (201).", - "tags": [ - "publishers" - ], - "summary": "Creates a new publisher.", - "operationId": "createPublisher", - "parameters": [ - { - "description": "publisher to add to the list of publishers", - "name": "publisher", - "in": "body", - "schema": { - "$ref": "#/definitions/PubSub" - } - } - ], - "responses": { - "201": { - "$ref": "#/responses/pubSubResp" - }, - "400": { - "$ref": "#/responses/badReq" + "$ref": "#/responses/notFoundReq" } } } @@ -121,35 +67,11 @@ } } } - }, - "/subscriptions/status": { - "post": { - "description": "If publisher status ping is success, call will be returned with status accepted.", - "tags": [ - "subscriptions" - ], - "summary": "Get status of publishing events.", - "operationId": "pingForSubscribedEventStatus", - "parameters": [ - { - "description": "subscription id to check status for", - "name": "subscriptionid" - } - ], - "responses": { - "201": { - "$ref": "#/responses/pubSubResp" - }, - "400": { - "$ref": "#/responses/badReq" - } - } - } } }, "definitions": { "Data": { - "description": "{\n\"version\": \"v1.0\",\n\"values\": [{\n\"resource\": \"/sync/sync-status/sync-state\",\n\"dataType\": \"notification\",\n\"valueType\": \"enumeration\",\n\"value\": \"ACQUIRING-SYNC\"\n}, {\n\"resource\": \"/sync/sync-status/sync-state\",\n\"dataType\": \"metric\",\n\"valueType\": \"decimal64.3\",\n\"value\": 100.3\n}, {\n\"resource\": \"/redfish/v1/Systems\",\n\"dataType\": \"notification\",\n\"valueType\": \"redfish-event\",\n\"value\": {\n\"@odata.context\": \"/redfish/v1/$metadata#Event.Event\",\n\"@odata.type\": \"#Event.v1_3_0.Event\",\n\"Context\": \"any string is valid\",\n\"Events\": [{\"EventId\": \"2162\", \"MemberId\": \"615703\", \"MessageId\": \"TMP0100\"}],\n\"Id\": \"5e004f5a-e3d1-11eb-ae9c-3448edf18a38\",\n\"Name\": \"Event Array\"\n}\n}]\n}", + "description": "{\n\"version\": \"v1.0\",\n\"values\": [{\n\"ResourceAddress\": \"/sync/sync-status/sync-state\",\n\"data_type\": \"notification\",\n\"value_type\": \"enumeration\",\n\"value\": \"ACQUIRING-SYNC\"\n}, {\n\"ResourceAddress\": \"/sync/sync-status/sync-state\",\n\"data_type\": \"metric\",\n\"value_type\": \"decimal64.3\",\n\"value\": 100.3\n}, {\n\"ResourceAddress\": \"/redfish/v1/Systems\",\n\"data_type\": \"notification\",\n\"value_type\": \"redfish-event\",\n\"value\": {\n\"@odata.context\": \"/redfish/v1/$metadata#Event.Event\",\n\"@odata.type\": \"#Event.v1_3_0.Event\",\n\"Context\": \"any string is valid\",\n\"Events\": [{\"EventId\": \"2162\", \"MemberId\": \"615703\", \"MessageId\": \"TMP0100\"}],\n\"Id\": \"5e004f5a-e3d1-11eb-ae9c-3448edf18a38\",\n\"Name\": \"Event Array\"\n}\n}]\n}", "type": "object", "title": "Data ... cloud native events data\nData Json payload is as follows,", "properties": { @@ -173,28 +95,28 @@ "x-go-package": "github.com/redhat-cne/sdk-go/pkg/event" }, "DataValue": { - "description": "{\n\"resource\": \"/cluster/node/ptp\",\n\"dataType\": \"notification\",\n\"valueType\": \"enumeration\",\n\"value\": \"ACQUIRING-SYNC\"\n}", + "description": "{\n\"ResourceAddress\": \"/cluster/node/ptp\",\n\"data_type\": \"notification\",\n\"value_type\": \"enumeration\",\n\"value\": \"ACQUIRING-SYNC\"\n}", "type": "object", "title": "DataValue ...\nDataValue Json payload is as follows,", "properties": { - "dataType": { - "$ref": "#/definitions/DataType" - }, - "resource": { + "ResourceAddress": { "type": "string", "x-go-name": "Resource" }, + "data_type": { + "$ref": "#/definitions/DataType" + }, "value": { "x-go-name": "Value" }, - "valueType": { + "value_type": { "$ref": "#/definitions/ValueType" } }, "x-go-package": "github.com/redhat-cne/sdk-go/pkg/event" }, "Event": { - "description": "{\n\"id\": \"5ce55d17-9234-4fee-a589-d0f10cb32b8e\",\n\"type\": \"event.sync.sync-status.synchronization-state-change\",\n\"source\": \"/cluster/node/example.com/ptp/clock_realtime\",\n\"time\": \"2021-02-05T17:31:00Z\",\n\"data\": {\n\"version\": \"v1.0\",\n\"values\": [{\n\"resource\": \"/sync/sync-status/sync-state\",\n\"dataType\": \"notification\",\n\"valueType\": \"enumeration\",\n\"value\": \"ACQUIRING-SYNC\"\n}, {\n\"resource\": \"/sync/sync-status/sync-state\",\n\"dataType\": \"metric\",\n\"valueType\": \"decimal64.3\",\n\"value\": 100.3\n}]\n}\n}\n\nEvent request model", + "description": "{\n\"id\": \"5ce55d17-9234-4fee-a589-d0f10cb32b8e\",\n\"type\": \"event.sync.sync-status.synchronization-state-change\",\n\"source\": \"/cluster/node/example.com/ptp/clock_realtime\",\n\"time\": \"2021-02-05T17:31:00Z\",\n\"data\": {\n\"version\": \"v1.0\",\n\"values\": [{\n\"ResourceAddress\": \"/sync/sync-status/sync-state\",\n\"data_type\": \"notification\",\n\"value_type\": \"enumeration\",\n\"value\": \"ACQUIRING-SYNC\"\n}, {\n\"ResourceAddress\": \"/sync/sync-status/sync-state\",\n\"data_type\": \"metric\",\n\"value_type\": \"decimal64.3\",\n\"value\": 100.3\n}]\n}\n}\n\nEvent request model", "type": "object", "title": "Event represents the canonical representation of a Cloud Native Event.\nEvent Json payload is as follows,", "properties": { @@ -232,29 +154,32 @@ }, "x-go-package": "github.com/redhat-cne/sdk-go/pkg/event" }, - "PubSub": { - "description": "{\n\"id\": \"789be75d-7ac3-472e-bbbc-6d62878aad4a\",\n\"endpointUri\": \"http://localhost:9090/ack/event\",\n\"uriLocation\": \"http://localhost:8080/api/ocloudNotifications/v1/publishers/{publisherid}\",\n\"resource\": \"/east-edge-10/vdu3/o-ran-sync/sync-group/sync-status/sync-state\"\n}\n\nPubSub request model", + "SubscriptionInfo": { + "description": "publisher/subscription data model\nSubscriptionInfo defines data types used for subscription.", "type": "object", - "title": "PubSub represents the canonical representation of a Cloud Native Event Publisher and Sender .\nPubSub Json request payload is as follows,", "properties": { - "endpointUri": { - "$ref": "#/definitions/URI" - }, - "id": { - "description": "ID of the pub/sub; is updated on successful creation of publisher/subscription.", + "EndpointUri": { + "description": "A URI describing the call back address.\n+required", "type": "string", - "x-go-name": "ID" + "x-go-name": "EndPointURI" }, - "resource": { - "description": "Resource - The type of the Resource.\n+required", + "ResourceAddress": { + "description": "The resource address specifies the Event Producer with a hierarchical path.\nFormat /{clusterName}/{siteName}(/optional/hierarchy/..)/{nodeName}/{(/optional/hierarchy)/resource}\n+required", "type": "string", "x-go-name": "Resource" }, - "uriLocation": { - "$ref": "#/definitions/URI" + "SubscriptionId": { + "description": "Identifier for the created subscription resource.\n+required", + "type": "string", + "x-go-name": "ID" + }, + "UriLocation": { + "description": "A URI describing the publisher/subscription get link.", + "type": "string", + "x-go-name": "URILocation" } }, - "x-go-package": "github.com/redhat-cne/sdk-go/pkg/pubsub" + "x-go-package": "github.com/redhat-cne/rest-api/v2" }, "URI": { "description": "URI is a wrapper to url.URL. It is intended to enforce compliance with\nthe Cloud Native Events spec for their definition of URI. Custom\nmarshal methods are implemented to ensure the outbound URI object\nis a flat string.", @@ -297,7 +222,7 @@ "x-go-package": "github.com/redhat-cne/sdk-go/pkg/types" }, "Userinfo": { - "description": "The Userinfo type is an immutable encapsulation of username and\npassword details for a URL. An existing Userinfo value is guaranteed\nto have a username set (potentially empty, as allowed by RFC 2396),\nand optionally a password.", + "description": "The Userinfo type is an immutable encapsulation of username and\npassword details for a [URL]. An existing Userinfo value is guaranteed\nto have a username set (potentially empty, as allowed by RFC 2396),\nand optionally a password.", "type": "object", "x-go-package": "net/url" }, @@ -357,9 +282,18 @@ } }, "pubSubResp": { - "description": "publisher/subscription data model", + "description": "", "schema": { - "$ref": "#/definitions/PubSub" + "$ref": "#/definitions/SubscriptionInfo" + } + }, + "publishers": { + "description": "", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/SubscriptionInfo" + } } } }