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