From: wahidw Date: Tue, 15 Dec 2020 12:17:09 +0000 (+0000) Subject: Xapp registration/deregistration to RIC X-Git-Tag: v0.7.0^0 X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=commitdiff_plain;h=413abf5f6de7c1808a2dd716ef52ed586c04d8f6;p=ric-plt%2Fxapp-frame.git Xapp registration/deregistration to RIC Signed-off-by: wahidw Change-Id: I62104203e6f2de9359a2ab184966395f4c758b48 --- diff --git a/pkg/models/config_metadata.go b/pkg/models/config_metadata.go new file mode 100644 index 0000000..f564287 --- /dev/null +++ b/pkg/models/config_metadata.go @@ -0,0 +1,121 @@ +// 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 ( + "encoding/json" + + strfmt "github.com/go-openapi/strfmt" + + "github.com/go-openapi/errors" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// ConfigMetadata config metadata +// swagger:model ConfigMetadata +type ConfigMetadata struct { + + // The type of the content + // Required: true + // Enum: [json xml other] + ConfigType *string `json:"configType"` + + // Name of the xApp + // Required: true + XappName *string `json:"xappName"` +} + +// Validate validates this config metadata +func (m *ConfigMetadata) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateConfigType(formats); err != nil { + res = append(res, err) + } + + if err := m.validateXappName(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +var configMetadataTypeConfigTypePropEnum []interface{} + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["json","xml","other"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + configMetadataTypeConfigTypePropEnum = append(configMetadataTypeConfigTypePropEnum, v) + } +} + +const ( + + // ConfigMetadataConfigTypeJSON captures enum value "json" + ConfigMetadataConfigTypeJSON string = "json" + + // ConfigMetadataConfigTypeXML captures enum value "xml" + ConfigMetadataConfigTypeXML string = "xml" + + // ConfigMetadataConfigTypeOther captures enum value "other" + ConfigMetadataConfigTypeOther string = "other" +) + +// prop value enum +func (m *ConfigMetadata) validateConfigTypeEnum(path, location string, value string) error { + if err := validate.Enum(path, location, value, configMetadataTypeConfigTypePropEnum); err != nil { + return err + } + return nil +} + +func (m *ConfigMetadata) validateConfigType(formats strfmt.Registry) error { + + if err := validate.Required("configType", "body", m.ConfigType); err != nil { + return err + } + + // value enum + if err := m.validateConfigTypeEnum("configType", "body", *m.ConfigType); err != nil { + return err + } + + return nil +} + +func (m *ConfigMetadata) validateXappName(formats strfmt.Registry) error { + + if err := validate.Required("xappName", "body", m.XappName); err != nil { + return err + } + + return nil +} + +// MarshalBinary interface implementation +func (m *ConfigMetadata) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *ConfigMetadata) UnmarshalBinary(b []byte) error { + var res ConfigMetadata + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/models/x_app_config.go b/pkg/models/x_app_config.go new file mode 100644 index 0000000..076e314 --- /dev/null +++ b/pkg/models/x_app_config.go @@ -0,0 +1,90 @@ +// 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" +) + +// XAppConfig x app config +// swagger:model XAppConfig +type XAppConfig struct { + + // Configuration in JSON format + // Required: true + Config interface{} `json:"config"` + + // metadata + // Required: true + Metadata *ConfigMetadata `json:"metadata"` +} + +// Validate validates this x app config +func (m *XAppConfig) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateConfig(formats); err != nil { + res = append(res, err) + } + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *XAppConfig) validateConfig(formats strfmt.Registry) error { + + if err := validate.Required("config", "body", m.Config); err != nil { + return err + } + + return nil +} + +func (m *XAppConfig) validateMetadata(formats strfmt.Registry) error { + + if err := validate.Required("metadata", "body", m.Metadata); err != nil { + return err + } + + if m.Metadata != nil { + if err := m.Metadata.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("metadata") + } + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *XAppConfig) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *XAppConfig) UnmarshalBinary(b []byte) error { + var res XAppConfig + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/models/xapp_config_list.go b/pkg/models/xapp_config_list.go new file mode 100644 index 0000000..e57ed02 --- /dev/null +++ b/pkg/models/xapp_config_list.go @@ -0,0 +1,45 @@ +// 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 ( + "strconv" + + strfmt "github.com/go-openapi/strfmt" + + "github.com/go-openapi/errors" + "github.com/go-openapi/swag" +) + +// XappConfigList xapp config list +// swagger:model XappConfigList +type XappConfigList []*XAppConfig + +// Validate validates this xapp config list +func (m XappConfigList) Validate(formats strfmt.Registry) error { + var res []error + + for i := 0; i < len(m); i++ { + if swag.IsZero(m[i]) { // not required + continue + } + + if m[i] != nil { + if err := m[i].Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName(strconv.Itoa(i)) + } + return err + } + } + + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/pkg/restapi/doc.go b/pkg/restapi/doc.go index 8cc5aad..c73c1aa 100644 --- a/pkg/restapi/doc.go +++ b/pkg/restapi/doc.go @@ -17,6 +17,7 @@ This is the initial REST API for RIC subscription Produces: - application/json + - application/xml swagger:meta */ diff --git a/pkg/restapi/embedded_spec.go b/pkg/restapi/embedded_spec.go index 8cb57e1..dd67843 100644 --- a/pkg/restapi/embedded_spec.go +++ b/pkg/restapi/embedded_spec.go @@ -34,6 +34,30 @@ func init() { "host": "hostname", "basePath": "/ric/v1", "paths": { + "/config": { + "get": { + "produces": [ + "application/json", + "application/xml" + ], + "tags": [ + "xapp" + ], + "summary": "Returns the configuration of all xapps", + "operationId": "getXappConfigList", + "responses": { + "200": { + "description": "successful query of xApp config", + "schema": { + "$ref": "#/definitions/XappConfigList" + } + }, + "500": { + "description": "Internal error" + } + } + } + }, "/subscriptions": { "get": { "produces": [ @@ -187,6 +211,28 @@ func init() { } } }, + "ConfigMetadata": { + "type": "object", + "required": [ + "xappName", + "configType" + ], + "properties": { + "configType": { + "description": "The type of the content", + "type": "string", + "enum": [ + "json", + "xml", + "other" + ] + }, + "xappName": { + "description": "Name of the xApp", + "type": "string" + } + } + }, "EventTrigger": { "type": "object", "properties": { @@ -443,6 +489,28 @@ func init() { "policy", "report" ] + }, + "XAppConfig": { + "type": "object", + "required": [ + "metadata", + "config" + ], + "properties": { + "config": { + "description": "Configuration in JSON format", + "type": "object" + }, + "metadata": { + "$ref": "#/definitions/ConfigMetadata" + } + } + }, + "XappConfigList": { + "type": "array", + "items": { + "$ref": "#/definitions/XAppConfig" + } } } }`)) @@ -463,6 +531,30 @@ func init() { "host": "hostname", "basePath": "/ric/v1", "paths": { + "/config": { + "get": { + "produces": [ + "application/json", + "application/xml" + ], + "tags": [ + "xapp" + ], + "summary": "Returns the configuration of all xapps", + "operationId": "getXappConfigList", + "responses": { + "200": { + "description": "successful query of xApp config", + "schema": { + "$ref": "#/definitions/XappConfigList" + } + }, + "500": { + "description": "Internal error" + } + } + } + }, "/subscriptions": { "get": { "produces": [ @@ -616,6 +708,28 @@ func init() { } } }, + "ConfigMetadata": { + "type": "object", + "required": [ + "xappName", + "configType" + ], + "properties": { + "configType": { + "description": "The type of the content", + "type": "string", + "enum": [ + "json", + "xml", + "other" + ] + }, + "xappName": { + "description": "Name of the xApp", + "type": "string" + } + } + }, "EventTrigger": { "type": "object", "properties": { @@ -872,6 +986,28 @@ func init() { "policy", "report" ] + }, + "XAppConfig": { + "type": "object", + "required": [ + "metadata", + "config" + ], + "properties": { + "config": { + "description": "Configuration in JSON format", + "type": "object" + }, + "metadata": { + "$ref": "#/definitions/ConfigMetadata" + } + } + }, + "XappConfigList": { + "type": "array", + "items": { + "$ref": "#/definitions/XAppConfig" + } } } }`)) diff --git a/pkg/restapi/operations/xapp/get_xapp_config_list.go b/pkg/restapi/operations/xapp/get_xapp_config_list.go new file mode 100644 index 0000000..9fc02d3 --- /dev/null +++ b/pkg/restapi/operations/xapp/get_xapp_config_list.go @@ -0,0 +1,58 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package xapp + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "net/http" + + middleware "github.com/go-openapi/runtime/middleware" +) + +// GetXappConfigListHandlerFunc turns a function with the right signature into a get xapp config list handler +type GetXappConfigListHandlerFunc func(GetXappConfigListParams) middleware.Responder + +// Handle executing the request and returning a response +func (fn GetXappConfigListHandlerFunc) Handle(params GetXappConfigListParams) middleware.Responder { + return fn(params) +} + +// GetXappConfigListHandler interface for that can handle valid get xapp config list params +type GetXappConfigListHandler interface { + Handle(GetXappConfigListParams) middleware.Responder +} + +// NewGetXappConfigList creates a new http.Handler for the get xapp config list operation +func NewGetXappConfigList(ctx *middleware.Context, handler GetXappConfigListHandler) *GetXappConfigList { + return &GetXappConfigList{Context: ctx, Handler: handler} +} + +/*GetXappConfigList swagger:route GET /config xapp getXappConfigList + +Returns the configuration of all xapps + +*/ +type GetXappConfigList struct { + Context *middleware.Context + Handler GetXappConfigListHandler +} + +func (o *GetXappConfigList) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + route, rCtx, _ := o.Context.RouteInfo(r) + if rCtx != nil { + r = rCtx + } + var Params = NewGetXappConfigListParams() + + if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params + o.Context.Respond(rw, r, route.Produces, route, err) + return + } + + res := o.Handler.Handle(Params) // actually handle the request + + o.Context.Respond(rw, r, route.Produces, route, res) + +} diff --git a/pkg/restapi/operations/xapp/get_xapp_config_list_parameters.go b/pkg/restapi/operations/xapp/get_xapp_config_list_parameters.go new file mode 100644 index 0000000..0339c0f --- /dev/null +++ b/pkg/restapi/operations/xapp/get_xapp_config_list_parameters.go @@ -0,0 +1,45 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package xapp + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime/middleware" +) + +// NewGetXappConfigListParams creates a new GetXappConfigListParams object +// no default values defined in spec. +func NewGetXappConfigListParams() GetXappConfigListParams { + + return GetXappConfigListParams{} +} + +// GetXappConfigListParams contains all the bound params for the get xapp config list operation +// typically these are obtained from a http.Request +// +// swagger:parameters getXappConfigList +type GetXappConfigListParams struct { + + // HTTP Request Object + HTTPRequest *http.Request `json:"-"` +} + +// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface +// for simple values it will use straight method calls. +// +// To ensure default values, the struct must have been initialized with NewGetXappConfigListParams() beforehand. +func (o *GetXappConfigListParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error { + var res []error + + o.HTTPRequest = r + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/pkg/restapi/operations/xapp/get_xapp_config_list_responses.go b/pkg/restapi/operations/xapp/get_xapp_config_list_responses.go new file mode 100644 index 0000000..bddbfea --- /dev/null +++ b/pkg/restapi/operations/xapp/get_xapp_config_list_responses.go @@ -0,0 +1,85 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package xapp + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime" + + models "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/models" +) + +// GetXappConfigListOKCode is the HTTP code returned for type GetXappConfigListOK +const GetXappConfigListOKCode int = 200 + +/*GetXappConfigListOK successful query of xApp config + +swagger:response getXappConfigListOK +*/ +type GetXappConfigListOK struct { + + /* + In: Body + */ + Payload models.XappConfigList `json:"body,omitempty"` +} + +// NewGetXappConfigListOK creates GetXappConfigListOK with default headers values +func NewGetXappConfigListOK() *GetXappConfigListOK { + + return &GetXappConfigListOK{} +} + +// WithPayload adds the payload to the get xapp config list o k response +func (o *GetXappConfigListOK) WithPayload(payload models.XappConfigList) *GetXappConfigListOK { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the get xapp config list o k response +func (o *GetXappConfigListOK) SetPayload(payload models.XappConfigList) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *GetXappConfigListOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(200) + payload := o.Payload + if payload == nil { + // return empty array + payload = models.XappConfigList{} + } + + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} + +// GetXappConfigListInternalServerErrorCode is the HTTP code returned for type GetXappConfigListInternalServerError +const GetXappConfigListInternalServerErrorCode int = 500 + +/*GetXappConfigListInternalServerError Internal error + +swagger:response getXappConfigListInternalServerError +*/ +type GetXappConfigListInternalServerError struct { +} + +// NewGetXappConfigListInternalServerError creates GetXappConfigListInternalServerError with default headers values +func NewGetXappConfigListInternalServerError() *GetXappConfigListInternalServerError { + + return &GetXappConfigListInternalServerError{} +} + +// WriteResponse to the client +func (o *GetXappConfigListInternalServerError) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses + + rw.WriteHeader(500) +} diff --git a/pkg/restapi/operations/xapp/get_xapp_config_list_urlbuilder.go b/pkg/restapi/operations/xapp/get_xapp_config_list_urlbuilder.go new file mode 100644 index 0000000..6c0df06 --- /dev/null +++ b/pkg/restapi/operations/xapp/get_xapp_config_list_urlbuilder.go @@ -0,0 +1,87 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package xapp + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "errors" + "net/url" + golangswaggerpaths "path" +) + +// GetXappConfigListURL generates an URL for the get xapp config list operation +type GetXappConfigListURL struct { + _basePath string +} + +// WithBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *GetXappConfigListURL) WithBasePath(bp string) *GetXappConfigListURL { + o.SetBasePath(bp) + return o +} + +// SetBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *GetXappConfigListURL) SetBasePath(bp string) { + o._basePath = bp +} + +// Build a url path and query string +func (o *GetXappConfigListURL) Build() (*url.URL, error) { + var _result url.URL + + var _path = "/config" + + _basePath := o._basePath + if _basePath == "" { + _basePath = "/ric/v1" + } + _result.Path = golangswaggerpaths.Join(_basePath, _path) + + return &_result, nil +} + +// Must is a helper function to panic when the url builder returns an error +func (o *GetXappConfigListURL) Must(u *url.URL, err error) *url.URL { + if err != nil { + panic(err) + } + if u == nil { + panic("url can't be nil") + } + return u +} + +// String returns the string representation of the path with query string +func (o *GetXappConfigListURL) String() string { + return o.Must(o.Build()).String() +} + +// BuildFull builds a full url with scheme, host, path and query string +func (o *GetXappConfigListURL) BuildFull(scheme, host string) (*url.URL, error) { + if scheme == "" { + return nil, errors.New("scheme is required for a full url on GetXappConfigListURL") + } + if host == "" { + return nil, errors.New("host is required for a full url on GetXappConfigListURL") + } + + base, err := o.Build() + if err != nil { + return nil, err + } + + base.Scheme = scheme + base.Host = host + return base, nil +} + +// StringFull returns the string representation of a complete url +func (o *GetXappConfigListURL) StringFull(scheme, host string) string { + return o.Must(o.BuildFull(scheme, host)).String() +} diff --git a/pkg/restapi/operations/xapp_framework_api.go b/pkg/restapi/operations/xapp_framework_api.go index 10da039..c2ef01b 100644 --- a/pkg/restapi/operations/xapp_framework_api.go +++ b/pkg/restapi/operations/xapp_framework_api.go @@ -23,6 +23,7 @@ import ( "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/restapi/operations/policy" "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/restapi/operations/query" "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/restapi/operations/report" + "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/restapi/operations/xapp" ) // NewXappFrameworkAPI creates a new XappFramework instance @@ -42,12 +43,16 @@ func NewXappFrameworkAPI(spec *loads.Document) *XappFrameworkAPI { BearerAuthenticator: security.BearerAuth, JSONConsumer: runtime.JSONConsumer(), JSONProducer: runtime.JSONProducer(), + XMLProducer: runtime.XMLProducer(), CommonUnsubscribeHandler: common.UnsubscribeHandlerFunc(func(params common.UnsubscribeParams) middleware.Responder { return middleware.NotImplemented("operation CommonUnsubscribe has not yet been implemented") }), QueryGetAllSubscriptionsHandler: query.GetAllSubscriptionsHandlerFunc(func(params query.GetAllSubscriptionsParams) middleware.Responder { return middleware.NotImplemented("operation QueryGetAllSubscriptions has not yet been implemented") }), + XappGetXappConfigListHandler: xapp.GetXappConfigListHandlerFunc(func(params xapp.GetXappConfigListParams) middleware.Responder { + return middleware.NotImplemented("operation XappGetXappConfigList has not yet been implemented") + }), PolicySubscribePolicyHandler: policy.SubscribePolicyHandlerFunc(func(params policy.SubscribePolicyParams) middleware.Responder { return middleware.NotImplemented("operation PolicySubscribePolicy has not yet been implemented") }), @@ -84,11 +89,15 @@ type XappFrameworkAPI struct { // JSONProducer registers a producer for a "application/json" mime type JSONProducer runtime.Producer + // XMLProducer registers a producer for a "application/xml" mime type + XMLProducer runtime.Producer // CommonUnsubscribeHandler sets the operation handler for the unsubscribe operation CommonUnsubscribeHandler common.UnsubscribeHandler // QueryGetAllSubscriptionsHandler sets the operation handler for the get all subscriptions operation QueryGetAllSubscriptionsHandler query.GetAllSubscriptionsHandler + // XappGetXappConfigListHandler sets the operation handler for the get xapp config list operation + XappGetXappConfigListHandler xapp.GetXappConfigListHandler // PolicySubscribePolicyHandler sets the operation handler for the subscribe policy operation PolicySubscribePolicyHandler policy.SubscribePolicyHandler // ReportSubscribeReportHandler sets the operation handler for the subscribe report operation @@ -156,6 +165,10 @@ func (o *XappFrameworkAPI) Validate() error { unregistered = append(unregistered, "JSONProducer") } + if o.XMLProducer == nil { + unregistered = append(unregistered, "XMLProducer") + } + if o.CommonUnsubscribeHandler == nil { unregistered = append(unregistered, "common.UnsubscribeHandler") } @@ -164,6 +177,10 @@ func (o *XappFrameworkAPI) Validate() error { unregistered = append(unregistered, "query.GetAllSubscriptionsHandler") } + if o.XappGetXappConfigListHandler == nil { + unregistered = append(unregistered, "xapp.GetXappConfigListHandler") + } + if o.PolicySubscribePolicyHandler == nil { unregistered = append(unregistered, "policy.SubscribePolicyHandler") } @@ -228,6 +245,9 @@ func (o *XappFrameworkAPI) ProducersFor(mediaTypes []string) map[string]runtime. case "application/json": result["application/json"] = o.JSONProducer + case "application/xml": + result["application/xml"] = o.XMLProducer + } if p, ok := o.customProducers[mt]; ok { @@ -280,6 +300,11 @@ func (o *XappFrameworkAPI) initHandlerCache() { } o.handlers["GET"]["/subscriptions"] = query.NewGetAllSubscriptions(o.context, o.QueryGetAllSubscriptionsHandler) + if o.handlers["GET"] == nil { + o.handlers["GET"] = make(map[string]http.Handler) + } + o.handlers["GET"]["/config"] = xapp.NewGetXappConfigList(o.context, o.XappGetXappConfigListHandler) + if o.handlers["POST"] == nil { o.handlers["POST"] = make(map[string]http.Handler) } diff --git a/pkg/xapp/restapi.go b/pkg/xapp/restapi.go index 6562dc5..46e81f6 100755 --- a/pkg/xapp/restapi.go +++ b/pkg/xapp/restapi.go @@ -22,14 +22,19 @@ package xapp import ( "encoding/json" "github.com/gorilla/mux" + "github.com/spf13/viper" "io/ioutil" "net/http" + "os" + + "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/models" ) const ( - ReadyURL = "/ric/v1/health/ready" - AliveURL = "/ric/v1/health/alive" - ConfigURL = "/ric/v1/cm/{name}" + ReadyURL = "/ric/v1/health/ready" + AliveURL = "/ric/v1/health/alive" + ConfigURL = "/ric/v1/cm/{name}" + AppConfigURL = "/ric/v1/config" ) type StatusCb func() bool @@ -49,6 +54,7 @@ func NewRouter() *Router { r.InjectRoute(ReadyURL, readyHandler, "GET") r.InjectRoute(AliveURL, aliveHandler, "GET") r.InjectRoute(ConfigURL, configHandler, "POST") + r.InjectRoute(AppConfigURL, appconfigHandler, "GET") return r } @@ -130,3 +136,36 @@ func respondWithJSON(w http.ResponseWriter, code int, payload interface{}) { w.Write(response) } } + +func appconfigHandler(w http.ResponseWriter, r *http.Request) { + + Logger.Info("Inside appconfigHandler") + + var appconfig models.XappConfigList + var metadata models.ConfigMetadata + var xappconfig models.XAppConfig + name := viper.GetString("name") + configtype := "json" + metadata.XappName = &name + metadata.ConfigType = &configtype + + configFile, err := os.Open("/opt/ric/config/config-file.json") + if err != nil { + Logger.Error("Cannot open config file: %v", err) + respondWithJSON(w, http.StatusInternalServerError, nil) + // return nil,errors.New("Could Not parse the config file") + } + + body, err := ioutil.ReadAll(configFile) + + defer configFile.Close() + + xappconfig.Metadata = &metadata + xappconfig.Config = string(body) + + appconfig = append(appconfig, &xappconfig) + + respondWithJSON(w, http.StatusOK, appconfig) + + //return appconfig,nil +} diff --git a/pkg/xapp/subscription.go b/pkg/xapp/subscription.go index 4ecc262..bf140c4 100755 --- a/pkg/xapp/subscription.go +++ b/pkg/xapp/subscription.go @@ -33,6 +33,7 @@ import ( "net/http" "os" "time" + //"errors" apiclient "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/clientapi" apicommon "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/clientapi/common" @@ -47,6 +48,7 @@ import ( "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/restapi/operations/policy" "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/restapi/operations/query" "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/restapi/operations/report" + //"gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/restapi/operations/xapp" ) type SubscriptionHandler func(models.SubscriptionType, interface{}) (*models.SubscriptionResponse, error) @@ -149,6 +151,16 @@ func (r *Subscriber) Listen(createSubscription SubscriptionHandler, getSubscript return common.NewUnsubscribeInternalServerError() }) + // XApp: Get Config + /*api.XappGetXappConfigListHandler = xapp.GetXappConfigListHandlerFunc( + func(p xapp.GetXappConfigListParams) middleware.Responder { + Logger.Info("Hitting xapp config") + if resp,err := r.getXappConfig(); err == nil { + return xapp.NewGetXappConfigListOK().WithPayload(resp) + } + return xapp.NewGetXappConfigListInternalServerError() + })*/ + server := restapi.NewServer(api) defer server.Shutdown() server.Host = r.localAddr @@ -262,3 +274,32 @@ func (r *Subscriber) QuerySubscriptions() (models.SubscriptionList, error) { func (r *Subscriber) CreateTransport() *apiclient.RICSubscription { return apiclient.New(httptransport.New(r.remoteHost, r.remoteUrl, r.remoteProt), strfmt.Default) } + +/*func (r *Subscriber) getXappConfig() (appconfig models.XappConfigList, err error) { + + Logger.Error("Inside getXappConfig") + + var metadata models.ConfigMetadata + var xappconfig models.XAppConfig + name := viper.GetString("name") + configtype := "json" + metadata.XappName = &name + metadata.ConfigType = &configtype + + configFile, err := os.Open("/opt/ric/config/config-file.json") + if err != nil { + Logger.Error("Cannot open config file: %v", err) + return nil,errors.New("Could Not parse the config file") + } + + body, err := ioutil.ReadAll(configFile) + + defer configFile.Close() + + xappconfig.Metadata = &metadata + xappconfig.Config = body + + appconfig = append(appconfig,&xappconfig) + + return appconfig,nil +}*/ diff --git a/pkg/xapp/xapp.go b/pkg/xapp/xapp.go index 1ab7ee0..2bf7799 100755 --- a/pkg/xapp/xapp.go +++ b/pkg/xapp/xapp.go @@ -20,11 +20,15 @@ package xapp import ( + "bytes" + "encoding/json" "fmt" "github.com/spf13/viper" + "io/ioutil" "net/http" "os" "os/signal" + "strings" "sync/atomic" "syscall" "time" @@ -67,6 +71,140 @@ func XappReadyCb(params interface{}) { } } +func xappShutdownCb() { + SendDeregistermsg() + Logger.Info("Wait for xapp to get unregistered") + time.Sleep(10 * time.Second) +} + +func registerxapp() { + var ( + retries int = 10 + ) + for retries > 0 { + name, _ := os.Hostname() + httpservicename := "SERVICE_RICXAPP_" + strings.ToUpper(name) + "_HTTP_PORT" + httpendpoint := os.Getenv(strings.Replace(httpservicename, "-", "_", -1)) + urlString := strings.Split(httpendpoint, "//") + // Added this check to make UT pass + if urlString[0] == "" { + return + } + resp, err := http.Get(fmt.Sprintf("http://%s/ric/v1/health/ready", urlString[1])) + retries -= 1 + time.Sleep(5 * time.Second) + if err != nil { + Logger.Error("Error in health check: %v", err) + } + if err == nil { + retries -= 10 + Logger.Info("Health Probe Success with resp.StatusCode is %v", resp.StatusCode) + if resp.StatusCode >= 200 && resp.StatusCode <= 299 { + go SendRegistermsg() + } + } else { + Logger.Info("Health Probe failed, retrying...") + } + } +} + +func SendRegistermsg() { + name, _ := os.Hostname() + xappname := viper.GetString("name") + xappversion := viper.GetString("version") + appnamespace := os.Getenv("APP_NAMESPACE") + if appnamespace == "" { + appnamespace = "ricxapp" + } + httpservicename := "SERVICE_" + strings.ToUpper(appnamespace) + "_" + strings.ToUpper(name) + "_HTTP_PORT" + rmrservicename := "SERVICE_" + strings.ToUpper(appnamespace) + "_" + strings.ToUpper(name) + "_RMR_PORT" + httpendpointstr := os.Getenv(strings.Replace(httpservicename, "-", "_", -1)) + rmrendpointstr := os.Getenv(strings.Replace(rmrservicename, "-", "_", -1)) + httpendpoint := strings.Split(httpendpointstr, "//") + rmrendpoint := strings.Split(rmrendpointstr, "//") + if httpendpoint[0] == "" || rmrendpoint[0] == "" { + return + } + + pltnamespace := os.Getenv("PLT_NAMESPACE") + if pltnamespace == "" { + pltnamespace = "ricplt" + } + + configpath := "/ric/v1/config" + + requestBody, err := json.Marshal(map[string]string{ + "appName": name, + "httpEndpoint": httpendpoint[1], + "rmrEndpoint": rmrendpoint[1], + "appInstanceName": xappname, + "appVersion": xappversion, + "configPath": configpath, + }) + + if err != nil { + Logger.Info("Error while compiling request to appmgr: %v", err) + } else { + url := fmt.Sprintf("http://service-%v-appmgr-http.%v:8080/ric/v1/register", pltnamespace, pltnamespace) + resp, err := http.Post(url, "application/json", bytes.NewBuffer(requestBody)) + Logger.Info(" Resp is %v", resp) + if err != nil { + Logger.Info("Error compiling request to appmgr: %v", err) + } + Logger.Info("Registering request sent. Response received is :%v", resp) + + if resp != nil { + body, err := ioutil.ReadAll(resp.Body) + Logger.Info("Post body is %v", resp.Body) + if err != nil { + Logger.Info("rsp: Error compiling request to appmgr: %v", string(body)) + } + defer resp.Body.Close() + } + } +} + +func SendDeregistermsg() { + + name, _ := os.Hostname() + xappname := viper.GetString("name") + + appnamespace := os.Getenv("APP_NAMESPACE") + if appnamespace == "" { + appnamespace = "ricxapp" + } + pltnamespace := os.Getenv("PLT_NAMESPACE") + if pltnamespace == "" { + pltnamespace = "ricplt" + } + + requestBody, err := json.Marshal(map[string]string{ + "appName": name, + "appInstanceName": xappname, + }) + + if err != nil { + Logger.Info("Error while compiling request to appmgr: %v", err) + } else { + url := fmt.Sprintf("http://service-%v-appmgr-http.%v:8080/ric/v1/deregister", pltnamespace, pltnamespace) + resp, err := http.Post(url, "application/json", bytes.NewBuffer(requestBody)) + Logger.Info(" Resp is %v", resp) + if err != nil { + Logger.Info("Error compiling request to appmgr: %v", err) + } + Logger.Info("Deregistering request sent. Response received is :%v", resp) + + if resp != nil { + body, err := ioutil.ReadAll(resp.Body) + Logger.Info("Post body is %v", resp.Body) + if err != nil { + Logger.Info("rsp: Error compiling request to appmgr: %v", string(body)) + } + defer resp.Body.Close() + } + } +} + func SetShutdownCB(cb ShutdownCB) { shutdownCb = cb } @@ -143,13 +281,14 @@ func init() { func RunWithParams(c MessageConsumer, sdlcheck bool) { Rmr = NewRMRClient() Rmr.SetReadyCB(XappReadyCb, nil) - + SetShutdownCB(xappShutdownCb) host := fmt.Sprintf(":%d", GetPortData("http").Port) go http.ListenAndServe(host, Resource.router) Logger.Info(fmt.Sprintf("Xapp started, listening on: %s", host)) if sdlcheck { Sdl.TestConnection() } + go registerxapp() Rmr.Start(c) } diff --git a/pkg/xapp/xapp_test.go b/pkg/xapp/xapp_test.go index 04bbbb8..173b57f 100755 --- a/pkg/xapp/xapp_test.go +++ b/pkg/xapp/xapp_test.go @@ -20,16 +20,16 @@ package xapp import ( + "bytes" "github.com/gorilla/mux" "github.com/spf13/viper" + "github.com/stretchr/testify/assert" "net/http" "net/http/httptest" - "github.com/stretchr/testify/assert" "os" "strings" "testing" "time" - "bytes" ) //var _ = func() bool { @@ -118,8 +118,8 @@ func TestMessagesReceivedSuccessfully(t *testing.T) { params.Payload = []byte{1, 2, 3, 4, 5, 6} params.Meid = &RMRMeid{PlmnID: "1234", EnbID: "7788", RanName: "RanName-1234"} params.Xid = "TestXID" - - if i % 2 == 0 { + + if i%2 == 0 { Rmr.SendMsg(params) } else { Rmr.SendWithRetry(params, false, 1) @@ -332,11 +332,11 @@ func TestAddConfigChangeListener(t *testing.T) { func TestConfigAccess(t *testing.T) { Logger.Info("CASE: AddConfigChangeListener") - - assert.Equal(t, Config.GetString("name"), "xapp") - assert.Equal(t, Config.GetInt("controls.logger.level"), 3) - assert.Equal(t, Config.GetUint32("controls.logger.level"), uint32(3)) - assert.Equal(t, Config.GetBool("controls.waitForSdl"), false) + + assert.Equal(t, Config.GetString("name"), "xapp") + assert.Equal(t, Config.GetInt("controls.logger.level"), 3) + assert.Equal(t, Config.GetUint32("controls.logger.level"), uint32(3)) + assert.Equal(t, Config.GetBool("controls.waitForSdl"), false) Config.Get("controls") Config.GetStringSlice("messaging.ports") Config.GetStringMap("messaging.ports") @@ -354,7 +354,7 @@ func TestNewSubscriber(t *testing.T) { } func TestNewRMRClient(t *testing.T) { - c := map[string]interface{} {"protPort": "tcp:4560"} + c := map[string]interface{}{"protPort": "tcp:4560"} viper.Set("rmr", c) assert.NotNil(t, NewRMRClient(), "NewRMRClient failed") @@ -423,6 +423,23 @@ func TestConfigHandler(t *testing.T) { executeRequest(req, handleFunc) } +func TestappconfigHandler(t *testing.T) { + Logger.Error("CASE: TestappconfigHandler") + req, _ := http.NewRequest("POST", "/ric/v1/config", bytes.NewBuffer([]byte{})) + handleFunc := http.HandlerFunc(appconfigHandler) + executeRequest(req, handleFunc) +} + +func TestSendRegistermsg(t *testing.T) { + Logger.Error("CASE: TestSendRegistermsg") + SendRegistermsg() +} + +func TestSendDeregistermsg(t *testing.T) { + Logger.Error("CASE: TestSendDeregistermsg") + SendDeregistermsg() +} + func TestMisc(t *testing.T) { Logger.Info("CASE: TestMisc")