Updating licenses in all files
[appc.git] / appc-adapters / appc-iaas-adapter / appc-iaas-adapter-bundle / src / main / java / org / openecomp / appc / adapter / iaas / provider / operation / impl / base / ProviderOperation.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * APPC
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
11  * 
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  * 
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.
21  */
22
23 package org.openecomp.appc.adapter.iaas.provider.operation.impl.base;
24
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;
44 import org.slf4j.MDC;
45
46 import java.net.URI;
47 import java.util.Map;
48 import java.util.Set;
49 import java.util.regex.Pattern;
50
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;
54
55 /**
56  * @since September 26, 2016
57  */
58 public abstract class ProviderOperation implements IProviderOperation {
59
60     private static final EELFLogger logger = EELFManager.getInstance().getLogger(ProviderOperation.class);
61     protected static final Configuration configuration = ConfigurationFactory.getConfiguration();
62
63     public void setProviderCache(Map<String, ProviderCache> providerCache) {
64         this.providerCache = providerCache;
65     }
66
67     /**
68      * A cache of providers that are predefined.
69      */
70     private Map<String /* provider name */, ProviderCache> providerCache;
71
72
73     public void setDefaultUser(String defaultUser) {
74         DEFAULT_USER = defaultUser;
75     }
76
77     public void setDefaultPass(String defaultPass) {
78         DEFAULT_PASS = defaultPass;
79     }
80
81     /**
82      * The username and password to use for dynamically created connections
83      */
84     private static String DEFAULT_USER;
85     private static String DEFAULT_PASS;
86
87
88     /**
89      * set MDC props
90      * @param service
91      * @param serviceName
92      * @param adapterName
93      */
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);
98     }
99
100     /**
101      * initial log of the operation
102      * @param msg
103      * @param params
104      * @param context
105      */
106     protected void logOperation(Msg msg, Map<String, String> params, SvcLogicContext context){
107
108         String appName = configuration.getProperty(org.openecomp.appc.Constants.PROPERTY_APPLICATION_NAME);
109         logger.info(msg, appName);
110
111         debugParameters(params);
112         debugContext(context);
113     }
114
115     /**
116      * This method is used to dump the value of the parameters to the log for debugging purposes.
117      *
118      * @param parameters
119      *            The parameters to be printed to the log
120      */
121     private void debugParameters(Map<String, String> parameters) {
122         for (String key : parameters.keySet()) {
123             logger.debug(Msg.PROPERTY_VALUE, key, parameters.get(key));
124         }
125     }
126
127     /**
128      * This method is used to create a diagnostic dump of the context for the log
129      *
130      * @param context
131      *            The context to be dumped
132      */
133     @SuppressWarnings({
134             "nls", "static-method"
135     })
136     private void debugContext(SvcLogicContext context) {
137         Set<String> keys = context.getAttributeKeySet();
138         StringBuilder builder = new StringBuilder();
139
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);
154                 builder.append(key);
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);
161             }
162         }
163
164         logger.debug(builder.toString());
165     }
166
167
168     /**
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.
171      *
172      * @param parameters
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
178      */
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) {
187                 success = false;
188                 msg.append(Constants.QUOTE);
189                 msg.append(propertyName);
190                 msg.append(Constants.QUOTE);
191                 msg.append(Constants.SPACE);
192             }
193         }
194
195         if (!success) {
196             logger.error(msg.toString());
197             throw new RequestFailedException("Check Parameters", msg.toString(), HttpStatus.BAD_REQUEST_400, (Server)null);
198         }
199     }
200
201     /**
202      * @param rc
203      *            The request context that manages the state and recovery of the request for the life of its processing.
204      * @param code
205      * @param message
206      */
207     protected void doFailure(RequestContext rc, HttpStatus code, String message) {
208         try {
209             doFailure(rc, code, message, null);
210         } catch (APPCException ignored) {/* never happens */}
211     }
212
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"));
218         }
219         String status;
220         try {
221             status = Integer.toString(code.getStatusCode());
222         } catch (Exception e) {
223             status = "500";
224         }
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);
228
229         if (null != cause) throw new APPCException(cause);
230     }
231
232     /**
233      * @param rc
234      *            The request context that manages the state and recovery of the request for the life of its processing.
235      */
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()));
241     }
242
243     protected boolean validateVM(RequestContext rc, String appName, String vm_url, VMURL vm)
244             throws RequestFailedException {
245         String msg;
246         if (vm == null) {
247             msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, vm_url);
248             logger.error(msg);
249             doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
250             return true;
251         }
252         validateVMURL(vm);
253         return false;
254     }
255
256     protected void validateVMURL(VMURL vm) throws RequestFailedException {
257         String name = "vm-id";
258         if (vm == null) {
259             throw new RequestFailedException(String.format("The value %s cannot be null.", name));
260         }
261
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
265         try {
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()));
271         }
272
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);
276
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()));
280         }
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()));
284         }
285     }
286
287     private ProviderCache createProviderCache(VMURL vm, IdentityURL ident) {
288         if (vm != null && ident != null) {
289             ProviderCache cache = new ProviderCache();
290
291             cache.setIdentityURL(ident.toString());
292             cache.setProviderName(ident.toString());
293             // cache.setProviderType("OpenStack");
294
295             TenantCache tenant = cache.addTenant(vm.getTenantId(),null, DEFAULT_USER, DEFAULT_PASS);
296
297             // Make sure we could initialize the the cache otherwise return null
298             if (tenant != null && tenant.isInitialized()) {
299                 return cache;
300             }
301         }
302         return null;
303     }
304
305     /**
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
308      * server.
309      *
310      * @param rc
311      *            The request context that wraps and manages the state of the request
312      * @param selfLinkURL
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.
317      */
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);
323
324         if (vm == null) {
325             String msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, selfLinkURL);
326             logger.error(msg);
327             doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
328             return null;
329         }
330
331         /*
332          * Get the cache of tenants and contexts for the named provider, if one exists
333          */
334         ProviderCache cache = providerCache.get(providerName);
335
336         /*
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.
339          */
340         if (cache == null) {
341             if (ident != null) {
342                 cache = createProviderCache(vm, ident);
343             }
344             if (cache != null) {
345                 providerCache.put(cache.getProviderName(), cache);
346             } else {
347                 String msg =
348                         EELFResourceManager.format(Msg.UNKNOWN_PROVIDER, providerName, providerCache.keySet().toString());
349                 logger.error(msg);
350                 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
351                 return null;
352             }
353         }
354
355         if (providerName == null) {
356             logger
357                     .debug(String.format("Using the default provider cache [%s] since no valid identity url was passed in.",
358                             cache.getIdentityURL()));
359         }
360
361         // get the tenant cache for the vm
362         String identityURL = cache.getIdentityURL();
363         TenantCache tenantCache = cache.getTenant(vm.getTenantId());
364
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);
368
369             if(tenantCache == null){
370                 //tenant not found
371                 String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, selfLinkURL);
372                 logger.error(msg);
373                 doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
374                 return null;
375             }
376         }
377
378         //reserve the context
379         String tenantName = tenantCache.getTenantName();
380         String tenantId = tenantCache.getTenantId();
381         String region = tenantCache.determineRegion(vm);
382
383         if (region != null) {
384             Pool<Context> pool = tenantCache.getPools().get(region);
385
386             while (rc.attempt()) {
387                 try {
388                     Context context = pool.reserve();
389
390                     /*
391                      * Insert logic here to test the context for connectivity because we may have gotten one from
392                      * the pool that was previously created.
393                      */
394                     if (context.isStale()) {
395                         context.relogin();
396                     }
397                     return context;
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);
403                     rc.delay();
404                 } catch (Exception e) {
405                     String msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, e,
406                             e.getClass().getSimpleName(), "find", selfLinkURL, tenantCache.getTenantName());
407
408                     logger.error(msg, e);
409                     doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
410                     return null;
411                 }
412             }
413
414             String msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, providerName, identityURL);
415             logger.error(msg);
416             doFailure(rc, HttpStatus.BAD_GATEWAY_502, msg);
417             return null;
418         }
419
420
421         String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, selfLinkURL);
422         logger.error(msg);
423         doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
424         return null;
425     }
426
427     protected Context resolveContext(RequestContext rc, Map<String, String> params, String appName, String vm_url)
428             throws RequestFailedException {
429
430         VMURL vm = VMURL.parseURL(vm_url);
431         if (vm == null) {
432             String msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, vm_url);
433             doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
434             logger.error(msg);
435             return null;
436         }
437         validateVMURL(vm);
438         IdentityURL ident = IdentityURL.parseURL(params.get(ProviderAdapter.PROPERTY_IDENTITY_URL));
439         String identStr = (ident == null) ? null : ident.toString();
440
441         return getContext(rc, vm_url, identStr);
442
443     }
444
445
446
447
448
449
450
451     protected abstract ModelObject executeProviderOperation(Map<String, String> params, SvcLogicContext context) throws APPCException;
452
453     @Override
454     public ModelObject doOperation(Map<String, String> params, SvcLogicContext context) throws APPCException {
455
456         return executeProviderOperation(params,context);
457     }
458 }