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