Merge of new rebased code
[appc.git] / appc-adapters / appc-iaas-adapter / appc-iaas-adapter-bundle / src / main / java / org / openecomp / appc / adapter / iaas / provider / operation / impl / RebuildServer.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.provider.operation.impl;
23
24 import org.openecomp.appc.Constants;
25 import org.openecomp.appc.adapter.iaas.ProviderAdapter;
26 import org.openecomp.appc.adapter.iaas.impl.IdentityURL;
27 import org.openecomp.appc.adapter.iaas.impl.RequestContext;
28 import org.openecomp.appc.adapter.iaas.impl.RequestFailedException;
29 import org.openecomp.appc.adapter.iaas.impl.VMURL;
30 import org.openecomp.appc.adapter.iaas.provider.operation.common.enums.Operation;
31 import org.openecomp.appc.adapter.iaas.provider.operation.common.enums.Outcome;
32 import org.openecomp.appc.adapter.iaas.provider.operation.impl.base.ProviderServerOperation;
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.i18n.Msg;
37 import com.att.cdp.exceptions.ContextConnectionException;
38 import com.att.cdp.exceptions.ResourceNotFoundException;
39 import com.att.cdp.exceptions.ZoneException;
40 import com.att.cdp.zones.ComputeService;
41 import com.att.cdp.zones.Context;
42 import com.att.cdp.zones.ImageService;
43 import com.att.cdp.zones.Provider;
44 import com.att.cdp.zones.model.Image;
45 import com.att.cdp.zones.model.ModelObject;
46 import com.att.cdp.zones.model.Server;
47 import com.att.cdp.zones.model.ServerBootSource;
48 import com.att.eelf.configuration.EELFLogger;
49 import com.att.eelf.configuration.EELFManager;
50 import com.att.eelf.i18n.EELFResourceManager;
51 import org.openecomp.sdnc.sli.SvcLogicContext;
52 import org.glassfish.grizzly.http.util.HttpStatus;
53
54 import java.util.List;
55 import java.util.Map;
56
57 import static org.openecomp.appc.adapter.iaas.provider.operation.common.constants.Constants.MDC_SERVICE;
58 import static org.openecomp.appc.adapter.iaas.provider.operation.common.enums.Operation.STOP_SERVICE;
59 import static org.openecomp.appc.adapter.utils.Constants.ADAPTER_NAME;
60
61 import org.slf4j.MDC;
62 import java.text.DateFormat;
63 import java.text.SimpleDateFormat;
64 import java.util.Date;
65 import java.util.TimeZone;
66
67 /**
68  * @since September 26, 2016
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
76     /**
77      * Rebuild the indicated server with the indicated image. This method assumes the server has been determined to be
78      * in the correct state to do the rebuild.
79      *
80      * @param rc
81      *            The request context that manages the state and recovery of the request for the life of its processing.
82      * @param server
83      *            the server to be rebuilt
84      * @param image
85      *            The image to be used (or snapshot)
86      * @throws RequestFailedException
87      *             if the server does not change state in the allotted time
88      */
89     @SuppressWarnings("nls")
90     private void rebuildServer(RequestContext rc, Server server, String image) throws RequestFailedException {
91         logger.debug(Msg.REBUILD_SERVER, server.getId());
92         
93         String msg;
94         Context context = server.getContext();
95         Provider provider = context.getProvider();
96         ComputeService service = context.getComputeService();  
97         
98         /*
99          * Set Time for Metrics Logger
100          */
101         long startTime = System.currentTimeMillis();
102         TimeZone tz = TimeZone.getTimeZone("UTC");
103         DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
104         df.setTimeZone(tz);
105         String startTimeStr = df.format(new Date());
106         long endTime = System.currentTimeMillis();
107         long duration = endTime - startTime;
108         String endTimeStr = String.valueOf(endTime);
109         String durationStr = String.valueOf(duration);
110         String endTimeStrUTC = df.format(new Date());
111         MDC.put("EndTimestamp", endTimeStrUTC);
112         MDC.put("ElapsedTime", durationStr);
113         MDC.put("TargetEntity", "cdp");
114         MDC.put("TargetServiceName", "rebuild server");
115         MDC.put("ClassName", "org.openecomp.appc.adapter.iaas.provider.operation.impl.RebuildServer"); 
116
117         try {
118             while (rc.attempt()) {
119                 try {
120                     server.rebuild(image);
121                     break;
122                 } catch (ContextConnectionException e) {
123                     msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(), service.getURL(),
124                             context.getTenant().getName(), context.getTenant().getId(), e.getMessage(),
125                             Long.toString(rc.getRetryDelay()), Integer.toString(rc.getAttempts()),
126                             Integer.toString(rc.getRetryLimit()));
127                     logger.error(msg, e);
128                     metricsLogger.error(msg,e);
129                     rc.delay();
130                 }
131             }
132
133             /*
134              * We need to provide some time for OpenStack to start processing the request.
135              */
136             try {
137                 Thread.sleep(10L * 1000L);
138             } catch (InterruptedException e) {
139                 logger.trace("Sleep threw interrupted exception, should never occur");
140                 metricsLogger.trace("Sleep threw interrupted exception, should never occur");
141             }
142         } catch (ZoneException e) {
143             msg =
144                     EELFResourceManager.format(Msg.REBUILD_SERVER_FAILED, server.getName(), server.getId(), e.getMessage());
145             logger.error(msg);
146             metricsLogger.error(msg);
147             throw new RequestFailedException("Rebuild Server", msg, HttpStatus.BAD_GATEWAY_502, server);
148         }
149
150         rc.reset();
151         /*
152          * Once we have started the process, now we wait for the final state of stopped. This should be the final state
153          * (since we started the rebuild with the server stopped).
154          */
155         waitForStateChange(rc, server, Server.Status.READY);
156
157         if (rc.isFailed()) {
158             msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL());
159             logger.error(msg);
160             metricsLogger.error(msg);
161             throw new RequestFailedException("Rebuild Server", msg, HttpStatus.BAD_GATEWAY_502, server);
162         }
163         rc.reset();
164     }
165
166     /**
167      * This method is called to rebuild the provided server.
168      * <p>
169      * If the server was booted from a volume, then the request is failed immediately and no action is taken. Rebuilding
170      * a VM from a bootable volume, where the bootable volume itself is not rebuilt, serves no purpose.
171      * </p>
172      *
173      * @param rc
174      *            The request context that manages the state and recovery of the request for the life of its processing.
175      * @param server
176      * @throws ZoneException
177      * @throws RequestFailedException
178      */
179     @SuppressWarnings("nls")
180         private void rebuildServer(RequestContext rc, Server server, SvcLogicContext ctx)
181                         throws ZoneException, RequestFailedException {
182
183                 ServerBootSource builtFrom = server.getBootSource();
184                 String msg;
185
186                 /*
187                  * Set Time for Metrics Logger
188                  */
189                 long startTime = System.currentTimeMillis();
190                 TimeZone tz = TimeZone.getTimeZone("UTC");
191                 DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
192                 df.setTimeZone(tz);
193                 String startTimeStr = df.format(new Date());
194                 long endTime = System.currentTimeMillis();
195                 long duration = endTime - startTime;
196                 String endTimeStr = String.valueOf(endTime);
197                 String durationStr = String.valueOf(duration);
198                 String endTimeStrUTC = df.format(new Date());
199                 MDC.put("EndTimestamp", endTimeStrUTC);
200                 MDC.put("ElapsedTime", durationStr);
201                 MDC.put("TargetEntity", "cdp");
202                 MDC.put("TargetServiceName", "rebuild server");
203                 MDC.put("ClassName", "org.openecomp.appc.adapter.iaas.provider.operation.impl.RebuildServer");
204
205                 // Throw exception for non image/snap boot source
206                 if (ServerBootSource.VOLUME.equals(builtFrom)) {
207                         msg = String.format("Rebuilding is currently not supported for servers built from bootable volumes [%s]",
208                                         server.getId());
209                         generateEvent(rc, false, msg);
210                         logger.error(msg);
211                         metricsLogger.error(msg);
212                         throw new RequestFailedException("Rebuild Server", msg, HttpStatus.FORBIDDEN_403, server);
213                 }
214
215                 /*
216                  * Pending is a bit of a special case. If we find the server is in a
217                  * pending state, then the provider is in the process of changing state
218                  * of the server. So, lets try to wait a little bit and see if the state
219                  * settles down to one we can deal with. If not, then we have to fail
220                  * the request.
221                  */
222                 Context context = server.getContext();
223                 Provider provider = context.getProvider();
224                 ComputeService service = context.getComputeService();
225                 if (server.getStatus().equals(Server.Status.PENDING)) {
226             rc.reset();
227             waitForStateChange(rc, server, Server.Status.READY, Server.Status.RUNNING, Server.Status.ERROR,
228                                         Server.Status.SUSPENDED, Server.Status.PAUSED);
229                 }
230
231                 // Is the skip Hypervisor check attribute populated?
232                 String skipHypervisorCheck = null;
233                 if (ctx != null) {
234                         skipHypervisorCheck = ctx.getAttribute(ProviderAdapter.SKIP_HYPERVISOR_CHECK);
235
236                 }
237
238                 // Always perform Hypervisor Status checks
239                 // unless the skip is set to true
240                 if (skipHypervisorCheck == null || (!skipHypervisorCheck.equalsIgnoreCase("true"))) {
241
242                         // Check of the Hypervisor for the VM Server is UP and reachable
243                         checkHypervisor(server);
244                 }
245
246                 /*
247                  * Get the image to use. This is determined by the presence or
248                          * absence of snapshot images. If any snapshots exist, then the
249                          * latest snapshot is used, otherwise the image used to construct
250                          * the VM is used.
251                          */
252                         List<Image> snapshots = server.getSnapshots();
253                         String imageToUse;
254                         if (snapshots != null && !snapshots.isEmpty()) {
255                                 imageToUse = snapshots.get(0).getId();
256                         } else {
257                                 imageToUse = server.getImage();
258                                 ImageService imageService = server.getContext().getImageService();
259                 rc.reset();
260                                 try {
261                                         while (rc.attempt()) {
262                                                 try {
263                                                         /*
264                                                          * We are just trying to make sure that the image
265                                                          * exists. We arent interested in the details at
266                                                          * this point.
267                                                          */
268                                                         imageService.getImage(imageToUse);
269                                                         break;
270                                                 } catch (ContextConnectionException e) {
271                                                         msg = EELFResourceManager.format(Msg.CONNECTION_FAILED_RETRY, provider.getName(),
272                                                                         imageService.getURL(), context.getTenant().getName(), context.getTenant().getId(),
273                                                                         e.getMessage(), Long.toString(rc.getRetryDelay()),
274                                                                         Integer.toString(rc.getAttempts()), Integer.toString(rc.getRetryLimit()));
275                                                         logger.error(msg, e);
276                                                         metricsLogger.error(msg);
277                                                         rc.delay();
278                                                 }
279                                         }
280                                 } catch (ZoneException e) {
281                                         msg = EELFResourceManager.format(Msg.IMAGE_NOT_FOUND, imageToUse, "rebuild");
282                                         generateEvent(rc, false, msg);
283                                         logger.error(msg);
284                                         metricsLogger.error(msg);
285                                         throw new RequestFailedException("Rebuild Server", msg, HttpStatus.METHOD_NOT_ALLOWED_405, server);
286                                 }
287                         }
288                         if (rc.isFailed()) {
289                                 msg = EELFResourceManager.format(Msg.CONNECTION_FAILED, provider.getName(), service.getURL());
290                                 logger.error(msg);
291                                 metricsLogger.error(msg);
292                                 throw new RequestFailedException("Rebuild Server", msg, HttpStatus.BAD_GATEWAY_502, server);
293                         }
294                         rc.reset();
295
296         /*
297          * We determine what to do based on the current state of the server
298          */
299         switch (server.getStatus()) {
300             case DELETED:
301                 // Nothing to do, the server is gone
302                 msg = EELFResourceManager.format(Msg.SERVER_DELETED, server.getName(), server.getId(),
303                         server.getTenantId(), "rebuilt");
304                 generateEvent(rc, false, msg);
305                 logger.error(msg);
306                 metricsLogger.error(msg);
307                 throw new RequestFailedException("Rebuild Server", msg, HttpStatus.METHOD_NOT_ALLOWED_405, server);
308
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
320             case ERROR:
321                 msg = EELFResourceManager.format(Msg.SERVER_ERROR_STATE, server.getName(), server.getId(),
322                         server.getTenantId(), "rebuild");
323                 generateEvent(rc, false, msg);
324                 logger.error(msg);
325                 metricsLogger.error(msg);
326                 throw new RequestFailedException("Rebuild Server", msg, HttpStatus.METHOD_NOT_ALLOWED_405, server);
327
328             case READY:
329                 // Attempt to rebuild the server
330                 rebuildServer(rc, server, imageToUse);
331                 rc.reset();
332                 startServer(rc, server);
333                 generateEvent(rc, true, Outcome.SUCCESS.toString());
334                 metricsLogger.info("Server status: READY");
335                 break;
336
337             case PAUSED:
338                 // if paused, un-pause it, stop it, and rebuild it
339                 unpauseServer(rc, server);
340                 rc.reset();
341                 stopServer(rc, server);
342                 rc.reset();
343                 rebuildServer(rc, server, imageToUse);
344                 rc.reset();
345                 startServer(rc, server);
346                 generateEvent(rc, true, Outcome.SUCCESS.toString());
347                 metricsLogger.info("Server status: PAUSED");
348                 break;
349
350             case SUSPENDED:
351                 // Attempt to resume the suspended server, stop it, and rebuild it
352                 resumeServer(rc, server);
353                 rc.reset();
354                 stopServer(rc, server);
355                 rc.reset();
356                 rebuildServer(rc, server, imageToUse);
357                 rc.reset();
358                 startServer(rc, server);
359                 generateEvent(rc, true, Outcome.SUCCESS.toString());
360                 metricsLogger.info("Server status: SUSPENDED");
361                 break;
362
363                         default:
364                                 // Hmmm, unknown status, should never occur
365                                 msg = EELFResourceManager.format(Msg.UNKNOWN_SERVER_STATE, server.getName(), server.getId(),
366                                                 server.getTenantId(), server.getStatus().name());
367                                 generateEvent(rc, false, msg);
368                                 logger.error(msg);
369                                 metricsLogger.error(msg);
370                                 throw new RequestFailedException("Rebuild Server", msg, HttpStatus.METHOD_NOT_ALLOWED_405, server);
371                         }
372
373
374         }
375
376     /**
377      * @see org.openecomp.appc.adapter.iaas.ProviderAdapter#rebuildServer(java.util.Map, org.openecomp.sdnc.sli.SvcLogicContext)
378      */
379     @SuppressWarnings("nls")
380     public Server rebuildServer(Map<String, String> params, SvcLogicContext ctx) throws APPCException {
381         Server server = null;
382         RequestContext rc = new RequestContext(ctx);
383         rc.isAlive();
384
385         String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME);
386         String msg;
387         
388         /*
389          * Set Time for Metrics Logger
390          */
391         long startTime = System.currentTimeMillis();
392         TimeZone tz = TimeZone.getTimeZone("UTC");
393         DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
394         df.setTimeZone(tz);
395         String startTimeStr = df.format(new Date());
396         long endTime = System.currentTimeMillis();
397         long duration = endTime - startTime;
398         String endTimeStr = String.valueOf(endTime);
399         String durationStr = String.valueOf(duration);
400         String endTimeStrUTC = df.format(new Date());
401         MDC.put("EndTimestamp", endTimeStrUTC);
402         MDC.put("ElapsedTime", durationStr);
403         MDC.put("TargetEntity", "cdp");
404         MDC.put("TargetServiceName", "rebuild server");
405         MDC.put("ClassName", "org.openecomp.appc.adapter.iaas.provider.operation.impl.RebuildServer");
406
407         try {
408             validateParametersExist(params, ProviderAdapter.PROPERTY_INSTANCE_URL,
409                     ProviderAdapter.PROPERTY_PROVIDER_NAME);
410             String vm_url = params.get(ProviderAdapter.PROPERTY_INSTANCE_URL);
411
412             VMURL vm = VMURL.parseURL(vm_url);
413             if (validateVM(rc, appName, vm_url, vm)) return null;
414
415             IdentityURL ident = IdentityURL.parseURL(params.get(ProviderAdapter.PROPERTY_IDENTITY_URL));
416             String identStr = (ident == null) ? null : ident.toString();
417             ctx.setAttribute("REBUILD_STATUS", "ERROR");
418
419             Context context = null;
420             try {
421                 context = getContext(rc, vm_url, identStr);
422                 if (context != null) {
423                     rc.reset();
424                     server = lookupServer(rc, context, vm.getServerId());
425                     logger.debug(Msg.SERVER_FOUND, vm_url, context.getTenantName(), server.getStatus().toString());
426
427                     // Manually checking image service until new PAL release
428                     if (hasImageAccess(rc, context)) {
429                         rebuildServer(rc, server, ctx);
430                         doSuccess(rc);
431                         ctx.setAttribute("REBUILD_STATUS", "SUCCESS");
432                     } else {
433                         msg = EELFResourceManager.format(Msg.REBUILD_SERVER_FAILED, server.getName(), server.getId(),
434                                 "Accessing Image Service Failed");
435                         logger.error(msg);
436                         metricsLogger.error(msg);
437                         doFailure(rc, HttpStatus.FORBIDDEN_403, msg);
438                     }
439                     context.close();
440                 }
441                 else
442                 {
443                     ctx.setAttribute("REBUILD_STATUS", "CONTEXT_NOT_FOUND");
444                 }
445             }
446             catch (RequestFailedException e) {
447                 doFailure(rc, e.getStatus(), e.getMessage());
448                 ctx.setAttribute("REBUILD_STATUS", "ERROR");
449             }
450             catch (ResourceNotFoundException e) {
451                 msg = EELFResourceManager.format(Msg.SERVER_NOT_FOUND, e, vm_url);
452                 ctx.setAttribute("REBUILD_STATUS", "ERROR");
453                 logger.error(msg);
454                 metricsLogger.error(msg);
455                 doFailure(rc, HttpStatus.NOT_FOUND_404, msg);
456             } catch (Throwable t) {
457                 msg = EELFResourceManager.format(Msg.SERVER_OPERATION_EXCEPTION, t, t.getClass().getSimpleName(),
458                         STOP_SERVICE.toString(), vm_url, context == null ? "Unknown" : context.getTenantName());
459                 ctx.setAttribute("REBUILD_STATUS", "ERROR");
460                 logger.error(msg, t);
461                 metricsLogger.error(msg);
462                 doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, msg);
463             }
464         } catch (RequestFailedException e) {
465             doFailure(rc, e.getStatus(), e.getMessage());
466             ctx.setAttribute("REBUILD_STATUS", "ERROR");
467         }
468
469         return server;
470     }
471
472     @Override
473     protected ModelObject executeProviderOperation(Map<String, String> params, SvcLogicContext context) throws APPCException {
474
475         setMDC(Operation.REBUILD_SERVICE.toString(), "App-C IaaS Adapter:Rebuild", ADAPTER_NAME);
476         logOperation(Msg.REBUILDING_SERVER, params, context);
477         
478         /*
479          * Set Time for Metrics Logger
480          */
481         long startTime = System.currentTimeMillis();
482         TimeZone tz = TimeZone.getTimeZone("UTC");
483         DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
484         df.setTimeZone(tz);
485         String startTimeStr = df.format(new Date());
486         long endTime = System.currentTimeMillis();
487         long duration = endTime - startTime;
488         String endTimeStr = String.valueOf(endTime);
489         String durationStr = String.valueOf(duration);
490         String endTimeStrUTC = df.format(new Date());
491         MDC.put("EndTimestamp", endTimeStrUTC);
492         MDC.put("ElapsedTime", durationStr);
493         MDC.put("TargetEntity", "cdp");
494         MDC.put("TargetServiceName", "rebuild server");
495         MDC.put("ClassName", "org.openecomp.appc.adapter.iaas.provider.operation.impl.RebuildServer");
496
497         
498         metricsLogger.info("Executing Provider Operation: Rebuild");
499         
500         
501         return rebuildServer(params, context);
502     }
503 }