AAPC-1659 removing unused import
[appc.git] / appc-adapters / appc-iaas-adapter / appc-iaas-adapter-bundle / src / main / java / org / onap / appc / adapter / iaas / provider / operation / impl / RebuildServer.java
1 /*
2 * ============LICENSE_START=======================================================
3 * ONAP : APPC
4 * ================================================================================
5 * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Copyright (C) 2017 Amdocs
8 * =============================================================================
9 * Modifications Copyright (C) 2019 IBM
10 * =============================================================================
11 * Licensed under the Apache License, Version 2.0 (the "License");
12 * you may not use this file except in compliance with the License.
13 * You may obtain a copy of the License at
14
15 *      http://www.apache.org/licenses/LICENSE-2.0
16
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS,
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
22
23 * ============LICENSE_END=========================================================
24 */
25
26 package org.onap.appc.adapter.iaas.provider.operation.impl;
27
28 import com.att.cdp.exceptions.ContextConnectionException;
29 import com.att.cdp.exceptions.ResourceNotFoundException;
30 import com.att.cdp.exceptions.ZoneException;
31 import com.att.cdp.zones.ComputeService;
32 import com.att.cdp.zones.Context;
33 import com.att.cdp.zones.ImageService;
34 import com.att.cdp.zones.Provider;
35 import com.att.cdp.zones.model.Image;
36 import com.att.cdp.zones.model.ModelObject;
37 import com.att.cdp.zones.model.Server;
38 import com.att.cdp.zones.model.ServerBootSource;
39 import com.att.eelf.configuration.EELFLogger;
40 import com.att.eelf.configuration.EELFManager;
41 import com.att.eelf.i18n.EELFResourceManager;
42 import org.glassfish.grizzly.http.util.HttpStatus;
43 import org.onap.appc.Constants;
44 import com.fasterxml.jackson.databind.JsonNode;
45 import com.fasterxml.jackson.databind.ObjectMapper;
46 import org.onap.appc.adapter.iaas.ProviderAdapter;
47 import org.onap.appc.adapter.iaas.impl.IdentityURL;
48 import org.onap.appc.adapter.iaas.impl.RequestContext;
49 import org.onap.appc.adapter.iaas.impl.RequestFailedException;
50 import org.onap.appc.adapter.iaas.impl.VMURL;
51 import org.onap.appc.adapter.iaas.provider.operation.common.constants.Property;
52 import org.onap.appc.adapter.iaas.provider.operation.common.enums.Operation;
53 import org.onap.appc.adapter.iaas.provider.operation.common.enums.Outcome;
54 import org.onap.appc.adapter.iaas.provider.operation.impl.base.ProviderServerOperation;
55 import org.onap.appc.configuration.Configuration;
56 import org.onap.appc.configuration.ConfigurationFactory;
57 import org.onap.appc.exceptions.APPCException;
58 import org.onap.appc.i18n.Msg;
59 import org.onap.appc.logging.LoggingConstants;
60 import org.onap.appc.logging.LoggingUtils;
61 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
62 import org.slf4j.MDC;
63 import java.util.Date;
64 import java.util.List;
65 import java.util.Map;
66 import static org.onap.appc.adapter.iaas.provider.operation.common.enums.Operation.STOP_SERVICE;
67 import static org.onap.appc.adapter.utils.Constants.ADAPTER_NAME;
68 import com.att.cdp.exceptions.StateException;
69
70 public class RebuildServer extends ProviderServerOperation {
71
72     private static final EELFLogger logger = EELFManager.getInstance().getLogger(RebuildServer.class);
73     private static EELFLogger metricsLogger = EELFManager.getInstance().getMetricsLogger();
74     private static final Configuration configuration = ConfigurationFactory.getConfiguration();
75     // the sleep time used by thread.sleep to give "some time for OpenStack to start
76     // processing the request"
77     private long rebuildSleepTime = 10L * 1000L;
78
79     /**
80      * Rebuild the indicated server with the indicated image. This method assumes
81      * the server has been determined to be in the correct state to do the rebuild.
82      *
83      * @param rc
84      *            The request context that manages the state and recovery of the
85      *            request for the life of its processing.
86      * @param server
87      *            the server to be rebuilt
88      * @param image
89      *            The image to be used (or snapshot)
90      * @throws RequestFailedException
91      *             if the server does not change state in the allotted time
92      */
93     @SuppressWarnings("nls")
94     private void rebuildServer(RequestContext rc, Server server, String image) throws RequestFailedException {
95         logger.debug(Msg.REBUILD_SERVER, server.getId());
96         String msg;
97         Context context = server.getContext();
98         Provider provider = context.getProvider();
99         ComputeService service = context.getComputeService();
100         /*
101          * Set Time for Metrics Logger
102          */
103         setTimeForMetricsLogger();
104         try {
105             while (rc.attempt()) {
106                 try {
107                     server.rebuild(image);
108                     break;
109                 } catch (ContextConnectionException e) {
110                     msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(),
111                             context.getTenant().getName(), context.getTenant().getId(), e.getMessage(),
112                             Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()),
113                             Integer.toString(rc.getRetryLimit()));
114                     logger.error(msg, e);
115                     metricsLogger.error(msg, e);
116                     rc.delay();
117                 }
118             }
119             /*
120              * We need to provide some time for OpenStack to start processing the request.
121              */
122             try {
123                 Thread.sleep(rebuildSleepTime);
124             } catch (InterruptedException e) {
125                 logger.trace("Sleep threw interrupted exception, should never occur");
126                 metricsLogger.trace("Sleep threw interrupted exception, should never occur");
127                 Thread.currentThread().interrupt();
128             }
129         } catch (ZoneException e) {
130             msg = EELFResourceManager.format(Msg.REBUILD_SERVER_FAILED, server.getName(), server.getId(),
131                     e.getMessage());
132             logger.error(msg);
133             metricsLogger.error(msg);
134             throw new RequestFailedException("Rebuild Server", msg, HttpStatus.BAD_GATEWAY_502, server);
135         }
136         rc.reset();
137         /*
138          * Once we have started the process, now we wait for the final state of stopped.
139          * This should be the final state (since we started the rebuild with the server
140          * stopped).
141          */
142         waitForStateChange(rc, server, Server.Status.READY);
143         if (rc.isFailed()) {
144             msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL());
145             logger.error(msg);
146             metricsLogger.error(msg);
147             throw new RequestFailedException("Rebuild Server", msg, HttpStatus.BAD_GATEWAY_502, server);
148         }
149         rc.reset();
150     }
151
152     /**
153      * This method is called to rebuild the provided server.
154      * <p>
155      * If the server was booted from a volume, then the request is failed
156      * immediately and no action is taken. Rebuilding a VM from a bootable volume,
157      * where the bootable volume itself is not rebuilt, serves no purpose.
158      * </p>
159      *
160      * @param rc
161      *            The request context that manages the state and recovery of the
162      *            request for the life of its processing.
163      * @param server
164      *            The server to be rebuilt
165      * @throws ZoneException
166      *             When error occurs
167      * @throws RequestFailedException
168      *             When server status is error
169      */
170     @SuppressWarnings("nls")
171     private void rebuildServer(RequestContext rc, Server server, SvcLogicContext ctx)
172             throws ZoneException, RequestFailedException {
173         ServerBootSource builtFrom = server.getBootSource();
174         /*
175          * Set Time for Metrics Logger
176          */
177         setTimeForMetricsLogger();
178         String msg;
179         // Throw error if boot source is unknown
180         if (ServerBootSource.UNKNOWN.equals(builtFrom)) {
181             logger.debug("Boot Source Unknown");
182             msg = String.format("Error occured when retrieving server boot source [%s]!!!", server.getId());
183             logger.error(msg);
184             generateEvent(rc, false, msg);
185             metricsLogger.error(msg);
186             throw new RequestFailedException("Rebuild Server", msg, HttpStatus.INTERNAL_SERVER_ERROR_500, server);
187         }
188
189         // Throw exception for non image/snap boot source
190         if (ServerBootSource.VOLUME.equals(builtFrom)) {
191             logger.debug("Boot Source Not Supported built from bootable volume");
192             msg = String.format("Rebuilding is currently not supported for servers built from bootable volumes [%s]",
193                     server.getId());
194             generateEvent(rc, false, msg);
195             logger.error(msg);
196             metricsLogger.error(msg);
197             throw new RequestFailedException("Rebuild Server", msg, HttpStatus.FORBIDDEN_403, server);
198         }
199         /*
200          * Pending is a bit of a special case. If we find the server is in a pending
201          * state, then the provider is in the process of changing state of the server.
202          * So, lets try to wait a little bit and see if the state settles down to one we
203          * can deal with. If not, then we have to fail the request.
204          */
205         Context context = server.getContext();
206         Provider provider = context.getProvider();
207         ComputeService service = context.getComputeService();
208         if (server.getStatus().equals(Server.Status.PENDING)) {
209             rc.reset();
210             waitForStateChange(rc, server, Server.Status.READY, Server.Status.RUNNING, Server.Status.ERROR,
211                     Server.Status.SUSPENDED, Server.Status.PAUSED);
212         }
213         // Is the skip Hypervisor check attribute populated?
214         String skipHypervisorCheck = configuration.getProperty(Property.SKIP_HYPERVISOR_CHECK);
215         if (skipHypervisorCheck == null && ctx != null) {
216             skipHypervisorCheck = ctx.getAttribute(ProviderAdapter.SKIP_HYPERVISOR_CHECK);
217         }
218         // Always perform Hypervisor Status checks
219         // unless the skip is set to true
220         if (skipHypervisorCheck == null || (!"true".equalsIgnoreCase(skipHypervisorCheck))) {
221             // Check of the Hypervisor for the VM Server is UP and reachable
222             checkHypervisor(server);
223         }
224         /*
225          * Get the image to use in this priority order: (1) If snapshot-id provided in
226          * the request, use this (2) If any snapshots exist, then the latest snapshot is
227          * used (3) Otherwise the image used to construct the VM is used.
228          */
229         String imageToUse = "";
230         try {
231             ObjectMapper mapper = new ObjectMapper();
232             String payloadStr = configuration.getProperty(Property.PAYLOAD);
233             if (payloadStr == null || payloadStr.isEmpty()) {
234                 payloadStr = ctx.getAttribute(ProviderAdapter.PAYLOAD);
235             }
236             JsonNode payloadNode = mapper.readTree(payloadStr);
237             imageToUse = payloadNode.get(ProviderAdapter.PROPERTY_REQUEST_SNAPSHOT_ID).textValue();
238             logger.debug("Pulled snapshot-id " + imageToUse + " from the payload");
239         } catch (Exception e) {
240             logger.debug("Exception attempting to pull snapshot-id from the payload: " + e.toString());
241         }
242         List<Image> snapshots = server.getSnapshots();
243         ImageService imageService = server.getContext().getImageService();
244         List<Image> imageList = imageService.listImages();
245         if (!imageToUse.isEmpty()) {
246             logger.debug("Using snapshot-id " + imageToUse + " for the rebuild request");
247             boolean imgFound = validateSnapshotId(imageToUse, snapshots, imageList);
248
249             if (!imgFound) {
250                 logger.debug("Image Snapshot Not Found");
251                 msg = EELFResourceManager.format(Msg.REBUILD_SERVER_FAILED, server.getName(), server.getId(),
252                         "Invalid Snapshot-Id");
253                 logger.error(msg);
254                 metricsLogger.error(msg);
255                 throw new RequestFailedException("Rebuild Server", msg, HttpStatus.FORBIDDEN_403, server);
256             }
257         } else if (snapshots != null && !snapshots.isEmpty()) {
258             logger.debug("Using snapshot-id when image is Empty" + imageToUse + " for the rebuild request");
259             imageToUse = snapshots.get(0).getId();
260         } else {
261             imageToUse = server.getImage();
262             rc.reset();
263             try {
264                 while (rc.attempt()) {
265                     try {
266                         /*
267                          * We are just trying to make sure that the image exists. We arent interested in
268                          * the details at this point.
269                          */
270                         imageService.getImage(imageToUse);
271                         break;
272                     } catch (ContextConnectionException e) {
273                         msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(),
274                                 imageService.getURL(), context.getTenant().getName(), context.getTenant().getId(),
275                                 e.getMessage(), Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()),
276                                 Integer.toString(rc.getRetryLimit()));
277                         logger.error(msg, e);
278                         metricsLogger.error(msg);
279                         rc.delay();
280                     }
281                 }
282             } catch (ZoneException e) {
283                 msg = EELFResourceManager.format(Msg.IMAGE_NOT_FOUND, imageToUse, "rebuild");
284                 generateEvent(rc, false, msg);
285                 logger.error(msg);
286                 metricsLogger.error(msg);
287                 throw new RequestFailedException("Rebuild Server", msg, HttpStatus.METHOD_NOT_ALLOWED_405, server);
288             }
289         }
290         if (rc.isFailed()) {
291             msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL());
292             logger.error(msg);
293             metricsLogger.error(msg);
294             throw new RequestFailedException("Rebuild Server", msg, HttpStatus.BAD_GATEWAY_502, server);
295         }
296         rc.reset();
297         /*
298          * We determine what to do based on the current state of the server
299          */
300         switch (server.getStatus()) {
301         case DELETED:
302             // Nothing to do, the server is gone
303             msg = EELFResourceManager.format(Msg.SERVER_DELETED, server.getName(), server.getId(), server.getTenantId(),
304                     "rebuilt");
305             generateEvent(rc, false, msg);
306             logger.error(msg);
307             metricsLogger.error(msg);
308             throw new RequestFailedException("Rebuild Server", msg, HttpStatus.METHOD_NOT_ALLOWED_405, server);
309         case RUNNING:
310             // Attempt to stop the server, then rebuild it
311             stopServer(rc, server);
312             rc.reset();
313             rebuildServer(rc, server, imageToUse);
314             rc.reset();
315             startServer(rc, server);
316             generateEvent(rc, true, Outcome.SUCCESS.toString());
317             metricsLogger.info("Server status: RUNNING");
318             break;
319         case ERROR:
320             msg = EELFResourceManager.format(Msg.SERVER_ERROR_STATE, server.getName(), server.getId(),
321                     server.getTenantId(), "rebuild");
322             generateEvent(rc, false, msg);
323             logger.error(msg);
324             metricsLogger.error(msg);
325             throw new RequestFailedException("Rebuild Server", msg, HttpStatus.METHOD_NOT_ALLOWED_405, server);
326         case READY:
327             // Attempt to rebuild the server
328             rebuildServer(rc, server, imageToUse);
329             rc.reset();
330             startServer(rc, server);
331             generateEvent(rc, true, Outcome.SUCCESS.toString());
332             metricsLogger.info("Server status: READY");
333             break;
334         case PAUSED:
335             // if paused, un-pause it, stop it, and rebuild it
336             unpauseServer(rc, server);
337             rc.reset();
338             stopServer(rc, server);
339             rc.reset();
340             rebuildServer(rc, server, imageToUse);
341             rc.reset();
342             startServer(rc, server);
343             generateEvent(rc, true, Outcome.SUCCESS.toString());
344             metricsLogger.info("Server status: PAUSED");
345             break;
346         case SUSPENDED:
347             // Attempt to resume the suspended server, stop it, and rebuild it
348             resumeServer(rc, server);
349             rc.reset();
350             stopServer(rc, server);
351             rc.reset();
352             rebuildServer(rc, server, imageToUse);
353             rc.reset();
354             startServer(rc, server);
355             generateEvent(rc, true, Outcome.SUCCESS.toString());
356             metricsLogger.info("Server status: SUSPENDED");
357             break;
358         default:
359             // Hmmm, unknown status, should never occur
360             msg = EELFResourceManager.format(Msg.UNKNOWN_SERVER_STATE, server.getName(), server.getId(),
361                     server.getTenantId(), server.getStatus().name());
362             generateEvent(rc, false, msg);
363             logger.error(msg);
364             metricsLogger.error(msg);
365             throw new RequestFailedException("Rebuild Server", msg, HttpStatus.METHOD_NOT_ALLOWED_405, server);
366         }
367     }
368
369     /**
370      * @see org.onap.appc.adapter.iaas.ProviderAdapter#rebuildServer(java.util.Map,
371      *      org.onap.ccsdk.sli.core.sli.SvcLogicContext)
372      */
373     @SuppressWarnings("nls")
374     public Server rebuildServer(Map<String, String> params, SvcLogicContext ctx) throws APPCException {
375         Server server = null;
376         RequestContext rc = new RequestContext(ctx);
377         rc.isAlive();
378         setTimeForMetricsLogger();
379         String msg;
380         try {
381             validateParametersExist(params, ProviderAdapter.PROPERTY_INSTANCE_URL,
382                     ProviderAdapter.PROPERTY_PROVIDER_NAME);
383             String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME);
384             String vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL);
385             VMURL vm = VMURL.parseURL(vm_url);
386             if (validateVM(rc, appName, vm_url, vm))
387                 return null;
388             IdentityURL ident = IdentityURL.parseURL(params.get(ProviderAdapter.PROPERTY_IDENTITY_URL));
389             String identStr = (ident == null) ? null : ident.toString();
390             ctx.setAttribute("REBUILD_STATUS", "ERROR");
391             Context context = null;
392             String tenantName = "Unknown";// to be used also in case of exception
393             try {
394                 context = getContext(rc, vm_url, identStr);
395                 if (context != null) {
396                     tenantName = context.getTenantName();// this varaible also is used in case of exception
397                     rc.reset();
398                     server = lookupServer(rc, context, vm.getServerId());
399                     logger.debug(Msg.SERVER_FOUND, vm_url, tenantName, server.getStatus().toString());
400                     // Manually checking image service until new PAL release
401                     if (hasImageAccess(rc, context)) {
402                         rebuildServer(rc, server, ctx);
403                         doSuccess(rc);
404                         ctx.setAttribute("REBUILD_STATUS", "SUCCESS");
405                     } else {
406                         msg = EELFResourceManager.format(Msg.REBUILD_SERVER_FAILED, server.getName(), server.getId(),
407                                 "Accessing Image Service Failed");
408                         logger.error(msg);
409                         metricsLogger.error(msg);
410                         doFailure(rc, HttpStatus.FORBIDDEN_403, msg);
411                     }
412                     context.close();
413                 } else {
414                     ctx.setAttribute("REBUILD_STATUS", "CONTEXT_NOT_FOUND");
415                 }
416             } catch (StateException ex) {
417                 logger.error(ex.getMessage());
418                 ctx.setAttribute("REBUILD_STATUS", "ERROR");
419                 doFailure(rc, HttpStatus.CONFLICT_409, ex.getMessage());
420             } catch (RequestFailedException e) {
421                 doFailure(rc, e.getStatus(), e.getMessage());
422                 ctx.setAttribute("REBUILD_STATUS", "ERROR");
423             } catch (ResourceNotFoundException e) {
424                 msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, e, vm_url);
425                 ctx.setAttribute("REBUILD_STATUS", "ERROR");
426                 logger.error(msg);
427                 metricsLogger.error(msg);
428                 doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
429             } catch (Exception e1) {
430                 msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, e1, e1.getClass().getSimpleName(),
431                         STOP_SERVICE.toString(), vm_url, tenantName);
432                 ctx.setAttribute("REBUILD_STATUS", "ERROR");
433                 logger.error(msg, e1);
434                 metricsLogger.error(msg);
435                 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
436             }
437         } catch (RequestFailedException e) {
438             ctx.setAttribute("REBUILD_STATUS", "ERROR");
439             doFailure(rc, e.getStatus(), e.getMessage());
440         }
441         return server;
442     }
443
444     @Override
445     protected ModelObject executeProviderOperation(Map<String, String> params, SvcLogicContext context)
446             throws APPCException {
447         setMDC(Operation.REBUILD_SERVICE.toString(), "App-C IaaS Adapter:Rebuild", ADAPTER_NAME);
448         logOperation(Msg.REBUILDING_SERVER, params, context);
449         setTimeForMetricsLogger();
450         metricsLogger.info("Executing Provider Operation: Rebuild");
451         return rebuildServer(params, context);
452     }
453
454     private void setTimeForMetricsLogger() {
455         String timestamp = LoggingUtils.generateTimestampStr(((Date) new Date()).toInstant());
456         MDC.put(LoggingConstants.MDCKeys.BEGIN_TIMESTAMP, timestamp);
457         MDC.put(LoggingConstants.MDCKeys.END_TIMESTAMP, timestamp);
458         MDC.put(LoggingConstants.MDCKeys.ELAPSED_TIME, "0");
459         MDC.put(LoggingConstants.MDCKeys.STATUS_CODE, LoggingConstants.StatusCodes.COMPLETE);
460         MDC.put(LoggingConstants.MDCKeys.TARGET_ENTITY, "cdp");
461         MDC.put(LoggingConstants.MDCKeys.TARGET_SERVICE_NAME, "rebuild server");
462         MDC.put(LoggingConstants.MDCKeys.CLASS_NAME,
463                 "org.onap.appc.adapter.iaas.provider.operation.impl.RebuildServer");
464
465     }
466
467     /**
468      * Sets the sleep time used by thread.sleep to give "some time for OpenStack to
469      * start processing the request".
470      *
471      * @param millis
472      *            Time to sleep in milliseconds
473      */
474     public void setRebuildSleepTime(long millis) {
475         this.rebuildSleepTime = millis;
476     }
477
478     private boolean validateSnapshotId(String imageToUse, List<Image> snapshotList, List<Image> imageList) {
479
480         logger.debug("Validating snapshot-id " + imageToUse + " for the rebuild request from payload");
481         boolean imageFound = false;
482         // If image is empty , the validation si not required . Hence return false.
483         // Ideally function should not be called with empty image Id
484         if (imageToUse.isEmpty()) {
485             return imageFound;
486         } else {
487             // The supplied snapshot id can be a snapshot id or an image Id. Check both
488             // available for the vnf.
489             // Check against snapshot id list and image list
490             return findImageExists(snapshotList, imageToUse, "snapshotidList")
491                     || findImageExists(imageList, imageToUse, "imageidList");
492         }
493     }
494
495     boolean findImageExists(List<Image> list, String imageToUse, String source) {
496         boolean imageExists = false;
497         logger.debug("Available Image-ids from :" + source + "Start\n");
498         for (Image img : list) {
499             String imgId = img.getId();
500             logger.debug("Image Id - " + imgId + "\n");
501             if (imgId.equals(imageToUse)) {
502                 logger.debug("Image found in available " + source);
503                 imageExists = true;
504                 break;
505             }
506         }
507         return imageExists;
508
509     }
510 }