sync from Azure to LF
[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/e2managererrors"
22         "e2mgr/logger"
23         "e2mgr/models"
24         "e2mgr/providers/httpmsghandlerprovider"
25         "encoding/json"
26         "github.com/gorilla/mux"
27         "io"
28         "io/ioutil"
29         "net/http"
30         "net/http/httputil"
31         "strings"
32 )
33
34 const (
35         ParamRanName = "ranName"
36         LimitRequest = 2000
37 )
38
39 type INodebController interface {
40         Shutdown(writer http.ResponseWriter, r *http.Request)
41         X2Reset(writer http.ResponseWriter, r *http.Request)
42         X2Setup(writer http.ResponseWriter, r *http.Request)
43         EndcSetup(writer http.ResponseWriter, r *http.Request)
44         GetNodeb(writer http.ResponseWriter, r *http.Request)
45         GetNodebIdList(writer http.ResponseWriter, r *http.Request)
46 }
47
48 type NodebController struct {
49         logger          *logger.Logger
50         handlerProvider *httpmsghandlerprovider.IncomingRequestHandlerProvider
51 }
52
53 func NewNodebController(logger *logger.Logger, handlerProvider *httpmsghandlerprovider.IncomingRequestHandlerProvider) *NodebController {
54         return &NodebController{
55                 logger:          logger,
56                 handlerProvider: handlerProvider,
57         }
58 }
59
60 func (c *NodebController) GetNodebIdList(writer http.ResponseWriter, r *http.Request) {
61         c.logger.Infof("[Client -> E2 Manager] #NodebController.GetNodebIdList - request: %v", c.prettifyRequest(r))
62
63         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.GetNodebIdListRequest, nil, false)
64 }
65
66 func (c *NodebController) GetNodeb(writer http.ResponseWriter, r *http.Request) {
67         c.logger.Infof("[Client -> E2 Manager] #NodebController.GetNodeb - request: %v", c.prettifyRequest(r))
68         vars := mux.Vars(r)
69         ranName := vars["ranName"]
70         request := models.GetNodebRequest{RanName: ranName}
71         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.GetNodebRequest, request, false)
72 }
73
74 func (c *NodebController) Shutdown(writer http.ResponseWriter, r *http.Request) {
75         c.logger.Infof("[Client -> E2 Manager] #NodebController.Shutdown - request: %v", c.prettifyRequest(r))
76         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.ShutdownRequest, nil, false)
77 }
78
79 func (c *NodebController) X2Reset(writer http.ResponseWriter, r *http.Request) {
80         c.logger.Infof("[Client -> E2 Manager] #NodebController.X2Reset - request: %v", c.prettifyRequest(r))
81         request := models.ResetRequest{}
82         vars := mux.Vars(r)
83         ranName := vars[ParamRanName]
84
85         if r.ContentLength > 0 && !c.extractJsonBody(r, &request, writer) {
86                 return
87         }
88         request.RanName = ranName
89         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.ResetRequest, request, false)
90 }
91
92 func (c *NodebController) X2Setup(writer http.ResponseWriter, r *http.Request) {
93         c.logger.Infof("[Client -> E2 Manager] #NodebController.X2Setup - request: %v", c.prettifyRequest(r))
94
95         request := models.SetupRequest{}
96
97         if !c.extractJsonBody(r, &request, writer) {
98                 return
99         }
100
101         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.X2SetupRequest, request, true)
102 }
103
104 func (c *NodebController) EndcSetup(writer http.ResponseWriter, r *http.Request) {
105         c.logger.Infof("[Client -> E2 Manager] #NodebController.EndcSetup - request: %v", c.prettifyRequest(r))
106
107         request := models.SetupRequest{}
108
109         if !c.extractJsonBody(r, &request, writer) {
110                 return
111         }
112
113         c.handleRequest(writer, &r.Header, httpmsghandlerprovider.EndcSetupRequest, request, true)
114 }
115
116 func (c *NodebController) extractJsonBody(r *http.Request, request models.Request, writer http.ResponseWriter) bool {
117         defer r.Body.Close()
118         body, err := ioutil.ReadAll(io.LimitReader(r.Body, LimitRequest))
119
120         if err != nil {
121                 c.logger.Errorf("[Client -> E2 Manager] #NodebController.extractJsonBody - unable to extract json body - error: %s", err)
122                 c.handleErrorResponse(e2managererrors.NewInvalidJsonError(), writer)
123                 return false
124         }
125
126         err = json.Unmarshal(body, &request)
127         if err != nil {
128                 c.logger.Errorf("[Client -> E2 Manager] #NodebController.extractJsonBody - unable to extract json body - error: %s", err)
129                 c.handleErrorResponse(e2managererrors.NewInvalidJsonError(), writer)
130                 return false
131         }
132
133         return true
134 }
135
136 func (c *NodebController) handleRequest(writer http.ResponseWriter, header *http.Header, requestName httpmsghandlerprovider.IncomingRequest, request models.Request, validateHeader bool) {
137
138         if validateHeader {
139
140                 err := c.validateRequestHeader(header)
141                 if err != nil {
142                         c.handleErrorResponse(err, writer)
143                         return
144                 }
145         }
146
147         handler, err := c.handlerProvider.GetHandler(requestName)
148
149         if err != nil {
150                 c.handleErrorResponse(err, writer)
151                 return
152         }
153
154         response, err := handler.Handle(request)
155
156         if err != nil {
157                 c.handleErrorResponse(err, writer)
158                 return
159         }
160
161         if response == nil {
162                 writer.WriteHeader(http.StatusNoContent)
163                 c.logger.Infof("[E2 Manager -> Client] #NodebController.handleRequest - status response: %v", http.StatusNoContent)
164                 return
165         }
166
167         result, err := response.Marshal()
168
169         if err != nil {
170                 c.handleErrorResponse(err, writer)
171                 return
172         }
173
174         c.logger.Infof("[E2 Manager -> Client] #NodebController.handleRequest - response: %s", result)
175         writer.Header().Set("Content-Type", "application/json")
176         writer.Write([]byte(result))
177 }
178
179 func (c *NodebController) validateRequestHeader(header *http.Header) error {
180
181         if header.Get("Content-Type") != "application/json" {
182                 c.logger.Errorf("#NodebController.validateRequestHeader - validation failure, incorrect content type")
183
184                 return e2managererrors.NewHeaderValidationError()
185         }
186         return nil
187 }
188
189 func (c *NodebController) handleErrorResponse(err error, writer http.ResponseWriter) {
190
191         var errorResponseDetails models.ErrorResponse
192         var httpError int
193
194         if err != nil {
195                 switch err.(type) {
196                 case *e2managererrors.RnibDbError:
197                         e2Error, _ := err.(*e2managererrors.RnibDbError)
198                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
199                         httpError = http.StatusInternalServerError
200                 case *e2managererrors.CommandAlreadyInProgressError:
201                         e2Error, _ := err.(*e2managererrors.CommandAlreadyInProgressError)
202                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
203                         httpError = http.StatusMethodNotAllowed
204                 case *e2managererrors.HeaderValidationError:
205                         e2Error, _ := err.(*e2managererrors.HeaderValidationError)
206                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
207                         httpError = http.StatusUnsupportedMediaType
208                 case *e2managererrors.WrongStateError:
209                         e2Error, _ := err.(*e2managererrors.WrongStateError)
210                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
211                         httpError = http.StatusBadRequest
212                 case *e2managererrors.RequestValidationError:
213                         e2Error, _ := err.(*e2managererrors.RequestValidationError)
214                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
215                         httpError = http.StatusBadRequest
216                 case *e2managererrors.InvalidJsonError:
217                         e2Error, _ := err.(*e2managererrors.InvalidJsonError)
218                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
219                         httpError = http.StatusBadRequest
220                 case *e2managererrors.RmrError:
221                         e2Error, _ := err.(*e2managererrors.RmrError)
222                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
223                         httpError = http.StatusInternalServerError
224                 case *e2managererrors.ResourceNotFoundError:
225                         e2Error, _ := err.(*e2managererrors.ResourceNotFoundError)
226                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
227                         httpError = http.StatusNotFound
228
229                 default:
230                         e2Error := e2managererrors.NewInternalError()
231                         errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message}
232                         httpError = http.StatusInternalServerError
233                 }
234         }
235         errorResponse, _ := json.Marshal(errorResponseDetails)
236
237         c.logger.Errorf("[E2 Manager -> Client] #NodebController.handleErrorResponse - http status: %d, error response: %+v", httpError, errorResponseDetails)
238
239         writer.Header().Set("Content-Type", "application/json")
240         writer.WriteHeader(httpError)
241         _, err = writer.Write(errorResponse)
242
243         if err != nil {
244                 c.logger.Errorf("#NodebController.handleErrorResponse - Cannot send response. writer:%v", writer)
245         }
246 }
247
248 func (c *NodebController) prettifyRequest(request *http.Request) string {
249         dump, _ := httputil.DumpRequest(request, true)
250         requestPrettyPrint := strings.Replace(string(dump), "\r\n", " ", -1)
251         return strings.Replace(requestPrettyPrint, "\n", "", -1)
252 }