46bba914e76995a3dd885ba6dc1b463906c7f054
[policy/drools-pdp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * feature-state-management
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.drools.statemanagement;
22
23 import java.io.IOException;
24 import java.util.ArrayList;
25 import java.util.Properties;
26 import org.onap.policy.common.im.IntegrityMonitor;
27 import org.onap.policy.common.im.IntegrityMonitorException;
28 import org.onap.policy.drools.http.server.HttpServletServer;
29 import org.onap.policy.drools.properties.Startable;
30 import org.onap.policy.drools.utils.PropertyUtil;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 /**
35  * This class extends 'IntegrityMonitor' for use in the 'Drools PDP'
36  * virtual machine. The included audits are 'Database' and 'Repository'.
37  */
38 public class DroolsPDPIntegrityMonitor extends IntegrityMonitor
39 {
40         
41         private static final String INVALID_PROPERTY_VALUE = "init: property {} does not have the expected value of {}";
42
43 // get an instance of logger 
44   private static final Logger  logger = LoggerFactory.getLogger(DroolsPDPIntegrityMonitor.class);       
45
46   // static global instance
47   private static DroolsPDPIntegrityMonitor im = null;
48
49   // list of audits to run
50   private static AuditBase[] audits =
51         new AuditBase[]{DbAudit.getInstance(), RepositoryAudit.getInstance()};
52   
53   private static Properties subsystemTestProperties = null;
54
55   private static final String PROPERTIES_NAME = "feature-state-management.properties";
56
57   /**
58    * Constructor - pass arguments to superclass, but remember properties
59    * @param resourceName unique name of this Integrity Monitor
60    * @param url the JMX URL of the MBean server
61    * @param properties properties used locally, as well as by
62    *    'IntegrityMonitor'
63    * @throws Exception (passed from superclass)
64    */
65         private DroolsPDPIntegrityMonitor(String resourceName,
66                         Properties consolidatedProperties
67                         ) throws Exception {
68         super(resourceName, consolidatedProperties);
69   }
70   
71   private static void missingProperty(String prop) throws IntegrityMonitorException{
72                 String msg = "init: missing IntegrityMonitor property: ".concat(prop);
73                 logger.error(msg);
74                 throw new IntegrityMonitorException(msg);
75   }
76   
77   private static void logPropertyValue(String prop, String val){
78           if(logger.isInfoEnabled()){
79                   String msg = "\n\n    init: property: " + prop + " = " + val + "\n";
80                   logger.info(msg);
81           }
82   }
83   
84   /**
85    * Static initialization -- create Drools Integrity Monitor, and
86    * an HTTP server to handle REST 'test' requests
87    * @throws StateManagementPropertiesException
88    * @throws IntegrityMonitorException 
89    */
90   public static DroolsPDPIntegrityMonitor init(String configDir) throws IntegrityMonitorException
91   {
92                   
93         logger.info("init: Entering and invoking PropertyUtil.getProperties() on '{}'", configDir);
94                 
95         // read in properties
96         Properties stateManagementProperties = getProperties(configDir);
97         
98         // fetch and verify definitions of some properties, adding defaults where
99         // appropriate
100         // (the 'IntegrityMonitor' constructor does some additional verification)
101         
102         checkPropError(stateManagementProperties, StateManagementProperties.TEST_HOST);
103         checkPropError(stateManagementProperties, StateManagementProperties.TEST_PORT);
104
105         addDefaultPropError(stateManagementProperties,
106                         StateManagementProperties.TEST_SERVICES,
107                         StateManagementProperties.TEST_SERVICES_DEFAULT);
108         
109         addDefaultPropError(stateManagementProperties,
110                         StateManagementProperties.TEST_REST_CLASSES,
111                         StateManagementProperties.TEST_REST_CLASSES_DEFAULT);
112
113         addDefaultPropWarn(stateManagementProperties,
114                         StateManagementProperties.TEST_MANAGED,
115                         StateManagementProperties.TEST_MANAGED_DEFAULT);
116         
117         addDefaultPropWarn(stateManagementProperties,
118                         StateManagementProperties.TEST_SWAGGER,
119                         StateManagementProperties.TEST_SWAGGER_DEFAULT);
120         
121         checkPropError(stateManagementProperties, StateManagementProperties.RESOURCE_NAME);
122         checkPropError(stateManagementProperties, StateManagementProperties.FP_MONITOR_INTERVAL);
123         checkPropError(stateManagementProperties, StateManagementProperties.FAILED_COUNTER_THRESHOLD);
124         checkPropError(stateManagementProperties, StateManagementProperties.TEST_TRANS_INTERVAL);
125         checkPropError(stateManagementProperties, StateManagementProperties.WRITE_FPC_INTERVAL);
126         checkPropError(stateManagementProperties, StateManagementProperties.SITE_NAME);
127         checkPropError(stateManagementProperties, StateManagementProperties.NODE_TYPE);
128         checkPropError(stateManagementProperties, StateManagementProperties.DEPENDENCY_GROUPS);
129         checkPropError(stateManagementProperties, StateManagementProperties.DB_DRIVER);
130         checkPropError(stateManagementProperties, StateManagementProperties.DB_URL);
131         checkPropError(stateManagementProperties, StateManagementProperties.DB_USER);
132         checkPropError(stateManagementProperties, StateManagementProperties.DB_PWD);
133         
134         String testHost = stateManagementProperties.getProperty(StateManagementProperties.TEST_HOST);
135         String testPort = stateManagementProperties.getProperty(StateManagementProperties.TEST_PORT);
136         String resourceName = stateManagementProperties.getProperty(StateManagementProperties.RESOURCE_NAME);
137
138         subsystemTestProperties = stateManagementProperties;
139
140         // Now that we've validated the properties, create Drools Integrity Monitor
141         // with these properties.
142         im = makeMonitor(resourceName, stateManagementProperties);
143         logger.info("init: New DroolsPDPIntegrityMonitor instantiated, resourceName = ", resourceName);
144
145         // create http server
146         makeRestServer(testHost, testPort, stateManagementProperties);
147         logger.info("init: Exiting and returning DroolsPDPIntegrityMonitor");
148         
149         return im;
150   }
151
152   /**
153    * Makes an Integrity Monitor.
154    * @param resourceName unique name of this Integrity Monitor
155    * @param properties properties used to configure the Integrity Monitor
156    * @return
157    * @throws IntegrityMonitorException
158    */
159   private static DroolsPDPIntegrityMonitor makeMonitor(String resourceName, Properties properties)
160                 throws IntegrityMonitorException {
161           
162         try {
163                 return new DroolsPDPIntegrityMonitor(resourceName, properties);
164                 
165         } catch (Exception e) {
166                 throw new IntegrityMonitorException(e);
167         }
168   }
169
170   /**
171    * Makes a rest server for the Integrity Monitor.
172    * @param testHost            host name
173    * @param testPort            port
174    * @param properties          properties used to configure the rest server
175    * @throws IntegrityMonitorException
176    */
177   private static void makeRestServer(String testHost, String testPort, Properties properties)
178                 throws IntegrityMonitorException {
179           
180         try {
181                 logger.info("init: Starting HTTP server, addr= {}", testHost+":"+testPort);
182                 
183                 IntegrityMonitorRestServer server = new IntegrityMonitorRestServer();
184                 server.init(properties);
185                 
186         } catch (Exception e) {
187                 logger.error("init: Caught Exception attempting to start server on testPort= {} message:",
188                                                                 testPort, e);
189                 throw new IntegrityMonitorException(e);
190         }
191   }
192
193   /**
194    * Gets the properties from the property file.
195    * @param configDir   directory containing the property file
196    * @return the properties
197    * @throws IntegrityMonitorException 
198    */
199   private static Properties getProperties(String configDir) throws IntegrityMonitorException {
200         try {
201                 return PropertyUtil.getProperties(configDir + "/" + PROPERTIES_NAME);
202                 
203         } catch (IOException e) {
204                 throw new IntegrityMonitorException(e);
205         }
206   }
207   
208   /**
209    * Checks that a property is defined.
210    * @param props       set of properties
211    * @param name        name of the property to check
212    * @throws IntegrityMonitorException
213    */
214   private static void checkPropError(Properties props, String name) throws IntegrityMonitorException {
215           String val = props.getProperty(name);
216           if(val == null) {
217                   missingProperty(name);
218           }
219           
220           logPropertyValue(name, val);
221   }
222   
223   /**
224    * Checks a property's value to verify that it matches the expected value.
225    * If the property is not defined, then it is added to the property set,
226    * with the expected value.  Logs an error if the property is defined,
227    * but does not have the expected value.
228    * @param props               set of properties
229    * @param name                name of the property to check
230    * @param expected    expected/default value
231    */
232   private static void addDefaultPropError(Properties props, String name, String expected) {
233           String val = props.getProperty(name);
234           if(val == null) {
235                   props.setProperty(name, expected);
236                   
237           } else if( ! val.equals(expected)) {
238                   logger.error(INVALID_PROPERTY_VALUE, name, expected);
239           }
240           
241           logPropertyValue(name, val);
242   }
243   
244   /**
245    * Checks a property's value to verify that it matches the expected value.
246    * If the property is not defined, then it is added to the property set,
247    * with the expected value.  Logs a warning if the property is defined,
248    * but does not have the expected value.
249    * @param props               set of properties
250    * @param name                name of the property to check
251    * @param expected    expected/default value
252    */
253   private static void addDefaultPropWarn(Properties props, String name, String dflt) {
254           String val = props.getProperty(name);
255           if(val == null) {
256                   props.setProperty(name, dflt);
257                   
258           } else if( ! val.equals(dflt)) {
259                   logger.warn(INVALID_PROPERTY_VALUE, name, dflt);
260           }
261           
262           logPropertyValue(name, val);
263   }
264
265   /**
266    * Run tests (audits) unique to Drools PDP VM (Database + Repository)
267    */
268   @Override
269         public void subsystemTest() throws IntegrityMonitorException
270   {
271         logger.info("DroolsPDPIntegrityMonitor.subsystemTest called");
272
273         // clear all responses (non-null values indicate an error)
274         for (AuditBase audit : audits)
275           {
276                 audit.setResponse(null);
277           }
278
279         // invoke all of the audits
280         for (AuditBase audit : audits)
281           {
282                 try
283                   {
284                         // invoke the audit (responses are stored within the audit object)
285                         audit.invoke(subsystemTestProperties);
286                   }
287                 catch (Exception e)
288                   {
289                         logger.error("{} audit error", audit.getName(), e);
290                         if (audit.getResponse() == null)
291                           {
292                                 // if there is no current response, use the exception message
293                                 audit.setResponse(e.getMessage());
294                           }
295                   }
296           }
297         
298           // will contain list of subsystems where the audit failed
299           String responseMsg = "";
300
301           // Loop through all of the audits, and see which ones have failed.
302           // NOTE: response information is stored within the audit objects
303           // themselves -- only one can run at a time.
304           for (AuditBase audit : audits)
305                 {
306                   String response = audit.getResponse();
307                   if (response != null)
308                         {
309                           // the audit has failed -- add subsystem and 
310                           // and 'responseValue' with the new information
311                           responseMsg = responseMsg.concat("\n" + audit.getName() + ": " + response);
312                         }
313                 }
314           
315           if(!responseMsg.isEmpty()){
316                   throw new IntegrityMonitorException(responseMsg);
317           }
318   }
319
320   /* ============================================================ */
321
322   /**
323    * This is the base class for audits invoked in 'subsystemTest'
324    */
325   public abstract static class AuditBase
326   {
327         // name of the audit
328         protected String name;
329
330         // non-null indicates the error response
331         protected String response;
332
333         /**
334          * Constructor - initialize the name, and clear the initial response
335          * @param name name of the audit
336          */
337         public AuditBase(String name)
338         {
339           this.name = name;
340           this.response = null;
341         }
342
343         /**
344          * @return the name of this audit
345          */
346         public String getName()
347         {
348           return name;
349         }
350
351         /**
352          * @return the response String (non-null indicates the error message)
353          */
354         public String getResponse()
355         {
356           return response;
357         }
358
359         /**
360          * Set the response string to the specified value
361          * @param value the new value of the response string (null = no errors)
362          */
363         public void setResponse(String value)
364         {
365           response = value;
366         }
367
368         /**
369          * Abstract method to invoke the audit
370          * @param persistenceProperties Used for DB access
371          * @throws Exception passed in by the audit
372          */
373         abstract void invoke(Properties persistenceProperties) throws Exception;
374   }
375   
376         public static class IntegrityMonitorRestServer implements Startable {
377                 protected volatile HttpServletServer server = null;
378                 protected volatile Properties integrityMonitorRestServerProperties = null;
379                 
380                 public void init(Properties props) {
381                         this.integrityMonitorRestServerProperties = props;
382                         this.start();
383                 }
384                 
385                 @Override
386                 public boolean start() {
387                         try {
388                                 ArrayList<HttpServletServer> servers = HttpServletServer.factory.build(integrityMonitorRestServerProperties);
389                                 
390                                 if (!servers.isEmpty()) {
391                                         server = servers.get(0);
392                                         
393                                         waitServerStart();
394                                 }
395                         } catch (Exception e) {
396                                 logger.error("Exception building servers", e);
397                                 return false;
398                         }
399                         
400                         return true;
401                 }
402
403                 private void waitServerStart() {
404                         try {
405                                 server.waitedStart(5);
406                         } catch (Exception e) {
407                                 logger.error("Exception waiting for servers to start: ", e);
408                         }
409                 }
410
411                 @Override
412                 public boolean stop() {
413                         try {
414                                 server.stop();
415                         } catch (Exception e) {
416                                 logger.error("Exception during stop", e);
417                         }
418                         
419                         return true;
420                 }
421
422                 @Override
423                 public void shutdown() {
424                         this.stop();
425                 }
426                 
427                 @Override
428                 public synchronized boolean isAlive() {
429                         return this.integrityMonitorRestServerProperties != null;
430                 }
431         }
432
433         public static DroolsPDPIntegrityMonitor getInstance() throws IntegrityMonitorException{
434                 if(logger.isDebugEnabled()){
435                         logger.debug("getInstance() called");
436                 }
437                 if (im == null) {
438                         String msg = "No DroolsPDPIntegrityMonitor instance exists."
439                                         + " Please use the method DroolsPDPIntegrityMonitor init(String configDir)";
440                         throw new IntegrityMonitorException(msg);
441                 }else{
442                         return im;
443                 }
444         }
445 }