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