Subscription REST interface update 04/6704/1 v0.8.5
authorAnssi Mannila <anssi.mannila@nokia.com>
Thu, 16 Sep 2021 11:48:04 +0000 (14:48 +0300)
committerAnssi Mannila <anssi.mannila@nokia.com>
Thu, 16 Sep 2021 11:53:45 +0000 (14:53 +0300)
Added: - E2 interface subscription retry and timeout directives
 - Reject cause
 - Descriptive error inforamtion
 - Source of error information
 - Interface where timeout happened
Change-Id: Ie08f53135858137729a90995027a42bc82b08528
Signed-off-by: Anssi Mannila <anssi.mannila@nokia.com>
api/xapp_rest_api.yaml
pkg/clientmodel/subscription_details.go [deleted file]
pkg/clientmodel/subscription_instance.go
pkg/clientmodel/subscription_params.go
pkg/models/subscription_details.go [deleted file]
pkg/models/subscription_instance.go
pkg/models/subscription_params.go
pkg/xapp/subscription.go
pkg/xapp/subscription_test.go

index 2890b90..8f08dd9 100644 (file)
@@ -1,7 +1,7 @@
 swagger: '2.0'
 info:
   description: This is the initial REST API for RIC subscription
-  version: 0.0.2
+  version: 0.0.3
   title: RIC subscription
   license:
     name: Apache 2.0
@@ -243,6 +243,25 @@ definitions:
         type: integer
         minimum: 0
         maximum: 4095
+      E2SubscriptionDirectives:
+        type: object
+        properties:
+          E2TimeoutTimerValue:
+            description: How long time response is waited from E2 node
+            type: integer
+            default: 2
+            minimum: 1
+            maximum: 10
+          E2RetryCount:
+            description: How many times E2 subscription request is retried
+            type: integer
+            default: 2
+            minimum: 0
+            maximum: 10
+          RMRRoutingNeeded:
+            description: Subscription needs RMR route from E2Term to xApp 
+            type: boolean
+            default: True
       SubscriptionDetails:
         $ref: '#/definitions/SubscriptionDetailsList'
   SubscriptionResponse:
@@ -263,6 +282,8 @@ definitions:
       - XappEventInstanceId
       - E2EventInstanceId
       - ErrorCause
+      - ErrorSource
+      - TimeoutType
     properties:
       XappEventInstanceId:
         type: integer
@@ -272,9 +293,32 @@ definitions:
         type: integer
         minimum: 0
         maximum: 65535
+      RejectCause:
+        description: Reason for REST subscription rejection.
+        type: string
+        default: None
+        enum:
+        - None
+        - REST-subscription-ongoing         # xApp should retry after delay
+        - REST-subscription-delete-ongoing  # xApp should retry after delay
+        - Invalid-REST-request-message
+        - REST-subscription-with-given-id-does-not-exist
+        - E2-interface-down
+        - Other
       ErrorCause:
-        description: Empty string when no error.
+        description: Descriptive error cause. Empty string when no error.
+        type: string
+        default: ''
+      ErrorSource:
+        description: Source of error cause.
+        type: string
+        default: None
+        enum: [None, SUBMGR, RTMGR, DBAAS, ASN1, E2Node]
+      TimeoutType:
+        description: Type timeout. xApp should retry if timeout occours.
         type: string
+        default: None
+        enum: [None, E2-Timeout, RTMGR-Timeout, DBAAS-Timeout]
   SubscriptionData:
     type: object
     properties:
