2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.openecomp.mso.openstack.utils;
24 import java.lang.StackTraceElement;
25 import org.openecomp.mso.logger.MsoAlarmLogger;
26 import org.openecomp.mso.logger.MsoLogger;
27 import org.openecomp.mso.logger.MessageEnum;
28 import org.openecomp.mso.openstack.exceptions.MsoAdapterException;
29 import org.openecomp.mso.openstack.exceptions.MsoException;
30 import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory;
31 import org.openecomp.mso.openstack.exceptions.MsoIOException;
32 import org.openecomp.mso.openstack.exceptions.MsoOpenstackException;
33 import org.openecomp.mso.properties.MsoJavaProperties;
34 import com.woorea.openstack.base.client.OpenStackBaseException;
35 import com.woorea.openstack.base.client.OpenStackConnectException;
36 import com.woorea.openstack.base.client.OpenStackRequest;
37 import com.woorea.openstack.base.client.OpenStackResponseException;
38 import com.woorea.openstack.heat.model.Explanation;
39 import com.woorea.openstack.keystone.model.Error;
40 import com.woorea.openstack.quantum.model.NeutronError;
42 public class MsoCommonUtils {
44 private static MsoLogger LOGGER = MsoLogger.getMsoLogger(MsoLogger.Catalog.RA);
45 protected static MsoAlarmLogger alarmLogger = new MsoAlarmLogger();
47 protected static String retryDelayProp = "ecomp.mso.adapters.po.retryDelay";
48 protected static String retryCountProp = "ecomp.mso.adapters.po.retryCount";
49 protected static String retryCodesProp = "ecomp.mso.adapters.po.retryCodes";
51 protected static int retryDelayDefault = 5;
52 protected static int retryCountDefault = 3;
53 protected static String retryCodesDefault = "504";
56 * Method to execute an Openstack command and track its execution time.
57 * For the metrics log, a category of "Openstack" is used along with a
58 * sub-category that identifies the specific call (using the real
59 * openstack-java-sdk classname of the OpenStackRequest<T> parameter).
62 protected static <T> T executeAndRecordOpenstackRequest (OpenStackRequest <T> request)
64 return executeAndRecordOpenstackRequest (request, null);
66 protected static <T> T executeAndRecordOpenstackRequest (OpenStackRequest <T> request, MsoJavaProperties msoProps) {
69 // Get the name and method name of the parent class, which triggered this method
70 StackTraceElement[] classArr = new Exception ().getStackTrace ();
71 if (classArr.length >=2) {
74 limit = classArr.length;
76 String parentServiceMethodName = classArr[0].getClassName () + "." + classArr[0].getMethodName ();
77 for (int i = 1; i < limit; i++) {
78 String className = classArr[i].getClassName ();
79 if (!className.equals (MsoCommonUtils.class.getName ())) {
80 parentServiceMethodName = className + "." + classArr[i].getMethodName ();
85 long start = System.currentTimeMillis ();
87 if (request.getClass ().getEnclosingClass () != null) {
88 requestType = request.getClass ().getEnclosingClass ().getSimpleName () + "."
89 + request.getClass ().getSimpleName ();
91 requestType = request.getClass ().getSimpleName ();
94 int retryDelay = retryDelayDefault;
95 int retryCount = retryCountDefault;
96 String retryCodes = retryCodesDefault;
97 if (msoProps != null) //extra check to avoid NPE
99 retryDelay = msoProps.getIntProperty (retryDelayProp, retryDelayDefault);
100 retryCount = msoProps.getIntProperty (retryCountProp, retryCountDefault);
101 retryCodes = msoProps.getProperty (retryCodesProp, retryCodesDefault);
104 // Run the actual command. All exceptions will be propagated
108 return request.execute ();
110 catch (OpenStackResponseException e) {
111 boolean retry = false;
112 if (retryCodes != null ) {
113 int code = e.getStatus();
114 LOGGER.debug ("Config values RetryDelay:" + retryDelay + " RetryCount:" + retryCount + " RetryCodes:" + retryCodes + " ResponseCode:" + code);
115 for (String rCode : retryCodes.split (",")) {
117 if (retryCount > 0 && code == Integer.parseInt (rCode))
121 LOGGER.debug ("OpenStackResponseException ResponseCode:" + code + " at:" + parentServiceMethodName + " request:" + requestType + " Retry indicated. Attempts remaining:" + retryCount);
124 } catch (NumberFormatException e1) {
125 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");
133 Thread.sleep (retryDelay * 1000L);
134 } catch (InterruptedException e1) {
135 LOGGER.debug ("Thread interrupted while sleeping", e1);
139 throw e; // exceeded retryCount or code is not retryable
141 catch (OpenStackConnectException e) {
142 // Connection to Openstack failed
146 LOGGER.debug ("OpenstackConnectException at:" + parentServiceMethodName + " request:" + requestType + " Retry indicated. Attempts remaining:" + retryCount);
148 Thread.sleep (retryDelay * 1000L);
149 } catch (InterruptedException e1) {
150 LOGGER.debug ("Thread interrupted while sleeping", e1);
161 * Convert an Openstack Exception on a Keystone call to an MsoException.
162 * This method supports both OpenstackResponseException and OpenStackConnectException.
164 protected static MsoException keystoneErrorToMsoException (OpenStackBaseException e, String context) {
165 MsoException me = null;
167 if (e instanceof OpenStackResponseException) {
168 OpenStackResponseException re = (OpenStackResponseException) e;
171 // Failed Keystone calls return an Error entity body.
172 Error error = re.getResponse ().getErrorEntity (Error.class);
173 LOGGER.error (MessageEnum.RA_CONNECTION_EXCEPTION, "Openstack Keystone Error on " + context + ": " + error, "Openstack", "", MsoLogger.ErrorCode.DataError, "Openstack Keystone Error on " + context);
174 me = new MsoOpenstackException (error.getCode (), error.getTitle (), error.getMessage ());
175 } catch (Exception e2) {
176 // Can't parse the body as an "Error". Report the HTTP error
177 LOGGER.error (MessageEnum.RA_CONNECTION_EXCEPTION, "HTTP Error on " + context + ": " + re.getStatus() + "," + re.getMessage(), "Openstack", "", MsoLogger.ErrorCode.DataError, "HTTP Error on " + context, e2);
178 me = new MsoOpenstackException (re.getStatus (), re.getMessage (), "");
181 // Add the context of the error
182 me.addContext (context);
184 // Generate an alarm for 5XX and higher errors.
185 if (re.getStatus () >= 500) {
186 alarmLogger.sendAlarm ("KeystoneError", MsoAlarmLogger.CRITICAL, me.getContextMessage ());
188 } else if (e instanceof OpenStackConnectException) {
189 OpenStackConnectException ce = (OpenStackConnectException) e;
191 me = new MsoIOException (ce.getMessage ());
192 me.addContext (context);
194 // Generate an alarm for all connection errors.
195 LOGGER.error(MessageEnum.RA_GENERAL_EXCEPTION_ARG, "Openstack Keystone connection error on " + context + ": " + e, "Openstack", "", MsoLogger.ErrorCode.DataError, "Openstack Keystone connection error on " + context);
196 alarmLogger.sendAlarm ("KeystoneIOError", MsoAlarmLogger.CRITICAL, me.getContextMessage ());
203 * Convert an Openstack Exception on a Heat call to an MsoOpenstackException.
204 * This method supports both OpenstackResponseException and OpenStackConnectException.
206 protected MsoException heatExceptionToMsoException (OpenStackBaseException e, String context) {
207 MsoException me = null;
209 if (e instanceof OpenStackResponseException) {
210 OpenStackResponseException re = (OpenStackResponseException) e;
213 // Failed Heat calls return an Explanation entity body.
214 Explanation explanation = re.getResponse ().getErrorEntity (Explanation.class);
215 LOGGER.error (MessageEnum.RA_CONNECTION_EXCEPTION, "OpenStack", "Openstack Error on " + context + ": " + explanation.toString(), "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception - Openstack Error on " + context);
216 String fullError = explanation.getExplanation() + ", error.type=" + explanation.getError().getType() + ", error.message=" + explanation.getError().getMessage();
217 LOGGER.debug(fullError);
218 me = new MsoOpenstackException (explanation.getCode (),
219 explanation.getTitle (),
220 //explanation.getExplanation ());
222 } catch (Exception e2) {
223 // Couldn't parse the body as an "Explanation". Report the original HTTP error.
224 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);
225 me = new MsoOpenstackException (re.getStatus (), re.getMessage (), "");
228 // Add the context of the error
229 me.addContext (context);
231 // Generate an alarm for 5XX and higher errors.
232 if (re.getStatus () >= 500) {
233 alarmLogger.sendAlarm ("HeatError", MsoAlarmLogger.CRITICAL, me.getContextMessage ());
235 } else if (e instanceof OpenStackConnectException) {
236 OpenStackConnectException ce = (OpenStackConnectException) e;
238 me = new MsoIOException (ce.getMessage ());
239 me.addContext (context);
241 // Generate an alarm for all connection errors.
242 alarmLogger.sendAlarm ("HeatIOError", MsoAlarmLogger.CRITICAL, me.getContextMessage ());
243 LOGGER.error(MessageEnum.RA_CONNECTION_EXCEPTION, "OpenStack", "Openstack Heat connection error on " + context + ": " + e, "Openstack", "", MsoLogger.ErrorCode.DataError, "Openstack Heat connection error on " + context);
250 * Convert an Openstack Exception on a Neutron call to an MsoOpenstackException.
251 * This method supports both OpenstackResponseException and OpenStackConnectException.
253 protected MsoException neutronExceptionToMsoException (OpenStackBaseException e, String context) {
254 MsoException me = null;
256 if (e instanceof OpenStackResponseException) {
257 OpenStackResponseException re = (OpenStackResponseException) e;
260 // Failed Neutron calls return an NeutronError entity body
261 NeutronError error = re.getResponse ().getErrorEntity (NeutronError.class);
262 LOGGER.error (MessageEnum.RA_CONNECTION_EXCEPTION, "OpenStack", "Openstack Neutron Error on " + context + ": " + error, "Openstack", "", MsoLogger.ErrorCode.DataError, "Openstack Neutron Error on " + context);
263 me = new MsoOpenstackException (re.getStatus (), error.getType (), error.getMessage ());
264 } catch (Exception e2) {
265 // Couldn't parse body as a NeutronError. Report the HTTP error.
266 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);
267 me = new MsoOpenstackException (re.getStatus (), re.getMessage (), null);
270 // Add the context of the error
271 me.addContext (context);
273 // Generate an alarm for 5XX and higher errors.
274 if (re.getStatus () >= 500) {
275 alarmLogger.sendAlarm ("NeutronError", MsoAlarmLogger.CRITICAL, me.getContextMessage ());
277 } else if (e instanceof OpenStackConnectException) {
278 OpenStackConnectException ce = (OpenStackConnectException) e;
280 me = new MsoIOException (ce.getMessage ());
281 me.addContext (context);
283 // Generate an alarm for all connection errors.
284 alarmLogger.sendAlarm ("NeutronIOError", MsoAlarmLogger.CRITICAL, me.getContextMessage ());
285 LOGGER.error(MessageEnum.RA_CONNECTION_EXCEPTION, "OpenStack", "Openstack Neutron Connection error on "+ context + ": " + e, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Openstack Neutron Connection error on "+ context);
292 * Convert a Java Runtime Exception to an MsoException.
293 * All Runtime exceptions will be translated into an MsoAdapterException,
294 * which captures internal errors.
295 * Alarms will be generated on all such exceptions.
297 protected MsoException runtimeExceptionToMsoException (RuntimeException e, String context) {
298 MsoAdapterException me = new MsoAdapterException (e.getMessage (), e);
299 me.addContext (context);
300 me.setCategory (MsoExceptionCategory.INTERNAL);
302 // Always generate an alarm for internal exceptions
303 LOGGER.error(MessageEnum.RA_GENERAL_EXCEPTION_ARG, "An exception occured on "+ context + ": " + e, "OpenStack", "", MsoLogger.ErrorCode.DataError, "An exception occured on "+ context);
304 alarmLogger.sendAlarm ("AdapterInternalError", MsoAlarmLogger.CRITICAL, me.getContextMessage ());
309 public static boolean isNullOrEmpty (String s) {
310 return s == null || s.isEmpty();