f599e3dc0ff8802f897f4c4ba89b326e44b7c35f
[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 org.onap.policy.drools.statemanagement.StateManagementProperties;
24
25 import java.util.ArrayList;
26 import java.util.Properties;
27
28 import org.onap.policy.common.im.IntegrityMonitor;
29 import org.onap.policy.common.im.IntegrityMonitorException;
30 import org.onap.policy.drools.http.server.HttpServletServer;
31 import org.onap.policy.drools.properties.Startable;
32 import org.onap.policy.drools.utils.PropertyUtil;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 /**
37  * This class extends 'IntegrityMonitor' for use in the 'Drools PDP'
38  * virtual machine. The included audits are 'Database' and 'Repository'.
39  */
40 public class DroolsPDPIntegrityMonitor extends IntegrityMonitor
41 {
42         
43         private static final String INVALID_PROPERTY_VALUE = "init: property {} does not have the expected value of {}";
44
45 // get an instance of logger 
46   private static final Logger  logger = LoggerFactory.getLogger(DroolsPDPIntegrityMonitor.class);       
47
48   // static global instance
49   private static DroolsPDPIntegrityMonitor im = null;
50
51   // list of audits to run
52   private static AuditBase[] audits =
53         new AuditBase[]{DbAudit.getInstance(), RepositoryAudit.getInstance()};
54   
55   private static Properties subsystemTestProperties = null;
56
57   private static final String PROPERTIES_NAME = "feature-state-management.properties";
58
59   /**
60    * Constructor - pass arguments to superclass, but remember properties
61    * @param resourceName unique name of this Integrity Monitor
62    * @param url the JMX URL of the MBean server
63    * @param properties properties used locally, as well as by
64    *    'IntegrityMonitor'
65    * @throws Exception (passed from superclass)
66    */
67         private DroolsPDPIntegrityMonitor(String resourceName,
68                         Properties consolidatedProperties
69                         ) throws Exception {
70         super(resourceName, consolidatedProperties);
71   }
72   
73   private static void missingProperty(String prop) throws StateManagementPropertiesException{
74                 String msg = "init: missing IntegrityMonitor property: ".concat(prop);
75                 logger.error(msg);
76                 throw new StateManagementPropertiesException(msg);
77   }
78   
79   private static void logPropertyValue(String prop, String val){
80           if(logger.isInfoEnabled()){
81                   String msg = "\n\n    init: property: " + prop + " = " + val + "\n";
82                   logger.info(msg);
83           }
84   }
85   /**
86    * Static initialization -- create Drools Integrity Monitor, and
87    * an HTTP server to handle REST 'test' requests
88    */
89   public static DroolsPDPIntegrityMonitor init(String configDir) throws Exception
90   {
91                   
92         logger.info("init: Entering and invoking PropertyUtil.getProperties() on '{}'", configDir);
93                 
94         // read in properties
95         Properties stateManagementProperties =
96           PropertyUtil.getProperties(configDir + "/" + PROPERTIES_NAME);
97         // fetch and verify definitions of some properties
98         // (the 'IntegrityMonitor' constructor does some additional verification)
99         String testHost = stateManagementProperties.getProperty(StateManagementProperties.TEST_HOST);
100         String testPort = stateManagementProperties.getProperty(StateManagementProperties.TEST_PORT);
101         String testServices = stateManagementProperties.getProperty(StateManagementProperties.TEST_SERVICES,
102                         StateManagementProperties.TEST_SERVICES_DEFAULT);
103         String testRestClasses = stateManagementProperties.getProperty(StateManagementProperties.TEST_REST_CLASSES, 
104                         StateManagementProperties.TEST_REST_CLASSES_DEFAULT);
105         String testManaged = stateManagementProperties.getProperty(StateManagementProperties.TEST_MANAGED,
106                         StateManagementProperties.TEST_MANAGED_DEFAULT);
107         String testSwagger = stateManagementProperties.getProperty(StateManagementProperties.TEST_SWAGGER,
108                         StateManagementProperties.TEST_SWAGGER_DEFAULT);
109         String resourceName = stateManagementProperties.getProperty(StateManagementProperties.RESOURCE_NAME);
110         String fpMonitorInterval = stateManagementProperties.getProperty(StateManagementProperties.FP_MONITOR_INTERVAL);
111         String failedCounterThreshold = stateManagementProperties.getProperty(StateManagementProperties.FAILED_COUNTER_THRESHOLD);
112         String testTransInterval = stateManagementProperties.getProperty(StateManagementProperties.TEST_TRANS_INTERVAL);
113         String writeFpcInterval = stateManagementProperties.getProperty(StateManagementProperties.WRITE_FPC_INTERVAL);
114         String siteName = stateManagementProperties.getProperty(StateManagementProperties.SITE_NAME);
115         String nodeType = stateManagementProperties.getProperty(StateManagementProperties.NODE_TYPE);
116         String dependencyGroups = stateManagementProperties.getProperty(StateManagementProperties.DEPENDENCY_GROUPS);
117         String javaxPersistenceJdbcDriver = stateManagementProperties.getProperty(StateManagementProperties.DB_DRIVER);
118         String javaxPersistenceJdbcUrl = stateManagementProperties.getProperty(StateManagementProperties.DB_URL);
119         String javaxPersistenceJdbcUser = stateManagementProperties.getProperty(StateManagementProperties.DB_USER);
120         String javaxPersistenceJdbcPassword = stateManagementProperties.getProperty(StateManagementProperties.DB_PWD);
121
122         if (testHost == null){
123                 missingProperty(StateManagementProperties.TEST_HOST);
124         }
125         if (testPort == null){
126                 missingProperty(StateManagementProperties.TEST_PORT);
127         }
128         if (!testServices.equals(StateManagementProperties.TEST_SERVICES_DEFAULT)){
129                 logger.error(INVALID_PROPERTY_VALUE,
130                                 StateManagementProperties.TEST_SERVICES,
131                                 StateManagementProperties.TEST_SERVICES_DEFAULT);
132         }
133         if (!testRestClasses.equals(StateManagementProperties.TEST_REST_CLASSES_DEFAULT)){
134                 logger.error(INVALID_PROPERTY_VALUE,
135                                 StateManagementProperties.TEST_REST_CLASSES,
136                                 StateManagementProperties.TEST_REST_CLASSES_DEFAULT);
137         }
138         if (!testManaged.equals(StateManagementProperties.TEST_MANAGED_DEFAULT)){
139                 logger.warn(INVALID_PROPERTY_VALUE,
140                                 StateManagementProperties.TEST_MANAGED,
141                                 StateManagementProperties.TEST_MANAGED_DEFAULT);
142         }
143         if (!testSwagger.equals(StateManagementProperties.TEST_SWAGGER_DEFAULT)){
144                 logger.warn(INVALID_PROPERTY_VALUE,
145                                 StateManagementProperties.TEST_SWAGGER,
146                                 StateManagementProperties.TEST_SWAGGER_DEFAULT);
147         }
148         if (resourceName == null){
149                 missingProperty(StateManagementProperties.RESOURCE_NAME);
150           }
151         if (fpMonitorInterval == null){
152                 missingProperty(StateManagementProperties.FP_MONITOR_INTERVAL);
153           }     
154         if (failedCounterThreshold == null){
155                 missingProperty(StateManagementProperties.FAILED_COUNTER_THRESHOLD);
156           }     
157         if (testTransInterval == null){
158                 missingProperty(StateManagementProperties.TEST_TRANS_INTERVAL);
159           }     
160         if (writeFpcInterval == null){
161                 missingProperty(StateManagementProperties.WRITE_FPC_INTERVAL);
162           }     
163         if (siteName == null){
164                 missingProperty(StateManagementProperties.SITE_NAME);
165           }     
166         if (nodeType == null){
167                 missingProperty(StateManagementProperties.NODE_TYPE);
168           }     
169         if (dependencyGroups == null){
170                 missingProperty(StateManagementProperties.DEPENDENCY_GROUPS);
171           }     
172         if (javaxPersistenceJdbcDriver == null){
173                 missingProperty(StateManagementProperties.DB_DRIVER);
174           }             
175         if (javaxPersistenceJdbcUrl == null){
176                 missingProperty(StateManagementProperties.DB_URL);
177           }                     
178         if (javaxPersistenceJdbcUser == null){
179                 missingProperty(StateManagementProperties.DB_USER);
180           }                     
181         if (javaxPersistenceJdbcPassword == null){
182                 missingProperty(StateManagementProperties.DB_PWD);
183           }
184         
185         //Log the values so we can diagnose any issues
186         logPropertyValue(StateManagementProperties.TEST_HOST,testHost);
187         logPropertyValue(StateManagementProperties.TEST_PORT,testPort);
188         logPropertyValue(StateManagementProperties.TEST_SERVICES,testServices);
189         logPropertyValue(StateManagementProperties.TEST_REST_CLASSES,testRestClasses);
190         logPropertyValue(StateManagementProperties.TEST_MANAGED,testManaged);
191         logPropertyValue(StateManagementProperties.TEST_SWAGGER,testSwagger);
192         logPropertyValue(StateManagementProperties.RESOURCE_NAME,resourceName);
193         logPropertyValue(StateManagementProperties.FP_MONITOR_INTERVAL,fpMonitorInterval);
194         logPropertyValue(StateManagementProperties.FAILED_COUNTER_THRESHOLD,failedCounterThreshold);
195         logPropertyValue(StateManagementProperties.TEST_TRANS_INTERVAL,testTransInterval);
196         logPropertyValue(StateManagementProperties.WRITE_FPC_INTERVAL,writeFpcInterval);
197         logPropertyValue(StateManagementProperties.SITE_NAME,siteName);
198         logPropertyValue(StateManagementProperties.NODE_TYPE,nodeType);
199         logPropertyValue(StateManagementProperties.DEPENDENCY_GROUPS,dependencyGroups);
200         logPropertyValue(StateManagementProperties.DB_DRIVER,javaxPersistenceJdbcDriver);
201         logPropertyValue(StateManagementProperties.DB_URL,javaxPersistenceJdbcUrl);
202         logPropertyValue(StateManagementProperties.DB_USER,javaxPersistenceJdbcUser);
203         logPropertyValue(StateManagementProperties.DB_PWD,javaxPersistenceJdbcPassword);
204                 
205         subsystemTestProperties = stateManagementProperties;
206
207         // Now that we've validated the properties, create Drools Integrity Monitor
208         // with these properties.
209         im = new DroolsPDPIntegrityMonitor(resourceName,
210                                 stateManagementProperties);
211         logger.info("init: New DroolsPDPIntegrityMonitor instantiated, resourceName = ", resourceName);
212
213         // create http server
214         try {
215                 logger.info("init: Starting HTTP server, addr= {}", testHost+":"+testPort);
216                 IntegrityMonitorRestServer server = new IntegrityMonitorRestServer();
217                 
218                 server.init(stateManagementProperties);
219         } catch (Exception e) {
220                 logger.error("init: Caught Exception attempting to start server on testPort= {} message:",
221                                                                 testPort, e);
222                 throw e;
223         }
224         
225         logger.info("init: Exiting and returning DroolsPDPIntegrityMonitor");
226         return im;
227   }
228
229   /**
230    * Run tests (audits) unique to Drools PDP VM (Database + Repository)
231    */
232   @Override
233         public void subsystemTest() throws IntegrityMonitorException
234   {
235         logger.info("DroolsPDPIntegrityMonitor.subsystemTest called");
236
237         // clear all responses (non-null values indicate an error)
238         for (AuditBase audit : audits)
239           {
240                 audit.setResponse(null);
241           }
242
243         // invoke all of the audits
244         for (AuditBase audit : audits)
245           {
246                 try
247                   {
248                         // invoke the audit (responses are stored within the audit object)
249                         audit.invoke(subsystemTestProperties);
250                   }
251                 catch (Exception e)
252                   {
253                         logger.error("{} audit error", audit.getName(), e);
254                         if (audit.getResponse() == null)
255                           {
256                                 // if there is no current response, use the exception message
257                                 audit.setResponse(e.getMessage());
258                           }
259                   }
260           }
261         
262           // will contain list of subsystems where the audit failed
263           String responseMsg = "";
264
265           // Loop through all of the audits, and see which ones have failed.
266           // NOTE: response information is stored within the audit objects
267           // themselves -- only one can run at a time.
268           for (AuditBase audit : audits)
269                 {
270                   String response = audit.getResponse();
271                   if (response != null)
272                         {
273                           // the audit has failed -- add subsystem and 
274                           // and 'responseValue' with the new information
275                           responseMsg = responseMsg.concat("\n" + audit.getName() + ": " + response);
276                         }
277                 }
278           
279           if(!responseMsg.isEmpty()){
280                   throw new IntegrityMonitorException(responseMsg);
281           }
282   }
283
284   /* ============================================================ */
285
286   /**
287    * This is the base class for audits invoked in 'subsystemTest'
288    */
289   public abstract static class AuditBase
290   {
291         // name of the audit
292         protected String name;
293
294         // non-null indicates the error response
295         protected String response;
296
297         /**
298          * Constructor - initialize the name, and clear the initial response
299          * @param name name of the audit
300          */
301         public AuditBase(String name)
302         {
303           this.name = name;
304           this.response = null;
305         }
306
307         /**
308          * @return the name of this audit
309          */
310         public String getName()
311         {
312           return name;
313         }
314
315         /**
316          * @return the response String (non-null indicates the error message)
317          */
318         public String getResponse()
319         {
320           return response;
321         }
322
323         /**
324          * Set the response string to the specified value
325          * @param value the new value of the response string (null = no errors)
326          */
327         public void setResponse(String value)
328         {
329           response = value;
330         }
331
332         /**
333          * Abstract method to invoke the audit
334          * @param persistenceProperties Used for DB access
335          * @throws Exception passed in by the audit
336          */
337         abstract void invoke(Properties persistenceProperties) throws Exception;
338   }
339   
340         public static class IntegrityMonitorRestServer implements Startable {
341                 protected volatile HttpServletServer server = null;
342                 protected volatile Properties integrityMonitorRestServerProperties = null;
343                 
344                 public void init(Properties props) {
345                         this.integrityMonitorRestServerProperties = props;
346                         this.start();
347                 }
348                 
349                 @Override
350                 public boolean start() {
351                         try {
352                                 ArrayList<HttpServletServer> servers = HttpServletServer.factory.build(integrityMonitorRestServerProperties);
353                                 
354                                 if (!servers.isEmpty()) {
355                                         server = servers.get(0);
356                                         
357                                         waitServerStart();
358                                 }
359                         } catch (Exception e) {
360                                 logger.error("Exception building servers", e);
361                                 return false;
362                         }
363                         
364                         return true;
365                 }
366
367                 private void waitServerStart() {
368                         try {
369                                 server.waitedStart(5);
370                         } catch (Exception e) {
371                                 logger.error("Exception waiting for servers to start: ", e);
372                         }
373                 }
374
375                 @Override
376                 public boolean stop() {
377                         try {
378                                 server.stop();
379                         } catch (Exception e) {
380                                 logger.error("Exception during stop", e);
381                         }
382                         
383                         return true;
384                 }
385
386                 @Override
387                 public void shutdown() {
388                         this.stop();
389                 }
390                 
391                 @Override
392                 public synchronized boolean isAlive() {
393                         return this.integrityMonitorRestServerProperties != null;
394                 }
395         }
396
397         public static DroolsPDPIntegrityMonitor getInstance() throws Exception{
398                 if(logger.isDebugEnabled()){
399                         logger.debug("getInstance() called");
400                 }
401                 if (im == null) {
402                         String msg = "No DroolsPDPIntegrityMonitor instance exists."
403                                         + " Please use the method DroolsPDPIntegrityMonitor init(String configDir)";
404                         throw new Exception(msg);
405                 }else{
406                         return im;
407                 }
408         }
409 }