2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * Copyright (C) 2017 Amdocs
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
20 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
23 package org.openecomp.appc.adapter.iaas.provider.operation.impl.base;
25 import org.openecomp.appc.adapter.iaas.ProviderAdapter;
26 import org.openecomp.appc.adapter.iaas.impl.*;
27 import org.openecomp.appc.adapter.iaas.provider.operation.api.IProviderOperation;
28 import org.openecomp.appc.adapter.iaas.provider.operation.common.constants.Constants;
29 import org.openecomp.appc.adapter.iaas.provider.operation.common.enums.Outcome;
30 import org.openecomp.appc.configuration.Configuration;
31 import org.openecomp.appc.configuration.ConfigurationFactory;
32 import org.openecomp.appc.exceptions.APPCException;
33 import org.openecomp.appc.i18n.Msg;
34 import org.openecomp.appc.pool.Pool;
35 import org.openecomp.appc.pool.PoolExtensionException;
36 import com.att.cdp.zones.Context;
37 import com.att.cdp.zones.model.ModelObject;
38 import com.att.cdp.zones.model.Server;
39 import com.att.eelf.configuration.EELFLogger;
40 import com.att.eelf.configuration.EELFManager;
41 import com.att.eelf.i18n.EELFResourceManager;
42 import org.openecomp.sdnc.sli.SvcLogicContext;
43 import org.glassfish.grizzly.http.util.HttpStatus;
49 import java.util.regex.Pattern;
51 import static org.openecomp.appc.adapter.iaas.provider.operation.common.constants.Constants.MDC_ADAPTER;
52 import static org.openecomp.appc.adapter.iaas.provider.operation.common.constants.Constants.MDC_SERVICE;
53 import static com.att.eelf.configuration.Configuration.MDC_SERVICE_NAME;
56 * @since September 26, 2016
58 public abstract class ProviderOperation implements IProviderOperation {
60 private static final EELFLogger logger = EELFManager.getInstance().getLogger(ProviderOperation.class);
61 protected static final Configuration configuration = ConfigurationFactory.getConfiguration();
63 public void setProviderCache(Map<String, ProviderCache> providerCache) {
64 this.providerCache = providerCache;
68 * A cache of providers that are predefined.
70 private Map<String /* provider name */, ProviderCache> providerCache;
73 public void setDefaultUser(String defaultUser) {
74 DEFAULT_USER = defaultUser;
77 public void setDefaultPass(String defaultPass) {
78 DEFAULT_PASS = defaultPass;
82 * The username and password to use for dynamically created connections
84 private static String DEFAULT_USER;
85 private static String DEFAULT_PASS;
94 protected void setMDC(String service, String serviceName, String adapterName){
95 MDC.put(MDC_ADAPTER, adapterName);
96 MDC.put(MDC_SERVICE, service);
97 MDC.put(MDC_SERVICE_NAME, serviceName);
101 * initial log of the operation
106 protected void logOperation(Msg msg, Map<String, String> params, SvcLogicContext context){
108 String appName = configuration.getProperty(org.openecomp.appc.Constants.PROPERTY_APPLICATION_NAME);
109 logger.info(msg, appName);
111 debugParameters(params);
112 debugContext(context);
116 * This method is used to dump the value of the parameters to the log for debugging purposes.
119 * The parameters to be printed to the log
121 private void debugParameters(Map<String, String> parameters) {
122 for (String key : parameters.keySet()) {
123 logger.debug(Msg.PROPERTY_VALUE, key, parameters.get(key));
128 * This method is used to create a diagnostic dump of the context for the log
131 * The context to be dumped
134 "nls", "static-method"
136 private void debugContext(SvcLogicContext context) {
137 Set<String> keys = context.getAttributeKeySet();
138 StringBuilder builder = new StringBuilder();
140 builder.append("Service Logic Context: Status ");
141 builder.append(Constants.LPAREN);
142 builder.append(context.getStatus());
143 builder.append(Constants.RPAREN);
144 builder.append(", Attribute count ");
145 builder.append(Constants.LPAREN);
146 builder.append(keys == null ? "none" : Integer.toString(keys.size()));
147 builder.append(Constants.RPAREN);
148 if (keys != null && !keys.isEmpty()) {
149 builder.append(Constants.NL);
150 for (String key : keys) {
151 String value = context.getAttribute(key);
152 builder.append("Attribute ");
153 builder.append(Constants.LPAREN);
155 builder.append(Constants.RPAREN);
156 builder.append(", value ");
157 builder.append(Constants.LPAREN);
158 builder.append(value == null ? "" : value);
159 builder.append(Constants.RPAREN);
160 builder.append(Constants.NL);
164 logger.debug(builder.toString());
169 * This method is used to validate that the parameters contain all required property names, and that the values are
170 * non-null and non-empty strings. We are still not ensured that the value is valid, but at least it exists.
173 * The parameters to be checked
174 * @param propertyNames
175 * The list of property names that are required to be present.
176 * @throws RequestFailedException
177 * If the parameters are not valid
179 protected void validateParametersExist(Map<String, String> parameters, String... propertyNames)
180 throws RequestFailedException {
181 boolean success = true;
182 StringBuilder msg = new StringBuilder(EELFResourceManager.format(Msg.MISSING_REQUIRED_PROPERTIES, MDC.get(MDC_SERVICE)));
183 msg.append(Constants.NL);
184 for (String propertyName : propertyNames) {
185 String value = parameters.get(propertyName);
186 if (value == null || value.trim().length() == 0) {
188 msg.append(Constants.QUOTE);
189 msg.append(propertyName);
190 msg.append(Constants.QUOTE);
191 msg.append(Constants.SPACE);
196 logger.error(msg.toString());
197 throw new RequestFailedException("Check Parameters", msg.toString(), HttpStatus.BAD_REQUEST_400, (Server)null);
203 * The request context that manages the state and recovery of the request for the life of its processing.
207 protected void doFailure(RequestContext rc, HttpStatus code, String message) {
209 doFailure(rc, code, message, null);
210 } catch (APPCException ignored) {/* never happens */}
213 protected void doFailure(RequestContext rc, HttpStatus code, String message, Throwable cause) throws APPCException {
214 SvcLogicContext svcLogic = rc.getSvcLogicContext();
215 String msg = (message == null) ? code.getReasonPhrase() : message;
216 if (msg.contains("\n")) {
217 msg = msg.substring(0, msg.indexOf("\n"));
221 status = Integer.toString(code.getStatusCode());
222 } catch (Exception e) {
225 svcLogic.setStatus(Outcome.FAILURE.toString());
226 svcLogic.setAttribute(org.openecomp.appc.Constants.ATTRIBUTE_ERROR_CODE, status);
227 svcLogic.setAttribute(org.openecomp.appc.Constants.ATTRIBUTE_ERROR_MESSAGE, msg);
229 if (null != cause) throw new APPCException(cause);
234 * The request context that manages the state and recovery of the request for the life of its processing.
236 @SuppressWarnings("static-method")
237 protected void doSuccess(RequestContext rc) {
238 SvcLogicContext svcLogic = rc.getSvcLogicContext();
239 svcLogic.setStatus(Outcome.SUCCESS.toString());
240 svcLogic.setAttribute(org.openecomp.appc.Constants.ATTRIBUTE_ERROR_CODE, Integer.toString(HttpStatus.OK_200.getStatusCode()));
243 protected boolean validateVM(RequestContext rc, String appName, String vm_url, VMURL vm)
244 throws RequestFailedException {
247 msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, vm_url);
249 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
256 protected void validateVMURL(VMURL vm) throws RequestFailedException {
257 String name = "vm-id";
259 throw new RequestFailedException(String.format("The value %s cannot be null.", name));
262 // Check that its a good uri
263 // This will probably never get hit bc of an earlier check while parsing
264 // the string to a VMURL
266 //noinspection ResultOfMethodCallIgnored
267 URI.create(vm.toString());
268 } catch (Exception e) {
269 throw new RequestFailedException(
270 String.format("The value %s is not well formed [%s].", name, vm.toString()));
273 // Check the tenant and vmid segments
274 String patternRegex = "([0-9a-f]{8}(-)?[0-9a-f]{4}(-)?[0-9a-f]{4}(-)?[0-9a-f]{4}(-)?[0-9a-f]{12})";
275 Pattern pattern = Pattern.compile(patternRegex, Pattern.CASE_INSENSITIVE);
277 if (!pattern.matcher(vm.getTenantId()).matches()) {
278 throw new RequestFailedException(
279 String.format("The value %s has an invalid tenantId [%s].", name, vm.getTenantId()));
281 if (!pattern.matcher(vm.getServerId()).matches()) {
282 throw new RequestFailedException(
283 String.format("The value %s has an invalid serverId [%s].", name, vm.getServerId()));
287 private ProviderCache createProviderCache(VMURL vm, IdentityURL ident) {
288 if (vm != null && ident != null) {
289 ProviderCache cache = new ProviderCache();
291 cache.setIdentityURL(ident.toString());
292 cache.setProviderName(ident.toString());
293 // cache.setProviderType("OpenStack");
295 TenantCache tenant = cache.addTenant(vm.getTenantId(),null, DEFAULT_USER, DEFAULT_PASS);
297 // Make sure we could initialize the the cache otherwise return null
298 if (tenant != null && tenant.isInitialized()) {
306 * This method is a general helper method used to locate a server given its fully-qualified self-link URL on a
307 * supported provider, regardless of region(s), and to return an opened context that can be used to access that
311 * The request context that wraps and manages the state of the request
313 * The fully-qualified self-link URL of the server
314 * @param providerName
315 * The name of the provider to be searched
316 * @return The context that can be used to access the server, or null if not found.
318 @SuppressWarnings("nls")
319 protected Context getContext(RequestContext rc, String selfLinkURL, String providerName) {
320 VMURL vm = VMURL.parseURL(selfLinkURL);
321 IdentityURL ident = IdentityURL.parseURL(providerName);
322 String appName = configuration.getProperty(org.openecomp.appc.Constants.PROPERTY_APPLICATION_NAME);
325 String msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, selfLinkURL);
327 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
332 * Get the cache of tenants and contexts for the named provider, if one exists
334 ProviderCache cache = providerCache.get(providerName);
337 * If one doesn't exist, try and create it. If we have enough information to create it successfully, add it to
338 * the cache and continue, otherwise fail the request.
342 cache = createProviderCache(vm, ident);
345 providerCache.put(cache.getProviderName(), cache);
348 EELFResourceManager.format(Msg.UNKNOWN_PROVIDER, providerName, providerCache.keySet().toString());
350 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
355 if (providerName == null) {
357 .debug(String.format("Using the default provider cache [%s] since no valid identity url was passed in.",
358 cache.getIdentityURL()));
361 // get the tenant cache for the vm
362 String identityURL = cache.getIdentityURL();
363 TenantCache tenantCache = cache.getTenant(vm.getTenantId());
365 if(tenantCache == null){
366 //no tenantCache matching tenant, add tenant to the provider cache
367 tenantCache = cache.addTenant(vm.getTenantId(),null,DEFAULT_USER, DEFAULT_PASS);
369 if(tenantCache == null){
371 String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, selfLinkURL);
373 doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
378 //reserve the context
379 String tenantName = tenantCache.getTenantName();
380 String tenantId = tenantCache.getTenantId();
381 String region = tenantCache.determineRegion(vm);
383 if (region != null) {
384 Pool<Context> pool = tenantCache.getPools().get(region);
386 while (rc.attempt()) {
388 Context context = pool.reserve();
391 * Insert logic here to test the context for connectivity because we may have gotten one from
392 * the pool that was previously created.
394 if (context.isStale()) {
398 } catch (PoolExtensionException e) {
399 String msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, providerName, identityURL,
400 tenantName, tenantId, e.getMessage(), Long.toString(rc.getRetryDelay()),
401 Integer.toString(rc.getAttempts()), Integer.toString(rc.getRetryLimit()));
402 logger.error(msg, e);
404 } catch (Exception e) {
405 String msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, e,
406 e.getClass().getSimpleName(), "find", selfLinkURL, tenantCache.getTenantName());
408 logger.error(msg, e);
409 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
414 String msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, providerName, identityURL);
416 doFailure(rc, HttpStatus.BAD_GATEWAY_502, msg);
421 String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, selfLinkURL);
423 doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
427 protected Context resolveContext(RequestContext rc, Map<String, String> params, String appName, String vm_url)
428 throws RequestFailedException {
430 VMURL vm = VMURL.parseURL(vm_url);
432 String msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, vm_url);
433 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
438 IdentityURL ident = IdentityURL.parseURL(params.get(ProviderAdapter.PROPERTY_IDENTITY_URL));
439 String identStr = (ident == null) ? null : ident.toString();
441 return getContext(rc, vm_url, identStr);
451 protected abstract ModelObject executeProviderOperation(Map<String, String> params, SvcLogicContext context) throws APPCException;
454 public ModelObject doOperation(Map<String, String> params, SvcLogicContext context) throws APPCException {
456 return executeProviderOperation(params,context);