Rename "LOGGER" field to match regular expression
[so.git] / adapters / mso-adapter-utils / src / main / java / org / openecomp / mso / openstack / utils / MsoCommonUtils.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
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.openecomp.mso.openstack.utils;
22
23
24 import org.openecomp.mso.logger.MsoAlarmLogger;
25 import org.openecomp.mso.logger.MsoLogger;
26 import org.openecomp.mso.logger.MessageEnum;
27 import org.openecomp.mso.openstack.exceptions.MsoAdapterException;
28 import org.openecomp.mso.openstack.exceptions.MsoException;
29 import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory;
30 import org.openecomp.mso.openstack.exceptions.MsoIOException;
31 import org.openecomp.mso.openstack.exceptions.MsoOpenstackException;
32 import org.openecomp.mso.properties.MsoJavaProperties;
33 import com.woorea.openstack.base.client.OpenStackBaseException;
34 import com.woorea.openstack.base.client.OpenStackConnectException;
35 import com.woorea.openstack.base.client.OpenStackRequest;
36 import com.woorea.openstack.base.client.OpenStackResponseException;
37 import com.woorea.openstack.heat.model.Explanation;
38 import com.woorea.openstack.keystone.model.Error;
39 import com.woorea.openstack.quantum.model.NeutronError;
40
41 public class MsoCommonUtils {
42
43         private static MsoLogger logger = MsoLogger.getMsoLogger(MsoLogger.Catalog.RA);
44         protected static MsoAlarmLogger alarmLogger = new MsoAlarmLogger();
45         
46         protected static String retryDelayProp = "ecomp.mso.adapters.po.retryDelay";
47     protected static String retryCountProp = "ecomp.mso.adapters.po.retryCount";
48     protected static String retryCodesProp = "ecomp.mso.adapters.po.retryCodes";
49         
50         protected static int retryDelayDefault = 5;
51     protected static int retryCountDefault = 3;
52     protected static String retryCodesDefault = "504";
53   
54     /*
55      * Method to execute an Openstack command and track its execution time.
56      * For the metrics log, a category of "Openstack" is used along with a
57      * sub-category that identifies the specific call (using the real
58      * openstack-java-sdk classname of the OpenStackRequest<T> parameter).
59      */
60     
61     protected static <T> T executeAndRecordOpenstackRequest (OpenStackRequest <T> request)
62     {
63         return executeAndRecordOpenstackRequest (request, null);
64     }
65     protected static <T> T executeAndRecordOpenstackRequest (OpenStackRequest <T> request, MsoJavaProperties msoProps) {
66         
67         int limit;
68         // Get the name and method name of the parent class, which triggered this method
69         StackTraceElement[] classArr = new Exception ().getStackTrace ();
70         if (classArr.length >=2) {
71                 limit = 3;
72         } else {
73                 limit = classArr.length;
74         }
75         String parentServiceMethodName = classArr[0].getClassName () + "." + classArr[0].getMethodName ();
76         for (int i = 1; i < limit; i++) {
77             String className = classArr[i].getClassName ();
78             if (!className.equals (MsoCommonUtils.class.getName ())) {
79                 parentServiceMethodName = className + "." + classArr[i].getMethodName ();
80                 break;
81             }
82         }
83
84         long start = System.currentTimeMillis ();
85         String requestType;
86         if (request.getClass ().getEnclosingClass () != null) {
87             requestType = request.getClass ().getEnclosingClass ().getSimpleName () + "."
88                           + request.getClass ().getSimpleName ();
89         } else {
90             requestType = request.getClass ().getSimpleName ();
91         }
92         
93         int retryDelay = retryDelayDefault;
94         int retryCount = retryCountDefault;
95         String retryCodes  = retryCodesDefault;
96         if (msoProps != null) //extra check to avoid NPE
97         {
98                 retryDelay = msoProps.getIntProperty (retryDelayProp, retryDelayDefault);
99                 retryCount = msoProps.getIntProperty (retryCountProp, retryCountDefault);
100                 retryCodes = msoProps.getProperty (retryCodesProp, retryCodesDefault);
101         }
102         
103         // Run the actual command. All exceptions will be propagated
104         while (true)
105         {
106                 try {
107                 return request.execute ();
108                 } 
109                 catch (OpenStackResponseException e) {
110                         boolean retry = false;
111                         if (retryCodes != null ) {
112                                 int code = e.getStatus();
113                     logger.debug ("Config values RetryDelay:" + retryDelay + " RetryCount:" + retryCount + " RetryCodes:" + retryCodes + " ResponseCode:" + code);
114                                 for (String rCode : retryCodes.split (",")) {
115                                         try {
116                                                 if (retryCount > 0 && code == Integer.parseInt (rCode))
117                                                 {
118                                                         retryCount--;
119                                                         retry = true;
120                                 logger.debug ("OpenStackResponseException ResponseCode:" + code +  " at:" + parentServiceMethodName + " request:" + requestType +  " Retry indicated. Attempts remaining:" + retryCount);
121                                                         break;
122                                                 }
123                                         } catch (NumberFormatException e1) {
124                             logger.error (MessageEnum.RA_CONFIG_EXC, "No retries. Exception in parsing retry code in config:" + rCode, "", "", MsoLogger.ErrorCode.SchemaError, "Exception in parsing retry code in config");
125                                                 throw e;
126                                         }
127                                 }
128                         }
129                         if (retry)
130                         {
131                                 try {
132                                         Thread.sleep (retryDelay * 1000L);
133                                 } catch (InterruptedException e1) {
134                         logger.debug ("Thread interrupted while sleeping", e1);
135                                 }
136                         }
137                         else
138                                 throw e; // exceeded retryCount or code is not retryable
139                 }
140                 catch (OpenStackConnectException e) {
141                         // Connection to Openstack failed
142                         if (retryCount > 0)
143                         {
144                                 retryCount--;
145                     logger.debug ("OpenstackConnectException at:" + parentServiceMethodName + " request:" + requestType + " Retry indicated. Attempts remaining:" + retryCount);
146                                 try {
147                                         Thread.sleep (retryDelay * 1000L);
148                                 } catch (InterruptedException e1) {
149                         logger.debug ("Thread interrupted while sleeping", e1);
150                                 }
151                         }
152                         else
153                                 throw e;
154                                 
155                 }
156         }
157     }
158   
159     /*
160      * Convert an Openstack Exception on a Keystone call to an MsoException.
161      * This method supports both OpenstackResponseException and OpenStackConnectException.
162      */
163     protected static MsoException keystoneErrorToMsoException (OpenStackBaseException e, String context) {
164         MsoException me = null;
165
166         if (e instanceof OpenStackResponseException) {
167             OpenStackResponseException re = (OpenStackResponseException) e;
168
169             try {
170                 // Failed Keystone calls return an Error entity body.
171                 Error error = re.getResponse ().getErrorEntity (Error.class);
172                 logger.error (MessageEnum.RA_CONNECTION_EXCEPTION, "Openstack Keystone Error on " + context + ": " + error, "Openstack", "", MsoLogger.ErrorCode.DataError, "Openstack Keystone Error on " + context);
173                                 me = new MsoOpenstackException (error.getCode (), error.getTitle (), error.getMessage ());
174             } catch (Exception e2) {
175                 // Can't parse the body as an "Error". Report the HTTP error
176                 logger.error (MessageEnum.RA_CONNECTION_EXCEPTION, "HTTP Error on " + context + ": " + re.getStatus() + "," + re.getMessage(), "Openstack", "", MsoLogger.ErrorCode.DataError, "HTTP Error on " + context, e2);
177                                 me = new MsoOpenstackException (re.getStatus (), re.getMessage (), "");
178             }
179
180             // Add the context of the error
181             me.addContext (context);
182
183             // Generate an alarm for 5XX and higher errors.
184             if (re.getStatus () >= 500) {
185                 alarmLogger.sendAlarm ("KeystoneError", MsoAlarmLogger.CRITICAL, me.getContextMessage ());
186             }
187         } else if (e instanceof OpenStackConnectException) {
188             OpenStackConnectException ce = (OpenStackConnectException) e;
189
190             me = new MsoIOException (ce.getMessage ());
191             me.addContext (context);
192
193             // Generate an alarm for all connection errors.
194             logger.error(MessageEnum.RA_GENERAL_EXCEPTION_ARG, "Openstack Keystone connection error on " + context + ": " + e, "Openstack", "", MsoLogger.ErrorCode.DataError, "Openstack Keystone connection error on " + context);
195                         alarmLogger.sendAlarm ("KeystoneIOError", MsoAlarmLogger.CRITICAL, me.getContextMessage ());
196         }
197
198         return me;
199     }
200
201     /*
202      * Convert an Openstack Exception on a Heat call to an MsoOpenstackException.
203      * This method supports both OpenstackResponseException and OpenStackConnectException.
204      */
205     protected MsoException heatExceptionToMsoException (OpenStackBaseException e, String context) {
206         MsoException me = null;
207
208         if (e instanceof OpenStackResponseException) {
209             OpenStackResponseException re = (OpenStackResponseException) e;
210
211             try {
212                 // Failed Heat calls return an Explanation entity body.
213                 Explanation explanation = re.getResponse ().getErrorEntity (Explanation.class);
214                 logger.error (MessageEnum.RA_CONNECTION_EXCEPTION, "OpenStack", "Openstack Error on " + context + ": " + explanation.toString(), "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception - Openstack Error on " + context);
215                 String fullError = explanation.getExplanation() + ", error.type=" + explanation.getError().getType() + ", error.message=" + explanation.getError().getMessage();
216                 logger.debug(fullError);
217                                 me = new MsoOpenstackException (explanation.getCode (),
218                                                 explanation.getTitle (),
219                                                 //explanation.getExplanation ());
220                                                 fullError);
221             } catch (Exception e2) {
222                 // Couldn't parse the body as an "Explanation". Report the original HTTP error.
223                 logger.error (MessageEnum.RA_CONNECTION_EXCEPTION, "OpenStack", "HTTP Error on " + context + ": " + re.getStatus() + "," + e.getMessage(), "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception - HTTP Error on " + context, e2);
224                                 me = new MsoOpenstackException (re.getStatus (), re.getMessage (), "");
225             }
226
227             // Add the context of the error
228             me.addContext (context);
229
230             // Generate an alarm for 5XX and higher errors.
231             if (re.getStatus () >= 500) {
232                 alarmLogger.sendAlarm ("HeatError", MsoAlarmLogger.CRITICAL, me.getContextMessage ());
233             }
234         } else if (e instanceof OpenStackConnectException) {
235             OpenStackConnectException ce = (OpenStackConnectException) e;
236
237             me = new MsoIOException (ce.getMessage ());
238             me.addContext (context);
239
240             // Generate an alarm for all connection errors.
241             alarmLogger.sendAlarm ("HeatIOError", MsoAlarmLogger.CRITICAL, me.getContextMessage ());
242             logger.error(MessageEnum.RA_CONNECTION_EXCEPTION, "OpenStack", "Openstack Heat connection error on " + context + ": " + e, "Openstack", "", MsoLogger.ErrorCode.DataError, "Openstack Heat connection error on " + context);
243         }
244
245         return me;
246     }
247
248     /*
249      * Convert an Openstack Exception on a Neutron call to an MsoOpenstackException.
250      * This method supports both OpenstackResponseException and OpenStackConnectException.
251      */
252     protected MsoException neutronExceptionToMsoException (OpenStackBaseException e, String context) {
253         MsoException me = null;
254
255         if (e instanceof OpenStackResponseException) {
256             OpenStackResponseException re = (OpenStackResponseException) e;
257
258             try {
259                 // Failed Neutron calls return an NeutronError entity body
260                 NeutronError error = re.getResponse ().getErrorEntity (NeutronError.class);
261                 logger.error (MessageEnum.RA_CONNECTION_EXCEPTION, "OpenStack", "Openstack Neutron Error on " + context + ": " + error, "Openstack", "", MsoLogger.ErrorCode.DataError, "Openstack Neutron Error on " + context);
262                                 me = new MsoOpenstackException (re.getStatus (), error.getType (), error.getMessage ());
263             } catch (Exception e2) {
264                 // Couldn't parse body as a NeutronError. Report the HTTP error.
265                 logger.error (MessageEnum.RA_CONNECTION_EXCEPTION, "OpenStack", "HTTP Error on " + context + ": " + re.getStatus() + "," + e.getMessage(), "Openstack", "", MsoLogger.ErrorCode.DataError, "Openstack HTTP Error on " + context, e2);
266                                 me = new MsoOpenstackException (re.getStatus (), re.getMessage (), null);
267             }
268
269             // Add the context of the error
270             me.addContext (context);
271
272             // Generate an alarm for 5XX and higher errors.
273             if (re.getStatus () >= 500) {
274                 alarmLogger.sendAlarm ("NeutronError", MsoAlarmLogger.CRITICAL, me.getContextMessage ());
275             }
276         } else if (e instanceof OpenStackConnectException) {
277             OpenStackConnectException ce = (OpenStackConnectException) e;
278
279             me = new MsoIOException (ce.getMessage ());
280             me.addContext (context);
281
282             // Generate an alarm for all connection errors.
283             alarmLogger.sendAlarm ("NeutronIOError", MsoAlarmLogger.CRITICAL, me.getContextMessage ());
284             logger.error(MessageEnum.RA_CONNECTION_EXCEPTION, "OpenStack", "Openstack Neutron Connection error on "+ context + ": " + e, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Openstack Neutron Connection error on "+ context);
285         }
286
287         return me;
288     }
289
290     /*
291      * Convert a Java Runtime Exception to an MsoException.
292      * All Runtime exceptions will be translated into an MsoAdapterException,
293      * which captures internal errors.
294      * Alarms will be generated on all such exceptions.
295      */
296     protected MsoException runtimeExceptionToMsoException (RuntimeException e, String context) {
297         MsoAdapterException me = new MsoAdapterException (e.getMessage (), e);
298         me.addContext (context);
299         me.setCategory (MsoExceptionCategory.INTERNAL);
300
301         // Always generate an alarm for internal exceptions
302         logger.error(MessageEnum.RA_GENERAL_EXCEPTION_ARG, "An exception occured on  "+ context + ": " + e, "OpenStack", "", MsoLogger.ErrorCode.DataError, "An exception occured on  "+ context);
303                 alarmLogger.sendAlarm ("AdapterInternalError", MsoAlarmLogger.CRITICAL, me.getContextMessage ());
304
305         return me;
306     }
307
308     public static boolean isNullOrEmpty (String s) {
309         return s == null || s.isEmpty();
310     }
311     
312     
313
314 }