Merge "[SO] Service Level Workflow Execution API"
[so.git] / mso-api-handlers / mso-api-handler-infra / src / main / java / org / onap / so / apihandlerinfra / GlobalHealthcheckHandler.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Modifications Copyright (c) 2019 Samsung
8  * ================================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  * 
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  * 
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.so.apihandlerinfra;
24
25
26 import java.net.URI;
27 import java.util.Collections;
28 import java.util.List;
29 import java.util.stream.Collectors;
30 import javax.annotation.PostConstruct;
31 import javax.transaction.Transactional;
32 import javax.ws.rs.DefaultValue;
33 import javax.ws.rs.GET;
34 import javax.ws.rs.Path;
35 import javax.ws.rs.Produces;
36 import javax.ws.rs.QueryParam;
37 import javax.ws.rs.container.ContainerRequestContext;
38 import javax.ws.rs.core.Context;
39 import javax.ws.rs.core.Response;
40 import javax.ws.rs.core.UriBuilder;
41 import org.apache.http.HttpStatus;
42 import org.onap.so.apihandlerinfra.HealthCheckConfig.Endpoint;
43 import org.onap.so.logger.LoggingAnchor;
44 import org.onap.so.logger.MessageEnum;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47 import org.springframework.beans.factory.annotation.Autowired;
48 import org.springframework.core.env.Environment;
49 import org.springframework.http.HttpEntity;
50 import org.springframework.http.HttpHeaders;
51 import org.springframework.http.HttpMethod;
52 import org.springframework.http.MediaType;
53 import org.springframework.http.ResponseEntity;
54 import org.springframework.stereotype.Component;
55 import org.springframework.web.client.RestTemplate;
56 import io.swagger.v3.oas.annotations.OpenAPIDefinition;
57 import io.swagger.v3.oas.annotations.Operation;
58 import io.swagger.v3.oas.annotations.info.Info;
59 import io.swagger.v3.oas.annotations.media.ArraySchema;
60 import io.swagger.v3.oas.annotations.media.Content;
61 import io.swagger.v3.oas.annotations.media.Schema;
62 import io.swagger.v3.oas.annotations.responses.ApiResponse;
63
64
65 @Component
66 @Path("/globalhealthcheck")
67 @OpenAPIDefinition(info = @Info(title = "/globalhealthcheck", description = "APIH Infra Global Health Check"))
68 public class GlobalHealthcheckHandler {
69     private static Logger logger = LoggerFactory.getLogger(GlobalHealthcheckHandler.class);
70     protected static final String CONTEXTPATH_PROPERTY = "management.endpoints.web.base-path";
71     protected static final String PROPERTY_DOMAIN = "mso.health";
72     protected static final String CATALOGDB_PROPERTY = PROPERTY_DOMAIN + ".endpoints.catalogdb";
73     protected static final String REQUESTDB_PROPERTY = PROPERTY_DOMAIN + ".endpoints.requestdb";
74     protected static final String SDNC_PROPERTY = PROPERTY_DOMAIN + ".endpoints.sdnc";
75     protected static final String OPENSTACK_PROPERTY = PROPERTY_DOMAIN + ".endpoints.openstack";
76     protected static final String BPMN_PROPERTY = PROPERTY_DOMAIN + ".endpoints.bpmn";
77     protected static final String ASDC_PROPERTY = PROPERTY_DOMAIN + ".endpoints.asdc";
78     protected static final String REQUESTDBATTSVC_PROPERTY = PROPERTY_DOMAIN + ".endpoints.requestdbattsvc";
79     protected static final String MSO_AUTH_PROPERTY = PROPERTY_DOMAIN + ".auth";
80     protected static final String DEFAULT_PROPERTY_VALUE = "";
81
82     // e.g. /manage
83     private String actuatorContextPath;
84
85     @Autowired
86     private Environment env;
87
88     @Autowired
89     private RestTemplate restTemplate;
90
91     @Autowired
92     private HealthCheckConfig config;
93
94     private static final String HEALTH = "/health";
95
96     private String msoAuth;
97
98     @PostConstruct
99     protected void init() {
100         actuatorContextPath = env.getProperty(CONTEXTPATH_PROPERTY, String.class, DEFAULT_PROPERTY_VALUE);
101         msoAuth = env.getProperty(MSO_AUTH_PROPERTY, String.class, DEFAULT_PROPERTY_VALUE);
102     }
103
104     @GET
105     @Produces("application/json")
106     @Operation(description = "Performing global health check", responses = @ApiResponse(
107             content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))))
108     @Transactional
109     public Response globalHealthcheck(@DefaultValue("true") @QueryParam("enableBpmn") boolean enableBpmn,
110             @Context ContainerRequestContext requestContext) {
111         Response HEALTH_CHECK_RESPONSE = null;
112         // Build internal response object
113         HealthCheckResponse rsp = new HealthCheckResponse();
114
115         try {
116             // Generated RequestId
117             String requestId = requestContext.getProperty("requestId").toString();
118             logger.info(LoggingAnchor.TWO, MessageEnum.APIH_GENERATED_REQUEST_ID.toString(), requestId);
119
120             List<Endpoint> endpoints = config.getEndpoints().stream().filter(item -> {
121                 if (!enableBpmn && SoSubsystems.BPMN.equals(item.getSubsystem())) {
122                     return false;
123                 } else {
124                     return true;
125                 }
126             }).collect(Collectors.toList());
127
128             for (Endpoint endpoint : endpoints) {
129                 rsp.getSubsystems().add(querySubsystemHealth(endpoint));
130             }
131
132             // set Message
133             rsp.setMessage(String.format("HttpStatus: %s", HttpStatus.SC_OK));
134             logger.info(rsp.toString());
135
136             HEALTH_CHECK_RESPONSE = Response.status(HttpStatus.SC_OK).entity(rsp).build();
137
138         } catch (Exception ex) {
139             logger.error("Exception occurred", ex);
140             rsp.setMessage(ex.getMessage());
141             HEALTH_CHECK_RESPONSE = Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).entity(rsp).build();
142         }
143
144         return HEALTH_CHECK_RESPONSE;
145     }
146
147     protected HttpEntity<String> buildHttpEntityForRequest() {
148         HttpHeaders headers = new HttpHeaders();
149         headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
150         headers.set(HttpHeaders.CONTENT_TYPE, "application/json");
151         headers.set(HttpHeaders.AUTHORIZATION, msoAuth);
152         HttpEntity<String> entity = new HttpEntity<>("parameters", headers);
153         return entity;
154     }
155
156     protected HealthCheckSubsystem querySubsystemHealth(Endpoint subsystem) {
157         HealthCheckStatus status = HealthCheckStatus.DOWN;
158         URI uri = subsystem.getUri();
159         try {
160             // get port number for the subsystem
161             // build final endpoint url
162             uri = UriBuilder.fromUri(subsystem.getUri()).path(actuatorContextPath).path(HEALTH).build();
163             logger.info("Calculated URL: {}", uri);
164
165             ResponseEntity<SubsystemHealthcheckResponse> result = restTemplate.exchange(uri, HttpMethod.GET,
166                     buildHttpEntityForRequest(), SubsystemHealthcheckResponse.class);
167
168             status = processResponseFromSubsystem(result, subsystem);
169
170
171         } catch (Exception ex) {
172             logger.error("Exception occured in GlobalHealthcheckHandler.querySubsystemHealth() ", ex);
173         }
174
175         return new HealthCheckSubsystem(subsystem.getSubsystem(), uri, status);
176     }
177
178     protected HealthCheckStatus processResponseFromSubsystem(ResponseEntity<SubsystemHealthcheckResponse> result,
179             Endpoint endpoint) {
180         if (result == null || result.getStatusCodeValue() != HttpStatus.SC_OK) {
181             logger.error(String.format("Globalhealthcheck: checking subsystem: %s failed ! result object is: %s",
182                     endpoint.getSubsystem(), result == null ? "NULL" : result));
183             return HealthCheckStatus.DOWN;
184         }
185
186         SubsystemHealthcheckResponse body = result.getBody();
187
188         String status = body.getStatus();
189         if ("UP".equalsIgnoreCase(status)) {
190             return HealthCheckStatus.UP;
191         } else {
192             logger.error("{}, query health endpoint did not return UP status!", endpoint.getSubsystem());
193             return HealthCheckStatus.DOWN;
194         }
195     }
196
197 }