2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Copyright (C) 2017 Amdocs
8 * =============================================================================
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
21 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22 * ============LICENSE_END=========================================================
25 package org.openecomp.appc.adapter.iaas.provider.operation.impl.base;
27 import org.openecomp.appc.adapter.iaas.ProviderAdapter;
28 import org.openecomp.appc.adapter.iaas.impl.*;
29 import org.openecomp.appc.adapter.iaas.provider.operation.api.IProviderOperation;
30 import org.openecomp.appc.adapter.iaas.provider.operation.common.constants.Constants;
31 import org.openecomp.appc.adapter.iaas.provider.operation.common.enums.Outcome;
32 import org.openecomp.appc.configuration.Configuration;
33 import org.openecomp.appc.configuration.ConfigurationFactory;
34 import org.openecomp.appc.exceptions.APPCException;
35 import org.openecomp.appc.i18n.Msg;
36 import org.openecomp.appc.pool.Pool;
37 import org.openecomp.appc.pool.PoolExtensionException;
38 import com.att.cdp.zones.Context;
39 import com.att.cdp.zones.model.ModelObject;
40 import com.att.cdp.zones.model.Server;
41 import com.att.eelf.configuration.EELFLogger;
42 import com.att.eelf.configuration.EELFManager;
43 import com.att.eelf.i18n.EELFResourceManager;
44 import org.openecomp.sdnc.sli.SvcLogicContext;
45 import org.glassfish.grizzly.http.util.HttpStatus;
51 import java.util.regex.Pattern;
53 import static org.openecomp.appc.adapter.iaas.provider.operation.common.constants.Constants.MDC_ADAPTER;
54 import static org.openecomp.appc.adapter.iaas.provider.operation.common.constants.Constants.MDC_SERVICE;
55 import static com.att.eelf.configuration.Configuration.MDC_SERVICE_NAME;
58 * @since September 26, 2016
60 public abstract class ProviderOperation implements IProviderOperation {
62 private static final EELFLogger logger = EELFManager.getInstance().getLogger(ProviderOperation.class);
63 protected static final Configuration configuration = ConfigurationFactory.getConfiguration();
65 public void setProviderCache(Map<String, ProviderCache> providerCache) {
66 this.providerCache = providerCache;
70 * A cache of providers that are predefined.
72 private Map<String /* provider name */, ProviderCache> providerCache;
75 public void setDefaultUser(String defaultUser) {
76 DEFAULT_USER = defaultUser;
79 public void setDefaultPass(String defaultPass) {
80 DEFAULT_PASS = defaultPass;
84 * The username and password to use for dynamically created connections
86 private static String DEFAULT_USER;
87 private static String DEFAULT_PASS;
96 protected void setMDC(String service, String serviceName, String adapterName){
97 MDC.put(MDC_ADAPTER, adapterName);
98 MDC.put(MDC_SERVICE, service);
99 MDC.put(MDC_SERVICE_NAME, serviceName);
103 * initial log of the operation
108 protected void logOperation(Msg msg, Map<String, String> params, SvcLogicContext context){
110 String appName = configuration.getProperty(org.openecomp.appc.Constants.PROPERTY_APPLICATION_NAME);
111 logger.info(msg, appName);
113 debugParameters(params);
114 debugContext(context);
118 * This method is used to dump the value of the parameters to the log for debugging purposes.
121 * The parameters to be printed to the log
123 private void debugParameters(Map<String, String> parameters) {
124 for (String key : parameters.keySet()) {
125 logger.debug(Msg.PROPERTY_VALUE, key, parameters.get(key));
130 * This method is used to create a diagnostic dump of the context for the log
133 * The context to be dumped
136 "nls", "static-method"
138 private void debugContext(SvcLogicContext context) {
139 Set<String> keys = context.getAttributeKeySet();
140 StringBuilder builder = new StringBuilder();
142 builder.append("Service Logic Context: Status ");
143 builder.append(Constants.LPAREN);
144 builder.append(context.getStatus());
145 builder.append(Constants.RPAREN);
146 builder.append(", Attribute count ");
147 builder.append(Constants.LPAREN);
148 builder.append(keys == null ? "none" : Integer.toString(keys.size()));
149 builder.append(Constants.RPAREN);
150 if (keys != null && !keys.isEmpty()) {
151 builder.append(Constants.NL);
152 for (String key : keys) {
153 String value = context.getAttribute(key);
154 builder.append("Attribute ");
155 builder.append(Constants.LPAREN);
157 builder.append(Constants.RPAREN);
158 builder.append(", value ");
159 builder.append(Constants.LPAREN);
160 builder.append(value == null ? "" : value);
161 builder.append(Constants.RPAREN);
162 builder.append(Constants.NL);
166 logger.debug(builder.toString());
171 * This method is used to validate that the parameters contain all required property names, and that the values are
172 * non-null and non-empty strings. We are still not ensured that the value is valid, but at least it exists.
175 * The parameters to be checked
176 * @param propertyNames
177 * The list of property names that are required to be present.
178 * @throws RequestFailedException
179 * If the parameters are not valid
181 protected void validateParametersExist(Map<String, String> parameters, String... propertyNames)
182 throws RequestFailedException {
183 boolean success = true;
184 StringBuilder msg = new StringBuilder(EELFResourceManager.format(Msg.MISSING_REQUIRED_PROPERTIES, MDC.get(MDC_SERVICE)));
185 msg.append(Constants.NL);
186 for (String propertyName : propertyNames) {
187 String value = parameters.get(propertyName);
188 if (value == null || value.trim().length() == 0) {
190 msg.append(Constants.QUOTE);
191 msg.append(propertyName);
192 msg.append(Constants.QUOTE);
193 msg.append(Constants.SPACE);
198 logger.error(msg.toString());
199 throw new RequestFailedException("Check Parameters", msg.toString(), HttpStatus.BAD_REQUEST_400, (Server)null);
205 * The request context that manages the state and recovery of the request for the life of its processing.
209 protected void doFailure(RequestContext rc, HttpStatus code, String message) {
211 doFailure(rc, code, message, null);
212 } catch (APPCException ignored) {/* never happens */}
215 protected void doFailure(RequestContext rc, HttpStatus code, String message, Throwable cause) throws APPCException {
216 SvcLogicContext svcLogic = rc.getSvcLogicContext();
217 String msg = (message == null) ? code.getReasonPhrase() : message;
218 if (msg.contains("\n")) {
219 msg = msg.substring(0, msg.indexOf("\n"));
223 status = Integer.toString(code.getStatusCode());
224 } catch (Exception e) {
227 svcLogic.setStatus(Outcome.FAILURE.toString());
228 svcLogic.setAttribute(org.openecomp.appc.Constants.ATTRIBUTE_ERROR_CODE, status);
229 svcLogic.setAttribute(org.openecomp.appc.Constants.ATTRIBUTE_ERROR_MESSAGE, msg);
231 if (null != cause) throw new APPCException(cause);
236 * The request context that manages the state and recovery of the request for the life of its processing.
238 @SuppressWarnings("static-method")
239 protected void doSuccess(RequestContext rc) {
240 SvcLogicContext svcLogic = rc.getSvcLogicContext();
241 svcLogic.setStatus(Outcome.SUCCESS.toString());
242 svcLogic.setAttribute(org.openecomp.appc.Constants.ATTRIBUTE_ERROR_CODE, Integer.toString(HttpStatus.OK_200.getStatusCode()));
245 protected boolean validateVM(RequestContext rc, String appName, String vm_url, VMURL vm)
246 throws RequestFailedException {
249 msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, vm_url);
251 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
258 protected void validateVMURL(VMURL vm) throws RequestFailedException {
259 String name = "vm-id";
261 throw new RequestFailedException(String.format("The value %s cannot be null.", name));
264 // Check that its a good uri
265 // This will probably never get hit bc of an earlier check while parsing
266 // the string to a VMURL
268 //noinspection ResultOfMethodCallIgnored
269 URI.create(vm.toString());
270 } catch (Exception e) {
271 throw new RequestFailedException(
272 String.format("The value %s is not well formed [%s].", name, vm.toString()));
275 // Check the tenant and vmid segments
276 String patternRegex = "([0-9a-f]{8}(-)?[0-9a-f]{4}(-)?[0-9a-f]{4}(-)?[0-9a-f]{4}(-)?[0-9a-f]{12})";
277 Pattern pattern = Pattern.compile(patternRegex, Pattern.CASE_INSENSITIVE);
279 if (!pattern.matcher(vm.getTenantId()).matches()) {
280 throw new RequestFailedException(
281 String.format("The value %s has an invalid tenantId [%s].", name, vm.getTenantId()));
283 if (!pattern.matcher(vm.getServerId()).matches()) {
284 throw new RequestFailedException(
285 String.format("The value %s has an invalid serverId [%s].", name, vm.getServerId()));
289 private ProviderCache createProviderCache(VMURL vm, IdentityURL ident) {
290 if (vm != null && ident != null) {
291 ProviderCache cache = new ProviderCache();
293 cache.setIdentityURL(ident.toString());
294 cache.setProviderName(ident.toString());
295 // cache.setProviderType("OpenStack");
297 TenantCache tenant = cache.addTenant(vm.getTenantId(),null, DEFAULT_USER, DEFAULT_PASS);
299 // Make sure we could initialize the the cache otherwise return null
300 if (tenant != null && tenant.isInitialized()) {
308 * This method is a general helper method used to locate a server given its fully-qualified self-link URL on a
309 * supported provider, regardless of region(s), and to return an opened context that can be used to access that
313 * The request context that wraps and manages the state of the request
315 * The fully-qualified self-link URL of the server
316 * @param providerName
317 * The name of the provider to be searched
318 * @return The context that can be used to access the server, or null if not found.
320 @SuppressWarnings("nls")
321 protected Context getContext(RequestContext rc, String selfLinkURL, String providerName) {
322 VMURL vm = VMURL.parseURL(selfLinkURL);
323 IdentityURL ident = IdentityURL.parseURL(providerName);
324 String appName = configuration.getProperty(org.openecomp.appc.Constants.PROPERTY_APPLICATION_NAME);
327 String msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, selfLinkURL);
329 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
334 * Get the cache of tenants and contexts for the named provider, if one exists
336 ProviderCache cache = providerCache.get(providerName);
339 * If one doesn't exist, try and create it. If we have enough information to create it successfully, add it to
340 * the cache and continue, otherwise fail the request.
344 cache = createProviderCache(vm, ident);
347 providerCache.put(cache.getProviderName(), cache);
350 EELFResourceManager.format(Msg.UNKNOWN_PROVIDER, providerName, providerCache.keySet().toString());
352 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
357 if (providerName == null) {
359 .debug(String.format("Using the default provider cache [%s] since no valid identity url was passed in.",
360 cache.getIdentityURL()));
363 // get the tenant cache for the vm
364 String identityURL = cache.getIdentityURL();
365 TenantCache tenantCache = cache.getTenant(vm.getTenantId());
367 if(tenantCache == null){
368 //no tenantCache matching tenant, add tenant to the provider cache
369 tenantCache = cache.addTenant(vm.getTenantId(),null,DEFAULT_USER, DEFAULT_PASS);
371 if(tenantCache == null){
373 String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, selfLinkURL);
375 doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
380 //reserve the context
381 String tenantName = tenantCache.getTenantName();
382 String tenantId = tenantCache.getTenantId();
383 String region = tenantCache.determineRegion(vm);
385 if (region != null) {
386 Pool<Context> pool = tenantCache.getPools().get(region);
388 while (rc.attempt()) {
390 Context context = pool.reserve();
393 * Insert logic here to test the context for connectivity because we may have gotten one from
394 * the pool that was previously created.
396 if (context.isStale()) {
400 } catch (PoolExtensionException e) {
401 String msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, providerName, identityURL,
402 tenantName, tenantId, e.getMessage(), Long.toString(rc.getRetryDelay()),
403 Integer.toString(rc.getAttempts()), Integer.toString(rc.getRetryLimit()));
404 logger.error(msg, e);
406 } catch (Exception e) {
407 String msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, e,
408 e.getClass().getSimpleName(), "find", selfLinkURL, tenantCache.getTenantName());
410 logger.error(msg, e);
411 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
416 String msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, providerName, identityURL);
418 doFailure(rc, HttpStatus.BAD_GATEWAY_502, msg);
423 String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, selfLinkURL);
425 doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
429 protected Context resolveContext(RequestContext rc, Map<String, String> params, String appName, String vm_url)
430 throws RequestFailedException {
432 VMURL vm = VMURL.parseURL(vm_url);
434 String msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, vm_url);
435 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
440 IdentityURL ident = IdentityURL.parseURL(params.get(ProviderAdapter.PROPERTY_IDENTITY_URL));
441 String identStr = (ident == null) ? null : ident.toString();
443 return getContext(rc, vm_url, identStr);
453 protected abstract ModelObject executeProviderOperation(Map<String, String> params, SvcLogicContext context) throws APPCException;
456 public ModelObject doOperation(Map<String, String> params, SvcLogicContext context) throws APPCException {
458 return executeProviderOperation(params,context);