diff --git a/pkg/clientmodel/subscription_details.go b/pkg/clientmodel/subscription_details.go
deleted file mode 100644 (file)
index 05677cd..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-// Code generated by go-swagger; DO NOT EDIT.
-
-package clientmodel
-
-// This file was generated by the swagger tool.
-// Editing this file might prove futile when you re-run the swagger generate command
-
-import (
-       strfmt "github.com/go-openapi/strfmt"
-
-       "github.com/go-openapi/errors"
-       "github.com/go-openapi/swag"
-       "github.com/go-openapi/validate"
-)
-
-// SubscriptionDetails subscription details
-// swagger:model SubscriptionDetails
-type SubscriptionDetails struct {
-
-       // action to be setup list
-       // Required: true
-       ActionToBeSetupList ActionsToBeSetup `json:"ActionToBeSetupList"`
-
-       // event trigger list
-       // Required: true
-       EventTriggerList *EventTriggerDefinition `json:"EventTriggerList"`
-}
-
-// Validate validates this subscription details
-func (m *SubscriptionDetails) Validate(formats strfmt.Registry) error {
-       var res []error
-
-       if err := m.validateActionToBeSetupList(formats); err != nil {
-               res = append(res, err)
-       }
-
-       if err := m.validateEventTriggerList(formats); err != nil {
-               res = append(res, err)
-       }
-
-       if len(res) > 0 {
-               return errors.CompositeValidationError(res...)
-       }
-       return nil
-}
-
-func (m *SubscriptionDetails) validateActionToBeSetupList(formats strfmt.Registry) error {
-
-       if err := validate.Required("ActionToBeSetupList", "body", m.ActionToBeSetupList); err != nil {
-               return err
-       }
-
-       if err := m.ActionToBeSetupList.Validate(formats); err != nil {
-               if ve, ok := err.(*errors.Validation); ok {
-                       return ve.ValidateName("ActionToBeSetupList")
-               }
-               return err
-       }
-
-       return nil
-}
-
-func (m *SubscriptionDetails) validateEventTriggerList(formats strfmt.Registry) error {
-
-       if err := validate.Required("EventTriggerList", "body", m.EventTriggerList); err != nil {
-               return err
-       }
-
-       if m.EventTriggerList != nil {
-               if err := m.EventTriggerList.Validate(formats); err != nil {
-                       if ve, ok := err.(*errors.Validation); ok {
-                               return ve.ValidateName("EventTriggerList")
-                       }
-                       return err
-               }
-       }
-
-       return nil
-}
-
-// MarshalBinary interface implementation
-func (m *SubscriptionDetails) MarshalBinary() ([]byte, error) {
-       if m == nil {
-               return nil, nil
-       }
-       return swag.WriteJSON(m)
-}
-
-// UnmarshalBinary interface implementation
-func (m *SubscriptionDetails) UnmarshalBinary(b []byte) error {
-       var res SubscriptionDetails
-       if err := swag.ReadJSON(b, &res); err != nil {
-               return err
-       }
-       *m = res
-       return nil
-}
index 4f099a6..8c6ae48 100644 (file)
@@ -6,6 +6,8 @@ package clientmodel
 // Editing this file might prove futile when you re-run the swagger generate command
 
 import (
+       "encoding/json"
+
        "github.com/go-openapi/errors"
        "github.com/go-openapi/strfmt"
        "github.com/go-openapi/swag"
@@ -23,10 +25,24 @@ type SubscriptionInstance struct {
        // Minimum: 0
        E2EventInstanceID *int64 `json:"E2EventInstanceId"`
 
-       // Empty string when no error.
+       // Descriptive error cause. Empty string when no error.
        // Required: true
        ErrorCause *string `json:"ErrorCause"`
 
+       // Source of error cause.
+       // Required: true
+       // Enum: [None SUBMGR RTMGR DBAAS ASN1 E2Node]
+       ErrorSource *string `json:"ErrorSource"`
+
+       // Reason for REST subscription rejection.
+       // Enum: [None REST-subscription-ongoing REST-subscription-delete-ongoing Invalid-REST-request-message REST-subscription-with-given-id-does-not-exist E2-interface-down Other]
+       RejectCause *string `json:"RejectCause,omitempty"`
+
+       // Type timeout. xApp should retry if timeout occours.
+       // Required: true
+       // Enum: [None E2-Timeout RTMGR-Timeout DBAAS-Timeout]
+       TimeoutType *string `json:"TimeoutType"`
+
        // xapp event instance Id
        // Required: true
        // Maximum: 65535
@@ -46,6 +62,18 @@ func (m *SubscriptionInstance) Validate(formats strfmt.Registry) error {
                res = append(res, err)
        }
 
+       if err := m.validateErrorSource(formats); err != nil {
+               res = append(res, err)
+       }
+
+       if err := m.validateRejectCause(formats); err != nil {
+               res = append(res, err)
+       }
+
+       if err := m.validateTimeoutType(formats); err != nil {
+               res = append(res, err)
+       }
+
        if err := m.validateXappEventInstanceID(formats); err != nil {
                res = append(res, err)
        }
@@ -82,6 +110,168 @@ func (m *SubscriptionInstance) validateErrorCause(formats strfmt.Registry) error
        return nil
 }
 
+var subscriptionInstanceTypeErrorSourcePropEnum []interface{}
+
+func init() {
+       var res []string
+       if err := json.Unmarshal([]byte(`["None","SUBMGR","RTMGR","DBAAS","ASN1","E2Node"]`), &res); err != nil {
+               panic(err)
+       }
+       for _, v := range res {
+               subscriptionInstanceTypeErrorSourcePropEnum = append(subscriptionInstanceTypeErrorSourcePropEnum, v)
+       }
+}
+
+const (
+
+       // SubscriptionInstanceErrorSourceNone captures enum value "None"
+       SubscriptionInstanceErrorSourceNone string = "None"
+
+       // SubscriptionInstanceErrorSourceSUBMGR captures enum value "SUBMGR"
+       SubscriptionInstanceErrorSourceSUBMGR string = "SUBMGR"
+
+       // SubscriptionInstanceErrorSourceRTMGR captures enum value "RTMGR"
+       SubscriptionInstanceErrorSourceRTMGR string = "RTMGR"
+
+       // SubscriptionInstanceErrorSourceDBAAS captures enum value "DBAAS"
+       SubscriptionInstanceErrorSourceDBAAS string = "DBAAS"
+
+       // SubscriptionInstanceErrorSourceASN1 captures enum value "ASN1"
+       SubscriptionInstanceErrorSourceASN1 string = "ASN1"
+
+       // SubscriptionInstanceErrorSourceE2Node captures enum value "E2Node"
+       SubscriptionInstanceErrorSourceE2Node string = "E2Node"
+)
+
+// prop value enum
+func (m *SubscriptionInstance) validateErrorSourceEnum(path, location string, value string) error {
+       if err := validate.Enum(path, location, value, subscriptionInstanceTypeErrorSourcePropEnum); err != nil {
+               return err
+       }
+       return nil
+}
+
+func (m *SubscriptionInstance) validateErrorSource(formats strfmt.Registry) error {
+
+       if err := validate.Required("ErrorSource", "body", m.ErrorSource); err != nil {
+               return err
+       }
+
+       // value enum
+       if err := m.validateErrorSourceEnum("ErrorSource", "body", *m.ErrorSource); err != nil {
+               return err
+       }
+
+       return nil
+}
+
+var subscriptionInstanceTypeRejectCausePropEnum []interface{}
+
+func init() {
+       var res []string
+       if err := json.Unmarshal([]byte(`["None","REST-subscription-ongoing","REST-subscription-delete-ongoing","Invalid-REST-request-message","REST-subscription-with-given-id-does-not-exist","E2-interface-down","Other"]`), &res); err != nil {
+               panic(err)
+       }
+       for _, v := range res {
+               subscriptionInstanceTypeRejectCausePropEnum = append(subscriptionInstanceTypeRejectCausePropEnum, v)
+       }
+}
+
+const (
+
+       // SubscriptionInstanceRejectCauseNone captures enum value "None"
+       SubscriptionInstanceRejectCauseNone string = "None"
+
+       // SubscriptionInstanceRejectCauseRESTSubscriptionOngoing captures enum value "REST-subscription-ongoing"
+       SubscriptionInstanceRejectCauseRESTSubscriptionOngoing string = "REST-subscription-ongoing"
+
+       // SubscriptionInstanceRejectCauseRESTSubscriptionDeleteOngoing captures enum value "REST-subscription-delete-ongoing"
+       SubscriptionInstanceRejectCauseRESTSubscriptionDeleteOngoing string = "REST-subscription-delete-ongoing"
+
+       // SubscriptionInstanceRejectCauseInvalidRESTRequestMessage captures enum value "Invalid-REST-request-message"
+       SubscriptionInstanceRejectCauseInvalidRESTRequestMessage string = "Invalid-REST-request-message"
+
+       // SubscriptionInstanceRejectCauseRESTSubscriptionWithGivenIDDoesNotExist captures enum value "REST-subscription-with-given-id-does-not-exist"
+       SubscriptionInstanceRejectCauseRESTSubscriptionWithGivenIDDoesNotExist string = "REST-subscription-with-given-id-does-not-exist"
+
+       // SubscriptionInstanceRejectCauseE2InterfaceDown captures enum value "E2-interface-down"
+       SubscriptionInstanceRejectCauseE2InterfaceDown string = "E2-interface-down"
+
+       // SubscriptionInstanceRejectCauseOther captures enum value "Other"
+       SubscriptionInstanceRejectCauseOther string = "Other"
+)
+
+// prop value enum
+func (m *SubscriptionInstance) validateRejectCauseEnum(path, location string, value string) error {
+       if err := validate.Enum(path, location, value, subscriptionInstanceTypeRejectCausePropEnum); err != nil {
+               return err
+       }
+       return nil
+}
+
+func (m *SubscriptionInstance) validateRejectCause(formats strfmt.Registry) error {
+
+       if swag.IsZero(m.RejectCause) { // not required
+               return nil
+       }
+
+       // value enum
+       if err := m.validateRejectCauseEnum("RejectCause", "body", *m.RejectCause); err != nil {
+               return err
+       }
+
+       return nil
+}
+
+var subscriptionInstanceTypeTimeoutTypePropEnum []interface{}
+
+func init() {
+       var res []string
+       if err := json.Unmarshal([]byte(`["None","E2-Timeout","RTMGR-Timeout","DBAAS-Timeout"]`), &res); err != nil {
+               panic(err)
+       }
+       for _, v := range res {
+               subscriptionInstanceTypeTimeoutTypePropEnum = append(subscriptionInstanceTypeTimeoutTypePropEnum, v)
+       }
+}
+
+const (
+
+       // SubscriptionInstanceTimeoutTypeNone captures enum value "None"
+       SubscriptionInstanceTimeoutTypeNone string = "None"
+
+       // SubscriptionInstanceTimeoutTypeE2Timeout captures enum value "E2-Timeout"
+       SubscriptionInstanceTimeoutTypeE2Timeout string = "E2-Timeout"
+
+       // SubscriptionInstanceTimeoutTypeRTMGRTimeout captures enum value "RTMGR-Timeout"
+       SubscriptionInstanceTimeoutTypeRTMGRTimeout string = "RTMGR-Timeout"
+
+       // SubscriptionInstanceTimeoutTypeDBAASTimeout captures enum value "DBAAS-Timeout"
+       SubscriptionInstanceTimeoutTypeDBAASTimeout string = "DBAAS-Timeout"
+)
+
+// prop value enum
+func (m *SubscriptionInstance) validateTimeoutTypeEnum(path, location string, value string) error {
+       if err := validate.Enum(path, location, value, subscriptionInstanceTypeTimeoutTypePropEnum); err != nil {
+               return err
+       }
+       return nil
+}
+
+func (m *SubscriptionInstance) validateTimeoutType(formats strfmt.Registry) error {
+
+       if err := validate.Required("TimeoutType", "body", m.TimeoutType); err != nil {
+               return err
+       }
+
+       // value enum
+       if err := m.validateTimeoutTypeEnum("TimeoutType", "body", *m.TimeoutType); err != nil {
+               return err
+       }
+
+       return nil
+}
+
 func (m *SubscriptionInstance) validateXappEventInstanceID(formats strfmt.Registry) error {
 
        if err := validate.Required("XappEventInstanceId", "body", m.XappEventInstanceID); err != nil {
index fdd41ca..b116e50 100644 (file)
@@ -21,6 +21,9 @@ type SubscriptionParams struct {
        // Required: true
        ClientEndpoint *SubscriptionParamsClientEndpoint `json:"ClientEndpoint"`
 
+       // e2 subscription directives
+       E2SubscriptionDirectives *SubscriptionParamsE2SubscriptionDirectives `json:"E2SubscriptionDirectives,omitempty"`
+
        // meid
        // Required: true
        Meid *string `json:"Meid"`
@@ -47,6 +50,10 @@ func (m *SubscriptionParams) Validate(formats strfmt.Registry) error {
                res = append(res, err)
        }
 
+       if err := m.validateE2SubscriptionDirectives(formats); err != nil {
+               res = append(res, err)
+       }
+
        if err := m.validateMeid(formats); err != nil {
                res = append(res, err)
        }
@@ -83,6 +90,24 @@ func (m *SubscriptionParams) validateClientEndpoint(formats strfmt.Registry) err
        return nil
 }
 
+func (m *SubscriptionParams) validateE2SubscriptionDirectives(formats strfmt.Registry) error {
+
+       if swag.IsZero(m.E2SubscriptionDirectives) { // not required
+               return nil
+       }
+
+       if m.E2SubscriptionDirectives != nil {
+               if err := m.E2SubscriptionDirectives.Validate(formats); err != nil {
+                       if ve, ok := err.(*errors.Validation); ok {
+                               return ve.ValidateName("E2SubscriptionDirectives")
+                       }
+                       return err
+               }
+       }
+
+       return nil
+}
+
 func (m *SubscriptionParams) validateMeid(formats strfmt.Registry) error {
 
        if err := validate.Required("Meid", "body", m.Meid); err != nil {
@@ -231,3 +256,92 @@ func (m *SubscriptionParamsClientEndpoint) UnmarshalBinary(b []byte) error {
        *m = res
        return nil
 }
+
+// SubscriptionParamsE2SubscriptionDirectives subscription params e2 subscription directives
+//
+// swagger:model SubscriptionParamsE2SubscriptionDirectives
+type SubscriptionParamsE2SubscriptionDirectives struct {
+
+       // How many times E2 subscription request is retried
+       // Maximum: 10
+       // Minimum: 0
+       E2RetryCount *int64 `json:"E2RetryCount,omitempty"`
+
+       // How long time response is waited from E2 node
+       // Maximum: 10
+       // Minimum: 1
+       E2TimeoutTimerValue int64 `json:"E2TimeoutTimerValue,omitempty"`
+
+       // Subscription needs RMR route from E2Term to xApp
+       RMRRoutingNeeded *bool `json:"RMRRoutingNeeded,omitempty"`
+}
+
+// Validate validates this subscription params e2 subscription directives
+func (m *SubscriptionParamsE2SubscriptionDirectives) Validate(formats strfmt.Registry) error {
+       var res []error
+
+       if err := m.validateE2RetryCount(formats); err != nil {
+               res = append(res, err)
+       }
+
+       if err := m.validateE2TimeoutTimerValue(formats); err != nil {
+               res = append(res, err)
+       }
+
+       if len(res) > 0 {
+               return errors.CompositeValidationError(res...)
+       }
+       return nil
+}
+
+func (m *SubscriptionParamsE2SubscriptionDirectives) validateE2RetryCount(formats strfmt.Registry) error {
+
+       if swag.IsZero(m.E2RetryCount) { // not required
+               return nil
+       }
+
+       if err := validate.MinimumInt("E2SubscriptionDirectives"+"."+"E2RetryCount", "body", int64(*m.E2RetryCount), 0, false); err != nil {
+               return err
+       }
+
+       if err := validate.MaximumInt("E2SubscriptionDirectives"+"."+"E2RetryCount", "body", int64(*m.E2RetryCount), 10, false); err != nil {
+               return err
+       }
+
+       return nil
+}
+
+func (m *SubscriptionParamsE2SubscriptionDirectives) validateE2TimeoutTimerValue(formats strfmt.Registry) error {
+
+       if swag.IsZero(m.E2TimeoutTimerValue) { // not required
+               return nil
+       }
+
+       if err := validate.MinimumInt("E2SubscriptionDirectives"+"."+"E2TimeoutTimerValue", "body", int64(m.E2TimeoutTimerValue), 1, false); err != nil {
+               return err
+       }
+
+       if err := validate.MaximumInt("E2SubscriptionDirectives"+"."+"E2TimeoutTimerValue", "body", int64(m.E2TimeoutTimerValue), 10, false); err != nil {
+               return err
+       }
+
+       return nil
+}
+
+// MarshalBinary interface implementation
+func (m *SubscriptionParamsE2SubscriptionDirectives) MarshalBinary() ([]byte, error) {
+       if m == nil {
+               return nil, nil
+       }
+       return swag.WriteJSON(m)
+}
+
+// UnmarshalBinary interface implementation
+func (m *SubscriptionParamsE2SubscriptionDirectives) UnmarshalBinary(b []byte) error {
+       var res SubscriptionParamsE2SubscriptionDirectives
+       if err := swag.ReadJSON(b, &res); err != nil {
+               return err
+       }
+       *m = res
+       return nil
+}
diff --git a/pkg/models/subscription_details.go b/pkg/models/subscription_details.go
deleted file mode 100644 (file)
index 69f6121..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-// Code generated by go-swagger; DO NOT EDIT.
-
-package models
-
-// This file was generated by the swagger tool.
-// Editing this file might prove futile when you re-run the swagger generate command
-
-import (
-       strfmt "github.com/go-openapi/strfmt"
-
-       "github.com/go-openapi/errors"
-       "github.com/go-openapi/swag"
-       "github.com/go-openapi/validate"
-)
-
-// SubscriptionDetails subscription details
-// swagger:model SubscriptionDetails
-type SubscriptionDetails struct {
-
-       // action to be setup list
-       // Required: true
-       ActionToBeSetupList ActionsToBeSetup `json:"ActionToBeSetupList"`
-
-       // event trigger list
-       // Required: true
-       EventTriggerList *EventTriggerDefinition `json:"EventTriggerList"`
-}
-
-// Validate validates this subscription details
-func (m *SubscriptionDetails) Validate(formats strfmt.Registry) error {
-       var res []error
-
-       if err := m.validateActionToBeSetupList(formats); err != nil {
-               res = append(res, err)
-       }
-
-       if err := m.validateEventTriggerList(formats); err != nil {
-               res = append(res, err)
-       }
-
-       if len(res) > 0 {
-               return errors.CompositeValidationError(res...)
-       }
-       return nil
-}
-
-func (m *SubscriptionDetails) validateActionToBeSetupList(formats strfmt.Registry) error {
-
-       if err := validate.Required("ActionToBeSetupList", "body", m.ActionToBeSetupList); err != nil {
-               return err
-       }
-
-       if err := m.ActionToBeSetupList.Validate(formats); err != nil {
-               if ve, ok := err.(*errors.Validation); ok {
-                       return ve.ValidateName("ActionToBeSetupList")
-               }
-               return err
-       }
-
-       return nil
-}
-
-func (m *SubscriptionDetails) validateEventTriggerList(formats strfmt.Registry) error {
-
-       if err := validate.Required("EventTriggerList", "body", m.EventTriggerList); err != nil {
-               return err
-       }
-
-       if m.EventTriggerList != nil {
-               if err := m.EventTriggerList.Validate(formats); err != nil {
-                       if ve, ok := err.(*errors.Validation); ok {
-                               return ve.ValidateName("EventTriggerList")
-                       }
-                       return err
-               }
-       }
-
-       return nil
-}
-
-// MarshalBinary interface implementation
-func (m *SubscriptionDetails) MarshalBinary() ([]byte, error) {
-       if m == nil {
-               return nil, nil
-       }
-       return swag.WriteJSON(m)
-}
-
-// UnmarshalBinary interface implementation
-func (m *SubscriptionDetails) UnmarshalBinary(b []byte) error {
-       var res SubscriptionDetails
-       if err := swag.ReadJSON(b, &res); err != nil {
-               return err
-       }
-       *m = res
-       return nil
-}
index fa3c3a7..e028de9 100644 (file)
@@ -6,6 +6,8 @@ package models
 // Editing this file might prove futile when you re-run the swagger generate command
 
 import (
+       "encoding/json"
+
        "github.com/go-openapi/errors"
        "github.com/go-openapi/strfmt"
        "github.com/go-openapi/swag"
@@ -23,10 +25,24 @@ type SubscriptionInstance struct {
        // Minimum: 0
        E2EventInstanceID *int64 `json:"E2EventInstanceId"`
 
-       // Empty string when no error.
+       // Descriptive error cause. Empty string when no error.
        // Required: true
        ErrorCause *string `json:"ErrorCause"`
 
+       // Source of error cause.
+       // Required: true
+       // Enum: [None SUBMGR RTMGR DBAAS ASN1 E2Node]
+       ErrorSource *string `json:"ErrorSource"`
+
+       // Reason for REST subscription rejection.
+       // Enum: [None REST-subscription-ongoing REST-subscription-delete-ongoing Invalid-REST-request-message REST-subscription-with-given-id-does-not-exist E2-interface-down Other]
+       RejectCause *string `json:"RejectCause,omitempty"`
+
+       // Type timeout. xApp should retry if timeout occours.
+       // Required: true
+       // Enum: [None E2-Timeout RTMGR-Timeout DBAAS-Timeout]
+       TimeoutType *string `json:"TimeoutType"`
+
        // xapp event instance Id
        // Required: true
        // Maximum: 65535
@@ -46,6 +62,18 @@ func (m *SubscriptionInstance) Validate(formats strfmt.Registry) error {
                res = append(res, err)
        }
 
+       if err := m.validateErrorSource(formats); err != nil {
+               res = append(res, err)
+       }
+
+       if err := m.validateRejectCause(formats); err != nil {
+               res = append(res, err)
+       }
+
+       if err := m.validateTimeoutType(formats); err != nil {
+               res = append(res, err)
+       }
+
        if err := m.validateXappEventInstanceID(formats); err != nil {
                res = append(res, err)
        }
@@ -82,6 +110,168 @@ func (m *SubscriptionInstance) validateErrorCause(formats strfmt.Registry) error
        return nil
 }
 
+var subscriptionInstanceTypeErrorSourcePropEnum []interface{}
+
+func init() {
+       var res []string
+       if err := json.Unmarshal([]byte(`["None","SUBMGR","RTMGR","DBAAS","ASN1","E2Node"]`), &res); err != nil {
+               panic(err)
+       }
+       for _, v := range res {
+               subscriptionInstanceTypeErrorSourcePropEnum = append(subscriptionInstanceTypeErrorSourcePropEnum, v)
+       }
+}
+
+const (
+
+       // SubscriptionInstanceErrorSourceNone captures enum value "None"
+       SubscriptionInstanceErrorSourceNone string = "None"
+
+       // SubscriptionInstanceErrorSourceSUBMGR captures enum value "SUBMGR"
+       SubscriptionInstanceErrorSourceSUBMGR string = "SUBMGR"
+
+       // SubscriptionInstanceErrorSourceRTMGR captures enum value "RTMGR"
+       SubscriptionInstanceErrorSourceRTMGR string = "RTMGR"
+
+       // SubscriptionInstanceErrorSourceDBAAS captures enum value "DBAAS"
+       SubscriptionInstanceErrorSourceDBAAS string = "DBAAS"
+
+       // SubscriptionInstanceErrorSourceASN1 captures enum value "ASN1"
+       SubscriptionInstanceErrorSourceASN1 string = "ASN1"
+
+       // SubscriptionInstanceErrorSourceE2Node captures enum value "E2Node"
+       SubscriptionInstanceErrorSourceE2Node string = "E2Node"
+)
+
+// prop value enum
+func (m *SubscriptionInstance) validateErrorSourceEnum(path, location string, value string) error {
+       if err := validate.Enum(path, location, value, subscriptionInstanceTypeErrorSourcePropEnum); err != nil {
+               return err
+       }
+       return nil
+}
+
+func (m *SubscriptionInstance) validateErrorSource(formats strfmt.Registry) error {
+
+       if err := validate.Required("ErrorSource", "body", m.ErrorSource); err != nil {
+               return err
+       }
+
+       // value enum
+       if err := m.validateErrorSourceEnum("ErrorSource", "body", *m.ErrorSource); err != nil {
+               return err
+       }
+
+       return nil
+}
+
+var subscriptionInstanceTypeRejectCausePropEnum []interface{}
+
+func init() {
+       var res []string
+       if err := json.Unmarshal([]byte(`["None","REST-subscription-ongoing","REST-subscription-delete-ongoing","Invalid-REST-request-message","REST-subscription-with-given-id-does-not-exist","E2-interface-down","Other"]`), &res); err != nil {
+               panic(err)
+       }
+       for _, v := range res {
+               subscriptionInstanceTypeRejectCausePropEnum = append(subscriptionInstanceTypeRejectCausePropEnum, v)
+       }
+}
+
+const (
+
+       // SubscriptionInstanceRejectCauseNone captures enum value "None"
+       SubscriptionInstanceRejectCauseNone string = "None"
+
+       // SubscriptionInstanceRejectCauseRESTSubscriptionOngoing captures enum value "REST-subscription-ongoing"
+       SubscriptionInstanceRejectCauseRESTSubscriptionOngoing string = "REST-subscription-ongoing"
+
+       // SubscriptionInstanceRejectCauseRESTSubscriptionDeleteOngoing captures enum value "REST-subscription-delete-ongoing"
+       SubscriptionInstanceRejectCauseRESTSubscriptionDeleteOngoing string = "REST-subscription-delete-ongoing"
+
+       // SubscriptionInstanceRejectCauseInvalidRESTRequestMessage captures enum value "Invalid-REST-request-message"
+       SubscriptionInstanceRejectCauseInvalidRESTRequestMessage string = "Invalid-REST-request-message"
+
+       // SubscriptionInstanceRejectCauseRESTSubscriptionWithGivenIDDoesNotExist captures enum value "REST-subscription-with-given-id-does-not-exist"
+       SubscriptionInstanceRejectCauseRESTSubscriptionWithGivenIDDoesNotExist string = "REST-subscription-with-given-id-does-not-exist"
+
+       // SubscriptionInstanceRejectCauseE2InterfaceDown captures enum value "E2-interface-down"
+       SubscriptionInstanceRejectCauseE2InterfaceDown string = "E2-interface-down"
+
+       // SubscriptionInstanceRejectCauseOther captures enum value "Other"
+       SubscriptionInstanceRejectCauseOther string = "Other"
+)
+
+// prop value enum
+func (m *SubscriptionInstance) validateRejectCauseEnum(path, location string, value string) error {
+       if err := validate.Enum(path, location, value, subscriptionInstanceTypeRejectCausePropEnum); err != nil {
+               return err
+       }
+       return nil
+}
+
+func (m *SubscriptionInstance) validateRejectCause(formats strfmt.Registry) error {
+
+       if swag.IsZero(m.RejectCause) { // not required
+               return nil
+       }
+
+       // value enum
+       if err := m.validateRejectCauseEnum("RejectCause", "body", *m.RejectCause); err != nil {
+               return err
+       }
+
+       return nil
+}
+
+var subscriptionInstanceTypeTimeoutTypePropEnum []interface{}
+
+func init() {
+       var res []string
+       if err := json.Unmarshal([]byte(`["None","E2-Timeout","RTMGR-Timeout","DBAAS-Timeout"]`), &res); err != nil {
+               panic(err)
+       }
+       for _, v := range res {
+               subscriptionInstanceTypeTimeoutTypePropEnum = append(subscriptionInstanceTypeTimeoutTypePropEnum, v)
+       }
+}
+
+const (
+
+       // SubscriptionInstanceTimeoutTypeNone captures enum value "None"
+       SubscriptionInstanceTimeoutTypeNone string = "None"
+
+       // SubscriptionInstanceTimeoutTypeE2Timeout captures enum value "E2-Timeout"
+       SubscriptionInstanceTimeoutTypeE2Timeout string = "E2-Timeout"
+
+       // SubscriptionInstanceTimeoutTypeRTMGRTimeout captures enum value "RTMGR-Timeout"
+       SubscriptionInstanceTimeoutTypeRTMGRTimeout string = "RTMGR-Timeout"
+
+       // SubscriptionInstanceTimeoutTypeDBAASTimeout captures enum value "DBAAS-Timeout"
+       SubscriptionInstanceTimeoutTypeDBAASTimeout string = "DBAAS-Timeout"
+)
+
+// prop value enum
+func (m *SubscriptionInstance) validateTimeoutTypeEnum(path, location string, value string) error {
+       if err := validate.Enum(path, location, value, subscriptionInstanceTypeTimeoutTypePropEnum); err != nil {
+               return err
+       }
+       return nil
+}
+
+func (m *SubscriptionInstance) validateTimeoutType(formats strfmt.Registry) error {
+
+       if err := validate.Required("TimeoutType", "body", m.TimeoutType); err != nil {
+               return err
+       }
+
+       // value enum
+       if err := m.validateTimeoutTypeEnum("TimeoutType", "body", *m.TimeoutType); err != nil {
+               return err
+       }
+
+       return nil
+}
+
 func (m *SubscriptionInstance) validateXappEventInstanceID(formats strfmt.Registry) error {
 
        if err := validate.Required("XappEventInstanceId", "body", m.XappEventInstanceID); err != nil {
index 5616e98..a7151d5 100644 (file)
@@ -21,6 +21,9 @@ type SubscriptionParams struct {
        // Required: true
        ClientEndpoint *SubscriptionParamsClientEndpoint `json:"ClientEndpoint"`
 
+       // e2 subscription directives
+       E2SubscriptionDirectives *SubscriptionParamsE2SubscriptionDirectives `json:"E2SubscriptionDirectives,omitempty"`
+
        // meid
        // Required: true
        Meid *string `json:"Meid"`
@@ -47,6 +50,10 @@ func (m *SubscriptionParams) Validate(formats strfmt.Registry) error {
                res = append(res, err)
        }
 
+       if err := m.validateE2SubscriptionDirectives(formats); err != nil {
+               res = append(res, err)
+       }
+
        if err := m.validateMeid(formats); err != nil {
                res = append(res, err)
        }
@@ -83,6 +90,24 @@ func (m *SubscriptionParams) validateClientEndpoint(formats strfmt.Registry) err
        return nil
 }
 
+func (m *SubscriptionParams) validateE2SubscriptionDirectives(formats strfmt.Registry) error {
+
+       if swag.IsZero(m.E2SubscriptionDirectives) { // not required
+               return nil
+       }
+
+       if m.E2SubscriptionDirectives != nil {
+               if err := m.E2SubscriptionDirectives.Validate(formats); err != nil {
+                       if ve, ok := err.(*errors.Validation); ok {
+                               return ve.ValidateName("E2SubscriptionDirectives")
+                       }
+                       return err
+               }
+       }
+
+       return nil
+}
+
 func (m *SubscriptionParams) validateMeid(formats strfmt.Registry) error {
 
        if err := validate.Required("Meid", "body", m.Meid); err != nil {
@@ -231,3 +256,92 @@ func (m *SubscriptionParamsClientEndpoint) UnmarshalBinary(b []byte) error {
        *m = res
        return nil
 }
+
+// SubscriptionParamsE2SubscriptionDirectives subscription params e2 subscription directives
+//
+// swagger:model SubscriptionParamsE2SubscriptionDirectives
+type SubscriptionParamsE2SubscriptionDirectives struct {
+
+       // How many times E2 subscription request is retried
+       // Maximum: 10
+       // Minimum: 0
+       E2RetryCount *int64 `json:"E2RetryCount,omitempty"`
+
+       // How long time response is waited from E2 node
+       // Maximum: 10
+       // Minimum: 1
+       E2TimeoutTimerValue int64 `json:"E2TimeoutTimerValue,omitempty"`
+
+       // Subscription needs RMR route from E2Term to xApp
+       RMRRoutingNeeded *bool `json:"RMRRoutingNeeded,omitempty"`
+}
+
+// Validate validates this subscription params e2 subscription directives
+func (m *SubscriptionParamsE2SubscriptionDirectives) Validate(formats strfmt.Registry) error {
+       var res []error
+
+       if err := m.validateE2RetryCount(formats); err != nil {
+               res = append(res, err)
+       }
+
+       if err := m.validateE2TimeoutTimerValue(formats); err != nil {
+               res = append(res, err)
+       }
+
+       if len(res) > 0 {
+               return errors.CompositeValidationError(res...)
+       }
+       return nil
+}
+
+func (m *SubscriptionParamsE2SubscriptionDirectives) validateE2RetryCount(formats strfmt.Registry) error {
+
+       if swag.IsZero(m.E2RetryCount) { // not required
+               return nil
+       }
+
+       if err := validate.MinimumInt("E2SubscriptionDirectives"+"."+"E2RetryCount", "body", int64(*m.E2RetryCount), 0, false); err != nil {
+               return err
+       }
+
+       if err := validate.MaximumInt("E2SubscriptionDirectives"+"."+"E2RetryCount", "body", int64(*m.E2RetryCount), 10, false); err != nil {
+               return err
+       }
+
+       return nil
+}
+
+func (m *SubscriptionParamsE2SubscriptionDirectives) validateE2TimeoutTimerValue(formats strfmt.Registry) error {
+
+       if swag.IsZero(m.E2TimeoutTimerValue) { // not required
+               return nil
+       }
+
+       if err := validate.MinimumInt("E2SubscriptionDirectives"+"."+"E2TimeoutTimerValue", "body", int64(m.E2TimeoutTimerValue), 1, false); err != nil {
+               return err
+       }
+
+       if err := validate.MaximumInt("E2SubscriptionDirectives"+"."+"E2TimeoutTimerValue", "body", int64(m.E2TimeoutTimerValue), 10, false); err != nil {
+               return err
+       }
+
+       return nil
+}
+
+// MarshalBinary interface implementation
+func (m *SubscriptionParamsE2SubscriptionDirectives) MarshalBinary() ([]byte, error) {
+       if m == nil {
+               return nil, nil
+       }
+       return swag.WriteJSON(m)
+}
+
+// UnmarshalBinary interface implementation
+func (m *SubscriptionParamsE2SubscriptionDirectives) UnmarshalBinary(b []byte) error {
+       var res SubscriptionParamsE2SubscriptionDirectives
+       if err := swag.ReadJSON(b, &res); err != nil {
+               return err
+       }
+       *m = res
+       return nil
+}
index efaf0f8..01e351f 100755 (executable)
@@ -44,9 +44,9 @@ import (
        "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/restapi/operations/common"
 )
 
-type SubscriptionHandler func(interface{}) (*models.SubscriptionResponse, error)
+type SubscriptionHandler func(interface{}) (*models.SubscriptionResponse, int)
 type SubscriptionQueryHandler func() (models.SubscriptionList, error)
-type SubscriptionDeleteHandler func(string) error
+type SubscriptionDeleteHandler func(string) int
 type SubscriptionResponseCallback func(*apimodel.SubscriptionResponse)
 
 type Subscriber struct {
@@ -121,20 +121,30 @@ func (r *Subscriber) Listen(createSubscription SubscriptionHandler, getSubscript
        api.CommonSubscribeHandler = common.SubscribeHandlerFunc(
                func(params common.SubscribeParams) middleware.Responder {
                        Logger.Error("Subscribe: Params=%+v", params.SubscriptionParams)
-                       if resp, err := createSubscription(params.SubscriptionParams); err == nil {
-                               return common.NewSubscribeCreated().WithPayload(resp)
+                       resp, retCode := createSubscription(params.SubscriptionParams)
+                       if retCode != common.SubscribeCreatedCode {
+                               if retCode == common.SubscribeBadRequestCode {
+                                       return common.NewSubscribeBadRequest()
+                               } else {
+                                       return common.NewSubscribeInternalServerError()
+                               }
                        }
-                       return common.NewSubscribeInternalServerError()
+                       return common.NewSubscribeCreated().WithPayload(resp)
                })
 
        // Subscription: Unsubscribe
        api.CommonUnsubscribeHandler = common.UnsubscribeHandlerFunc(
                func(p common.UnsubscribeParams) middleware.Responder {
                        Logger.Error("Unsubscribe: SubscriptionID=%+v", p.SubscriptionID)
-                       if err := delSubscription(p.SubscriptionID); err == nil {
-                               return common.NewUnsubscribeNoContent()
+                       retCode := delSubscription(p.SubscriptionID)
+                       if retCode != common.UnsubscribeNoContentCode {
+                               if retCode == common.UnsubscribeBadRequestCode {
+                                       return common.NewUnsubscribeBadRequest()
+                               } else {
+                                       return common.NewUnsubscribeInternalServerError()
+                               }
                        }
-                       return common.NewUnsubscribeInternalServerError()
+                       return common.NewUnsubscribeNoContent()
                })
 
        server := restapi.NewServer(api)
index af8938c..d41649f 100755 (executable)
@@ -16,6 +16,7 @@ import (
 
        "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/clientmodel"
        "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/models"
+       "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/restapi/operations/common"
        "github.com/stretchr/testify/assert"
 )
 
@@ -58,29 +59,7 @@ func TestSubscriptionQueryHandling(t *testing.T) {
 }
 
 func TestSubscriptionHandling(t *testing.T) {
-       subscriptionParams := clientmodel.SubscriptionParams{
-               SubscriptionID: "",
-               Meid:           &meid,
-               RANFunctionID:  &funId,
-               ClientEndpoint: &clientEndpoint,
-               SubscriptionDetails: clientmodel.SubscriptionDetailsList{
-                       &clientmodel.SubscriptionDetail{
-                               XappEventInstanceID: &eventInstanceId,
-                               EventTriggers:       clientmodel.EventTriggerDefinition{00, 0x11, 0x12, 0x13, 0x00, 0x21, 0x22, 0x24, 0x1B, 0x80},
-                               ActionToBeSetupList: clientmodel.ActionsToBeSetup{
-                                       &clientmodel.ActionToBeSetup{
-                                               ActionID:         &actionId,
-                                               ActionType:       &actionType,
-                                               ActionDefinition: clientmodel.ActionDefinition{5, 6, 7, 8},
-                                               SubsequentAction: &clientmodel.SubsequentAction{
-                                                       SubsequentActionType: &subsequestActioType,
-                                                       TimeToWait:           &timeToWait,
-                                               },
-                                       },
-                               },
-                       },
-               },
-       }
+       subscriptionParams := GetSubscriptionparams()
 
        Subscription.SetResponseCB(func(resp *clientmodel.SubscriptionResponse) {
                assert.Equal(t, len(resp.SubscriptionInstances), 1)
@@ -88,13 +67,57 @@ func TestSubscriptionHandling(t *testing.T) {
                assert.Equal(t, *resp.SubscriptionInstances[0].E2EventInstanceID, int64(22))
        })
 
-       _, err := Subscription.Subscribe(&subscriptionParams)
+       _, err := Subscription.Subscribe(subscriptionParams)
        assert.Equal(t, err, nil)
 }
 
 func TestSubscriptionWithClientProvidedIdHandling(t *testing.T) {
-       subscriptionParams := clientmodel.SubscriptionParams{
-               SubscriptionID: "myxapp",
+       subscriptionParams := GetSubscriptionparams()
+       subscriptionParams.SubscriptionID = "myxapp"
+    
+       Subscription.SetResponseCB(func(resp *clientmodel.SubscriptionResponse) {
+               assert.Equal(t, len(resp.SubscriptionInstances), 1)
+               assert.Equal(t, *resp.SubscriptionInstances[0].XappEventInstanceID, int64(11))
+               assert.Equal(t, *resp.SubscriptionInstances[0].E2EventInstanceID, int64(22))
+       })
+
+       _, err := Subscription.Subscribe(subscriptionParams)
+       assert.Equal(t, err, nil)
+}
+
+func TestBadRequestSubscriptionHandling(t *testing.T) {
+       subscriptionParams := GetSubscriptionparams()
+       subscriptionParams.SubscriptionID = "123_send_bad_request_response"
+
+       Subscription.SetResponseCB(func(resp *clientmodel.SubscriptionResponse) {
+               assert.Equal(t, len(resp.SubscriptionInstances), 1)
+               assert.Equal(t, *resp.SubscriptionInstances[0].XappEventInstanceID, int64(11))
+               assert.Equal(t, *resp.SubscriptionInstances[0].E2EventInstanceID, int64(22))
+       })
+
+       _, err := Subscription.Subscribe(subscriptionParams)
+       assert.Equal(t, err.Error(), "[POST /subscriptions][400] subscribeBadRequest ")
+       fmt.Println("Error:",err)
+}
+
+func TestInternalServerErrorSubscriptionHandling(t *testing.T) {
+       subscriptionParams := GetSubscriptionparams()
+       subscriptionParams.SubscriptionID = "123_send_internal_server_error_response"
+
+       Subscription.SetResponseCB(func(resp *clientmodel.SubscriptionResponse) {
+               assert.Equal(t, len(resp.SubscriptionInstances), 1)
+               assert.Equal(t, *resp.SubscriptionInstances[0].XappEventInstanceID, int64(11))
+               assert.Equal(t, *resp.SubscriptionInstances[0].E2EventInstanceID, int64(22))
+       })
+
+       _, err := Subscription.Subscribe(subscriptionParams)
+       assert.Equal(t, err.Error(), "[POST /subscriptions][500] subscribeInternalServerError ")
+       fmt.Println("Error:",err)
+}
+
+func GetSubscriptionparams() *clientmodel.SubscriptionParams {
+       return &clientmodel.SubscriptionParams{
+               SubscriptionID: "",
                Meid:           &meid,
                RANFunctionID:  &funId,
                ClientEndpoint: &clientEndpoint,
@@ -116,21 +139,29 @@ func TestSubscriptionWithClientProvidedIdHandling(t *testing.T) {
                        },
                },
        }
+}
 
-       Subscription.SetResponseCB(func(resp *clientmodel.SubscriptionResponse) {
-               assert.Equal(t, len(resp.SubscriptionInstances), 1)
-               assert.Equal(t, *resp.SubscriptionInstances[0].XappEventInstanceID, int64(11))
-               assert.Equal(t, *resp.SubscriptionInstances[0].E2EventInstanceID, int64(22))
-       })
-
-       _, err := Subscription.Subscribe(&subscriptionParams)
+func TestSuccessfulSubscriptionDeleteHandling(t *testing.T) {
+       subscriptionId = "123_send_successful_response"
+       err := Subscription.Unsubscribe(subscriptionId)
        assert.Equal(t, err, nil)
+       fmt.Println("Error:",err)
 }
 
-func TestSubscriptionDeleteHandling(t *testing.T) {
+func TestBadRequestSubscriptionDeleteHandling(t *testing.T) {
+       subscriptionId = "123_send_bad_request_response"
        err := Subscription.Unsubscribe(subscriptionId)
-       fmt.Println(err)
-       assert.Equal(t, err, nil)
+       assert.NotEqual(t, err, nil)
+       fmt.Println("Error:",err.Error())
+       assert.Equal(t, err.Error(), "[DELETE /subscriptions/{subscriptionId}][400] unsubscribeBadRequest ")
+}
+
+func TestInternalServerErrorSubscriptionDeleteHandling(t *testing.T) {
+       subscriptionId = "123_send_internal_server_error_response"
+       err := Subscription.Unsubscribe(subscriptionId)
+       assert.NotEqual(t, err, nil)
+       fmt.Println("Error:",err.Error())
+       assert.Equal(t, err.Error(), "[DELETE /subscriptions/{subscriptionId}][500] unsubscribeInternalServerError ")
 }
 
 func TestResponseHandler(t *testing.T) {
@@ -175,7 +206,7 @@ func processSubscriptions(subscriptionId string) {
        Subscription.Notify(resp, models.SubscriptionParamsClientEndpoint{Host: "localhost", HTTPPort: &hPort, RMRPort: &rPort})
 }
 
-func subscriptionHandler(params interface{}) (*models.SubscriptionResponse, error) {
+func subscriptionHandler(params interface{}) (*models.SubscriptionResponse, int) {
        p := params.(*models.SubscriptionParams)
 
        assert.Equal(suite, meid, *p.Meid)
@@ -197,13 +228,25 @@ func subscriptionHandler(params interface{}) (*models.SubscriptionResponse, erro
        // Generate a unique subscriptionId
        subscriptionId = fmt.Sprintf("%s-%s", meid, clientEndpoint.Host)
 
+       if p.SubscriptionID == "123_send_bad_request_response" {
+               // Simulate bad request case
+               return &models.SubscriptionResponse{
+               }, common.UnsubscribeBadRequestCode
+
+       }
+
+       if p.SubscriptionID == "123_send_internal_server_error_response" {
+               // Simulate bad internal server error case
+               return &models.SubscriptionResponse{
+                       }, common.UnsubscribeInternalServerErrorCode
+       }
        // Process subscriptions on the background
        go processSubscriptions(subscriptionId)
 
        // and send response immediately
        return &models.SubscriptionResponse{
                SubscriptionID: &subscriptionId,
-       }, nil
+       }, common.SubscribeCreatedCode
 }
 
 func queryHandler() (models.SubscriptionList, error) {
@@ -217,7 +260,13 @@ func queryHandler() (models.SubscriptionList, error) {
        return resp, nil
 }
 
-func deleteHandler(ep string) error {
+func deleteHandler(ep string) int {
        assert.Equal(suite, subscriptionId, ep)
-       return nil
+       if subscriptionId == "123_send_successful_response" {
+               return common.UnsubscribeNoContentCode
+       } else if subscriptionId == "123_send_bad_request_response" {
+               return common.UnsubscribeBadRequestCode
+       } else {
+               return common.UnsubscribeInternalServerErrorCode
+       }
 }