re base code
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / distribution / engine / DmaapHealth.java
1 package org.openecomp.sdc.be.components.distribution.engine;
2
3 import org.apache.commons.validator.routines.UrlValidator;
4 import org.apache.http.client.utils.URIUtils;
5 import org.openecomp.sdc.be.config.BeEcompErrorManager;
6 import org.openecomp.sdc.be.config.ConfigurationManager;
7 import org.openecomp.sdc.be.config.DmaapConsumerConfiguration;
8 import org.openecomp.sdc.common.api.HealthCheckInfo;
9 import org.openecomp.sdc.common.log.wrappers.Logger;
10 import org.springframework.stereotype.Component;
11
12 import javax.annotation.PostConstruct;
13 import javax.annotation.PreDestroy;
14 import java.io.IOException;
15 import java.net.InetAddress;
16 import java.net.URI;
17 import java.net.URISyntaxException;
18 import java.util.concurrent.Executors;
19 import java.util.concurrent.ScheduledExecutorService;
20 import java.util.concurrent.ScheduledFuture;
21 import java.util.concurrent.TimeUnit;
22 import java.util.concurrent.atomic.AtomicBoolean;
23
24 import static org.apache.commons.lang3.StringUtils.countMatches;
25 import static org.apache.commons.lang3.StringUtils.isNotBlank;
26 import static org.openecomp.sdc.common.api.Constants.HC_COMPONENT_DMAAP_ENGINE;
27
28 @Component("dmaapHealth")
29 public class DmaapHealth {
30
31
32     private static final String DMAAP_HEALTH_LOG_CONTEXT = "dmaap.healthcheck";
33     private static final String DMAAP_HEALTH_CHECK_STR = "dmaapHealthCheck";
34     private static final Logger log = Logger.getLogger(DmaapHealth.class.getName());
35     private static final Logger logHealth = Logger.getLogger(DMAAP_HEALTH_LOG_CONTEXT);
36     private HealthCheckInfo healthCheckInfo = DmaapHealth.HealthCheckInfoResult.UNAVAILABLE.getHealthCheckInfo();
37     private long healthCheckReadTimeout = 20;
38     private long reconnectInterval = 5;
39     private HealthCheckScheduledTask healthCheckScheduledTask = null ;
40     private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
41     private ScheduledFuture<?> scheduledFuture = null;
42     private DmaapConsumerConfiguration configuration = null ;
43
44     private volatile AtomicBoolean lastHealthState = new AtomicBoolean(false);
45     private volatile AtomicBoolean reportedHealthState = null;
46
47     public enum HealthCheckInfoResult {
48         OK(new HealthCheckInfo(HC_COMPONENT_DMAAP_ENGINE, HealthCheckInfo.HealthCheckStatus.UP, null, DmaapStatusDescription.OK.getDescription())),
49         UNAVAILABLE(new HealthCheckInfo(HC_COMPONENT_DMAAP_ENGINE, HealthCheckInfo.HealthCheckStatus.DOWN, null, DmaapStatusDescription.UNAVAILABLE.getDescription())),
50         DOWN(new HealthCheckInfo(HC_COMPONENT_DMAAP_ENGINE, HealthCheckInfo.HealthCheckStatus.DOWN, null, DmaapStatusDescription.DOWN.getDescription()));
51
52         private HealthCheckInfo healthCheckInfo;
53         HealthCheckInfoResult(HealthCheckInfo healthCheckInfo) {
54             this.healthCheckInfo = healthCheckInfo;
55         }
56         public HealthCheckInfo getHealthCheckInfo() {
57             return healthCheckInfo;
58         }
59     }
60
61     public enum DmaapStatusDescription {
62         OK("OK"), UNAVAILABLE("Dmaap is not available"),DOWN("DOWN"), NOT_CONFIGURED("Dmaap configuration is missing/wrong ");
63
64         private String desc;
65         DmaapStatusDescription(String desc) {
66             this.desc = desc;
67         }
68         public String getDescription() {
69             return desc;
70         }
71
72     }
73
74     @PostConstruct
75     public DmaapHealth init() {
76         log.trace("Enter init method of Dmaap health");
77         synchronized (DmaapHealth.class){
78             this.configuration = ConfigurationManager.getConfigurationManager().getConfiguration().getDmaapConsumerConfiguration();
79
80             Integer pollingInterval = configuration.getPollingInterval();
81             if (pollingInterval != null && pollingInterval!=0) {
82                 reconnectInterval = pollingInterval;
83             }
84             Integer healthCheckReadTimeoutConfig = configuration.getTimeoutMs();
85             if (healthCheckReadTimeoutConfig != null) {
86                 this.healthCheckReadTimeout = healthCheckReadTimeoutConfig;
87             }
88             this.healthCheckScheduledTask = new HealthCheckScheduledTask( configuration ); //what is the representation? csv? delimiter? json or other
89             startHealthCheckTask(true);
90         }
91         log.trace("Exit init method of DistributionEngineClusterHealth");
92         return this;
93     }
94
95     @PreDestroy
96     protected void destroy() {
97         if (scheduledFuture != null) {
98             scheduledFuture.cancel(true);
99             scheduledFuture = null;
100         }
101         if (scheduler != null) {
102             scheduler.shutdown();
103         }
104     }
105
106     /**
107      * Start health check task.
108      *
109      * @param startTask
110      */
111     private void startHealthCheckTask(boolean startTask) {
112         synchronized (DmaapHealth.class){
113             if (startTask && this.scheduledFuture == null) {
114                 this.scheduledFuture = this.scheduler.scheduleAtFixedRate(this.healthCheckScheduledTask , 0, reconnectInterval, TimeUnit.SECONDS);
115             }
116         }
117     }
118
119     void report(Boolean isUp){
120         if (reportedHealthState == null)
121             reportedHealthState = new AtomicBoolean(isUp);
122         reportedHealthState.set(isUp);
123     }
124
125
126     public HealthCheckInfo getHealthCheckInfo() {
127         return healthCheckInfo;
128     }
129
130     /**
131      * Health Check Task Scheduler - infinite check.
132      */
133     public class HealthCheckScheduledTask implements Runnable {
134         private final DmaapConsumerConfiguration config;
135         private static final int TIMEOUT = 8192;
136
137         HealthCheckScheduledTask(final DmaapConsumerConfiguration config){
138             this.config = config;
139         }
140         @Override
141         public void run() {
142             logHealth.trace("Executing Dmaap Health Check Task - Start");
143             boolean prevIsReachable;
144             boolean reachable;
145             //first try simple ping
146             try{
147                 if ( reportedHealthState != null ){
148                     reachable = reportedHealthState.get();
149                 }
150                 else{
151                     reachable =  false;
152                 }
153                 prevIsReachable = lastHealthState.getAndSet( reachable );
154                 healthCheckInfo = reachable ? HealthCheckInfoResult.OK.healthCheckInfo : HealthCheckInfoResult.DOWN.healthCheckInfo;
155             }
156             catch( Exception e ){
157                 log.debug("{} | cannot check connectivity -> {}",DMAAP_HEALTH_CHECK_STR, e );
158                 prevIsReachable = lastHealthState.getAndSet(false);
159                 healthCheckInfo = HealthCheckInfoResult.UNAVAILABLE.healthCheckInfo;
160             }
161             if (prevIsReachable != lastHealthState.get())
162                 logAlarm( lastHealthState.get() );
163         }
164
165
166         /**
167          * @deprecated (health is reported outside from EnvironmentEngine consumer fetch)
168          */
169         @Deprecated
170         public boolean isICMPReachable( ) throws IOException{
171             try{
172                 String hostname = getUrlHost(config.getHosts());
173                 return InetAddress.getByName( hostname ).isReachable(TIMEOUT);
174             }catch( URISyntaxException e ){
175                 log.debug("{} | malformed host configuration -> ",DMAAP_HEALTH_CHECK_STR , e);
176             }
177             return false;
178         }
179
180         private void logAlarm(boolean lastHealthState) {
181             try{
182                 if ( lastHealthState ) {
183                     BeEcompErrorManager.getInstance().logDmaapHealthCheckRecovery( DMAAP_HEALTH_CHECK_STR );
184                 } else {
185                     BeEcompErrorManager.getInstance().logDmaapHealthCheckError( DMAAP_HEALTH_CHECK_STR );
186                 }
187             }catch( Exception e ){
188                 log.debug("cannot logAlarm -> {}" ,e );
189             }
190         }
191
192     }
193
194     public static String getUrlHost(String qualifiedHost) throws URISyntaxException{
195         //region - parse complex format ex. <http://URL:PORT>
196         try{
197             UrlValidator validator = new UrlValidator();
198             if (validator.isValid(qualifiedHost)){
199                 return URIUtils.extractHost(new URI(qualifiedHost)).getHostName();
200             }else{
201                 log.debug("{} | invalid url format, continuing ", DMAAP_HEALTH_CHECK_STR );
202             }
203         }catch(URISyntaxException e){
204             log.debug("{} | invalid url format, continuing {} ", DMAAP_HEALTH_CHECK_STR , e);
205         }
206         //endregion
207
208         //region - try shortcut format <URL> or <URL:PORT>
209         if ( countMatches( qualifiedHost , ":") <= 1){
210             String[] address = qualifiedHost.split(":");
211             if ( address.length>0 && isNotBlank(address[0]) ){
212                 return address[0];
213             }
214         }
215         //endregion
216         throw new URISyntaxException( qualifiedHost , "invalid hostname, expecting a single <host:port> ,  (valid ex. www.google.com:80 | www.google.com | http:\\\\www.google.com:8181)");
217     }
218 }