Merge "[RICPLT-1852] Supports E2T Initialize - missing protocol and ran name in setup...
[ric-plt/e2mgr.git] / E2Manager / controllers / nodeb_controller.go
1 //
2 // Copyright 2019 AT&T Intellectual Property
3 // Copyright 2019 Nokia
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //      http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17
18 package controllers
19
20 import (
21         "e2mgr/logger"
22         "e2mgr/models"
23         "e2mgr/providers/httpmsghandlerprovider"
24         "e2mgr/rNibWriter"
25         "e2mgr/services"
26         "e2mgr/sessions"
27         "e2mgr/utils"
28         "encoding/json"
29         "errors"
30         "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common"
31         "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader"
32         "github.com/go-ozzo/ozzo-validation"
33         "github.com/go-ozzo/ozzo-validation/is"
34         "github.com/golang/protobuf/jsonpb"
35         "github.com/gorilla/mux"
36         "net/http"
37         "net/http/httputil"
38         "strings"
39         "sync"
40         "time"
41 )
42
43 const (
44         parseErrorCode            int = 401
45         validationErrorCode       int = 402
46         notFoundErrorCode         int = 404
47         internalErrorCode         int = 501
48         requiredInputErrorMessage     = "Mandatory fields are missing"
49         validationFailedMessage       = "Validation failed"
50         parseErrorMessage             = "Parse failure"
51         notFoundErrorMessage          = "Resource not found"
52         internalErrorMessage          = "Internal Server Error. Please try again later"
53         sendMessageErrorMessage       = "Failed to send message. For more information please check logs"
54 )
55
56 var E2Sessions = make(sessions.E2Sessions)
57
58 var messageChannel chan *models.E2RequestMessage
59 var errorChannel chan error
60
61 type INodebController interface {
62         HandleRequest(writer http.ResponseWriter, request *http.Request)
63         GetNodebIdList (writer http.ResponseWriter, request *http.Request)
64         GetNodeb(writer http.ResponseWriter, request *http.Request)
65         HandleHealthCheckRequest(writer http.ResponseWriter, request *http.Request)
66 }
67
68 type NodebController struct {
69         rmrService         *services.RmrService
70         Logger             *logger.Logger
71         rnibReaderProvider func() reader.RNibReader
72         rnibWriterProvider func() rNibWriter.RNibWriter
73 }
74
75 func NewNodebController(logger *logger.Logger, rmrService *services.RmrService, rnibReaderProvider func() reader.RNibReader,
76         rnibWriterProvider func() rNibWriter.RNibWriter) *NodebController {
77         messageChannel = make(chan *models.E2RequestMessage)
78         errorChannel = make(chan error)
79         return &NodebController{
80                 rmrService:         rmrService,
81                 Logger:             logger,
82                 rnibReaderProvider: rnibReaderProvider,
83                 rnibWriterProvider: rnibWriterProvider,
84         }
85 }
86
87 func prettifyRequest(request *http.Request) string {
88         dump, _ := httputil.DumpRequest(request, true)
89         requestPrettyPrint := strings.Replace(string(dump), "\r\n", " ", -1)
90         return strings.Replace(requestPrettyPrint, "\n", "", -1)
91 }
92
93 func (rc NodebController) HandleRequest(writer http.ResponseWriter, request *http.Request) {
94         startTime := time.Now()
95         rc.Logger.Infof("[Client -> E2 Manager] #nodeb_controller.HandleRequest - request: %v", prettifyRequest(request))
96
97         vars := mux.Vars(request)
98         messageTypeParam := vars["messageType"]
99         requestHandlerProvider := httpmsghandlerprovider.NewRequestHandlerProvider(rc.rnibWriterProvider)
100         handler, err := requestHandlerProvider.GetHandler(rc.Logger, messageTypeParam)
101
102         if err != nil {
103                 handleErrorResponse(rc.Logger, http.StatusNotFound, notFoundErrorCode, notFoundErrorMessage, writer, startTime)
104                 return
105         }
106
107         requestDetails, err := parseJson(rc.Logger, request)
108
109         if err != nil {
110                 handleErrorResponse(rc.Logger, http.StatusBadRequest, parseErrorCode, parseErrorMessage, writer, startTime)
111                 return
112         }
113
114         rc.Logger.Infof("#nodeb_controller.HandleRequest - request: %+v", requestDetails)
115
116         if err := validateRequestDetails(rc.Logger, requestDetails); err != nil {
117                 handleErrorResponse(rc.Logger, http.StatusBadRequest, validationErrorCode, requiredInputErrorMessage, writer, startTime)
118                 return
119         }
120
121         err = handler.PreHandle(rc.Logger, &requestDetails)
122
123         if err != nil {
124                 handleErrorResponse(rc.Logger, http.StatusInternalServerError, internalErrorCode, err.Error(), writer, startTime)
125                 return
126         }
127
128         rc.Logger.Infof("[E2 Manager -> Client] #nodeb_controller.HandleRequest - http status: 200")
129         writer.WriteHeader(http.StatusOK)
130
131         var wg sync.WaitGroup
132
133         go handler.CreateMessage(rc.Logger, &requestDetails, messageChannel, E2Sessions, startTime, wg)
134
135         go rc.rmrService.SendMessage(handler.GetMessageType(), messageChannel, errorChannel, wg)
136
137         wg.Wait()
138
139         err = <-errorChannel
140
141         if err != nil {
142                 handleErrorResponse(rc.Logger, http.StatusInternalServerError, internalErrorCode, sendMessageErrorMessage, writer, startTime)
143                 return
144         }
145
146         printHandlingRequestElapsedTimeInMs(rc.Logger, startTime)
147 }
148
149 func (rc NodebController) GetNodebIdList (writer http.ResponseWriter, request *http.Request) {
150         startTime := time.Now()
151         rnibReaderService := services.NewRnibReaderService(rc.rnibReaderProvider)
152         nodebIdList, rnibError := rnibReaderService.GetNodebIdList()
153
154         if rnibError != nil {
155                 rc.Logger.Errorf("%v", rnibError);
156                 httpStatusCode, errorCode, errorMessage := rnibErrorToHttpError(rnibError)
157                 handleErrorResponse(rc.Logger, httpStatusCode, errorCode, errorMessage, writer, startTime)
158                 return;
159         }
160
161         pmList := utils.ConvertNodebIdListToProtoMessageList(nodebIdList)
162         result, err := utils.MarshalProtoMessageListToJsonArray(pmList)
163
164         if err != nil {
165                 rc.Logger.Errorf("%v", err);
166                 handleErrorResponse(rc.Logger, http.StatusInternalServerError, internalErrorCode, internalErrorMessage, writer, startTime)
167                 return;
168         }
169
170         writer.Header().Set("Content-Type", "application/json")
171         rc.Logger.Infof("[E2 Manager -> Client] #nodeb_controller.GetNodebIdList - response: %s", result)
172         writer.Write([]byte(result))
173 }
174
175 func (rc NodebController) GetNodeb(writer http.ResponseWriter, request *http.Request) {
176         startTime := time.Now()
177         vars := mux.Vars(request)
178         ranName := vars["ranName"]
179         // WAS: respondingNode, rnibError := reader.GetRNibReader().GetNodeb(ranName)
180         rnibReaderService := services.NewRnibReaderService(rc.rnibReaderProvider);
181         respondingNode, rnibError := rnibReaderService.GetNodeb(ranName)
182         if rnibError != nil {
183                 rc.Logger.Errorf("%v", rnibError)
184                 httpStatusCode, errorCode, errorMessage := rnibErrorToHttpError(rnibError)
185                 handleErrorResponse(rc.Logger, httpStatusCode, errorCode, errorMessage, writer, startTime)
186                 return
187         }
188
189         m := jsonpb.Marshaler{}
190         result, err := m.MarshalToString(respondingNode)
191
192         if err != nil {
193                 rc.Logger.Errorf("%v", err)
194                 handleErrorResponse(rc.Logger, http.StatusInternalServerError, internalErrorCode, internalErrorMessage, writer, startTime)
195                 return
196         }
197
198         writer.Header().Set("Content-Type", "application/json")
199         rc.Logger.Infof("[E2 Manager -> Client] #nodeb_controller.GetNodeb - response: %s", result)
200         writer.Write([]byte(result))
201 }
202
203 func (rc NodebController) HandleHealthCheckRequest(writer http.ResponseWriter, request *http.Request) {
204         //fmt.Println("[X-APP -> Client] #HandleHealthCheckRequest - http status: 200")
205         writer.WriteHeader(http.StatusOK)
206 }
207
208 func parseJson(logger *logger.Logger, request *http.Request) (models.RequestDetails, error) {
209         var requestDetails models.RequestDetails
210         if err := json.NewDecoder(request.Body).Decode(&requestDetails); err != nil {
211                 logger.Errorf("#nodeb_controller.parseJson - cannot deserialize incoming request. request: %v, error: %v", request, err)
212                 return requestDetails, err
213         }
214         return requestDetails, nil
215 }
216
217 func validateRequestDetails(logger *logger.Logger, requestDetails models.RequestDetails) error {
218
219         if requestDetails.RanPort == 0 {
220                 logger.Errorf("#nodeb_controller.validateRequestDetails - validation failure: port cannot be zero")
221                 return errors.New("port: cannot be blank")
222         }
223         err := validation.ValidateStruct(&requestDetails,
224                 validation.Field(&requestDetails.RanIp, validation.Required, is.IP),
225                 validation.Field(&requestDetails.RanName, validation.Required),
226         )
227         if err != nil {
228                 logger.Errorf("#nodeb_controller.validateRequestDetails - validation failure, error: %v", err)
229         }
230
231         return err
232 }
233
234 func handleErrorResponse(logger *logger.Logger, httpStatus int, errorCode int, errorMessage string, writer http.ResponseWriter, startTime time.Time) {
235         errorResponseDetails := models.ErrorResponse{errorCode, errorMessage}
236         errorResponse, _ := json.Marshal(errorResponseDetails)
237         printHandlingRequestElapsedTimeInMs(logger, startTime)
238         logger.Infof("[E2 Manager -> Client] #nodeb_controller.handleErrorResponse - http status: %d, error response: %+v", httpStatus, errorResponseDetails)
239         writer.Header().Set("Content-Type", "application/json")
240         writer.WriteHeader(httpStatus)
241         _, err := writer.Write(errorResponse)
242
243         if err != nil {
244                 logger.Errorf("#nodeb_controller.handleErrorResponse - Cannot send response. writer:%v", writer)
245         }
246 }
247
248 func printHandlingRequestElapsedTimeInMs(logger *logger.Logger, startTime time.Time) {
249         logger.Infof("Summary: #nodeb_controller.printElapsedTimeInMs - Elapsed time for handling request from client to E2 termination: %f ms",
250                 float64(time.Since(startTime))/float64(time.Millisecond))
251 }
252
253 func rnibErrorToHttpError(rnibError common.IRNibError) (int, int, string) {
254         switch rnibError.GetCode() {
255         case common.RESOURCE_NOT_FOUND:
256                 return http.StatusNotFound, notFoundErrorCode, notFoundErrorMessage
257         case common.INTERNAL_ERROR:
258                 return http.StatusInternalServerError, internalErrorCode, internalErrorMessage
259         case common.VALIDATION_ERROR:
260                 return http.StatusBadRequest, validationErrorCode, validationFailedMessage
261         default:
262                 return http.StatusInternalServerError, internalErrorCode, internalErrorMessage
263         }
264 }