[CCSDK-1985]GR Toolkit Refactor
[ccsdk/sli/plugins.git] / grToolkit / provider / src / main / java / org / onap / ccsdk / sli / plugins / grtoolkit / resolver / HealthResolver.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * openECOMP : SDN-C
4  * ================================================================================
5  * Copyright (C) 2019 AT&T Intellectual Property. All rights
6  *                      reserved.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.ccsdk.sli.plugins.grtoolkit.resolver;
23
24 import org.json.JSONException;
25 import org.json.JSONObject;
26
27 import org.onap.ccsdk.sli.core.dblib.DbLibService;
28 import org.onap.ccsdk.sli.plugins.grtoolkit.connection.ConnectionManager;
29 import org.onap.ccsdk.sli.plugins.grtoolkit.connection.ConnectionResponse;
30 import org.onap.ccsdk.sli.plugins.grtoolkit.data.AdminHealth;
31 import org.onap.ccsdk.sli.plugins.grtoolkit.data.ClusterActor;
32 import org.onap.ccsdk.sli.plugins.grtoolkit.data.ClusterHealth;
33 import org.onap.ccsdk.sli.plugins.grtoolkit.data.DatabaseHealth;
34 import org.onap.ccsdk.sli.plugins.grtoolkit.data.FailoverStatus;
35 import org.onap.ccsdk.sli.plugins.grtoolkit.data.Health;
36 import org.onap.ccsdk.sli.plugins.grtoolkit.data.PropertyKeys;
37 import org.onap.ccsdk.sli.plugins.grtoolkit.data.SiteHealth;
38
39 import org.opendaylight.yang.gen.v1.org.onap.ccsdk.sli.plugins.gr.toolkit.rev180926.FailoverInput;
40
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 import java.io.IOException;
45 import java.sql.Connection;
46 import java.sql.SQLException;
47 import java.util.List;
48 import java.util.Map;
49 import java.util.Properties;
50
51 import static org.onap.ccsdk.sli.plugins.grtoolkit.data.Health.HEALTHY;
52
53 /**
54  * Abstract class for the Health Resolver system, which allows for custom logic
55  * to be implemented, while leaving inputs/outputs generic and architecture
56  * agnostic. This class provides some simple implementations of both Admin and
57  * Database health checking, but leaves cluster and site health determinations
58  * up to the implementer. Useful implementation examples can be found in the
59  * {@code SingleNodeHealthResolver}, {@code ThreeNodeHealthResolver}, and
60  * {@code SixNodeHealthResolver} classes.
61  *
62  * @author Anthony Haddox
63  * @see org.onap.ccsdk.sli.plugins.grtoolkit.GrToolkitProvider
64  * @see SingleNodeHealthResolver
65  * @see ThreeNodeHealthResolver
66  * @see SixNodeHealthResolver
67  */
68 public abstract class HealthResolver {
69     private final Logger log = LoggerFactory.getLogger(HealthResolver.class);
70     static final String OUTPUT = "output";
71     final String httpProtocol;
72     final String controllerPort;
73     final String credentials;
74     final Map<String, ClusterActor> memberMap;
75     private DbLibService dbLib;
76     final ShardResolver shardResolver;
77     private String adminPath;
78     private String siteIdentifier;
79
80     /**
81      * Constructs the health resolver used by the {@code GrToolkitProvider} to
82      * determine the health of the application components.
83      *
84      * @param map a HashMap containing all of the nodes in the akka cluster
85      * @param properties the properties passed ino the provider
86      * @param dbLib a reference to the {@code DbLibService} of the provider
87      * @see org.onap.ccsdk.sli.plugins.grtoolkit.GrToolkitProvider
88      */
89     HealthResolver(Map<String, ClusterActor> map, Properties properties, DbLibService dbLib) {
90         log.info("Creating {}", this.getClass().getCanonicalName());
91         this.memberMap = map;
92         this.dbLib = dbLib;
93         shardResolver = ShardResolver.getInstance(properties);
94
95         String adminProtocol = "true".equals(properties.getProperty(PropertyKeys.ADM_USE_SSL)) ? "https://" : "http://";
96         String adminPort = "true".equals(properties.getProperty(PropertyKeys.ADM_USE_SSL)) ? properties.getProperty(PropertyKeys.ADM_PORT_SSL) : properties.getProperty(PropertyKeys.ADM_PORT_HTTP);
97         adminPath = adminProtocol + properties.getProperty(PropertyKeys.ADM_FQDN) + ":" + adminPort + properties.getProperty(PropertyKeys.ADM_HEALTHCHECK);
98         siteIdentifier = properties.getProperty(PropertyKeys.SITE_IDENTIFIER).trim();
99
100         controllerPort = "true".equals(properties.getProperty(PropertyKeys.CONTROLLER_USE_SSL).trim()) ? properties.getProperty(PropertyKeys.CONTROLLER_PORT_SSL).trim() : properties.getProperty(PropertyKeys.CONTROLLER_PORT_HTTP).trim();
101         httpProtocol = "true".equals(properties.getProperty(PropertyKeys.CONTROLLER_USE_SSL).trim()) ? "https://" : "http://";
102         if(siteIdentifier == null || siteIdentifier.isEmpty()) {
103             siteIdentifier = properties.getProperty(PropertyKeys.SITE_IDENTIFIER).trim();
104         }
105         credentials = properties.getProperty(PropertyKeys.CONTROLLER_CREDENTIALS).trim();
106     }
107
108     public abstract ClusterHealth getClusterHealth();
109     public abstract List<SiteHealth> getSiteHealth();
110     public abstract FailoverStatus tryFailover(FailoverInput input);
111     public abstract void resolveSites();
112
113     /**
114      * Gets a connection to the admin portal. If the status code is 200, the
115      * admin portal is assumed to be healthy.
116      *
117      * @return an {@code AdminHealth} object with health of the admin portal
118      * @see org.onap.ccsdk.sli.plugins.grtoolkit.GrToolkitProvider
119      * @see AdminHealth
120      */
121     public AdminHealth getAdminHealth() {
122         log.info("getAdminHealth(): Requesting health check from {}", adminPath);
123         try {
124             ConnectionResponse response = ConnectionManager.getConnectionResponse(adminPath, ConnectionManager.HttpMethod.GET, null, null);
125             Health health = (response.statusCode == 200) ? HEALTHY : Health.FAULTY;
126             AdminHealth adminHealth = new AdminHealth(health, response.statusCode);
127             log.info("getAdminHealth(): Response: {}", response);
128             return adminHealth;
129         } catch(IOException e) {
130             log.error("getAdminHealth(): Problem getting ADM health.", e);
131             return new AdminHealth(Health.FAULTY, 500);
132         }
133     }
134
135     /**
136      * Uses {@code DbLibService} to get a connection to the database. If
137      * {@code DbLibService} is active and the connection it returns is not read
138      * only, the database(s) is assumed to be healthy.
139      *
140      * @return an {@code DatabaseHealth} object with health of the database
141      * @see org.onap.ccsdk.sli.plugins.grtoolkit.GrToolkitProvider
142      * @see DatabaseHealth
143      */
144     public DatabaseHealth getDatabaseHealth() {
145         log.info("getDatabaseHealth(): Determining database health...");
146         try (Connection connection = dbLib.getConnection()){
147             log.debug("getDatabaseHealth(): DBLib isActive(): {}", dbLib.isActive());
148             log.debug("getDatabaseHealth(): DBLib isReadOnly(): {}", connection.isReadOnly());
149             log.debug("getDatabaseHealth(): DBLib isClosed(): {}", connection.isClosed());
150             if(!dbLib.isActive() || connection.isClosed() || connection.isReadOnly()) {
151                 log.warn("getDatabaseHealth(): Database is FAULTY");
152                 return new DatabaseHealth(Health.FAULTY);
153             }
154             log.info("getDatabaseHealth(): Database is HEALTHY");
155         } catch(SQLException e) {
156             log.error("getDatabaseHealth(): Database is FAULTY");
157             log.error("getDatabaseHealth(): Error", e);
158             return new DatabaseHealth(Health.FAULTY);
159         }
160
161         return new DatabaseHealth(HEALTHY);
162     }
163
164     /**
165      * Utility method to see if an input is healthy.
166      *
167      * @return true if the input is healthy
168      * @see Health
169      */
170     boolean isHealthy(Health h) {
171         return HEALTHY == h;
172     }
173
174     public String getSiteIdentifier() {
175         return siteIdentifier;
176     }
177
178     public void setSiteIdentifier(String siteIdentifier) {
179         this.siteIdentifier = siteIdentifier;
180     }
181
182     /**
183      * Used to invoke the admin-health or database-health RPC to check if that
184      * component is healthy.
185      *
186      * @param path the path to the admin-health or database-health RPCs
187      * @return true if the component is healthy
188      * @throws IOException if a connection cannot be obtained
189      */
190     boolean isRemoteComponentHealthy(String path) throws IOException {
191         String content = ConnectionManager.getConnectionResponse(path, ConnectionManager.HttpMethod.POST, null, credentials).content;
192         try {
193             JSONObject responseJson = new JSONObject(content);
194             JSONObject responseValue = responseJson.getJSONObject(OUTPUT);
195             return HEALTHY.toString().equals(responseValue.getString("health"));
196         } catch(JSONException e) {
197             log.error("Error parsing JSON", e);
198             throw new IOException();
199         }
200     }
201
202     /**
203      * Checks a {@code ClusterActor} object to see if the node is healthy.
204      *
205      * @param controller the controller to check
206      * @return true if the controller is up and reachable
207      * @see ClusterActor
208      */
209     public boolean isControllerHealthy(ClusterActor controller) {
210         return (controller.isUp() && ! controller.isUnreachable());
211     }
212 }