Moving all files to root directory
[appc.git] / appc-adapters / appc-iaas-adapter / appc-iaas-adapter-bundle / src / main / java / org / openecomp / appc / adapter / iaas / impl / ProviderAdapterImpl.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * openECOMP : APP-C
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights
6  *                                              reserved.
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  */
21
22 package org.openecomp.appc.adapter.iaas.impl;
23
24 import com.woorea.openstack.base.client.OpenStackBaseException;
25 import com.woorea.openstack.heat.Heat;
26 import org.glassfish.grizzly.http.util.HttpStatus;
27 import org.openecomp.appc.Constants;
28 import org.openecomp.appc.adapter.iaas.ProviderAdapter;
29 import org.openecomp.appc.adapter.openstack.heat.SnapshotResource;
30 import org.openecomp.appc.adapter.openstack.heat.StackResource;
31 import org.openecomp.appc.adapter.openstack.heat.model.CreateSnapshotParams;
32 import org.openecomp.appc.adapter.openstack.heat.model.Snapshot;
33 import org.openecomp.appc.configuration.Configuration;
34 import org.openecomp.appc.configuration.ConfigurationFactory;
35 import org.openecomp.appc.exceptions.APPCException;
36 import org.openecomp.appc.exceptions.UnknownProviderException;
37 import org.openecomp.appc.i18n.Msg;
38 import org.openecomp.appc.pool.Pool;
39 import org.openecomp.appc.pool.PoolExtensionException;
40 import org.openecomp.appc.util.StructuredPropertyHelper;
41 import org.openecomp.appc.util.StructuredPropertyHelper.Node;
42 import com.att.cdp.exceptions.*;
43 import com.att.cdp.openstack.OpenStackContext;
44 import com.att.cdp.openstack.connectors.HeatConnector;
45 import com.att.cdp.openstack.util.ExceptionMapper;
46 import com.att.cdp.pal.util.StringHelper;
47 import com.att.cdp.zones.*;
48 import com.att.cdp.zones.model.Image;
49 import com.att.cdp.zones.model.Server;
50 import com.att.cdp.zones.model.ServerBootSource;
51 import com.att.cdp.zones.model.Stack;
52 import com.att.cdp.zones.model.Server.Status;
53 import com.att.cdp.zones.spi.AbstractService;
54 import com.att.cdp.zones.spi.RequestState;
55 import com.att.eelf.configuration.EELFLogger;
56 import com.att.eelf.configuration.EELFManager;
57 import com.att.eelf.i18n.EELFResourceManager;
58 import org.openecomp.sdnc.sli.SvcLogicContext;
59 import org.slf4j.MDC;
60
61 import static com.att.eelf.configuration.Configuration.MDC_SERVICE_NAME;
62
63 import java.io.IOException;
64 import java.net.URI;
65 import java.text.SimpleDateFormat;
66 import java.util.*;
67 import java.util.regex.Pattern;
68
69 /**
70  * This class implements the {@link ProviderAdapter} interface. This interface defines the behaviors that our service
71  * provides.
72  */
73 @SuppressWarnings("javadoc")
74 public class ProviderAdapterImpl implements ProviderAdapter {
75
76     /**
77      * The name of the adapter
78      */
79     @SuppressWarnings("nls")
80     private static final String ADAPTER_NAME = "Appc IaaS Adapter";
81
82     /**
83      * The username and password to use for dynamically created connections
84      */
85     private static String DEFAULT_USER;
86     private static String DEFAULT_PASS;
87
88     /**
89      * The constant used to define the adapter name in the mapped diagnostic context
90      */
91     @SuppressWarnings("nls")
92     private static final String MDC_ADAPTER = "adapter";
93
94     /**
95      * The constant used to define the service name in the mapped diagnostic context
96      */
97     @SuppressWarnings("nls")
98     static final String MDC_SERVICE = "service";
99
100     /**
101      * The constant for the status code for a failed outcome
102      */
103     @SuppressWarnings("nls")
104     private static final String OUTCOME_FAILURE = "failure";
105
106     /**
107      * The constant for the status code for a successful outcome
108      */
109     @SuppressWarnings("nls")
110     private static final String OUTCOME_SUCCESS = "success";
111
112     /**
113      * A constant for the property token "provider" used in the structured property specifications
114      */
115     @SuppressWarnings("nls")
116     private static final String PROPERTY_PROVIDER = "provider";
117
118     /**
119      * A constant for the property token "identity" used in the structured property specifications
120      */
121     @SuppressWarnings("nls")
122     private static final String PROPERTY_PROVIDER_IDENTITY = "identity";
123
124     /**
125      * A constant for the property token "tenant" used in the structured property specifications
126      */
127     @SuppressWarnings("nls")
128     private static final String PROPERTY_PROVIDER_TENANT = "tenant";
129
130     /**
131      * A constant for the property token "tenant name" used in the structured property specifications
132      */
133     @SuppressWarnings("nls")
134     private static final String PROPERTY_PROVIDER_TENANT_NAME = "name";
135
136     /**
137      * A constant for the property token "password" used in the structured property specifications
138      */
139     @SuppressWarnings("nls")
140     private static final String PROPERTY_PROVIDER_TENANT_PASSWORD = "password"; // NOSONAR
141
142     /**
143      * A constant for the property token "userid" used in the structured property specifications
144      */
145     @SuppressWarnings("nls")
146     private static final String PROPERTY_PROVIDER_TENANT_USERID = "userid";
147
148     /**
149      * A constant for the property token "type" used in the structured property specifications
150      */
151     @SuppressWarnings("nls")
152     private static final String PROPERTY_PROVIDER_TYPE = "type";
153
154     /**
155      * The name of the service to evacuate a server
156      */
157     @SuppressWarnings("nls")
158     private static final String EVACUATE_SERVICE = "evacuateServer";
159
160     /**
161      * The name of the service to migrate a server
162      */
163     @SuppressWarnings("nls")
164     private static final String MIGRATE_SERVICE = "migrateServer";
165
166     /**
167      * The name of the service to rebuild a server
168      */
169     @SuppressWarnings("nls")
170     private static final String REBUILD_SERVICE = "rebuildServer";
171
172     /**
173      * The name of the service to restart a server
174      */
175     @SuppressWarnings("nls")
176     private static final String RESTART_SERVICE = "restartServer";
177
178     /**
179          * The name of the service to check status of  a server
180          */
181         @SuppressWarnings("nls")
182     private static final String VMSTATUSCHECK_SERVICE = "vmStatuschecker";
183
184
185     /**
186      * The name of the service to restart a server
187      */
188     @SuppressWarnings("nls")
189     private static final String SNAPSHOT_SERVICE = "createSnapshot";
190
191     /**
192      * The name of the service to terminate a stack
193      */
194     @SuppressWarnings("nls")
195     private static final String TERMINATE_STACK = "terminateStack";
196
197     /**
198      * The name of the service to snapshot a stack
199      */
200     @SuppressWarnings("nls")
201     private static final String SNAPSHOT_STACK = "snapshotStack";
202
203     /**
204      * The name of a service to start a server
205      */
206     @SuppressWarnings("nls")
207     private static final String START_SERVICE = "startServer";
208
209     /**
210      * The name of the service to stop a server
211      */
212     @SuppressWarnings("nls")
213     private static final String STOP_SERVICE = "stopServer";
214
215     /**
216      * The name of the service to stop a server
217      */
218     @SuppressWarnings("nls")
219     private static final String TERMINATE_SERVICE = "terminateServer";
220
221     /**
222      * The name of the service to lookup a server
223      */
224     @SuppressWarnings("nls")
225     private static final String LOOKUP_SERVICE = "lookupServer";
226
227     /**
228      * The logger to be used
229      */
230     private static final EELFLogger logger = EELFManager.getInstance().getLogger(ProviderAdapterImpl.class);
231
232     private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
233
234     /**
235      * The constant for a left parenthesis
236      */
237     private static final char LPAREN = '(';
238
239     /**
240      * The constant for a new line control code
241      */
242     private static final char NL = '\n';
243
244     /**
245      * The constant for a single quote
246      */
247     private static final char QUOTE = '\'';
248
249     /**
250      * The constant for a right parenthesis
251      */
252     private static final char RPAREN = ')';
253
254     /**
255      * The constant for a space
256      */
257     private static final char SPACE = ' ';
258
259     /**
260      * A reference to the adapter configuration object.
261      */
262     private Configuration configuration;
263
264     /**
265      * A cache of providers that are predefined.
266      */
267     private Map<String /* provider name */, ProviderCache> providerCache;
268
269     /**
270      * A list of valid initial VM statuses for a migrate operations
271      */
272     private static final Collection<Status> migratableStatuses = Arrays.asList(Status.READY, Status.RUNNING, Status.SUSPENDED);
273
274     /**
275      * This default constructor is used as a work around because the activator wasnt getting called
276      */
277     @SuppressWarnings("all")
278     public ProviderAdapterImpl() {
279         initialize();
280
281     }
282
283     /**
284      * This constructor is used primarily in the test cases to bypass initialization of the adapter for isolated,
285      * disconnected testing
286      *
287      * @param initialize
288      *            True if the adapter is to be initialized, can false if not
289      */
290     @SuppressWarnings("all")
291     public ProviderAdapterImpl(boolean initialize) {
292         configuration = ConfigurationFactory.getConfiguration();
293         if (initialize) {
294             initialize();
295         }
296     }
297
298     /**
299      * @param props
300      *            not used
301      */
302     public ProviderAdapterImpl(@SuppressWarnings("unused") Properties props) {
303         initialize();
304
305     }
306
307     /**
308      * Returns the symbolic name of the adapter
309      *
310      * @return The adapter name
311      * @see org.openecomp.appc.adapter.iaas.ProviderAdapter#getAdapterName()
312      */
313     @Override
314     public String getAdapterName() {
315         return configuration.getProperty(Constants.PROPERTY_ADAPTER_NAME);
316     }
317
318     @SuppressWarnings("nls")
319     @Override
320     public Image createSnapshot(Map<String, String> params, SvcLogicContext ctx) throws APPCException {
321         Image snapshot = null;
322         RequestContext rc = new RequestContext(ctx);
323         rc.isAlive();
324         MDC.put(MDC_ADAPTER, ADAPTER_NAME);
325         MDC.put(MDC_SERVICE, SNAPSHOT_SERVICE);
326         MDC.put(MDC_SERVICE_NAME, "App-C IaaS Adapter:Snapshot");
327         String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME);
328         logger.info(Msg.SNAPSHOTING_SERVER, appName);
329         String msg;
330
331         try {
332             validateParametersExist(rc, params, ProviderAdapter.PROPERTY_INSTANCE_URL,
333                 ProviderAdapter.PROPERTY_PROVIDER_NAME);
334             String vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL);
335             debugParameters(params);
336             debugContext(ctx);
337
338             VMURL vm = VMURL.parseURL(vm_url);
339             if (validateVM(rc, appName, vm_url, vm)) return null;
340
341             IdentityURL ident = IdentityURL.parseURL(params.get(ProviderAdapter.PROPERTY_IDENTITY_URL));
342             String identStr = (ident == null) ? null : ident.toString();
343
344             Context context = null;
345             try {
346                 context = getContext(rc, vm_url, identStr);
347                 if (context != null) {
348                     Server server = lookupServer(rc, context, vm.getServerId());
349                     logger.debug(Msg.SERVER_FOUND, vm_url, context.getTenantName(), server.getStatus().toString());
350
351                     if (hasImageAccess(rc, context)) {
352                         snapshot = createSnapshot(rc, server);
353                         doSuccess(rc);
354                     } else {
355                         msg = EELFResourceManager.format(Msg.REBUILD_SERVER_FAILED, server.getName(), server.getId(),
356                             "Accessing Image Service Failed");
357                         logger.error(msg);
358                         doFailure(rc, HttpStatus.FORBIDDEN_403, msg);
359                     }
360                     context.close();
361                 }
362             } catch (ResourceNotFoundException e) {
363                 msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, e, vm_url);
364                 logger.error(msg);
365                 doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
366             } catch (Throwable t) {
367                 msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, t, t.getClass().getSimpleName(),
368                     SNAPSHOT_SERVICE, vm_url, context == null ? "Unknown" : context.getTenantName());
369                 logger.error(msg, t);
370                 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
371             }
372         } catch (RequestFailedException e) {
373             doFailure(rc, e.getStatus(), e.getMessage());
374         }
375         return snapshot;
376     }
377
378     private boolean validateVM(RequestContext rc, String appName, String vm_url, VMURL vm)
379                     throws RequestFailedException {
380         String msg;
381         if (vm == null) {
382             msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, vm_url);
383             logger.error(msg);
384             doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
385             return true;
386         }
387         validateVMURL(vm);
388         return false;
389     }
390
391     private Image createSnapshot(RequestContext rc, Server server) throws ZoneException, RequestFailedException {
392         Context context = server.getContext();
393         Provider provider = context.getProvider();
394         ImageService service = context.getImageService(); // Already checked access by this point
395
396         String snapshotName = generateSnapshotName(server.getName());
397
398         logger.info(String.format("Creating snapshot of server %s (%s) with name %s", server.getName(), server.getId(),
399             snapshotName));
400
401         // Request Snapshot
402         String msg;
403         while (rc.attempt()) {
404             try {
405                 server.createSnapshot(snapshotName);
406                 break;
407             } catch (ContextConnectionException e) {
408                 msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(),
409                     context.getTenant().getName(), context.getTenant().getId(), e.getMessage(),
410                     Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()),
411                     Integer.toString(rc.getRetryLimit()));
412                 logger.error(msg, e);
413                 rc.delay();
414             }
415         }
416         if (rc.isFailed()) {
417             msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL());
418             logger.error(msg);
419             throw new RequestFailedException("Stop Server", msg, HttpStatus.BAD_GATEWAY_502, server);
420         }
421         rc.reset();
422
423         // Locate snapshot image
424         Image snapshot = null;
425         while (rc.attempt()) {
426             try {
427                 snapshot = service.getImageByName(snapshotName);
428                 if (snapshot != null) {
429                     break;
430                 }
431             } catch (ContextConnectionException e) {
432                 msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(),
433                     context.getTenant().getName(), context.getTenant().getId(), e.getMessage(),
434                     Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()),
435                     Integer.toString(rc.getRetryLimit()));
436                 logger.error(msg, e);
437                 rc.delay();
438             }
439         }
440         if (rc.isFailed()) {
441             msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL());
442             logger.error(msg);
443             throw new RequestFailedException("Stop Server", msg, HttpStatus.BAD_GATEWAY_502, server);
444         }
445         rc.reset();
446
447         // Wait for it to be ready
448         waitForStateChange(rc, snapshot, Image.Status.ACTIVE);
449
450         return snapshot;
451     }
452
453     private String generateSnapshotName(String server) {
454         SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT);
455         return String.format("Snapshot of %s at %s", server, df.format(new Date()));
456     }
457
458     /**
459      * @see org.openecomp.appc.adapter.iaas.ProviderAdapter#evacuateServer(java.util.Map, org.openecomp.sdnc.sli.SvcLogicContext)
460      */
461     @SuppressWarnings("nls")
462     @Override
463     public Server evacuateServer(Map<String, String> params, SvcLogicContext ctx) throws APPCException {
464         Server server = null;
465         RequestContext rc = new RequestContext(ctx);
466         rc.isAlive();
467         MDC.put(MDC_ADAPTER, ADAPTER_NAME);
468         MDC.put(MDC_SERVICE, EVACUATE_SERVICE);
469         MDC.put(MDC_SERVICE_NAME, "App-C IaaS Adapter:Evacuate");
470         String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME);
471         logger.info(Msg.EVACUATING_SERVER, appName);
472         String msg;
473
474         try {
475             validateParametersExist(rc, params, ProviderAdapter.PROPERTY_INSTANCE_URL,
476                 ProviderAdapter.PROPERTY_PROVIDER_NAME);
477             String vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL);
478             String providerName = params.get(ProviderAdapter.PROPERTY_PROVIDER_NAME);
479             debugParameters(params);
480             debugContext(ctx);
481
482             VMURL vm = VMURL.parseURL(vm_url);
483             if (validateVM(rc, appName, vm_url, vm)) return null;
484
485             Context context = null;
486             try {
487                 context = getContext(rc, vm_url, providerName);
488                 if (context != null) {
489                     server = lookupServer(rc, context, vm.getServerId());
490                     logger.debug(Msg.SERVER_FOUND, vm_url, context.getTenantName(), server.getStatus().toString());
491                     evacuateServer(rc, server);
492                     server.refreshStatus();
493                     context.close();
494                     doSuccess(rc);
495                 }
496             } catch (ResourceNotFoundException e) {
497                 msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, e, vm_url);
498                 logger.error(msg);
499                 doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
500             } catch (Throwable t) {
501                 msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, t, t.getClass().getSimpleName(),
502                     EVACUATE_SERVICE, vm_url, context == null ? "Unknown" : context.getTenantName());
503                 logger.error(msg, t);
504                 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
505             }
506         } catch (RequestFailedException e) {
507             doFailure(rc, e.getStatus(), e.getMessage());
508         }
509
510         return server;
511     }
512
513     /**
514      * @see org.openecomp.appc.adapter.iaas.ProviderAdapter#migrateServer(java.util.Map, org.openecomp.sdnc.sli.SvcLogicContext)
515      */
516     @SuppressWarnings("nls")
517     @Override
518     public Server migrateServer(Map<String, String> params, SvcLogicContext ctx) throws APPCException {
519         Server server = null;
520         RequestContext rc = new RequestContext(ctx);
521         rc.isAlive();
522         MDC.put(MDC_ADAPTER, ADAPTER_NAME);
523         MDC.put(MDC_SERVICE, MIGRATE_SERVICE);
524         MDC.put(MDC_SERVICE_NAME, "App-C IaaS Adapter:Migrate");
525         String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME);
526         logger.info(Msg.MIGRATING_SERVER, appName);
527         String msg;
528
529         try {
530             validateParametersExist(rc, params, ProviderAdapter.PROPERTY_INSTANCE_URL,
531                 ProviderAdapter.PROPERTY_PROVIDER_NAME);
532             String vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL);
533             debugParameters(params);
534             debugContext(ctx);
535
536             VMURL vm = VMURL.parseURL(vm_url);
537             if (validateVM(rc, appName, vm_url, vm)) return null;
538
539             IdentityURL ident = IdentityURL.parseURL(params.get(ProviderAdapter.PROPERTY_IDENTITY_URL));
540             String identStr = (ident == null) ? null : ident.toString();
541
542             Context context = null;
543             try {
544                 context = getContext(rc, vm_url, identStr);
545                 if (context != null) {
546                     server = lookupServer(rc, context, vm.getServerId());
547                     logger.debug(Msg.SERVER_FOUND, vm_url, context.getTenantName(), server.getStatus().toString());
548                     migrateServer(rc, server);
549                     server.refreshStatus();
550                     context.close();
551                     doSuccess(rc);
552                 }
553             } catch (ResourceNotFoundException e) {
554                 msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, e, vm_url);
555                 logger.error(msg);
556                 doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
557             } catch (Throwable t) {
558                 msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, t, t.getClass().getSimpleName(),
559                     MIGRATE_SERVICE, vm_url, context == null ? "Unknown" : context.getTenantName());
560                 logger.error(msg, t);
561                 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
562             }
563         } catch (RequestFailedException e) {
564             doFailure(rc, e.getStatus(), e.getMessage());
565         }
566
567         return server;
568     }
569
570     private void evacuateServer(RequestContext rc, @SuppressWarnings("unused") Server server) throws ZoneException, RequestFailedException {
571         doFailure(rc, HttpStatus.NOT_IMPLEMENTED_501, "The operation 'EVACUATE' is not yet implemented");
572     }
573
574     private void migrateServer(RequestContext rc, Server server) throws ZoneException, RequestFailedException {
575         String msg;
576         Context ctx = server.getContext();
577         ComputeService service = ctx.getComputeService();
578
579         // Init status will equal final status
580         Status initialStatus = server.getStatus();
581
582         if (initialStatus == null) {
583             throw new ZoneException("Failed to determine server's starting status");
584         }
585
586         // We can only migrate certain statuses
587         if (!migratableStatuses.contains(initialStatus)) {
588             throw new ZoneException(String.format("Cannot migrate server that is in %s state. Must be in one of [%s]",
589                 initialStatus, migratableStatuses));
590         }
591
592         boolean inConfirmPhase = false;
593         try {
594             while (rc.attempt()) {
595                 try {
596                     if (!inConfirmPhase) {
597                         // Initial migrate request
598                         service.migrateServer(server.getId());
599                         // Wait for change to verify resize
600                         waitForStateChange(rc, server, Status.READY);
601                         inConfirmPhase = true;
602                     }
603
604                     // Verify resize
605                     service.processResize(server);
606                     // Wait for complete. will go back to init status
607                     waitForStateChange(rc, server, initialStatus);
608                     logger.info("Completed migrate request successfully");
609                     return;
610                 } catch (ContextConnectionException e) {
611                     msg = getConnectionExceptionMessage(rc, ctx, e);
612                     logger.error(msg, e);
613                     rc.delay();
614                 }
615             }
616         } catch (ZoneException e) {
617             String phase = inConfirmPhase ? "VERIFY MIGRATE" : "REQUEST MIGRATE";
618             msg = EELFResourceManager.format(Msg.MIGRATE_SERVER_FAILED, server.getName(), server.getId(), phase,
619                 e.getMessage());
620             generateEvent(rc, false, msg);
621             logger.error(msg, e);
622             throw new RequestFailedException("Migrate Server", msg, HttpStatus.METHOD_NOT_ALLOWED_405, server);
623         }
624
625     }
626
627     /**
628      * @see org.openecomp.appc.adapter.iaas.ProviderAdapter#rebuildServer(java.util.Map, org.openecomp.sdnc.sli.SvcLogicContext)
629      */
630     @SuppressWarnings("nls")
631     @Override
632     public Server rebuildServer(Map<String, String> params, SvcLogicContext ctx) throws APPCException {
633         Server server = null;
634         RequestContext rc = new RequestContext(ctx);
635         rc.isAlive();
636         MDC.put(MDC_ADAPTER, ADAPTER_NAME);
637         MDC.put(MDC_SERVICE, REBUILD_SERVICE);
638         MDC.put(MDC_SERVICE_NAME, "App-C IaaS Adapter:Rebuild");
639         String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME);
640         logger.info(Msg.REBUILDING_SERVER, appName);
641         String msg;
642
643         try {
644             validateParametersExist(rc, params, ProviderAdapter.PROPERTY_INSTANCE_URL,
645                 ProviderAdapter.PROPERTY_PROVIDER_NAME);
646             String vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL);
647             debugParameters(params);
648             debugContext(ctx);
649
650             VMURL vm = VMURL.parseURL(vm_url);
651             if (validateVM(rc, appName, vm_url, vm)) return null;
652
653             IdentityURL ident = IdentityURL.parseURL(params.get(ProviderAdapter.PROPERTY_IDENTITY_URL));
654             String identStr = (ident == null) ? null : ident.toString();
655
656             Context context = null;
657             try {
658                 context = getContext(rc, vm_url, identStr);
659                 if (context != null) {
660                     server = lookupServer(rc, context, vm.getServerId());
661                     logger.debug(Msg.SERVER_FOUND, vm_url, context.getTenantName(), server.getStatus().toString());
662
663                     // Manually checking image service until new PAL release
664                     if (hasImageAccess(rc, context)) {
665                         rebuildServer(rc, server);
666                         doSuccess(rc);
667                     } else {
668                         msg = EELFResourceManager.format(Msg.REBUILD_SERVER_FAILED, server.getName(), server.getId(),
669                             "Accessing Image Service Failed");
670                         logger.error(msg);
671                         doFailure(rc, HttpStatus.FORBIDDEN_403, msg);
672                     }
673                     context.close();
674                 }
675             } catch (ResourceNotFoundException e) {
676                 msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, e, vm_url);
677                 logger.error(msg);
678                 doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
679             } catch (Throwable t) {
680                 msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, t, t.getClass().getSimpleName(),
681                     STOP_SERVICE, vm_url, context == null ? "Unknown" : context.getTenantName());
682                 logger.error(msg, t);
683                 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
684             }
685         } catch (RequestFailedException e) {
686             doFailure(rc, e.getStatus(), e.getMessage());
687         }
688
689         return server;
690     }
691
692     /**
693      * This method is used to restart an existing virtual machine given the fully qualified URL of the machine.
694      * <p>
695      * The fully qualified URL contains enough information to locate the appropriate server. The URL is of the form
696      * <pre>
697      *  [scheme]://[host[:port]] / [path] / [tenant_id] / servers / [vm_id]
698      * </pre> Where the various parts of the URL can be parsed and extracted and used to locate the appropriate service
699      * in the provider service catalog. This then allows us to open a context using the CDP abstraction, obtain the
700      * server by its UUID, and then perform the restart.
701      * </p>
702      *
703      * @throws UnknownProviderException
704      *             If the provider cannot be found
705      * @throws IllegalArgumentException
706      *             if the expected argument(s) are not defined or are invalid
707      * @see org.openecomp.appc.adapter.iaas.ProviderAdapter#restartServer(java.util.Map, org.openecomp.sdnc.sli.SvcLogicContext)
708      */
709     @SuppressWarnings("nls")
710     @Override
711     public Server restartServer(Map<String, String> params, SvcLogicContext ctx)
712         throws UnknownProviderException, IllegalArgumentException {
713         Server server = null;
714         RequestContext rc = new RequestContext(ctx);
715         rc.isAlive();
716         MDC.put(MDC_ADAPTER, ADAPTER_NAME);
717         MDC.put(MDC_SERVICE, RESTART_SERVICE);
718         MDC.put(MDC_SERVICE_NAME, "App-C IaaS Adapter:Restart");
719         String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME);
720         logger.info(Msg.RESTARTING_SERVER, appName);
721
722         try {
723             validateParametersExist(rc, params, ProviderAdapter.PROPERTY_INSTANCE_URL,
724                 ProviderAdapter.PROPERTY_PROVIDER_NAME);
725             debugParameters(params);
726             debugContext(ctx);
727             String vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL);
728
729             VMURL vm = VMURL.parseURL(vm_url);
730             if (validateVM(rc, appName, vm_url, vm)) return null;
731
732             IdentityURL ident = IdentityURL.parseURL(params.get(ProviderAdapter.PROPERTY_IDENTITY_URL));
733             String identStr = (ident == null) ? null : ident.toString();
734
735             Context context = null;
736             try {
737                 context = getContext(rc, vm_url, identStr);
738                 if (context != null) {
739                     server = lookupServer(rc, context, vm.getServerId());
740                     logger.debug(Msg.SERVER_FOUND, vm_url, context.getTenantName(), server.getStatus().toString());
741                     restartServer(rc, server);
742                     context.close();
743                     doSuccess(rc);
744                 }
745             } catch (ResourceNotFoundException e) {
746                 String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, e, vm_url);
747                 logger.error(msg);
748                 doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
749             } catch (Throwable t) {
750                 String msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, t, t.getClass().getSimpleName(),
751                     RESTART_SERVICE, vm_url, context == null ? "Unknown" : context.getTenantName());
752                 logger.error(msg, t);
753                 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
754             }
755         } catch (RequestFailedException e) {
756             doFailure(rc, e.getStatus(), e.getMessage());
757         }
758
759         return server;
760     }
761
762     /* *********************************************************************************/
763         /* DEVEN PANCHAL: This method is used to check the status of the VM               */
764         /**********************************************************************************/
765     public Server vmStatuschecker(Map<String, String> params, SvcLogicContext ctx) throws UnknownProviderException, IllegalArgumentException {
766        Server server = null;
767        RequestContext rc = new RequestContext(ctx);
768        rc.isAlive();
769        MDC.put(MDC_ADAPTER, ADAPTER_NAME);
770        MDC.put(MDC_SERVICE, VMSTATUSCHECK_SERVICE);
771        MDC.put(MDC_SERVICE_NAME, "App-C IaaS Adapter: vmstatuscheck");
772        String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME);
773
774        try {
775            validateParametersExist(rc, params, ProviderAdapter.PROPERTY_INSTANCE_URL,
776                ProviderAdapter.PROPERTY_PROVIDER_NAME);
777            debugParameters(params);
778            debugContext(ctx);
779            String vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL);
780
781            VMURL vm = VMURL.parseURL(vm_url);
782            if (validateVM(rc, appName, vm_url, vm)) return null;
783
784            IdentityURL ident = IdentityURL.parseURL(params.get(ProviderAdapter.PROPERTY_IDENTITY_URL));
785            String identStr = (ident == null) ? null : ident.toString();
786
787            Context context = null;
788            try {
789                context = getContext(rc, vm_url, identStr);
790                if (context != null) {
791                    server = lookupServer(rc, context, vm.getServerId());
792                    logger.debug(Msg.SERVER_FOUND, vm_url, context.getTenantName(), server.getStatus().toString());
793
794                    String statusvm;
795                    switch (server.getStatus()) {
796                    case DELETED:
797                         statusvm = "deleted";
798                        break;
799
800                    case RUNNING:
801                         statusvm = "running";
802                        break;
803
804                    case ERROR:
805                         statusvm = "error";
806                         break;
807
808                    case READY:
809                         statusvm = "ready";
810                        break;
811
812                    case PAUSED:
813                         statusvm = "paused";
814                        break;
815
816                    case SUSPENDED:
817                         statusvm = "suspended";
818                        break;
819
820                    case PENDING:
821                         statusvm = "pending";
822                        break;
823
824                    default:
825                         statusvm = "default-unknown state-should never occur";
826                        break;
827                }
828
829
830                    String statusofVM = statusvm;
831                    context.close();
832                    SvcLogicContext svcLogic = rc.getSvcLogicContext();
833                    svcLogic.setStatus(OUTCOME_SUCCESS);
834                    svcLogic.setAttribute("org.openecomp.statusofvm", statusofVM);
835                    svcLogic.setAttribute(Constants.STATUS_OF_VM, statusofVM);
836                    svcLogic.setAttribute(Constants.ATTRIBUTE_ERROR_CODE, Integer.toString(HttpStatus.OK_200.getStatusCode()));
837                }
838            } catch (ResourceNotFoundException e) {
839                String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, e, vm_url);
840                logger.error(msg);
841                doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
842            } catch (Throwable t) {
843                String msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, t, t.getClass().getSimpleName(),
844                    RESTART_SERVICE, vm_url, context == null ? "Unknown" : context.getTenantName());
845                logger.error(msg, t);
846                doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
847            }
848        } catch (RequestFailedException e) {
849            doFailure(rc, e.getStatus(), e.getMessage());
850        }
851
852        return server;
853    }
854
855    /* *********************************************************************************/
856
857
858     /**
859      * @see org.openecomp.appc.adapter.iaas.ProviderAdapter#startServer(java.util.Map, org.openecomp.sdnc.sli.SvcLogicContext)
860      */
861     @SuppressWarnings("nls")
862     @Override
863     public Server startServer(Map<String, String> params, SvcLogicContext ctx) throws APPCException {
864         Server server = null;
865         RequestContext rc = new RequestContext(ctx);
866         rc.isAlive();
867         MDC.put(MDC_ADAPTER, ADAPTER_NAME);
868         MDC.put(MDC_SERVICE, START_SERVICE);
869         String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME);
870         logger.info(Msg.RESTARTING_SERVER, appName);
871
872         try {
873             validateParametersExist(rc, params, ProviderAdapter.PROPERTY_INSTANCE_URL,
874                 ProviderAdapter.PROPERTY_PROVIDER_NAME);
875             debugParameters(params);
876             debugContext(ctx);
877             String vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL);
878             String providerName = params.get(ProviderAdapter.PROPERTY_PROVIDER_NAME);
879
880             VMURL vm = VMURL.parseURL(vm_url);
881             if (validateVM(rc, appName, vm_url, vm)) return null;
882
883             Context context = null;
884             try {
885                 context = getContext(rc, vm_url, providerName);
886                 if (context != null) {
887                     server = lookupServer(rc, context, vm.getServerId());
888                     logger.debug(Msg.SERVER_FOUND, vm_url, context.getTenantName(), server.getStatus().toString());
889                     stopServer(rc, server);
890                     server.refreshStatus();
891                     context.close();
892                     doSuccess(rc);
893                 }
894             } catch (ResourceNotFoundException e) {
895                 String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, e, vm_url);
896                 logger.error(msg);
897                 doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
898             } catch (Throwable t) {
899                 String msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, t, t.getClass().getSimpleName(),
900                     START_SERVICE, vm_url, context == null ? "Unknown" : context.getTenantName());
901                 logger.error(msg, t);
902                 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
903             }
904         } catch (RequestFailedException e) {
905             doFailure(rc, e.getStatus(), e.getMessage());
906         }
907
908         return server;
909     }
910
911     /**
912      * @see org.openecomp.appc.adapter.iaas.ProviderAdapter#stopServer(java.util.Map, org.openecomp.sdnc.sli.SvcLogicContext)
913      */
914     @SuppressWarnings("nls")
915     @Override
916     public Server stopServer(Map<String, String> params, SvcLogicContext ctx) throws APPCException {
917         Server server = null;
918         RequestContext rc = new RequestContext(ctx);
919         rc.isAlive();
920         MDC.put(MDC_ADAPTER, ADAPTER_NAME);
921         MDC.put(MDC_SERVICE, STOP_SERVICE);
922         String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME);
923         logger.info(Msg.STOPPING_SERVER, appName);
924
925         try {
926             validateParametersExist(rc, params, ProviderAdapter.PROPERTY_INSTANCE_URL,
927                 ProviderAdapter.PROPERTY_PROVIDER_NAME);
928             debugParameters(params);
929             debugContext(ctx);
930             String vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL);
931             ctx.setAttribute("STOP_STATUS", "SUCCESS");
932
933             VMURL vm = VMURL.parseURL(vm_url);
934             if (validateVM(rc, appName, vm_url, vm)) return null;
935
936             IdentityURL ident = IdentityURL.parseURL(params.get(ProviderAdapter.PROPERTY_IDENTITY_URL));
937             String identStr = (ident == null) ? null : ident.toString();
938
939             Context context = null;
940             try {
941                 context = getContext(rc, vm_url, identStr);
942                 if (context != null) {
943                     server = lookupServer(rc, context, vm.getServerId());
944                     logger.debug(Msg.SERVER_FOUND, vm_url, context.getTenantName(), server.getStatus().toString());
945                     if (server.getStatus().equals(Status.PENDING)) {
946                         throw new RequestFailedException("Server is in pending Status");
947                     }
948                     stopServer(rc, server);
949                     server.refreshStatus();
950                     if (server.getStatus().equals(Status.ERROR)) {
951                         throw new RequestFailedException("Server is in ERROR state after operation");
952                     }
953                     context.close();
954                     doSuccess(rc);
955                 }else{
956                     ctx.setAttribute("STOP_STATUS", "SERVER_NOT_FOUND");
957                 }
958             } catch (ResourceNotFoundException e) {
959                 String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, e, vm_url);
960                 ctx.setAttribute("STOP_STATUS", "SERVER_NOT_FOUND");
961                 logger.error(msg);
962                 doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
963             } catch (Throwable t) {
964                 String msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, t, t.getClass().getSimpleName(),
965                     STOP_SERVICE, vm_url, context == null ? "Unknown" : context.getTenantName());
966                 logger.error(msg, t);
967                 ctx.setAttribute("STOP_STATUS", "ERROR");
968                 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
969             }
970         } catch (RequestFailedException e) {
971             logger.error(EELFResourceManager.format(Msg.STOP_SERVER_FAILED, appName, "n/a", "n/a", e.getMessage()));
972             ctx.setAttribute("STOP_STATUS", "ERROR");
973             doFailure(rc, e.getStatus(), e.getMessage());
974         }
975
976         return server;
977     }
978
979     /**
980      * This method is used to validate that the parameters contain all required property names, and that the values are
981      * non-null and non-empty strings. We are still not ensured that the value is valid, but at least it exists.
982      *
983      * @param ctx
984      *            The request context object that manages the request
985      * @param parameters
986      *            The parameters to be checked
987      * @param propertyNames
988      *            The list of property names that are required to be present.
989      * @throws RequestFailedException
990      *             If the parameters are not valid
991      */
992     @SuppressWarnings({
993         "nls", "static-method"
994     })
995     private void validateParametersExist(@SuppressWarnings("unused") RequestContext ctx, Map<String, String> parameters, String... propertyNames)
996         throws RequestFailedException {
997         boolean success = true;
998         StringBuilder msg = new StringBuilder(EELFResourceManager.format(Msg.MISSING_REQUIRED_PROPERTIES, MDC.get(MDC_SERVICE)));
999         msg.append(NL);
1000         for (String propertyName : propertyNames) {
1001             String value = parameters.get(propertyName);
1002             if (value == null || value.trim().length() == 0) {
1003                 success = false;
1004                 msg.append(QUOTE);
1005                 msg.append(propertyName);
1006                 msg.append(QUOTE);
1007                 msg.append(SPACE);
1008             }
1009         }
1010
1011         if (!success) {
1012             logger.error(msg.toString());
1013             throw new RequestFailedException("Check Parameters", msg.toString(), HttpStatus.BAD_REQUEST_400, (Server)null);
1014         }
1015     }
1016
1017     /**
1018      * This method is used to create a diagnostic dump of the context for the log
1019      *
1020      * @param context
1021      *            The context to be dumped
1022      */
1023     @SuppressWarnings({
1024         "nls", "static-method"
1025     })
1026     private void debugContext(SvcLogicContext context) {
1027         Set<String> keys = context.getAttributeKeySet();
1028         StringBuilder builder = new StringBuilder();
1029
1030         builder.append("Service Logic Context: Status ");
1031         builder.append(LPAREN);
1032         builder.append(context.getStatus());
1033         builder.append(RPAREN);
1034         builder.append(", Attribute count ");
1035         builder.append(LPAREN);
1036         builder.append(keys == null ? "none" : Integer.toString(keys.size()));
1037         builder.append(RPAREN);
1038         if (keys != null && !keys.isEmpty()) {
1039             builder.append(NL);
1040             for (String key : keys) {
1041                 String value = context.getAttribute(key);
1042                 builder.append("Attribute ");
1043                 builder.append(LPAREN);
1044                 builder.append(key);
1045                 builder.append(RPAREN);
1046                 builder.append(", value ");
1047                 builder.append(LPAREN);
1048                 builder.append(value == null ? "" : value);
1049                 builder.append(RPAREN);
1050                 builder.append(NL);
1051             }
1052         }
1053
1054         logger.debug(builder.toString());
1055     }
1056
1057     void validateVMURL(VMURL vm) throws RequestFailedException {
1058         String name = "vm-id";
1059         if (vm == null) {
1060             throw new RequestFailedException(String.format("The value %s cannot be null.", name));
1061         }
1062
1063         // Check that its a good uri
1064         // This will probably never get hit bc of an earlier check while parsing
1065         // the string to a VMURL
1066         try {
1067             //noinspection ResultOfMethodCallIgnored
1068             URI.create(vm.toString());
1069         } catch (Exception e) {
1070             throw new RequestFailedException(
1071                 String.format("The value %s is not well formed [%s].", name, vm.toString()));
1072         }
1073
1074         // Check the tenant and vmid segments
1075         String patternRegex = "([0-9a-f]{8}(-)?[0-9a-f]{4}(-)?[0-9a-f]{4}(-)?[0-9a-f]{4}(-)?[0-9a-f]{12})";
1076         Pattern pattern = Pattern.compile(patternRegex, Pattern.CASE_INSENSITIVE);
1077
1078         if (!pattern.matcher(vm.getTenantId()).matches()) {
1079             throw new RequestFailedException(
1080                 String.format("The value %s has an invalid tenantId [%s].", name, vm.getTenantId()));
1081         }
1082         if (!pattern.matcher(vm.getServerId()).matches()) {
1083             throw new RequestFailedException(
1084                 String.format("The value %s has an invalid serverId [%s].", name, vm.getServerId()));
1085         }
1086     }
1087
1088     @SuppressWarnings("unused")
1089     private void validateIdentityURL(IdentityURL id) throws RequestFailedException {
1090         String name = "identity-url";
1091         if (id == null) {
1092             throw new RequestFailedException(String.format("The value %s cannot be null.", name));
1093         }
1094
1095         // Check that its a good uri
1096         // This will probably never get hit bc of an earlier check while parsing
1097         // the string to a VMURL
1098         try {
1099             //noinspection ResultOfMethodCallIgnored
1100             URI.create(id.toString());
1101         } catch (Exception e) {
1102             throw new RequestFailedException(
1103                 String.format("The value %s is not well formed [%s].", name, id.toString()));
1104         }
1105     }
1106
1107     /**
1108      * This method is used to dump the value of the parameters to the log for debugging purposes.
1109      *
1110      * @param parameters
1111      *            The parameters to be printed to the log
1112      */
1113     @SuppressWarnings("static-method")
1114     private void debugParameters(Map<String, String> parameters) {
1115         for (String key : parameters.keySet()) {
1116             logger.debug(Msg.PROPERTY_VALUE, key, parameters.get(key));
1117         }
1118     }
1119
1120     /**
1121      * @param rc
1122      *            The request context that manages the state and recovery of the request for the life of its processing.
1123      * @param code
1124      * @param message
1125      */
1126     @SuppressWarnings("static-method")
1127     private void doFailure(RequestContext rc, HttpStatus code, String message) {
1128         try {
1129             doFailure(rc, code, message, null);
1130         } catch (APPCException ignored) {/* never happens */}
1131     }
1132
1133
1134     private void doFailure(RequestContext rc, HttpStatus code, String message, Throwable cause) throws APPCException {
1135         SvcLogicContext svcLogic = rc.getSvcLogicContext();
1136         String msg = (message == null) ? code.getReasonPhrase() : message;
1137         if (msg.contains("\n")) {
1138             msg = msg.substring(0, msg.indexOf("\n"));
1139         }
1140         String status;
1141         try {
1142             status = Integer.toString(code.getStatusCode());
1143         } catch (Exception e) {
1144             status = "500";
1145         }
1146         svcLogic.setStatus(OUTCOME_FAILURE);
1147         svcLogic.setAttribute(Constants.ATTRIBUTE_ERROR_CODE, status);
1148         svcLogic.setAttribute(Constants.ATTRIBUTE_ERROR_MESSAGE, msg);
1149         svcLogic.setAttribute(Constants.DG_OUTPUT_STATUS_MESSAGE, msg);
1150
1151         if (null != cause) throw new APPCException(cause);
1152     }
1153
1154     /**
1155      * @param rc
1156      *            The request context that manages the state and recovery of the request for the life of its processing.
1157      */
1158     @SuppressWarnings("static-method")
1159     private void doSuccess(RequestContext rc) {
1160         SvcLogicContext svcLogic = rc.getSvcLogicContext();
1161         svcLogic.setStatus(OUTCOME_SUCCESS);
1162         svcLogic.setAttribute(Constants.ATTRIBUTE_ERROR_CODE, Integer.toString(HttpStatus.OK_200.getStatusCode()));
1163     }
1164
1165     /**
1166      * Generates the event indicating what happened
1167      *
1168      * @param rc
1169      *            The request context that manages the state and recovery of the request for the life of its processing.
1170      * @param success
1171      *            True if the event represents a successful outcome
1172      * @param msg
1173      *            The detailed message
1174      */
1175     private void generateEvent(@SuppressWarnings("unused") RequestContext rc, @SuppressWarnings("unused") boolean success, @SuppressWarnings("unused") String msg) {
1176         // indication to the DG to generate the event?
1177     }
1178
1179     /**
1180      * This method is a general helper method used to locate a server given its fully-qualified self-link URL on a
1181      * supported provider, regardless of region(s), and to return an opened context that can be used to access that
1182      * server.
1183      *
1184      * @param rc
1185      *            The request context that wraps and manages the state of the request
1186      * @param selfLinkURL
1187      *            The fully-qualified self-link URL of the server
1188      * @param providerName
1189      *            The name of the provider to be searched
1190      * @return The context that can be used to access the server, or null if not found.
1191      */
1192     @SuppressWarnings("nls")
1193     private Context getContext(RequestContext rc, String selfLinkURL, String providerName) {
1194         VMURL vm = VMURL.parseURL(selfLinkURL);
1195         IdentityURL ident = IdentityURL.parseURL(providerName);
1196         String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME);
1197
1198         if (vm == null) {
1199             String msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, selfLinkURL);
1200             logger.error(msg);
1201             doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
1202             return null;
1203         }
1204
1205         /*
1206          * Get the cache of tenants and contexts for the named provider, if one exists
1207          */
1208         ProviderCache cache = providerCache.get(providerName);
1209
1210         /*
1211          * If one doesn't exist, try and create it. If we have enough information to create it successfully, add it to
1212          * the cache and continue, otherwise fail the request.
1213          */
1214         if (cache == null) {
1215             if (ident != null) {
1216                 cache = createProviderCache(vm, ident);
1217             }
1218             if (cache != null) {
1219                 providerCache.put(cache.getProviderName(), cache);
1220             } else {
1221                 String msg =
1222                     EELFResourceManager.format(Msg.UNKNOWN_PROVIDER, providerName, providerCache.keySet().toString());
1223                 logger.error(msg);
1224                 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
1225                 return null;
1226             }
1227         }
1228
1229         if (providerName == null) {
1230             logger
1231                 .debug(String.format("Using the default provider cache [%s] since no valid identity url was passed in.",
1232                     cache.getIdentityURL()));
1233         }
1234
1235         // get the tenant cache for the vm
1236         String identityURL = cache.getIdentityURL();
1237          TenantCache tenantCache = cache.getTenant(vm.getTenantId());
1238
1239         if(tenantCache == null){
1240             //no tenantCache matching tenant, add tenant to the provider cache
1241                 tenantCache = cache.addTenant(vm.getTenantId(),null,DEFAULT_USER, DEFAULT_PASS);
1242
1243                 if(tenantCache == null){
1244                     //tenant not found
1245                     String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, selfLinkURL);
1246                     logger.error(msg);
1247                     doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
1248                     return null;
1249                 }
1250         }
1251
1252         //reserve the context
1253         String tenantName = tenantCache.getTenantName();
1254         String tenantId = tenantCache.getTenantId();
1255         String region = tenantCache.determineRegion(vm);
1256
1257         if (region != null) {
1258             Pool<Context> pool = tenantCache.getPools().get(region);
1259
1260             while (rc.attempt()) {
1261                 try {
1262                     Context context = pool.reserve();
1263
1264                     /*
1265                      * Insert logic here to test the context for connectivity because we may have gotten one from
1266                      * the pool that was previously created.
1267                      */
1268                     if (context.isStale()) {
1269                         context.relogin();
1270                     }
1271                     return context;
1272                 } catch (PoolExtensionException e) {
1273                     String msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, providerName, identityURL,
1274                         tenantName, tenantId, e.getMessage(), Long.toString(rc.getRetryDelay()),
1275                         Integer.toString(rc.getAttempts()), Integer.toString(rc.getRetryLimit()));
1276                     logger.error(msg, e);
1277                     rc.delay();
1278                 } catch (Exception e) {
1279                     String msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, e,
1280                         e.getClass().getSimpleName(), "find", selfLinkURL, tenantCache.getTenantName());
1281
1282                     logger.error(msg, e);
1283                     doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
1284                     return null;
1285                 }
1286             }
1287
1288             String msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, providerName, identityURL);
1289             logger.error(msg);
1290             doFailure(rc, HttpStatus.BAD_GATEWAY_502, msg);
1291             return null;
1292         }
1293
1294
1295         String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, selfLinkURL);
1296         logger.error(msg);
1297         doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
1298         return null;
1299     }
1300
1301     /**
1302      * initialize the provider adapter by building the context cache
1303      */
1304     private void initialize() {
1305         configuration = ConfigurationFactory.getConfiguration();
1306
1307         /*
1308          * Initialize the provider cache for all defined providers. The definition of the providers uses a structured
1309          * property set, where the names form a hierarchical name space (dotted notation, such as one.two.three). Each
1310          * name in the name space can also be serialized by appending a sequence number. All nodes at the same level
1311          * with the same serial number are grouped together in the namespace hierarchy. This allows a hierarchical
1312          * multi-valued property to be defined, which can then be used to setup the provider and tenant caches.
1313          * <p>
1314          * For example, the following definitions show how the namespace hierarchy is defined for two providers, with
1315          * two tenants on the first provider and a single tenant for the second provider. <pre>
1316          * provider1.type=OpenStackProvider1
1317          * provider1.name=OpenStackProviderName1
1318          * provider1.identity=http://192.168.1.2:5000/v2.0
1319          * provider1.tenant1.name=MY-TENANT-NAME
1320          * provider1.tenant1.userid=userid
1321          * provider1.tenant1.password=userid@123
1322          * provider1.tenant2.name=MY-TENANT-NAME
1323          * provider1.tenant2.userid=userid
1324          * provider1.tenant2.password=userid@123
1325          * provider2.type=OpenStackProvider2
1326          * provider2.name=OpenStackProviderName2
1327          * provider2.identity=http://192.168.1.2:5000/v2.0
1328          * provider2.tenant1.name=MY-TENANT-NAME
1329          * provider2.tenant1.userid=userid
1330          * provider2.tenant1.password=userid@123
1331          * </pre>
1332          * </p>
1333          */
1334         providerCache = new HashMap<>();
1335         Properties properties = configuration.getProperties();
1336         List<Node> providers = StructuredPropertyHelper.getStructuredProperties(properties, PROPERTY_PROVIDER);
1337
1338         for (Node provider : providers) {
1339             ProviderCache cache = new ProviderCache();
1340             List<Node> providerNodes = provider.getChildren();
1341             for (Node node : providerNodes) {
1342                 if (node.getName().equals(PROPERTY_PROVIDER_TYPE)) {
1343                     cache.setProviderType(node.getValue());
1344                 } else if (node.getName().equals(PROPERTY_PROVIDER_IDENTITY)) {
1345                     cache.setIdentityURL(node.getValue());
1346                     cache.setProviderName(node.getValue());
1347                 } else if (node.getName().startsWith(PROPERTY_PROVIDER_TENANT)) {
1348                     String tenantName = null;
1349                     String userId = null;
1350                     String password = null;
1351                     for (Node node2 : node.getChildren()) {
1352                         switch (node2.getName()) {
1353                             case PROPERTY_PROVIDER_TENANT_NAME:
1354                                 tenantName = node2.getValue();
1355                                 break;
1356                             case PROPERTY_PROVIDER_TENANT_USERID:
1357                                 userId = node2.getValue();
1358                                 DEFAULT_USER = node2.getValue();
1359                                 break;
1360                             case PROPERTY_PROVIDER_TENANT_PASSWORD:
1361                                 password = node2.getValue();
1362                                 DEFAULT_PASS = node2.getValue();
1363                                 break;
1364                         }
1365                     }
1366
1367                     cache.addTenant(null, tenantName, userId, password);
1368                 }
1369             }
1370
1371             /*
1372              * Add the provider to the set of providers cached
1373              */
1374             if (cache.getIdentityURL() != null && cache.getProviderType() != null) {
1375                 providerCache.put(null, cache);
1376                 providerCache.put(cache.getIdentityURL(), cache);
1377             }
1378
1379             /*
1380              * Now, initialize the cache for the loaded provider
1381              */
1382             cache.initialize();
1383         }
1384     }
1385
1386     /**
1387      * This method is called to rebuild the provided server.
1388      * <p>
1389      * If the server was booted from a volume, then the request is failed immediately and no action is taken. Rebuilding
1390      * a VM from a bootable volume, where the bootable volume itself is not rebuilt, serves no purpose.
1391      * </p>
1392      *
1393      * @param rc
1394      *            The request context that manages the state and recovery of the request for the life of its processing.
1395      * @param server
1396      * @throws ZoneException
1397      * @throws RequestFailedException
1398      */
1399     @SuppressWarnings("nls")
1400     private void rebuildServer(RequestContext rc, Server server) throws ZoneException, RequestFailedException {
1401
1402         ServerBootSource builtFrom = server.getBootSource();
1403         String msg;
1404
1405         // Throw exception for non image/snap boot source
1406         if (ServerBootSource.VOLUME.equals(builtFrom)) {
1407             msg = String.format("Rebuilding is currently not supported for servers built from bootable volumes [%s]",
1408                 server.getId());
1409             generateEvent(rc, false, msg);
1410             logger.error(msg);
1411             throw new RequestFailedException("Rebuild Server", msg, HttpStatus.FORBIDDEN_403, server);
1412         }
1413         /*
1414          * Pending is a bit of a special case. If we find the server is in a pending state, then the provider is in the
1415          * process of changing state of the server. So, lets try to wait a little bit and see if the state settles down
1416          * to one we can deal with. If not, then we have to fail the request.
1417          */
1418         Context context = server.getContext();
1419         Provider provider = context.getProvider();
1420         ComputeService service = context.getComputeService();
1421         if (server.getStatus().equals(Status.PENDING)) {
1422             waitForStateChange(rc, server, Status.READY, Status.RUNNING, Status.ERROR, Status.SUSPENDED, Status.PAUSED);
1423         }
1424
1425         /*
1426          * Get the image to use. This is determined by the presence or absence of snapshot images. If any snapshots
1427          * exist, then the latest snapshot is used, otherwise the image used to construct the VM is used.
1428          */
1429         List<Image> snapshots = server.getSnapshots();
1430         String imageToUse;
1431         if (snapshots != null && !snapshots.isEmpty()) {
1432             imageToUse = snapshots.get(0).getId();
1433         } else {
1434             imageToUse = server.getImage();
1435             ImageService imageService = server.getContext().getImageService();
1436             try {
1437                 while (rc.attempt()) {
1438                     try {
1439                         /*
1440                          * We are just trying to make sure that the image exists. We arent interested in the details at
1441                          * this point.
1442                          */
1443                         imageService.getImage(imageToUse);
1444                         break;
1445                     } catch (ContextConnectionException e) {
1446                         msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(),
1447                             imageService.getURL(), context.getTenant().getName(), context.getTenant().getId(),
1448                             e.getMessage(), Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()),
1449                             Integer.toString(rc.getRetryLimit()));
1450                         logger.error(msg, e);
1451                         rc.delay();
1452                     }
1453                 }
1454             } catch (ZoneException e) {
1455                 msg = EELFResourceManager.format(Msg.IMAGE_NOT_FOUND, imageToUse, "rebuild");
1456                 generateEvent(rc, false, msg);
1457                 logger.error(msg);
1458                 throw new RequestFailedException("Rebuild Server", msg, HttpStatus.METHOD_NOT_ALLOWED_405, server);
1459             }
1460         }
1461         if (rc.isFailed()) {
1462             msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL());
1463             logger.error(msg);
1464             throw new RequestFailedException("Rebuild Server", msg, HttpStatus.BAD_GATEWAY_502, server);
1465         }
1466         rc.reset();
1467
1468         /*
1469          * We determine what to do based on the current state of the server
1470          */
1471         switch (server.getStatus()) {
1472             case DELETED:
1473                 // Nothing to do, the server is gone
1474                 msg = EELFResourceManager.format(Msg.SERVER_DELETED, server.getName(), server.getId(),
1475                     server.getTenantId(), "rebuilt");
1476                 generateEvent(rc, false, msg);
1477                 logger.error(msg);
1478                 throw new RequestFailedException("Rebuild Server", msg, HttpStatus.METHOD_NOT_ALLOWED_405, server);
1479
1480             case RUNNING:
1481                 // Attempt to stop the server, then rebuild it
1482                 stopServer(rc, server);
1483                 rebuildServer(rc, server, imageToUse);
1484                 startServer(rc, server);
1485                 generateEvent(rc, true, OUTCOME_SUCCESS);
1486                 break;
1487
1488             case ERROR:
1489                 msg = EELFResourceManager.format(Msg.SERVER_ERROR_STATE, server.getName(), server.getId(),
1490                     server.getTenantId(), "rebuild");
1491                 generateEvent(rc, false, msg);
1492                 logger.error(msg);
1493                 throw new RequestFailedException("Rebuild Server", msg, HttpStatus.METHOD_NOT_ALLOWED_405, server);
1494
1495             case READY:
1496                 // Attempt to rebuild the server
1497                 rebuildServer(rc, server, imageToUse);
1498                 startServer(rc, server);
1499                 generateEvent(rc, true, OUTCOME_SUCCESS);
1500                 break;
1501
1502             case PAUSED:
1503                 // if paused, un-pause it, stop it, and rebuild it
1504                 unpauseServer(rc, server);
1505                 stopServer(rc, server);
1506                 rebuildServer(rc, server, imageToUse);
1507                 startServer(rc, server);
1508                 generateEvent(rc, true, OUTCOME_SUCCESS);
1509                 break;
1510
1511             case SUSPENDED:
1512                 // Attempt to resume the suspended server, stop it, and rebuild it
1513                 resumeServer(rc, server);
1514                 stopServer(rc, server);
1515                 rebuildServer(rc, server, imageToUse);
1516                 startServer(rc, server);
1517                 generateEvent(rc, true, OUTCOME_SUCCESS);
1518                 break;
1519
1520             default:
1521                 // Hmmm, unknown status, should never occur
1522                 msg = EELFResourceManager.format(Msg.UNKNOWN_SERVER_STATE, server.getName(), server.getId(),
1523                     server.getTenantId(), server.getStatus().name());
1524                 generateEvent(rc, false, msg);
1525                 logger.error(msg);
1526                 throw new RequestFailedException("Rebuild Server", msg, HttpStatus.METHOD_NOT_ALLOWED_405, server);
1527         }
1528     }
1529
1530     /**
1531      * This method handles the case of restarting a server once we have found the server and have obtained the abstract
1532      * representation of the server via the context (i.e., the "Server" object from the CDP-Zones abstraction).
1533      *
1534      * @param rc
1535      *            The request context that manages the state and recovery of the request for the life of its processing.
1536      * @param server
1537      *            The server object representing the server we want to operate on
1538      * @throws ZoneException
1539      */
1540     @SuppressWarnings("nls")
1541     private void restartServer(RequestContext rc, Server server) throws ZoneException, RequestFailedException {
1542         /*
1543          * Pending is a bit of a special case. If we find the server is in a pending state, then the provider is in the
1544          * process of changing state of the server. So, lets try to wait a little bit and see if the state settles down
1545          * to one we can deal with. If not, then we have to fail the request.
1546          */
1547         String msg;
1548         if (server.getStatus().equals(Status.PENDING)) {
1549             waitForStateChange(rc, server, Status.READY, Status.RUNNING, Status.ERROR, Status.SUSPENDED, Status.PAUSED);
1550         }
1551
1552         /*
1553          * We determine what to do based on the current state of the server
1554          */
1555         switch (server.getStatus()) {
1556             case DELETED:
1557                 // Nothing to do, the server is gone
1558                 msg = EELFResourceManager.format(Msg.SERVER_DELETED, server.getName(), server.getId(),
1559                     server.getTenantId(), "restarted");
1560                 generateEvent(rc, false, msg);
1561                 logger.error(msg);
1562                 break;
1563
1564             case RUNNING:
1565                 // Attempt to stop and start the server
1566                 stopServer(rc, server);
1567                 startServer(rc, server);
1568                 generateEvent(rc, true, OUTCOME_SUCCESS);
1569                 break;
1570
1571             case ERROR:
1572                 msg = EELFResourceManager.format(Msg.SERVER_ERROR_STATE, server.getName(), server.getId(),
1573                     server.getTenantId(), "rebuild");
1574                 generateEvent(rc, false, msg);
1575                 logger.error(msg);
1576                 throw new RequestFailedException("Rebuild Server", msg, HttpStatus.METHOD_NOT_ALLOWED_405, server);
1577
1578             case READY:
1579                 // Attempt to start the server
1580                 startServer(rc, server);
1581                 generateEvent(rc, true, OUTCOME_SUCCESS);
1582                 break;
1583
1584             case PAUSED:
1585                 // if paused, un-pause it
1586                 unpauseServer(rc, server);
1587                 generateEvent(rc, true, OUTCOME_SUCCESS);
1588                 break;
1589
1590             case SUSPENDED:
1591                 // Attempt to resume the suspended server
1592                 resumeServer(rc, server);
1593                 generateEvent(rc, true, OUTCOME_SUCCESS);
1594                 break;
1595
1596             default:
1597                 // Hmmm, unknown status, should never occur
1598                 msg = EELFResourceManager.format(Msg.UNKNOWN_SERVER_STATE, server.getName(), server.getId(),
1599                     server.getTenantId(), server.getStatus().name());
1600                 generateEvent(rc, false, msg);
1601                 logger.error(msg);
1602                 break;
1603         }
1604
1605     }
1606
1607     /**
1608      * Resume a suspended server and wait for it to enter a running state
1609      *
1610      * @param rc
1611      *            The request context that manages the state and recovery of the request for the life of its processing.
1612      * @param server
1613      *            The server to be resumed
1614      * @throws ZoneException
1615      * @throws RequestFailedException
1616      */
1617     @SuppressWarnings("nls")
1618     private void resumeServer(RequestContext rc, Server server) throws ZoneException, RequestFailedException {
1619         logger.debug(Msg.RESUME_SERVER, server.getId());
1620
1621         Context context = server.getContext();
1622         String msg;
1623         Provider provider = context.getProvider();
1624         ComputeService service = context.getComputeService();
1625         while (rc.attempt()) {
1626             try {
1627                 server.resume();
1628                 break;
1629             } catch (ContextConnectionException e) {
1630                 msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(),
1631                     context.getTenant().getName(), context.getTenant().getId(), e.getMessage(),
1632                     Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()),
1633                     Integer.toString(rc.getRetryLimit()));
1634                 logger.error(msg, e);
1635                 rc.delay();
1636             }
1637         }
1638         if (rc.isFailed()) {
1639             msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL());
1640             logger.error(msg);
1641             throw new RequestFailedException("Resume Server", msg, HttpStatus.BAD_GATEWAY_502, server);
1642         }
1643         rc.reset();
1644         waitForStateChange(rc, server, Status.RUNNING);
1645     }
1646
1647     /**
1648      * Start the server and wait for it to enter a running state
1649      *
1650      * @param rc
1651      *            The request context that manages the state and recovery of the request for the life of its processing.
1652      * @param server
1653      *            The server to be started
1654      * @throws ZoneException
1655      * @throws RequestFailedException
1656      */
1657     @SuppressWarnings("nls")
1658     private void startServer(RequestContext rc, Server server) throws ZoneException, RequestFailedException {
1659         logger.debug(Msg.START_SERVER, server.getId());
1660         String msg;
1661         Context context = server.getContext();
1662         Provider provider = context.getProvider();
1663         ComputeService service = context.getComputeService();
1664         while (rc.attempt()) {
1665             try {
1666                 server.start();
1667                 break;
1668             } catch (ContextConnectionException e) {
1669                 msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(),
1670                     context.getTenant().getName(), context.getTenant().getId(), e.getMessage(),
1671                     Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()),
1672                     Integer.toString(rc.getRetryLimit()));
1673                 logger.error(msg, e);
1674                 rc.delay();
1675             }
1676         }
1677         if (rc.isFailed()) {
1678             msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL());
1679             logger.error(msg);
1680             throw new RequestFailedException("Start Server", msg, HttpStatus.BAD_GATEWAY_502, server);
1681         }
1682         rc.reset();
1683         waitForStateChange(rc, server, Status.RUNNING);
1684     }
1685
1686     /**
1687      * Stop the specified server and wait for it to stop
1688      *
1689      * @param rc
1690      *            The request context that manages the state and recovery of the request for the life of its processing.
1691      * @param server
1692      *            The server to be stopped
1693      * @throws ZoneException
1694      * @throws RequestFailedException
1695      */
1696     @SuppressWarnings("nls")
1697     private void stopServer(RequestContext rc, Server server) throws ZoneException, RequestFailedException {
1698         logger.debug(Msg.STOP_SERVER, server.getId());
1699
1700         String msg;
1701         Context context = server.getContext();
1702         Provider provider = context.getProvider();
1703         ComputeService service = context.getComputeService();
1704         while (rc.attempt()) {
1705             try {
1706                 server.stop();
1707                 break;
1708             } catch (ContextConnectionException e) {
1709                 msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(),
1710                     context.getTenant().getName(), context.getTenant().getId(), e.getMessage(),
1711                     Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()),
1712                     Integer.toString(rc.getRetryLimit()));
1713                 logger.error(msg, e);
1714                 rc.delay();
1715             }
1716         }
1717         if (rc.isFailed()) {
1718             msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL());
1719             logger.error(msg);
1720             throw new RequestFailedException("Stop Server", msg, HttpStatus.BAD_GATEWAY_502, server);
1721         }
1722         rc.reset();
1723         waitForStateChange(rc, server, Status.READY, Status.ERROR);
1724     }
1725
1726     /**
1727      * Un-Pause a paused server and wait for it to enter a running state
1728      *
1729      * @param rc
1730      *            The request context that manages the state and recovery of the request for the life of its processing.
1731      * @param server
1732      *            The server to be un-paused
1733      * @throws ZoneException
1734      * @throws RequestFailedException
1735      */
1736     @SuppressWarnings("nls")
1737     private void unpauseServer(RequestContext rc, Server server) throws ZoneException, RequestFailedException {
1738         logger.debug(Msg.UNPAUSE_SERVER, server.getId());
1739
1740         String msg;
1741         Context context = server.getContext();
1742         Provider provider = context.getProvider();
1743         ComputeService service = context.getComputeService();
1744         while (rc.attempt()) {
1745             try {
1746                 server.unpause();
1747                 break;
1748             } catch (ContextConnectionException e) {
1749                 msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(),
1750                     context.getTenant().getName(), context.getTenant().getId(), e.getMessage(),
1751                     Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()),
1752                     Integer.toString(rc.getRetryLimit()));
1753                 logger.error(msg, e);
1754                 rc.delay();
1755             }
1756         }
1757         if (rc.isFailed()) {
1758             msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL());
1759             logger.error(msg);
1760             throw new RequestFailedException("Unpause Server", msg, HttpStatus.BAD_GATEWAY_502, server);
1761         }
1762         rc.reset();
1763         waitForStateChange(rc, server, Status.RUNNING, Status.READY);
1764     }
1765
1766     /**
1767      * Enter a pool-wait loop checking the server state to see if it has entered one of the desired states or not.
1768      * <p>
1769      * This method checks the state of the server periodically for one of the desired states. When the server enters one
1770      * of the desired states, the method returns a successful indication (true). If the server never enters one of the
1771      * desired states within the allocated timeout period, then the method returns a failed response (false). No
1772      * exceptions are thrown from this method.
1773      * </p>
1774      *
1775      * @param rc
1776      *            The request context that manages the state and recovery of the request for the life of its processing.
1777      * @param server
1778      *            The server to wait on
1779      * @param desiredStates
1780      *            A variable list of desired states, any one of which is allowed.
1781      * @throws RequestFailedException
1782      *             If the request times out or fails for some reason
1783      */
1784     @SuppressWarnings("nls")
1785     private void waitForStateChange(RequestContext rc, Server server, Server.Status... desiredStates)
1786         throws RequestFailedException {
1787         int pollInterval = configuration.getIntegerProperty(Constants.PROPERTY_OPENSTACK_POLL_INTERVAL);
1788         int timeout = configuration.getIntegerProperty(Constants.PROPERTY_SERVER_STATE_CHANGE_TIMEOUT);
1789         Context context = server.getContext();
1790         Provider provider = context.getProvider();
1791         ComputeService service = context.getComputeService();
1792         String msg;
1793
1794         long endTime = System.currentTimeMillis() + (timeout * 1000); //
1795
1796         while (rc.attempt()) {
1797             try {
1798                 try {
1799                     server.waitForStateChange(pollInterval, timeout, desiredStates);
1800                     break;
1801                 } catch (TimeoutException e) {
1802                     @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
1803                     List<String> list = new ArrayList<>();
1804                     for (Server.Status desiredState : desiredStates) {
1805                         list.add(desiredState.name());
1806                     }
1807                     msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(),
1808                         context.getTenant().getName(), context.getTenant().getId(), e.getMessage(),
1809                         Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()),
1810                         Integer.toString(rc.getRetryLimit()));
1811                     logger.error(msg, e);
1812                     rc.delay();
1813                 }
1814             } catch (ZoneException e) {
1815                 List<String> list = new ArrayList<>();
1816                 for (Server.Status desiredState : desiredStates) {
1817                     list.add(desiredState.name());
1818                 }
1819                 String reason = EELFResourceManager.format(Msg.STATE_CHANGE_EXCEPTION, e.getClass().getSimpleName(),
1820                     "server", server.getName(), server.getId(), StringHelper.asList(list), server.getStatus().name(),
1821                     e.getMessage());
1822                 logger.error(reason);
1823                 logger.error(EELFResourceManager.format(e));
1824
1825                 // Instead of failing we are going to wait and try again.
1826                 // Timeout is reduced by delay time
1827                 logger.info(String.format("Retrying in %ds", rc.getRetryDelay()));
1828                 rc.delay();
1829                 timeout = (int) (endTime - System.currentTimeMillis()) / 1000;
1830                 // throw new RequestFailedException(e, operation, reason,
1831                 // HttpStatus.BAD_GATEWAY_502, server);
1832             }
1833         }
1834
1835         if (rc.isFailed()) {
1836             msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL());
1837             logger.error(msg);
1838             throw new RequestFailedException("Waiting for State Change", msg, HttpStatus.BAD_GATEWAY_502, server);
1839         }
1840         rc.reset();
1841     }
1842
1843     /**
1844      * Enter a pool-wait loop checking the server state to see if it has entered one of the desired states or not.
1845      * <p>
1846      * This method checks the state of the server periodically for one of the desired states. When the server enters one
1847      * of the desired states, the method returns a successful indication (true). If the server never enters one of the
1848      * desired states within the allocated timeout period, then the method returns a failed response (false). No
1849      * exceptions are thrown from this method.
1850      * </p>
1851      *
1852      * @param rc
1853      *            The request context that manages the state and recovery of the request for the life of its processing.
1854      * @param image
1855      *            The server to wait on
1856      * @param desiredStates
1857      *            A variable list of desired states, any one of which is allowed.
1858      * @throws RequestFailedException
1859      *             If the request times out or fails for some reason
1860      * @throws NotLoggedInException
1861      */
1862     @SuppressWarnings("nls")
1863     private void waitForStateChange(RequestContext rc, Image image, Image.Status... desiredStates)
1864         throws RequestFailedException, NotLoggedInException {
1865         int pollInterval = configuration.getIntegerProperty(Constants.PROPERTY_OPENSTACK_POLL_INTERVAL);
1866         int timeout = configuration.getIntegerProperty(Constants.PROPERTY_SERVER_STATE_CHANGE_TIMEOUT);
1867         Context context = image.getContext();
1868         Provider provider = context.getProvider();
1869         ImageService service = context.getImageService();
1870         String msg;
1871
1872         long endTime = System.currentTimeMillis() + (timeout * 1000); //
1873
1874         while (rc.attempt()) {
1875             try {
1876                 try {
1877                     image.waitForStateChange(pollInterval, timeout, desiredStates);
1878                     break;
1879                 } catch (TimeoutException e) {
1880                     @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
1881                     List<String> list = new ArrayList<>();
1882                     for (Image.Status desiredState : desiredStates) {
1883                         list.add(desiredState.name());
1884                     }
1885                     msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(),
1886                         context.getTenant().getName(), context.getTenant().getId(), e.getMessage(),
1887                         Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()),
1888                         Integer.toString(rc.getRetryLimit()));
1889                     logger.error(msg, e);
1890                     rc.delay();
1891                 }
1892             } catch (ZoneException e) {
1893                 List<String> list = new ArrayList<>();
1894                 for (Image.Status desiredState : desiredStates) {
1895                     list.add(desiredState.name());
1896                 }
1897                 String reason = EELFResourceManager.format(Msg.STATE_CHANGE_EXCEPTION, e.getClass().getSimpleName(),
1898                     "server", image.getName(), image.getId(), StringHelper.asList(list), image.getStatus().name(),
1899                     e.getMessage());
1900                 logger.error(reason);
1901                 logger.error(EELFResourceManager.format(e));
1902
1903                 // Instead of failing we are going to wait and try again.
1904                 // Timeout is reduced by delay time
1905                 logger.info(String.format("Retrying in %ds", rc.getRetryDelay()));
1906                 rc.delay();
1907                 timeout = (int) (endTime - System.currentTimeMillis()) / 1000;
1908                 // throw new RequestFailedException(e, operation, reason,
1909                 // HttpStatus.BAD_GATEWAY_502, server);
1910             }
1911         }
1912
1913         if (rc.isFailed()) {
1914             msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL());
1915             logger.error(msg);
1916             throw new RequestFailedException("Waiting for State Change", msg, HttpStatus.BAD_GATEWAY_502, new Server());
1917         }
1918         rc.reset();
1919     }
1920
1921     /**
1922      * Rebuild the indicated server with the indicated image. This method assumes the server has been determined to be
1923      * in the correct state to do the rebuild.
1924      *
1925      * @param rc
1926      *            The request context that manages the state and recovery of the request for the life of its processing.
1927      * @param server
1928      *            the server to be rebuilt
1929      * @param image
1930      *            The image to be used (or snapshot)
1931      * @throws RequestFailedException
1932      *             if the server does not change state in the allotted time
1933      */
1934     @SuppressWarnings("nls")
1935     private void rebuildServer(RequestContext rc, Server server, String image) throws RequestFailedException {
1936         String msg;
1937         Context context = server.getContext();
1938         Provider provider = context.getProvider();
1939         ComputeService service = context.getComputeService();
1940
1941         try {
1942             while (rc.attempt()) {
1943                 try {
1944                     server.rebuild(image);
1945                     break;
1946                 } catch (ContextConnectionException e) {
1947                     msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(),
1948                         context.getTenant().getName(), context.getTenant().getId(), e.getMessage(),
1949                         Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()),
1950                         Integer.toString(rc.getRetryLimit()));
1951                     logger.error(msg, e);
1952                     rc.delay();
1953                 }
1954             }
1955
1956             /*
1957              * We need to provide some time for OpenStack to start processing the request.
1958              */
1959             try {
1960                 Thread.sleep(10L * 1000L);
1961             } catch (InterruptedException e) {
1962                 logger.trace("Sleep threw interrupted exception, should never occur");
1963             }
1964         } catch (ZoneException e) {
1965             msg =
1966                 EELFResourceManager.format(Msg.REBUILD_SERVER_FAILED, server.getName(), server.getId(), e.getMessage());
1967             logger.error(msg);
1968             throw new RequestFailedException("Rebuild Server", msg, HttpStatus.BAD_GATEWAY_502, server);
1969         }
1970
1971         /*
1972          * Once we have started the process, now we wait for the final state of stopped. This should be the final state
1973          * (since we started the rebuild with the server stopped).
1974          */
1975         waitForStateChange(rc, server, Status.READY);
1976
1977         if (rc.isFailed()) {
1978             msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL());
1979             logger.error(msg);
1980             throw new RequestFailedException("Rebuild Server", msg, HttpStatus.BAD_GATEWAY_502, server);
1981         }
1982         rc.reset();
1983     }
1984
1985     /**
1986      * Looks up the indicated server using the provided context and returns the server to the caller
1987      *
1988      * @param rc
1989      *            The request context
1990      * @param context
1991      *            The provider context
1992      * @param id
1993      *            The id of the server
1994      * @return The server, or null if there is a problem
1995      * @throws ZoneException
1996      *             If the server cannot be found
1997      * @throws RequestFailedException
1998      *             If the server cannot be found because we cant connect to the provider
1999      */
2000     @SuppressWarnings("nls")
2001     private Server lookupServer(RequestContext rc, Context context, String id)
2002         throws ZoneException, RequestFailedException {
2003         ComputeService service = context.getComputeService();
2004         Server server = null;
2005         String msg;
2006         Provider provider = context.getProvider();
2007
2008         while (rc.attempt()) {
2009             try {
2010                 server = service.getServer(id);
2011                 break;
2012             } catch (ContextConnectionException e) {
2013                 msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(),
2014                     context.getTenant().getName(), context.getTenant().getId(), e.getMessage(),
2015                     Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()),
2016                     Integer.toString(rc.getRetryLimit()));
2017                 logger.error(msg, e);
2018                 rc.delay();
2019             }
2020         }
2021         if (rc.isFailed()) {
2022             msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL());
2023             logger.error(msg);
2024             doFailure(rc, HttpStatus.BAD_GATEWAY_502, msg);
2025             throw new RequestFailedException("Lookup Server", msg, HttpStatus.BAD_GATEWAY_502, server);
2026         }
2027         return server;
2028     }
2029
2030     private String getConnectionExceptionMessage(RequestContext rc, Context ctx, ContextConnectionException e)
2031         throws ZoneException {
2032         return EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, ctx.getProvider().getName(),
2033             ctx.getComputeService().getURL(), ctx.getTenant().getName(), ctx.getTenant().getId(), e.getMessage(),
2034             Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()),
2035             Integer.toString(rc.getRetryLimit()));
2036     }
2037
2038     private ProviderCache createProviderCache(VMURL vm, IdentityURL ident) {
2039         if (vm != null && ident != null) {
2040             ProviderCache cache = new ProviderCache();
2041
2042             cache.setIdentityURL(ident.toString());
2043             cache.setProviderName(ident.toString());
2044             // cache.setProviderType("OpenStack");
2045
2046             TenantCache tenant = cache.addTenant(vm.getTenantId(),null, DEFAULT_USER, DEFAULT_PASS);
2047
2048             // Make sure we could initialize the the cache otherwise return null
2049             if (tenant != null && tenant.isInitialized()) {
2050                 return cache;
2051             }
2052         }
2053         return null;
2054     }
2055
2056     /**
2057      * This method is used to delete an existing virtual machine given the fully qualified URL of the machine.
2058      * <p>
2059      * The fully qualified URL contains enough information to locate the appropriate server. The URL is of the form
2060      * <pre>
2061      *  [scheme]://[host[:port]] / [path] / [tenant_id] / servers / [vm_id]
2062      * </pre> Where the various parts of the URL can be parsed and extracted and used to locate the appropriate service
2063      * in the provider service catalog. This then allows us to open a context using the CDP abstraction, obtain the
2064      * server by its UUID, and then perform the restart.
2065      * </p>
2066      *
2067      * @throws UnknownProviderException
2068      *             If the provider cannot be found
2069      * @throws IllegalArgumentException
2070      *             if the expected argument(s) are not defined or are invalid
2071      * @see org.openecomp.appc.adapter.iaas.ProviderAdapter#terminateServer(java.util.Map, org.openecomp.sdnc.sli.SvcLogicContext)
2072      */
2073     @SuppressWarnings("nls")
2074     @Override
2075     public Server terminateServer(Map<String, String> params, SvcLogicContext ctx)
2076         throws UnknownProviderException, IllegalArgumentException {
2077         Server server = null;
2078         RequestContext rc = new RequestContext(ctx);
2079         rc.isAlive();
2080         MDC.put(MDC_ADAPTER, ADAPTER_NAME);
2081         MDC.put(MDC_SERVICE, TERMINATE_SERVICE);
2082         MDC.put(MDC_SERVICE_NAME, "App-C IaaS Adapter:Terminate");
2083         String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME);
2084                 if (logger.isDebugEnabled()) {
2085                         logger.debug("Inside org.openecomp.appc.adapter.iaas.impl.ProviderAdapter.terminateServer");
2086                 }
2087
2088         try {
2089             validateParametersExist(rc, params, ProviderAdapter.PROPERTY_INSTANCE_URL,
2090                 ProviderAdapter.PROPERTY_PROVIDER_NAME);
2091             debugParameters(params);
2092             debugContext(ctx);
2093             String vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL);
2094             ctx.setAttribute("TERMINATE_STATUS", "SUCCESS");
2095
2096             VMURL vm = VMURL.parseURL(vm_url);
2097             if (validateVM(rc, appName, vm_url, vm)) return null;
2098
2099             IdentityURL ident = IdentityURL.parseURL(params.get(ProviderAdapter.PROPERTY_IDENTITY_URL));
2100             String identStr = (ident == null) ? null : ident.toString();
2101
2102             Context context = null;
2103             try {
2104                 context = getContext(rc, vm_url, identStr);
2105                 if (context != null) {
2106                     server = lookupServer(rc, context, vm.getServerId());
2107                     logger.debug(Msg.SERVER_FOUND, vm_url, context.getTenantName(), server.getStatus().toString());
2108                     logger.info(EELFResourceManager.format(Msg.TERMINATING_SERVER, server.getName()));
2109                     terminateServer(rc, server);
2110                     logger.info(EELFResourceManager.format(Msg.TERMINATE_SERVER, server.getName()));
2111                     context.close();
2112                     doSuccess(rc);
2113                 }else{
2114                     ctx.setAttribute("TERMINATE_STATUS", "SERVER_NOT_FOUND");
2115                 }
2116             } catch (ResourceNotFoundException e) {
2117                 String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, e, vm_url);
2118                 logger.error(msg);
2119                 doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
2120                 ctx.setAttribute("TERMINATE_STATUS", "SERVER_NOT_FOUND");
2121             } catch (Throwable t) {
2122                 String msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, t, t.getClass().getSimpleName(),
2123                     RESTART_SERVICE, vm_url, context == null ? "Unknown" : context.getTenantName());
2124                 logger.error(msg, t);
2125                 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
2126             }
2127         } catch (RequestFailedException e) {
2128             logger.error(EELFResourceManager.format(Msg.TERMINATE_SERVER_FAILED, appName, "n/a", "n/a", e.getMessage()));
2129             doFailure(rc, e.getStatus(), e.getMessage());
2130             ctx.setAttribute("TERMINATE_STATUS", "ERROR");
2131         }
2132
2133         return server;
2134     }
2135
2136     /**
2137      * This method handles the case of restarting a server once we have found the server and have obtained the abstract
2138      * representation of the server via the context (i.e., the "Server" object from the CDP-Zones abstraction).
2139      *
2140      * @param rc
2141      *            The request context that manages the state and recovery of the request for the life of its processing.
2142      * @param server
2143      *            The server object representing the server we want to operate on
2144      * @throws ZoneException
2145      */
2146     @SuppressWarnings("nls")
2147     private void terminateServer(RequestContext rc, Server server) throws ZoneException, RequestFailedException {
2148         /*
2149          * Pending is a bit of a special case. If we find the server is in a pending state, then the provider is in the
2150          * process of changing state of the server. So, lets try to wait a little bit and see if the state settles down
2151          * to one we can deal with. If not, then we have to fail the request.
2152          */
2153         String msg;
2154         if (server.getStatus().equals(Status.PENDING)) {
2155             waitForStateChange(rc, server, Status.READY, Status.RUNNING, Status.ERROR, Status.SUSPENDED, Status.PAUSED);
2156         }
2157
2158         /*
2159          * We determine what to do based on the current state of the server
2160          */
2161         switch (server.getStatus()) {
2162             case DELETED:
2163                 // Nothing to do, the server is gone
2164                 msg = EELFResourceManager.format(Msg.SERVER_DELETED, server.getName(), server.getId(),
2165                     server.getTenantId(), "restarted");
2166                 generateEvent(rc, false, msg);
2167                 logger.error(msg);
2168                 break;
2169
2170             case RUNNING:
2171                 // Attempt to stop and start the server
2172                 logger.info("stopping SERVER");
2173                 stopServer(rc, server);
2174                 deleteServer(rc, server);
2175                 logger.info("after delete SERVER");
2176                 generateEvent(rc, true, OUTCOME_SUCCESS);
2177                 break;
2178
2179             case ERROR:
2180
2181             case READY:
2182
2183             case PAUSED:
2184
2185             case SUSPENDED:
2186                 // Attempt to delete the suspended server
2187                 deleteServer(rc, server);
2188                 generateEvent(rc, true, OUTCOME_SUCCESS);
2189                 break;
2190
2191             default:
2192                 // Hmmm, unknown status, should never occur
2193                 msg = EELFResourceManager.format(Msg.UNKNOWN_SERVER_STATE, server.getName(), server.getId(),
2194                     server.getTenantId(), server.getStatus().name());
2195                 generateEvent(rc, false, msg);
2196                 logger.error(msg);
2197                 break;
2198         }
2199
2200     }
2201
2202     /**
2203      * Start the server and wait for it to enter a running state
2204      *
2205      * @param rc
2206      *            The request context that manages the state and recovery of the request for the life of its processing.
2207      * @param server
2208      *            The server to be started
2209      * @throws ZoneException
2210      * @throws RequestFailedException
2211      */
2212     @SuppressWarnings("nls")
2213     private void deleteServer(RequestContext rc, Server server) throws ZoneException, RequestFailedException {
2214         String msg;
2215         Context context = server.getContext();
2216         Provider provider = context.getProvider();
2217         ComputeService service = context.getComputeService();
2218         while (rc.attempt()) {
2219             try {
2220                 logger.info("deleting SERVER");
2221                 server.delete();
2222                 break;
2223             } catch (ContextConnectionException e) {
2224                 msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(),
2225                     context.getTenant().getName(), context.getTenant().getId(), e.getMessage(),
2226                     Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()),
2227                     Integer.toString(rc.getRetryLimit()));
2228                 logger.error(msg, e);
2229                 rc.delay();
2230             }
2231         }
2232         if (rc.isFailed()) {
2233             msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL());
2234             logger.error(msg);
2235             throw new RequestFailedException("Delete Server", msg, HttpStatus.BAD_GATEWAY_502, server);
2236         }
2237         rc.reset();
2238     }
2239
2240     private boolean hasImageAccess(@SuppressWarnings("unused") RequestContext rc, Context context) {
2241         logger.info("Checking permissions for image service.");
2242         try {
2243             ImageService service = context.getImageService();
2244             service.getImageByName("CHECK_IMAGE_ACCESS");
2245             logger.info("Image service is accessible.");
2246             return true;
2247         } catch (ZoneException e) {
2248             logger.warn("Image service could not be accessed. Some operations may fail.", e);
2249             return false;
2250         }
2251     }
2252
2253     @SuppressWarnings("nls")
2254     @Override
2255     public Stack terminateStack(Map<String, String> params, SvcLogicContext ctx) throws IllegalArgumentException, APPCException {
2256         Stack stack = null;
2257         RequestContext rc = new RequestContext(ctx);
2258         rc.isAlive();
2259
2260         ctx.setAttribute("TERMINATE_STATUS", "STACK_NOT_FOUND");
2261         String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME);
2262
2263         try {
2264
2265             logAndValidate(params, ctx, rc, TERMINATE_STACK, "Terminate Stack",
2266                             ProviderAdapter.PROPERTY_INSTANCE_URL,
2267                             ProviderAdapter.PROPERTY_PROVIDER_NAME,
2268                             ProviderAdapter.PROPERTY_STACK_ID);
2269
2270             String stackId = params.get(ProviderAdapter.PROPERTY_STACK_ID);
2271             String vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL);
2272
2273             Context context = resolveContext(rc, params, appName, vm_url);
2274
2275             try {
2276                 if (context != null) {
2277                     stack = lookupStack(rc, context, stackId);
2278                     logger.debug(Msg.STACK_FOUND, vm_url, context.getTenantName(), stack.getStatus().toString());
2279                     logger.info(EELFResourceManager.format(Msg.TERMINATING_STACK, stack.getName()));
2280                     deleteStack(rc, stack);
2281                     logger.info(EELFResourceManager.format(Msg.TERMINATE_STACK, stack.getName()));
2282                     context.close();
2283                     doSuccess(rc);
2284                 }else{
2285                     ctx.setAttribute("TERMINATE_STATUS", "SERVER_NOT_FOUND");
2286                 }
2287             } catch (ResourceNotFoundException e) {
2288                 String msg = EELFResourceManager.format(Msg.STACK_NOT_FOUND, e, vm_url);
2289                 logger.error(msg);
2290                 doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
2291             } catch (Throwable t) {
2292                 String msg = EELFResourceManager.format(Msg.STACK_OPERATION_EXCEPTION, t, t.getClass().getSimpleName(),
2293                     TERMINATE_STACK, vm_url, context.getTenantName());
2294                 logger.error(msg, t);
2295                 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
2296             }
2297         } catch (RequestFailedException e) {
2298             logger.error(EELFResourceManager.format(Msg.TERMINATE_STACK_FAILED, appName, "n/a", "n/a"));
2299             doFailure(rc, e.getStatus(), e.getMessage());
2300         }
2301         return stack;
2302     }
2303
2304     @Override
2305     public Stack snapshotStack(Map<String, String> params, SvcLogicContext ctx) throws IllegalArgumentException, APPCException {
2306         Stack stack = null;
2307         RequestContext rc = new RequestContext(ctx);
2308         rc.isAlive();
2309
2310         ctx.setAttribute("SNAPSHOT_STATUS", "STACK_NOT_FOUND");
2311         String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME);
2312
2313         String vm_url = null;
2314         Context context = null;
2315         try {
2316
2317             logAndValidate(params, ctx, rc, SNAPSHOT_STACK, "Snapshot Stack",
2318                             ProviderAdapter.PROPERTY_INSTANCE_URL,
2319                             ProviderAdapter.PROPERTY_PROVIDER_NAME,
2320                             ProviderAdapter.PROPERTY_STACK_ID);
2321
2322             String stackId = params.get(ProviderAdapter.PROPERTY_STACK_ID);
2323             vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL);
2324
2325             context = resolveContext(rc, params, appName, vm_url);
2326
2327             if (context != null) {
2328                 stack = lookupStack(rc, context, stackId);
2329                 logger.debug(Msg.STACK_FOUND, vm_url, context.getTenantName(), stack.getStatus().toString());
2330                 logger.info(EELFResourceManager.format(Msg.SNAPSHOTING_STACK, stack.getName()));
2331
2332                 Snapshot snapshot = snapshotStack(rc, stack);
2333
2334                 ctx.setAttribute(ProviderAdapter.DG_OUTPUT_PARAM_NAMESPACE +
2335                                 ProviderAdapter.PROPERTY_SNAPSHOT_ID, snapshot.getId());
2336
2337                 logger.info(EELFResourceManager.format(Msg.STACK_SNAPSHOTED, stack.getName(), snapshot.getId()));
2338                 context.close();
2339                 doSuccess(rc);
2340             } else {
2341                 ctx.setAttribute(Constants.DG_ATTRIBUTE_STATUS, "failure");
2342             }
2343
2344         } catch (ResourceNotFoundException e) {
2345             String msg = EELFResourceManager.format(Msg.STACK_NOT_FOUND, e, vm_url);
2346             logger.error(msg);
2347             doFailure(rc, HttpStatus.NOT_FOUND_404, msg, e);
2348         } catch (RequestFailedException e) {
2349             logger.error(EELFResourceManager.format(Msg.MISSING_PARAMETER_IN_REQUEST, e.getReason(), "snapshotStack"));
2350             doFailure(rc, e.getStatus(), e.getMessage(), e);
2351         } catch (Throwable t) {
2352             String msg = EELFResourceManager.format(Msg.STACK_OPERATION_EXCEPTION, t, t.getClass().getSimpleName(),
2353                             "snapshotStack", vm_url, null == context ? "n/a" : context.getTenantName());
2354             logger.error(msg, t);
2355             doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg, t);
2356         }
2357         return stack;
2358     }
2359
2360     @Override
2361     public Stack restoreStack(Map<String, String> params, SvcLogicContext ctx) throws IllegalArgumentException, APPCException {
2362         Stack stack = null;
2363         RequestContext rc = new RequestContext(ctx);
2364         rc.isAlive();
2365
2366         ctx.setAttribute("SNAPSHOT_STATUS", "STACK_NOT_FOUND");
2367         String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME);
2368
2369         String vm_url = null;
2370         Context context = null;
2371
2372         try {
2373
2374             logAndValidate(params, ctx, rc, SNAPSHOT_STACK, "Snapshot Stack",
2375                             ProviderAdapter.PROPERTY_INSTANCE_URL,
2376                             ProviderAdapter.PROPERTY_PROVIDER_NAME,
2377                             ProviderAdapter.PROPERTY_STACK_ID,
2378                             ProviderAdapter.PROPERTY_INPUT_SNAPSHOT_ID);
2379
2380             String stackId = params.get(ProviderAdapter.PROPERTY_STACK_ID);
2381             vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL);
2382
2383             String snapshotId = params.get(ProviderAdapter.PROPERTY_INPUT_SNAPSHOT_ID);
2384
2385             context = resolveContext(rc, params, appName, vm_url);
2386
2387             if (context != null) {
2388                 stack = lookupStack(rc, context, stackId);
2389                 logger.debug(Msg.STACK_FOUND, vm_url, context.getTenantName(), stack.getStatus().toString());
2390                 logger.info(EELFResourceManager.format(Msg.RESTORING_STACK, stack.getName(), snapshotId));
2391                 restoreStack(stack, snapshotId);
2392                 logger.info(EELFResourceManager.format(Msg.STACK_RESTORED, stack.getName(), snapshotId));
2393                 context.close();
2394                 doSuccess(rc);
2395             } else {
2396                 ctx.setAttribute(Constants.DG_ATTRIBUTE_STATUS, "failure");
2397             }
2398
2399         } catch (ResourceNotFoundException e) {
2400             String msg = EELFResourceManager.format(Msg.STACK_NOT_FOUND, e, vm_url);
2401             logger.error(msg);
2402             doFailure(rc, HttpStatus.NOT_FOUND_404, msg, e);
2403         } catch (RequestFailedException e) {
2404             logger.error(EELFResourceManager.format(Msg.MISSING_PARAMETER_IN_REQUEST, e.getReason(), "restoreStack"));
2405             doFailure(rc, e.getStatus(), e.getMessage(), e);
2406         } catch (Throwable t) {
2407             String msg = EELFResourceManager.format(Msg.STACK_OPERATION_EXCEPTION, t, t.getClass().getSimpleName(),
2408                             "restoreStack", vm_url, null == context ? "n/a" : context.getTenantName());
2409             logger.error(msg, t);
2410             doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg, t);
2411         }
2412         return stack;
2413     }
2414
2415     private void logAndValidate(Map<String, String> params, SvcLogicContext ctx, RequestContext rc, String methodName, String serviceName, String ... attributes)
2416                     throws RequestFailedException {
2417         MDC.put(MDC_ADAPTER, ADAPTER_NAME);
2418         MDC.put(MDC_SERVICE, SNAPSHOT_STACK);
2419         MDC.put(MDC_SERVICE_NAME, String.format("App-C IaaS Adapter:%s", serviceName));
2420         if (logger.isDebugEnabled()) {
2421             logger.debug(String.format("Inside org.openecomp.appc.adapter.iaas.impl.ProviderAdapter.%s", methodName));
2422         }
2423
2424         validateParametersExist(rc, params, attributes);
2425
2426         debugParameters(params);
2427         debugContext(ctx);
2428     }
2429
2430     private Context resolveContext(RequestContext rc, Map<String, String> params, String appName, String vm_url)
2431                     throws RequestFailedException {
2432
2433         VMURL vm = VMURL.parseURL(vm_url);
2434         if (vm == null) {
2435             String msg = EELFResourceManager.format(Msg.INVALID_SELF_LINK_URL, appName, vm_url);
2436             doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
2437             logger.error(msg);
2438             return null;
2439         }
2440         validateVMURL(vm);
2441         IdentityURL ident = IdentityURL.parseURL(params.get(ProviderAdapter.PROPERTY_IDENTITY_URL));
2442         String identStr = (ident == null) ? null : ident.toString();
2443
2444         return getContext(rc, vm_url, identStr);
2445
2446     }
2447
2448     private void deleteStack(RequestContext rc, Stack stack) throws ZoneException, RequestFailedException {
2449         SvcLogicContext ctx = rc.getSvcLogicContext();
2450         Context context = stack.getContext();
2451         StackService stackService = context.getStackService();
2452         logger.debug("Deleting Stack: " + "id:{ " + stack.getId() + "}");
2453         stackService.deleteStack(stack);
2454
2455         // wait for the stack deletion
2456         boolean success = waitForStackStatus(rc, stack, Stack.Status.DELETED);
2457         if (success) {
2458             ctx.setAttribute("TERMINATE_STATUS", "SUCCESS");
2459         } else {
2460             ctx.setAttribute("TERMINATE_STATUS", "ERROR");
2461             throw new RequestFailedException("Delete Stack failure : " + Msg.STACK_OPERATION_EXCEPTION.toString());
2462         }
2463     }
2464
2465     private boolean waitForStackStatus(RequestContext rc, Stack stack, Stack.Status expectedStatus) throws ZoneException, RequestFailedException {
2466         SvcLogicContext ctx = rc.getSvcLogicContext();
2467         Context context = stack.getContext();
2468         StackService stackService = context.getStackService();
2469
2470         int pollInterval = configuration.getIntegerProperty(Constants.PROPERTY_OPENSTACK_POLL_INTERVAL);
2471         int timeout = configuration.getIntegerProperty(Constants.PROPERTY_STACK_STATE_CHANGE_TIMEOUT);
2472         long maxTimeToWait = System.currentTimeMillis() + (long) timeout * 1000;
2473         Stack.Status stackStatus;
2474         while (System.currentTimeMillis() < maxTimeToWait) {
2475             stackStatus = stackService.getStack(stack.getName(), stack.getId()).getStatus();
2476             logger.debug("Stack status : " + stackStatus.toString());
2477             if (stackStatus == expectedStatus) {
2478                 return true;
2479             } else if (stackStatus == Stack.Status.FAILED) {
2480                 return false;
2481             } else {
2482                 try {
2483                     Thread.sleep(pollInterval * 1000);
2484                 } catch (InterruptedException e) {
2485                     logger.trace("Sleep threw interrupted exception, should never occur");
2486                 }
2487             }
2488         }
2489
2490         ctx.setAttribute("TERMINATE_STATUS", "ERROR");
2491         throw new TimeoutException("Timeout waiting for stack status change");
2492
2493     }
2494
2495     private Snapshot snapshotStack(@SuppressWarnings("unused") RequestContext rc, Stack stack) throws ZoneException, RequestFailedException {
2496         Snapshot snapshot = new Snapshot();
2497         Context context = stack.getContext();
2498
2499         OpenStackContext osContext = (OpenStackContext)context;
2500
2501         final HeatConnector heatConnector = osContext.getHeatConnector();
2502         ((OpenStackContext)context).refreshIfStale(heatConnector);
2503
2504         trackRequest(context);
2505         RequestState.put("SERVICE", "Orchestration");
2506         RequestState.put("SERVICE_URL", heatConnector.getEndpoint());
2507
2508         Heat heat = heatConnector.getClient();
2509
2510         SnapshotResource snapshotResource = new SnapshotResource(heat);
2511
2512         try {
2513
2514             snapshot = snapshotResource.create(stack.getName(), stack.getId(), new CreateSnapshotParams()).execute();
2515
2516             // wait for the stack deletion
2517             StackResource stackResource = new StackResource(heat);
2518             if (!waitForStack(stack, stackResource, "SNAPSHOT_COMPLETE")) {
2519                 throw new RequestFailedException("Stack Snapshot failed.");
2520             }
2521
2522         } catch (OpenStackBaseException e) {
2523             ExceptionMapper.mapException(e);
2524         }
2525
2526         return snapshot;
2527     }
2528
2529     private void restoreStack(Stack stack, String snapshotId) throws ZoneException, RequestFailedException {
2530         Context context = stack.getContext();
2531
2532         OpenStackContext osContext = (OpenStackContext)context;
2533
2534         final HeatConnector heatConnector = osContext.getHeatConnector();
2535         ((OpenStackContext)context).refreshIfStale(heatConnector);
2536
2537         trackRequest(context);
2538         RequestState.put("SERVICE", "Orchestration");
2539         RequestState.put("SERVICE_URL", heatConnector.getEndpoint());
2540
2541         Heat heat = heatConnector.getClient();
2542
2543         SnapshotResource snapshotResource = new SnapshotResource(heat);
2544
2545         try {
2546
2547             snapshotResource.restore(stack.getName(), stack.getId(), snapshotId).execute();
2548
2549             // wait for the snapshot restore
2550             StackResource stackResource = new StackResource(heat);
2551             if (!waitForStack(stack, stackResource, "RESTORE_COMPLETE")) {
2552                 throw new RequestFailedException("Snapshot restore failed.");
2553             }
2554
2555         } catch (OpenStackBaseException e) {
2556             ExceptionMapper.mapException(e);
2557         }
2558
2559     }
2560
2561     private boolean waitForStack(Stack stack, StackResource stackResource, String expectedStatus)
2562                     throws OpenStackBaseException, TimeoutException {
2563         int pollInterval = configuration.getIntegerProperty(Constants.PROPERTY_OPENSTACK_POLL_INTERVAL);
2564         int timeout = configuration.getIntegerProperty(Constants.PROPERTY_STACK_STATE_CHANGE_TIMEOUT);
2565         long maxTimeToWait = System.currentTimeMillis() + (long) timeout * 1000;
2566
2567         while (System.currentTimeMillis() < maxTimeToWait) {
2568             String stackStatus = stackResource.show(stack.getName(), stack.getId()).execute().getStackStatus();
2569             logger.debug("Stack status : " + stackStatus);
2570             if (stackStatus.toUpperCase().contains("FAILED")) return false;
2571             if(checkStatus(expectedStatus, pollInterval, stackStatus)) return true;
2572         }
2573         throw new TimeoutException("Timeout waiting for stack status change");
2574     }
2575
2576     private boolean checkStatus(String expectedStatus, int pollInterval, String actualStatus) {
2577         if (actualStatus.toUpperCase().equals(expectedStatus)) {
2578             return true;
2579         } else {
2580             try {
2581                 Thread.sleep(pollInterval * 1000);
2582             } catch (InterruptedException ignored) {
2583             }
2584         }
2585         return false;
2586     }
2587
2588     private void trackRequest(Context context, AbstractService.State... states) {
2589         RequestState.clear();
2590
2591         if (null == states) return;
2592         for (AbstractService.State state : states) {
2593             RequestState.put(state.getName(), state.getValue());
2594         }
2595
2596         Thread currentThread = Thread.currentThread();
2597         StackTraceElement[] stack = currentThread.getStackTrace();
2598         if (stack != null && stack.length > 0) {
2599             int index = 0;
2600             StackTraceElement element;
2601             for (; index < stack.length; index++) {
2602                 element = stack[index];
2603                 if ("trackRequest".equals(element.getMethodName())) {  //$NON-NLS-1$
2604                     break;
2605                 }
2606             }
2607             index++;
2608
2609             if (index < stack.length) {
2610                 element = stack[index];
2611                 RequestState.put(RequestState.METHOD, element.getMethodName());
2612                 RequestState.put(RequestState.CLASS, element.getClassName());
2613                 RequestState.put(RequestState.LINE_NUMBER, Integer.toString(element.getLineNumber()));
2614                 RequestState.put(RequestState.THREAD, currentThread.getName());
2615                 RequestState.put(RequestState.PROVIDER, context.getProvider().getName());
2616                 RequestState.put(RequestState.TENANT, context.getTenantName());
2617                 RequestState.put(RequestState.PRINCIPAL, context.getPrincipal());
2618             }
2619         }
2620     }
2621
2622     private Stack lookupStack(RequestContext rc, Context context, String id)
2623         throws ZoneException, RequestFailedException {
2624         StackService stackService = context.getStackService();
2625         Stack stack = null;
2626         String msg;
2627         Provider provider = context.getProvider();
2628         while (rc.attempt()) {
2629             try {
2630                 List<Stack> stackList = stackService.getStacks();
2631                 for (Stack stackObj : stackList) {
2632                     if (stackObj.getId().equals(id)) {
2633                         stack = stackObj;
2634                         break;
2635                     }
2636                 }
2637                 break;
2638             } catch (ContextConnectionException e) {
2639                 msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), stackService.getURL(),
2640                     context.getTenant().getName(), context.getTenant().getId(), e.getMessage(),
2641                     Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()),
2642                     Integer.toString(rc.getRetryLimit()));
2643                 logger.error(msg, e);
2644                 rc.delay();
2645             }
2646
2647         }
2648         if (rc.isFailed()) {
2649             msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), stackService.getURL());
2650             logger.error(msg);
2651             doFailure(rc, HttpStatus.BAD_GATEWAY_502, msg);
2652             throw new RequestFailedException("Lookup Stack", msg, HttpStatus.BAD_GATEWAY_502, stack);
2653         }
2654
2655         if (stack == null) {
2656             throw new ResourceNotFoundException("Stack not found with Id : {" + id + "}");
2657         }
2658         return stack;
2659     }
2660
2661     @SuppressWarnings("nls")
2662     @Override
2663     public Server lookupServer(Map<String, String> params, SvcLogicContext ctx) throws APPCException {
2664         Server server = null;
2665         RequestContext rc = new RequestContext(ctx);
2666         rc.isAlive(); //should we test the return and fail if false?
2667         MDC.put(MDC_ADAPTER, ADAPTER_NAME);
2668         MDC.put(MDC_SERVICE, LOOKUP_SERVICE);
2669         MDC.put(MDC_SERVICE_NAME, "App-C IaaS Adapter:LookupServer");
2670         String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME);
2671
2672         //for debugging merge into single method?
2673         debugParameters(params);
2674         debugContext(ctx);
2675
2676         String vm_url = null;
2677         VMURL vm = null;
2678         try {
2679
2680             //process vm_url
2681             validateParametersExist(rc, params, ProviderAdapter.PROPERTY_INSTANCE_URL,
2682                 ProviderAdapter.PROPERTY_PROVIDER_NAME);
2683             vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL);
2684             vm = VMURL.parseURL(vm_url);
2685             if (validateVM(rc, appName, vm_url, vm)) return null;
2686
2687
2688             //use try with resource to ensure context is closed (returned to pool)
2689             try(Context context = resolveContext(rc, params, appName, vm_url)){
2690               //resloveContext & getContext call doFailure and log errors before returning null
2691                 if (context != null){
2692                     server = lookupServer(rc, context, vm.getServerId());
2693                     logger.debug(Msg.SERVER_FOUND, vm_url, context.getTenantName(), server.getStatus().toString());
2694                     ctx.setAttribute("serverFound", "success");
2695                     doSuccess(rc);
2696                 }
2697             } catch (ZoneException e) {
2698                 //server not found
2699                 String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, e, vm_url);
2700                 logger.error(msg);
2701                 doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
2702                 ctx.setAttribute("serverFound", "failure");
2703             }  catch (IOException e) {
2704                 //exception closing context
2705                 String msg = EELFResourceManager.format(Msg.CLOSE_CONTEXT_FAILED, e, vm_url);
2706                 logger.error(msg);
2707             } catch (Throwable t) {
2708                 String msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, t, t.getClass().getSimpleName(),
2709                     LOOKUP_SERVICE, vm_url,  "Unknown" );
2710                 logger.error(msg, t);
2711                 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
2712             }
2713
2714         } catch (RequestFailedException e) {
2715             // parameters not valid, unable to connect to provider
2716             String msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, e, vm_url);
2717             logger.error(msg);
2718             doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
2719             ctx.setAttribute("serverFound", "failure");
2720         }
2721         return server;
2722     }
2723 }