2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights
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=========================================================
22 package org.openecomp.appc.adapter.iaas.provider.operation.impl.base;
24 import org.openecomp.appc.adapter.iaas.ProviderAdapter;
25 import org.openecomp.appc.adapter.iaas.impl.*;
26 import org.openecomp.appc.adapter.iaas.provider.operation.api.IProviderOperation;
27 import org.openecomp.appc.adapter.iaas.provider.operation.common.constants.Constants;
28 import org.openecomp.appc.adapter.iaas.provider.operation.common.enums.Outcome;
29 import org.openecomp.appc.configuration.Configuration;
30 import org.openecomp.appc.configuration.ConfigurationFactory;
31 import org.openecomp.appc.exceptions.APPCException;
32 import org.openecomp.appc.i18n.Msg;
33 import org.openecomp.appc.pool.Pool;
34 import org.openecomp.appc.pool.PoolExtensionException;
35 import com.att.cdp.zones.Context;
36 import com.att.cdp.zones.model.ModelObject;
37 import com.att.cdp.zones.model.Server;
38 import com.att.eelf.configuration.EELFLogger;
39 import com.att.eelf.configuration.EELFManager;
40 import com.att.eelf.i18n.EELFResourceManager;
41 import org.openecomp.sdnc.sli.SvcLogicContext;
42 import org.glassfish.grizzly.http.util.HttpStatus;
48 import java.util.regex.Pattern;
50 import static org.openecomp.appc.adapter.iaas.provider.operation.common.constants.Constants.MDC_ADAPTER;
51 import static org.openecomp.appc.adapter.iaas.provider.operation.common.constants.Constants.MDC_SERVICE;
52 import static com.att.eelf.configuration.Configuration.MDC_SERVICE_NAME;
55 * @since September 26, 2016
57 public abstract class ProviderOperation implements IProviderOperation {
59 private static final EELFLogger logger = EELFManager.getInstance().getLogger(ProviderOperation.class);
60 protected static final Configuration configuration = ConfigurationFactory.getConfiguration();
62 public void setProviderCache(Map<String, ProviderCache> providerCache) {
63 this.providerCache = providerCache;
67 * A cache of providers that are predefined.
69 private Map<String /* provider name */, ProviderCache> providerCache;
72 public void setDefaultUser(String defaultUser) {
73 DEFAULT_USER = defaultUser;
76 public void setDefaultPass(String defaultPass) {
77 DEFAULT_PASS = defaultPass;
81 * The username and password to use for dynamically created connections
83 private static String DEFAULT_USER;
84 private static String DEFAULT_PASS;
93 protected void setMDC(String service, String serviceName, String adapterName){
94 MDC.put(MDC_ADAPTER, adapterName);
95 MDC.put(MDC_SERVICE, service);
96 MDC.put(MDC_SERVICE_NAME, serviceName);
100 * initial log of the operation
105 protected void logOperation(Msg msg, Map<String, String> params, SvcLogicContext context){
107 String appName = configuration.getProperty(org.openecomp.appc.Constants.PROPERTY_APPLICATION_NAME);
108 logger.info(msg, appName);
110 debugParameters(params);
111 debugContext(context);
115 * This method is used to dump the value of the parameters to the log for debugging purposes.
118 * The parameters to be printed to the log
120 private void debugParameters(Map<String, String> parameters) {
121 for (String key : parameters.keySet()) {
122 logger.debug(Msg.PROPERTY_VALUE, key, parameters.get(key));
127 * This method is used to create a diagnostic dump of the context for the log
130 * The context to be dumped
133 "nls", "static-method"
135 private void debugContext(SvcLogicContext context) {
136 Set<String> keys = context.getAttributeKeySet();
137 StringBuilder builder = new StringBuilder();
139 builder.append("Service Logic Context: Status ");
140 builder.append(Constants.LPAREN);
141 builder.append(context.getStatus());
142 builder.append(Constants.RPAREN);
143 builder.append(", Attribute count ");
144 builder.append(Constants.LPAREN);
145 builder.append(keys == null ? "none" : Integer.toString(keys.size()));
146 builder.append(Constants.RPAREN);
147 if (keys != null && !keys.isEmpty()) {
148 builder.append(Constants.NL);
149 for (String key : keys) {
150 String value = context.getAttribute(key);
151 builder.append("Attribute ");
152 builder.append(Constants.LPAREN);
154 builder.append(Constants.RPAREN);
155 builder.append(", value ");
156 builder.append(Constants.LPAREN);
157 builder.append(value == null ? "" : value);
158 builder.append(Constants.RPAREN);
159 builder.append(Constants.NL);
163 logger.debug(builder.toString());
168 * This method is used to validate that the parameters contain all required property names, and that the values are
169 * non-null and non-empty strings. We are still not ensured that the value is valid, but at least it exists.
172 * The parameters to be checked
173 * @param propertyNames
174 * The list of property names that are required to be present.
175 * @throws RequestFailedException
176 * If the parameters are not valid
178 protected void validateParametersExist(Map<String, String> parameters, String... propertyNames)
179 throws RequestFailedException {
180 boolean success = true;
181 StringBuilder msg = new StringBuilder(EELFResourceManager.format(Msg.MISSING_REQUIRED_PROPERTIES, MDC.get(MDC_SERVICE)));
182 msg.append(Constants.NL);
183 for (String propertyName : propertyNames) {
184 String value = parameters.get(propertyName);
185 if (value == null || value.trim().length() == 0) {
187 msg.append(Constants.QUOTE);
188 msg.append(propertyName);
189 msg.append(Constants.QUOTE);
190 msg.append(Constants.SPACE);
195 logger.error(msg.toString());
196 throw new RequestFailedException("Check Parameters", msg.toString(), HttpStatus.BAD_REQUEST_400, (Server)null);
202 * The request context that manages the state and recovery of the request for the life of its processing.
206 protected void doFailure(RequestContext rc, HttpStatus code, String message) {
208 doFailure(rc, code, message, null);
209 } catch (APPCException ignored) {/* never happens */}
212 protected void doFailure(RequestContext rc, HttpStatus code, String message, Throwable cause) throws APPCException {
213 SvcLogicContext svcLogic = rc.getSvcLogicContext();
214 String msg = (message == null) ? code.getReasonPhrase() : message;
215 if (msg.contains("\n")) {
216 msg = msg.substring(0, msg.indexOf("\n"));
220 status = Integer.toString(code.getStatusCode());
221 } catch (Exception e) {
224 svcLogic.setStatus(Outcome.FAILURE.toString());
225 svcLogic.setAttribute(org.openecomp.appc.Constants.ATTRIBUTE_ERROR_CODE, status);
226 svcLogic.setAttribute(org.openecomp.appc.Constants.ATTRIBUTE_ERROR_MESSAGE, msg);
228 if (null != cause) throw new APPCException(cause);
233 * The request context that manages the state and recovery of the request for the life of its processing.
235 @SuppressWarnings("static-method")
236 protected void doSuccess(RequestContext rc) {
237 SvcLogicContext svcLogic = rc.getSvcLogicContext();
238 svcLogic.setStatus(Outcome.SUCCESS.toString());
239 svcLogic.setAttribute(org.openecomp.appc.Constants.ATTRIBUTE_ERROR_CODE, Integer.toString(HttpStatus.OK_200.getStatusCode()));
242 protected boolean validateVM(RequestContext rc, String appName, String vm_url, VMURL vm)
243 throws RequestFailedException {
246 msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, vm_url);
248 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
255 protected void validateVMURL(VMURL vm) throws RequestFailedException {
256 String name = "vm-id";
258 throw new RequestFailedException(String.format("The value %s cannot be null.", name));
261 // Check that its a good uri
262 // This will probably never get hit bc of an earlier check while parsing
263 // the string to a VMURL
265 //noinspection ResultOfMethodCallIgnored
266 URI.create(vm.toString());
267 } catch (Exception e) {
268 throw new RequestFailedException(
269 String.format("The value %s is not well formed [%s].", name, vm.toString()));
272 // Check the tenant and vmid segments
273 String patternRegex = "([0-9a-f]{8}(-)?[0-9a-f]{4}(-)?[0-9a-f]{4}(-)?[0-9a-f]{4}(-)?[0-9a-f]{12})";
274 Pattern pattern = Pattern.compile(patternRegex, Pattern.CASE_INSENSITIVE);
276 if (!pattern.matcher(vm.getTenantId()).matches()) {
277 throw new RequestFailedException(
278 String.format("The value %s has an invalid tenantId [%s].", name, vm.getTenantId()));
280 if (!pattern.matcher(vm.getServerId()).matches()) {
281 throw new RequestFailedException(
282 String.format("The value %s has an invalid serverId [%s].", name, vm.getServerId()));
286 private ProviderCache createProviderCache(VMURL vm, IdentityURL ident) {
287 if (vm != null && ident != null) {
288 ProviderCache cache = new ProviderCache();
290 cache.setIdentityURL(ident.toString());
291 cache.setProviderName(ident.toString());
292 // cache.setProviderType("OpenStack");
294 TenantCache tenant = cache.addTenant(vm.getTenantId(),null, DEFAULT_USER, DEFAULT_PASS);
296 // Make sure we could initialize the the cache otherwise return null
297 if (tenant != null && tenant.isInitialized()) {
305 * This method is a general helper method used to locate a server given its fully-qualified self-link URL on a
306 * supported provider, regardless of region(s), and to return an opened context that can be used to access that
310 * The request context that wraps and manages the state of the request
312 * The fully-qualified self-link URL of the server
313 * @param providerName
314 * The name of the provider to be searched
315 * @return The context that can be used to access the server, or null if not found.
317 @SuppressWarnings("nls")
318 protected Context getContext(RequestContext rc, String selfLinkURL, String providerName) {
319 VMURL vm = VMURL.parseURL(selfLinkURL);
320 IdentityURL ident = IdentityURL.parseURL(providerName);
321 String appName = configuration.getProperty(org.openecomp.appc.Constants.PROPERTY_APPLICATION_NAME);
324 String msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, selfLinkURL);
326 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
331 * Get the cache of tenants and contexts for the named provider, if one exists
333 ProviderCache cache = providerCache.get(providerName);
336 * If one doesn't exist, try and create it. If we have enough information to create it successfully, add it to
337 * the cache and continue, otherwise fail the request.
341 cache = createProviderCache(vm, ident);
344 providerCache.put(cache.getProviderName(), cache);
347 EELFResourceManager.format(Msg.UNKNOWN_PROVIDER, providerName, providerCache.keySet().toString());
349 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
354 if (providerName == null) {
356 .debug(String.format("Using the default provider cache [%s] since no valid identity url was passed in.",
357 cache.getIdentityURL()));
360 // get the tenant cache for the vm
361 String identityURL = cache.getIdentityURL();
362 TenantCache tenantCache = cache.getTenant(vm.getTenantId());
364 if(tenantCache == null){
365 //no tenantCache matching tenant, add tenant to the provider cache
366 tenantCache = cache.addTenant(vm.getTenantId(),null,DEFAULT_USER, DEFAULT_PASS);
368 if(tenantCache == null){
370 String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, selfLinkURL);
372 doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
377 //reserve the context
378 String tenantName = tenantCache.getTenantName();
379 String tenantId = tenantCache.getTenantId();
380 String region = tenantCache.determineRegion(vm);
382 if (region != null) {
383 Pool<Context> pool = tenantCache.getPools().get(region);
385 while (rc.attempt()) {
387 Context context = pool.reserve();
390 * Insert logic here to test the context for connectivity because we may have gotten one from
391 * the pool that was previously created.
393 if (context.isStale()) {
397 } catch (PoolExtensionException e) {
398 String msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, providerName, identityURL,
399 tenantName, tenantId, e.getMessage(), Long.toString(rc.getRetryDelay()),
400 Integer.toString(rc.getAttempts()), Integer.toString(rc.getRetryLimit()));
401 logger.error(msg, e);
403 } catch (Exception e) {
404 String msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, e,
405 e.getClass().getSimpleName(), "find", selfLinkURL, tenantCache.getTenantName());
407 logger.error(msg, e);
408 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
413 String msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, providerName, identityURL);
415 doFailure(rc, HttpStatus.BAD_GATEWAY_502, msg);
420 String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, selfLinkURL);
422 doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
426 protected Context resolveContext(RequestContext rc, Map<String, String> params, String appName, String vm_url)
427 throws RequestFailedException {
429 VMURL vm = VMURL.parseURL(vm_url);
431 String msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, vm_url);
432 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
437 IdentityURL ident = IdentityURL.parseURL(params.get(ProviderAdapter.PROPERTY_IDENTITY_URL));
438 String identStr = (ident == null) ? null : ident.toString();
440 return getContext(rc, vm_url, identStr);
450 protected abstract ModelObject executeProviderOperation(Map<String, String> params, SvcLogicContext context) throws APPCException;
453 public ModelObject doOperation(Map<String, String> params, SvcLogicContext context) throws APPCException {
455 return executeProviderOperation(params,context);