Merge "Automation of nodeb state API"
[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         GetNodebId(writer http.ResponseWriter, r *http.Request)
55         SetGeneralConfiguration(writer http.ResponseWriter, r *http.Request)
56         AddEnb(writer http.ResponseWriter, r *http.Request)
57         DeleteEnb(writer http.ResponseWriter, r *http.Request)
58         HealthCheckRequest(writer http.ResponseWriter, r *http.Request)
59 }
60
61 type NodebController struct {
62         logger          *logger.Logger
63         handlerProvider *httpmsghandlerprovider.IncomingRequestHandlerProvider
64 }
65
66 func NewNodebController(logger *logger.Logger, handlerProvider *httpmsghandlerprovider.IncomingRequestHandlerProvider) *NodebController {
67         return &NodebController{
68                 logger:          logger,
69                 handlerProvider: handlerProvider,
70         }
71 }
72
73 func (c *NodebController) GetNodebIdList(writer http.ResponseWriter, r *http.Request) {
74         c.logger.Infof("[Client -> E2 Manager] #NodebController.GetNodebIdList - request: %v", c.prettifyRequest(r))
75
76         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.GetNodebIdListRequest, nil, false, http.StatusOK)
77 }
78
79 func (c *NodebController) GetNodebId(writer http.ResponseWriter, r *http.Request) {
80         c.logger.Infof("[Client -> E2 Manager] #NodebController.GetNodebId - request: %v", c.prettifyRequest(r))
81         vars := mux.Vars(r)
82         ranName := vars["ranName"]
83         request := models.GetNodebIdRequest{RanName: ranName}
84
85         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.GetNodebIdRequest, request, false, http.StatusOK)
86 }
87
88 func (c *NodebController) GetNodeb(writer http.ResponseWriter, r *http.Request) {
89         c.logger.Infof("[Client -> E2 Manager] #NodebController.GetNodeb - request: %v", c.prettifyRequest(r))
90         vars := mux.Vars(r)
91         ranName := vars["ranName"]
92         request := models.GetNodebRequest{RanName: ranName}
93         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.GetNodebRequest, request, false, http.StatusOK)
94 }
95
96 func (c *NodebController) UpdateGnb(writer http.ResponseWriter, r *http.Request) {
97         c.logger.Infof("[Client -> E2 Manager] #NodebController.UpdateGnb - request: %v", c.prettifyRequest(r))
98         vars := mux.Vars(r)
99         ranName := vars[ParamRanName]
100
101         request := models.UpdateGnbRequest{}
102
103         gnb := entities.Gnb{}
104
105         if !c.extractRequestBodyToProto(r, &gnb, writer) {
106                 return
107         }
108
109         request.Gnb = &gnb
110         request.RanName = ranName
111         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.UpdateGnbRequest, &request, true, http.StatusOK)
112 }
113
114 func (c *NodebController) UpdateEnb(writer http.ResponseWriter, r *http.Request) {
115         c.logger.Infof("[Client -> E2 Manager] #NodebController.UpdateEnb - request: %v", c.prettifyRequest(r))
116
117         defer r.Body.Close()
118         body, err := ioutil.ReadAll(r.Body)
119
120         if err != nil {
121                 c.logger.Errorf("[Client -> E2 Manager] #NodebController.UpdateEnb - unable to read request body - error: %s", err)
122                 c.handleErrorResponse(e2managererrors.NewInvalidJsonError(), writer)
123                 return
124         }
125
126         updateEnbRequest := models.UpdateEnbRequest{}
127         err = json.Unmarshal(body, &updateEnbRequest)
128
129         if err != nil {
130                 c.logger.Errorf("[Client -> E2 Manager] #NodebController.UpdateEnb - unable to unmarshal json - error: %s", err)
131                 c.handleErrorResponse(e2managererrors.NewInvalidJsonError(), writer)
132                 return
133         }
134
135         vars := mux.Vars(r)
136         ranName := vars[ParamRanName]
137
138         updateEnbRequest.RanName = ranName
139
140         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.UpdateEnbRequest, &updateEnbRequest, true, http.StatusOK)
141 }
142
143 func (c *NodebController) AddEnb(writer http.ResponseWriter, r *http.Request) {
144         c.logger.Infof("[Client -> E2 Manager] #NodebController.AddEnb - request: %v", c.prettifyRequest(r))
145
146         defer r.Body.Close()
147         body, err := ioutil.ReadAll(r.Body)
148
149         if err != nil {
150                 c.logger.Errorf("[Client -> E2 Manager] #NodebController.AddEnb - unable to read request body - error: %s", err)
151                 c.handleErrorResponse(e2managererrors.NewInvalidJsonError(), writer)
152                 return
153         }
154
155         addEnbRequest := models.AddEnbRequest{}
156         err = json.Unmarshal(body, &addEnbRequest)
157
158         if err != nil {
159                 c.logger.Errorf("[Client -> E2 Manager] #NodebController.AddEnb - unable to unmarshal json - error: %s", err)
160                 c.handleErrorResponse(e2managererrors.NewInvalidJsonError(), writer)
161                 return
162         }
163
164         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.AddEnbRequest, &addEnbRequest, true, http.StatusCreated)
165 }
166
167 func (c *NodebController) DeleteEnb(writer http.ResponseWriter, r *http.Request) {
168         c.logger.Infof("[Client -> E2 Manager] #NodebController.DeleteEnb - request: %v", c.prettifyRequest(r))
169         vars := mux.Vars(r)
170         ranName := vars["ranName"]
171         request := &models.DeleteEnbRequest{RanName: ranName}
172         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.DeleteEnbRequest, request, true, http.StatusNoContent)
173 }
174
175 func (c *NodebController) SetGeneralConfiguration(writer http.ResponseWriter, r *http.Request) {
176         c.logger.Infof("[Client -> E2 Manager] #NodebController.SetGeneralConfiguration - request: %v", c.prettifyRequest(r))
177
178         request := models.GeneralConfigurationRequest{}
179
180         if !c.extractJsonBodyDisallowUnknownFields(r, &request, writer) {
181                 return
182         }
183         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.SetGeneralConfigurationRequest, request, false, http.StatusOK)
184 }
185
186 func (c *NodebController) Shutdown(writer http.ResponseWriter, r *http.Request) {
187         c.logger.Infof("[Client -> E2 Manager] #NodebController.Shutdown - request: %v", c.prettifyRequest(r))
188         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.ShutdownRequest, nil, false, http.StatusNoContent)
189 }
190
191 func (c *NodebController) X2Reset(writer http.ResponseWriter, r *http.Request) {
192         c.logger.Infof("[Client -> E2 Manager] #NodebController.X2Reset - request: %v", c.prettifyRequest(r))
193         request := models.ResetRequest{}
194         vars := mux.Vars(r)
195         ranName := vars[ParamRanName]
196
197         if err := c.extractJsonBody(r, &request); err != nil {
198                 c.handleErrorResponse(err, writer)
199                 return
200         }
201         request.RanName = ranName
202         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.ResetRequest, request, false, http.StatusNoContent)
203 }
204
205 func (c *NodebController) HealthCheckRequest(writer http.ResponseWriter, r *http.Request) {
206         c.logger.Infof("[Client -> E2 Manager] #NodebController.HealthCheckRequest - request: %v", c.prettifyRequest(r))
207
208         request := models.HealthCheckRequest{}
209
210         if err := c.extractJsonBody(r, &request); err != nil {
211                 c.handleErrorResponse(err, writer)
212                 return
213         }
214
215         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.HealthCheckRequest, request, true, http.StatusAccepted)
216 }
217
218 func (c *NodebController) extractRequestBodyToProto(r *http.Request, pb proto.Message, writer http.ResponseWriter) bool {
219         defer r.Body.Close()
220
221         err := jsonpb.Unmarshal(r.Body, pb)
222
223         if err != nil {
224                 c.logger.Errorf("[Client -> E2 Manager] #NodebController.extractJsonBody - unable to extract json body - error: %s", err)
225                 c.handleErrorResponse(e2managererrors.NewInvalidJsonError(), writer)
226                 return false
227         }
228
229         return true
230 }
231
232 func (c *NodebController) extractJsonBodyDisallowUnknownFields(r *http.Request, request models.Request, writer http.ResponseWriter) bool {
233         defer r.Body.Close()
234
235         decoder := json.NewDecoder(r.Body)
236         decoder.DisallowUnknownFields()
237
238         if err := decoder.Decode(&request); err != nil {
239                 c.logger.Errorf("[Client -> E2 Manager] #NodebController.extractJsonBody - unable to extract json body - error: %s", err)
240                 c.handleErrorResponse(e2managererrors.NewInvalidJsonError(), writer)
241                 return false
242         }
243
244         return true
245 }
246
247 func (c *NodebController) extractJsonBody(r *http.Request, request models.Request) error {
248         defer r.Body.Close()
249         body, err := ioutil.ReadAll(io.LimitReader(r.Body, LimitRequest))
250
251         if err != nil {
252                 c.logger.Errorf("[Client -> E2 Manager] #NodebController.extractJsonBody - unable to extract json body - error: %s", err)
253                 return e2managererrors.NewInvalidJsonError()
254         }
255
256         err = json.Unmarshal(body, &request)
257         if err != nil {
258                 c.logger.Errorf("[Client -> E2 Manager] #NodebController.extractJsonBody - unable to extract json body - error: %s", err)
259                 return e2managererrors.NewInvalidJsonError()
260         }
261
262         return nil
263 }
264
265 func (c *NodebController) handleRequest(writer http.ResponseWriter, header *http.Header, requestName httpmsghandlerprovider.IncomingRequest, request models.Request, validateRequestHeaders bool, successStatusCode int) {
266
267         if validateRequestHeaders {
268
269                 err := c.validateRequestHeader(header)
270                 if err != nil {
271                         c.handleErrorResponse(err, writer)
272                         return
273                 }
274         }
275
276         handler, err := c.handlerProvider.GetHandler(requestName)
277
278         if err != nil {
279                 c.handleErrorResponse(err, writer)
280                 return
281         }
282
283         response, err := handler.Handle(request)
284
285         if err != nil {
286                 c.handleErrorResponse(err, writer)
287                 return
288         }
289
290         if successStatusCode == http.StatusNoContent {
291                 writer.WriteHeader(successStatusCode)
292                 c.logger.Infof("[E2 Manager -> Client] #NodebController.handleRequest - status response: %v", http.StatusNoContent)
293                 return
294         }
295
296         result, err := response.Marshal()
297
298         if err != nil {
299                 c.handleErrorResponse(err, writer)
300                 return
301         }
302
303         c.logger.Infof("[E2 Manager -> Client] #NodebController.handleRequest - response: %s", result)
304         writer.Header().Set(ContentType, ApplicationJson)
305         writer.WriteHeader(successStatusCode)
306         writer.Write(result)
307 }
308
309 func (c *NodebController) validateRequestHeader(header *http.Header) error {
310
311         if header.Get(ContentType) != ApplicationJson {
312                 c.logger.Errorf("#NodebController.validateRequestHeader - validation failure, incorrect content type")
313
314                 return e2managererrors.NewHeaderValidationError()
315         }
316         return nil
317 }
318
319 func (c *NodebController) handleErrorResponse(err error, writer http.ResponseWriter) {
320
321         var errorResponseDetails models.ErrorResponse
322         var httpError int
323
324         if err != nil {
325                 switch err.(type) {
326                 case *e2managererrors.RnibDbError:
327                         e2Error, _ := err.(*e2managererrors.RnibDbError)
328                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
329                         httpError = http.StatusInternalServerError
330                 case *e2managererrors.CommandAlreadyInProgressError:
331                         e2Error, _ := err.(*e2managererrors.CommandAlreadyInProgressError)
332                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
333                         httpError = http.StatusMethodNotAllowed
334                 case *e2managererrors.HeaderValidationError:
335                         e2Error, _ := err.(*e2managererrors.HeaderValidationError)
336                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
337                         httpError = http.StatusUnsupportedMediaType
338                 case *e2managererrors.WrongStateError:
339                         e2Error, _ := err.(*e2managererrors.WrongStateError)
340                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
341                         httpError = http.StatusBadRequest
342                 case *e2managererrors.RequestValidationError:
343                         e2Error, _ := err.(*e2managererrors.RequestValidationError)
344                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
345                         httpError = http.StatusBadRequest
346                 case *e2managererrors.InvalidJsonError:
347                         e2Error, _ := err.(*e2managererrors.InvalidJsonError)
348                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
349                         httpError = http.StatusBadRequest
350                 case *e2managererrors.RmrError:
351                         e2Error, _ := err.(*e2managererrors.RmrError)
352                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
353                         httpError = http.StatusInternalServerError
354                 case *e2managererrors.ResourceNotFoundError:
355                         e2Error, _ := err.(*e2managererrors.ResourceNotFoundError)
356                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
357                         httpError = http.StatusNotFound
358                 case *e2managererrors.E2TInstanceAbsenceError:
359                         e2Error, _ := err.(*e2managererrors.E2TInstanceAbsenceError)
360                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
361                         httpError = http.StatusServiceUnavailable
362                 case *e2managererrors.RoutingManagerError:
363                         e2Error, _ := err.(*e2managererrors.RoutingManagerError)
364                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
365                         httpError = http.StatusServiceUnavailable
366                 case *e2managererrors.NodebExistsError:
367                         e2Error, _ := err.(*e2managererrors.NodebExistsError)
368                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
369                         httpError = http.StatusBadRequest
370                 case *e2managererrors.NoConnectedRanError:
371                         e2Error, _ := err.(*e2managererrors.NoConnectedRanError)
372                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
373                         httpError = http.StatusNotFound
374                 default:
375                         e2Error := e2managererrors.NewInternalError()
376                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
377                         httpError = http.StatusInternalServerError
378                 }
379         }
380         errorResponse, _ := json.Marshal(errorResponseDetails)
381
382         c.logger.Errorf("[E2 Manager -> Client] #NodebController.handleErrorResponse - http status: %d, error response: %+v", httpError, errorResponseDetails)
383
384         writer.Header().Set(ContentType, ApplicationJson)
385         writer.WriteHeader(httpError)
386         _, err = writer.Write(errorResponse)
387 }
388
389 func (c *NodebController) prettifyRequest(request *http.Request) string {
390         dump, _ := httputil.DumpRequest(request, true)
391         requestPrettyPrint := strings.Replace(string(dump), "\r\n", " ", -1)
392         return strings.Replace(requestPrettyPrint, "\n", "", -1)
393 }