8ed6cbf4e9942c2c82a6f7ae90f3c8d332492777
[ric-plt/e2mgr.git] / E2Manager / controllers / nodeb_controller.go
1 //
2 // Copyright 2019 AT&T Intellectual Property
3 // Copyright 2019 Nokia
4 // Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved.
5 //
6 // Licensed under the Apache License, Version 2.0 (the "License");
7 // you may not use this file except in compliance with the License.
8 // You may obtain a copy of the License at
9 //
10 //      http://www.apache.org/licenses/LICENSE-2.0
11 //
12 // Unless required by applicable law or agreed to in writing, software
13 // distributed under the License is distributed on an "AS IS" BASIS,
14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 // See the License for the specific language governing permissions and
16 // limitations under the License.
17
18 //  This source code is part of the near-RT RIC (RAN Intelligent Controller)
19 //  platform project (RICP).
20
21 package controllers
22
23 import (
24         "e2mgr/e2managererrors"
25         "e2mgr/logger"
26         "e2mgr/models"
27         "e2mgr/providers/httpmsghandlerprovider"
28         "encoding/json"
29         "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
30         "github.com/golang/protobuf/jsonpb"
31         "github.com/golang/protobuf/proto"
32         "github.com/gorilla/mux"
33         "io"
34         "io/ioutil"
35         "net/http"
36         "net/http/httputil"
37         "strings"
38 )
39
40 const (
41         ParamRanName = "ranName"
42         LimitRequest = 2000
43 )
44 const ApplicationJson = "application/json"
45 const ContentType = "Content-Type"
46
47 type INodebController interface {
48         Shutdown(writer http.ResponseWriter, r *http.Request)
49         X2Reset(writer http.ResponseWriter, r *http.Request)
50         GetNodeb(writer http.ResponseWriter, r *http.Request)
51         UpdateGnb(writer http.ResponseWriter, r *http.Request)
52         UpdateEnb(writer http.ResponseWriter, r *http.Request)
53         GetNodebIdList(writer http.ResponseWriter, r *http.Request)
54         SetGeneralConfiguration(writer http.ResponseWriter, r *http.Request)
55         AddEnb(writer http.ResponseWriter, r *http.Request)
56         DeleteEnb(writer http.ResponseWriter, r *http.Request)
57         HealthCheckRequest(writer http.ResponseWriter, r *http.Request)
58 }
59
60 type NodebController struct {
61         logger          *logger.Logger
62         handlerProvider *httpmsghandlerprovider.IncomingRequestHandlerProvider
63 }
64
65 func NewNodebController(logger *logger.Logger, handlerProvider *httpmsghandlerprovider.IncomingRequestHandlerProvider) *NodebController {
66         return &NodebController{
67                 logger:          logger,
68                 handlerProvider: handlerProvider,
69         }
70 }
71
72 func (c *NodebController) GetNodebIdList(writer http.ResponseWriter, r *http.Request) {
73         c.logger.Infof("[Client -> E2 Manager] #NodebController.GetNodebIdList - request: %v", c.prettifyRequest(r))
74
75         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.GetNodebIdListRequest, nil, false, http.StatusOK)
76 }
77
78 func (c *NodebController) GetNodeb(writer http.ResponseWriter, r *http.Request) {
79         c.logger.Infof("[Client -> E2 Manager] #NodebController.GetNodeb - request: %v", c.prettifyRequest(r))
80         vars := mux.Vars(r)
81         ranName := vars["ranName"]
82         request := models.GetNodebRequest{RanName: ranName}
83         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.GetNodebRequest, request, false, http.StatusOK)
84 }
85
86 func (c *NodebController) UpdateGnb(writer http.ResponseWriter, r *http.Request) {
87         c.logger.Infof("[Client -> E2 Manager] #NodebController.UpdateGnb - request: %v", c.prettifyRequest(r))
88         vars := mux.Vars(r)
89         ranName := vars[ParamRanName]
90
91         request := models.UpdateGnbRequest{}
92
93         gnb := entities.Gnb{}
94
95         if !c.extractRequestBodyToProto(r, &gnb, writer) {
96                 return
97         }
98
99         request.Gnb = &gnb
100         request.RanName = ranName
101         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.UpdateGnbRequest, &request, true, http.StatusOK)
102 }
103
104 func (c *NodebController) UpdateEnb(writer http.ResponseWriter, r *http.Request) {
105         c.logger.Infof("[Client -> E2 Manager] #NodebController.UpdateEnb - request: %v", c.prettifyRequest(r))
106
107         defer r.Body.Close()
108         body, err := ioutil.ReadAll(r.Body)
109
110         if err != nil {
111                 c.logger.Errorf("[Client -> E2 Manager] #NodebController.UpdateEnb - unable to read request body - error: %s", err)
112                 c.handleErrorResponse(e2managererrors.NewInvalidJsonError(), writer)
113                 return
114         }
115
116         updateEnbRequest := models.UpdateEnbRequest{}
117         err = json.Unmarshal(body, &updateEnbRequest)
118
119         if err != nil {
120                 c.logger.Errorf("[Client -> E2 Manager] #NodebController.UpdateEnb - unable to unmarshal json - error: %s", err)
121                 c.handleErrorResponse(e2managererrors.NewInvalidJsonError(), writer)
122                 return
123         }
124
125         vars := mux.Vars(r)
126         ranName := vars[ParamRanName]
127
128         updateEnbRequest.RanName = ranName
129
130         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.UpdateEnbRequest, &updateEnbRequest, true, http.StatusOK)
131 }
132
133 func (c *NodebController) AddEnb(writer http.ResponseWriter, r *http.Request) {
134         c.logger.Infof("[Client -> E2 Manager] #NodebController.AddEnb - request: %v", c.prettifyRequest(r))
135
136         defer r.Body.Close()
137         body, err := ioutil.ReadAll(r.Body)
138
139         if err != nil {
140                 c.logger.Errorf("[Client -> E2 Manager] #NodebController.AddEnb - unable to read request body - error: %s", err)
141                 c.handleErrorResponse(e2managererrors.NewInvalidJsonError(), writer)
142                 return
143         }
144
145         addEnbRequest := models.AddEnbRequest{}
146         err = json.Unmarshal(body, &addEnbRequest)
147
148         if err != nil {
149                 c.logger.Errorf("[Client -> E2 Manager] #NodebController.AddEnb - unable to unmarshal json - error: %s", err)
150                 c.handleErrorResponse(e2managererrors.NewInvalidJsonError(), writer)
151                 return
152         }
153
154         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.AddEnbRequest, &addEnbRequest, true, http.StatusCreated)
155 }
156
157 func (c *NodebController) DeleteEnb(writer http.ResponseWriter, r *http.Request) {
158         c.logger.Infof("[Client -> E2 Manager] #NodebController.DeleteEnb - request: %v", c.prettifyRequest(r))
159         vars := mux.Vars(r)
160         ranName := vars["ranName"]
161         request := &models.DeleteEnbRequest{RanName: ranName}
162         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.DeleteEnbRequest, request, true, http.StatusNoContent)
163 }
164
165 func (c *NodebController) SetGeneralConfiguration(writer http.ResponseWriter, r *http.Request) {
166         c.logger.Infof("[Client -> E2 Manager] #NodebController.SetGeneralConfiguration - request: %v", c.prettifyRequest(r))
167
168         request := models.GeneralConfigurationRequest{}
169
170         if !c.extractJsonBodyDisallowUnknownFields(r, &request, writer) {
171                 return
172         }
173         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.SetGeneralConfigurationRequest, request, false, http.StatusOK)
174 }
175
176 func (c *NodebController) Shutdown(writer http.ResponseWriter, r *http.Request) {
177         c.logger.Infof("[Client -> E2 Manager] #NodebController.Shutdown - request: %v", c.prettifyRequest(r))
178         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.ShutdownRequest, nil, false, http.StatusNoContent)
179 }
180
181 func (c *NodebController) X2Reset(writer http.ResponseWriter, r *http.Request) {
182         c.logger.Infof("[Client -> E2 Manager] #NodebController.X2Reset - request: %v", c.prettifyRequest(r))
183         request := models.ResetRequest{}
184         vars := mux.Vars(r)
185         ranName := vars[ParamRanName]
186
187         if err := c.extractJsonBody(r, &request); err != nil {
188                 c.handleErrorResponse(err, writer)
189                 return
190         }
191         request.RanName = ranName
192         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.ResetRequest, request, false, http.StatusNoContent)
193 }
194
195 func (c *NodebController) HealthCheckRequest(writer http.ResponseWriter, r *http.Request) {
196         c.logger.Infof("[Client -> E2 Manager] #NodebController.HealthCheckRequest - request: %v", c.prettifyRequest(r))
197
198         request := models.HealthCheckRequest{}
199
200         if err := c.extractJsonBody(r, &request); err != nil {
201                 c.handleErrorResponse(err, writer)
202                 return
203         }
204
205         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.HealthCheckRequest, request, true, http.StatusNoContent)
206 }
207
208 func (c *NodebController) extractRequestBodyToProto(r *http.Request, pb proto.Message, writer http.ResponseWriter) bool {
209         defer r.Body.Close()
210
211         err := jsonpb.Unmarshal(r.Body, pb)
212
213         if err != nil {
214                 c.logger.Errorf("[Client -> E2 Manager] #NodebController.extractJsonBody - unable to extract json body - error: %s", err)
215                 c.handleErrorResponse(e2managererrors.NewInvalidJsonError(), writer)
216                 return false
217         }
218
219         return true
220 }
221
222 func (c *NodebController) extractJsonBodyDisallowUnknownFields(r *http.Request, request models.Request, writer http.ResponseWriter) bool {
223         defer r.Body.Close()
224
225         decoder := json.NewDecoder(r.Body)
226         decoder.DisallowUnknownFields()
227
228         if err := decoder.Decode(&request); err != nil {
229                 c.logger.Errorf("[Client -> E2 Manager] #NodebController.extractJsonBody - unable to extract json body - error: %s", err)
230                 c.handleErrorResponse(e2managererrors.NewInvalidJsonError(), writer)
231                 return false
232         }
233
234         return true
235 }
236
237 func (c *NodebController) extractJsonBody(r *http.Request, request models.Request) error {
238         defer r.Body.Close()
239         body, err := ioutil.ReadAll(io.LimitReader(r.Body, LimitRequest))
240
241         if err != nil {
242                 c.logger.Errorf("[Client -> E2 Manager] #NodebController.extractJsonBody - unable to extract json body - error: %s", err)
243                 return e2managererrors.NewInvalidJsonError()
244         }
245
246         err = json.Unmarshal(body, &request)
247         if err != nil {
248                 c.logger.Errorf("[Client -> E2 Manager] #NodebController.extractJsonBody - unable to extract json body - error: %s", err)
249                 return e2managererrors.NewInvalidJsonError()
250         }
251
252         return nil
253 }
254
255 func (c *NodebController) handleRequest(writer http.ResponseWriter, header *http.Header, requestName httpmsghandlerprovider.IncomingRequest, request models.Request, validateRequestHeaders bool, successStatusCode int) {
256
257         if validateRequestHeaders {
258
259                 err := c.validateRequestHeader(header)
260                 if err != nil {
261                         c.handleErrorResponse(err, writer)
262                         return
263                 }
264         }
265
266         handler, err := c.handlerProvider.GetHandler(requestName)
267
268         if err != nil {
269                 c.handleErrorResponse(err, writer)
270                 return
271         }
272
273         response, err := handler.Handle(request)
274
275         if err != nil {
276                 c.handleErrorResponse(err, writer)
277                 return
278         }
279
280         if successStatusCode == http.StatusNoContent {
281                 writer.WriteHeader(successStatusCode)
282                 c.logger.Infof("[E2 Manager -> Client] #NodebController.handleRequest - status response: %v", http.StatusNoContent)
283                 return
284         }
285
286         result, err := response.Marshal()
287
288         if err != nil {
289                 c.handleErrorResponse(err, writer)
290                 return
291         }
292
293         c.logger.Infof("[E2 Manager -> Client] #NodebController.handleRequest - response: %s", result)
294         writer.Header().Set(ContentType, ApplicationJson)
295         writer.WriteHeader(successStatusCode)
296         writer.Write(result)
297 }
298
299 func (c *NodebController) validateRequestHeader(header *http.Header) error {
300
301         if header.Get(ContentType) != ApplicationJson {
302                 c.logger.Errorf("#NodebController.validateRequestHeader - validation failure, incorrect content type")
303
304                 return e2managererrors.NewHeaderValidationError()
305         }
306         return nil
307 }
308
309 func (c *NodebController) handleErrorResponse(err error, writer http.ResponseWriter) {
310
311         var errorResponseDetails models.ErrorResponse
312         var httpError int
313
314         if err != nil {
315                 switch err.(type) {
316                 case *e2managererrors.RnibDbError:
317                         e2Error, _ := err.(*e2managererrors.RnibDbError)
318                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
319                         httpError = http.StatusInternalServerError
320                 case *e2managererrors.CommandAlreadyInProgressError:
321                         e2Error, _ := err.(*e2managererrors.CommandAlreadyInProgressError)
322                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
323                         httpError = http.StatusMethodNotAllowed
324                 case *e2managererrors.HeaderValidationError:
325                         e2Error, _ := err.(*e2managererrors.HeaderValidationError)
326                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
327                         httpError = http.StatusUnsupportedMediaType
328                 case *e2managererrors.WrongStateError:
329                         e2Error, _ := err.(*e2managererrors.WrongStateError)
330                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
331                         httpError = http.StatusBadRequest
332                 case *e2managererrors.RequestValidationError:
333                         e2Error, _ := err.(*e2managererrors.RequestValidationError)
334                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
335                         httpError = http.StatusBadRequest
336                 case *e2managererrors.InvalidJsonError:
337                         e2Error, _ := err.(*e2managererrors.InvalidJsonError)
338                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
339                         httpError = http.StatusBadRequest
340                 case *e2managererrors.RmrError:
341                         e2Error, _ := err.(*e2managererrors.RmrError)
342                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
343                         httpError = http.StatusInternalServerError
344                 case *e2managererrors.ResourceNotFoundError:
345                         e2Error, _ := err.(*e2managererrors.ResourceNotFoundError)
346                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
347                         httpError = http.StatusNotFound
348                 case *e2managererrors.E2TInstanceAbsenceError:
349                         e2Error, _ := err.(*e2managererrors.E2TInstanceAbsenceError)
350                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
351                         httpError = http.StatusServiceUnavailable
352                 case *e2managererrors.RoutingManagerError:
353                         e2Error, _ := err.(*e2managererrors.RoutingManagerError)
354                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
355                         httpError = http.StatusServiceUnavailable
356                 case *e2managererrors.NodebExistsError:
357                         e2Error, _ := err.(*e2managererrors.NodebExistsError)
358                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
359                         httpError = http.StatusBadRequest
360                 case *e2managererrors.NoConnectedRanError:
361                         e2Error, _ := err.(*e2managererrors.NoConnectedRanError)
362                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
363                         httpError = http.StatusNotFound
364                 default:
365                         e2Error := e2managererrors.NewInternalError()
366                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
367                         httpError = http.StatusInternalServerError
368                 }
369         }
370         errorResponse, _ := json.Marshal(errorResponseDetails)
371
372         c.logger.Errorf("[E2 Manager -> Client] #NodebController.handleErrorResponse - http status: %d, error response: %+v", httpError, errorResponseDetails)
373
374         writer.Header().Set(ContentType, ApplicationJson)
375         writer.WriteHeader(httpError)
376         _, err = writer.Write(errorResponse)
377 }
378
379 func (c *NodebController) prettifyRequest(request *http.Request) string {
380         dump, _ := httputil.DumpRequest(request, true)
381         requestPrettyPrint := strings.Replace(string(dump), "\r\n", " ", -1)
382         return strings.Replace(requestPrettyPrint, "\n", "", -1)
383 }