blob: 50cb49baed0b249463c6652a74a0e07e0ffb5315 [file] [log] [blame]
//
// Copyright 2019 AT&T Intellectual Property
// Copyright 2019 Nokia
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package controllers
import (
"e2mgr/logger"
"e2mgr/models"
"e2mgr/providers/httpmsghandlerprovider"
"e2mgr/rNibWriter"
"e2mgr/services"
"e2mgr/sessions"
"e2mgr/utils"
"encoding/json"
"errors"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader"
"github.com/go-ozzo/ozzo-validation"
"github.com/go-ozzo/ozzo-validation/is"
"github.com/golang/protobuf/jsonpb"
"github.com/julienschmidt/httprouter"
"net/http"
"net/http/httputil"
"strings"
"sync"
"time"
)
const (
parseErrorCode int = 401
validationErrorCode int = 402
notFoundErrorCode int = 404
internalErrorCode int = 501
requiredInputErrorMessage = "Mandatory fields are missing"
validationFailedMessage = "Validation failed"
parseErrorMessage = "Parse failure"
notFoundErrorMessage = "Resource not found"
internalErrorMessage = "Internal Server Error. Please try again later"
sendMessageErrorMessage = "Failed to send message. For more information please check logs"
)
var E2Sessions = make(sessions.E2Sessions)
var messageChannel chan *models.E2RequestMessage
var errorChannel chan error
type NodebController struct {
rmrService *services.RmrService
Logger *logger.Logger
rnibReaderProvider func() reader.RNibReader
rnibWriterProvider func() rNibWriter.RNibWriter
}
func NewNodebController(logger *logger.Logger, rmrService *services.RmrService, rnibReaderProvider func() reader.RNibReader,
rnibWriterProvider func() rNibWriter.RNibWriter) *NodebController {
messageChannel = make(chan *models.E2RequestMessage)
errorChannel = make(chan error)
return &NodebController{
rmrService: rmrService,
Logger: logger,
rnibReaderProvider: rnibReaderProvider,
rnibWriterProvider: rnibWriterProvider,
}
}
func prettifyRequest(request *http.Request) string {
dump, _ := httputil.DumpRequest(request, true)
requestPrettyPrint := strings.Replace(string(dump), "\r\n", " ", -1)
return strings.Replace(requestPrettyPrint, "\n", "", -1)
}
func (rc NodebController) HandleRequest(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
startTime := time.Now()
rc.Logger.Infof("[Client -> E2 Manager] #nodeb_controller.HandleRequest - request: %v", prettifyRequest(request))
messageTypeParam := params.ByName("messageType")
requestHandlerProvider := httpmsghandlerprovider.NewRequestHandlerProvider(rc.rnibWriterProvider)
handler, err := requestHandlerProvider.GetHandler(rc.Logger, messageTypeParam)
if err != nil {
handleErrorResponse(rc.Logger, http.StatusNotFound, notFoundErrorCode, notFoundErrorMessage, writer, startTime)
return
}
requestDetails, err := parseJson(rc.Logger, request)
if err != nil {
handleErrorResponse(rc.Logger, http.StatusBadRequest, parseErrorCode, parseErrorMessage, writer, startTime)
return
}
rc.Logger.Infof("#nodeb_controller.HandleRequest - request: %+v", requestDetails)
if err := validateRequestDetails(rc.Logger, requestDetails); err != nil {
handleErrorResponse(rc.Logger, http.StatusBadRequest, validationErrorCode, requiredInputErrorMessage, writer, startTime)
return
}
err = handler.PreHandle(rc.Logger, &requestDetails)
if err != nil {
handleErrorResponse(rc.Logger, http.StatusInternalServerError, internalErrorCode, err.Error(), writer, startTime)
return
}
rc.Logger.Infof("[E2 Manager -> Client] #nodeb_controller.HandleRequest - http status: 200")
writer.WriteHeader(http.StatusOK)
var wg sync.WaitGroup
go handler.CreateMessage(rc.Logger, &requestDetails, messageChannel, E2Sessions, startTime, wg)
go rc.rmrService.SendMessage(handler.GetMessageType(), messageChannel, errorChannel, wg)
wg.Wait()
err = <-errorChannel
if err != nil {
handleErrorResponse(rc.Logger, http.StatusInternalServerError, internalErrorCode, sendMessageErrorMessage, writer, startTime)
return
}
printHandlingRequestElapsedTimeInMs(rc.Logger, startTime)
}
func (rc NodebController) GetNodebIdList(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
startTime := time.Now()
rnibReaderService := services.NewRnibReaderService(rc.rnibReaderProvider)
nodebIdList, rnibError := rnibReaderService.GetNodebIdList()
if rnibError != nil {
rc.Logger.Errorf("%v", rnibError);
httpStatusCode, errorCode, errorMessage := rnibErrorToHttpError(rnibError)
handleErrorResponse(rc.Logger, httpStatusCode, errorCode, errorMessage, writer, startTime)
return;
}
pmList := utils.ConvertNodebIdListToProtoMessageList(*nodebIdList)
result, err := utils.MarshalProtoMessageListToJsonArray(pmList)
if err != nil {
rc.Logger.Errorf("%v", err);
handleErrorResponse(rc.Logger, http.StatusInternalServerError, internalErrorCode, internalErrorMessage, writer, startTime)
return;
}
writer.Header().Set("Content-Type", "application/json")
rc.Logger.Infof("[E2 Manager -> Client] #nodeb_controller.GetNodebIdList - response: %s", result)
writer.Write([]byte(result))
}
func (rc NodebController) GetNodeb(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
startTime := time.Now()
ranName := params.ByName("ranName")
// WAS: respondingNode, rnibError := reader.GetRNibReader().GetNodeb(ranName)
rnibReaderService := services.NewRnibReaderService(rc.rnibReaderProvider);
respondingNode, rnibError := rnibReaderService.GetNodeb(ranName)
if rnibError != nil {
rc.Logger.Errorf("%v", rnibError)
httpStatusCode, errorCode, errorMessage := rnibErrorToHttpError(rnibError)
handleErrorResponse(rc.Logger, httpStatusCode, errorCode, errorMessage, writer, startTime)
return
}
m := jsonpb.Marshaler{}
result, err := m.MarshalToString(respondingNode)
if err != nil {
rc.Logger.Errorf("%v", err)
handleErrorResponse(rc.Logger, http.StatusInternalServerError, internalErrorCode, internalErrorMessage, writer, startTime)
return
}
writer.Header().Set("Content-Type", "application/json")
rc.Logger.Infof("[E2 Manager -> Client] #nodeb_controller.GetNodeb - response: %s", result)
writer.Write([]byte(result))
}
func (rc NodebController) HandleHealthCheckRequest(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
//fmt.Println("[X-APP -> Client] #HandleHealthCheckRequest - http status: 200")
writer.WriteHeader(http.StatusOK)
}
func parseJson(logger *logger.Logger, request *http.Request) (models.RequestDetails, error) {
var requestDetails models.RequestDetails
if err := json.NewDecoder(request.Body).Decode(&requestDetails); err != nil {
logger.Errorf("#nodeb_controller.parseJson - cannot deserialize incoming request. request: %v, error: %v", request, err)
return requestDetails, err
}
return requestDetails, nil
}
func validateRequestDetails(logger *logger.Logger, requestDetails models.RequestDetails) error {
if requestDetails.RanPort == 0 {
logger.Errorf("#nodeb_controller.validateRequestDetails - validation failure: port cannot be zero")
return errors.New("port: cannot be blank")
}
err := validation.ValidateStruct(&requestDetails,
validation.Field(&requestDetails.RanIp, validation.Required, is.IP),
validation.Field(&requestDetails.RanName, validation.Required),
)
if err != nil {
logger.Errorf("#nodeb_controller.validateRequestDetails - validation failure, error: %v", err)
}
return err
}
func handleErrorResponse(logger *logger.Logger, httpStatus int, errorCode int, errorMessage string, writer http.ResponseWriter, startTime time.Time) {
errorResponseDetails := models.ErrorResponse{errorCode, errorMessage}
errorResponse, _ := json.Marshal(errorResponseDetails)
printHandlingRequestElapsedTimeInMs(logger, startTime)
logger.Infof("[E2 Manager -> Client] #nodeb_controller.handleErrorResponse - http status: %d, error response: %+v", httpStatus, errorResponseDetails)
writer.Header().Set("Content-Type", "application/json")
writer.WriteHeader(httpStatus)
_, err := writer.Write(errorResponse)
if err != nil {
logger.Errorf("#nodeb_controller.handleErrorResponse - Cannot send response. writer:%v", writer)
}
}
func printHandlingRequestElapsedTimeInMs(logger *logger.Logger, startTime time.Time) {
logger.Infof("Summary: #nodeb_controller.printElapsedTimeInMs - Elapsed time for handling request from client to E2 termination: %f ms",
float64(time.Since(startTime))/float64(time.Millisecond))
}
func rnibErrorToHttpError(rnibError common.IRNibError) (int, int, string) {
switch rnibError.GetCode() {
case common.RESOURCE_NOT_FOUND:
return http.StatusNotFound, notFoundErrorCode, notFoundErrorMessage
case common.INTERNAL_ERROR:
return http.StatusInternalServerError, internalErrorCode, internalErrorMessage
case common.VALIDATION_ERROR:
return http.StatusBadRequest, validationErrorCode, validationFailedMessage
default:
return http.StatusInternalServerError, internalErrorCode, internalErrorMessage
}
}