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