Fix calls to multicloud adapter
[so.git] / adapters / mso-adapter-utils / src / main / java / org / onap / so / openstack / utils / MsoMulticloudUtils.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
4  * ================================================================================
5  * Copyright (C) 2018 Intel Corp. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.so.openstack.utils;
22
23 import java.net.MalformedURLException;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Scanner;
30
31 import javax.ws.rs.core.UriBuilder;
32 import javax.ws.rs.core.UriBuilderException;
33 import javax.ws.rs.core.Response.StatusType;
34 import javax.ws.rs.core.Response;
35
36 import org.apache.http.HttpStatus;
37 import org.onap.so.db.catalog.beans.CloudIdentity;
38 import org.onap.so.utils.CryptoUtils;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41 import org.onap.so.adapters.vdu.CloudInfo;
42 import org.onap.so.adapters.vdu.PluginAction;
43 import org.onap.so.adapters.vdu.VduArtifact;
44 import org.onap.so.adapters.vdu.VduArtifact.ArtifactType;
45 import org.onap.so.adapters.vdu.VduException;
46 import org.onap.so.adapters.vdu.VduInstance;
47 import org.onap.so.adapters.vdu.VduModelInfo;
48 import org.onap.so.adapters.vdu.VduPlugin;
49 import org.onap.so.adapters.vdu.VduStateType;
50 import org.onap.so.adapters.vdu.VduStatus;
51 import org.onap.so.openstack.beans.HeatStatus;
52 import org.onap.so.openstack.beans.StackInfo;
53 import org.onap.so.openstack.exceptions.MsoCloudSiteNotFound;
54 import org.onap.so.openstack.exceptions.MsoException;
55 import org.onap.so.openstack.exceptions.MsoOpenstackException;
56 import org.onap.so.openstack.mappers.StackInfoMapper;
57 import org.onap.so.client.HttpClient;
58 import org.onap.so.client.RestClient;
59 import org.onap.so.db.catalog.beans.CloudSite;
60 import org.onap.so.utils.TargetEntity;
61 import org.springframework.http.HttpEntity;
62 import org.springframework.http.HttpHeaders;
63 import org.springframework.http.MediaType;
64 import org.springframework.stereotype.Component;
65
66 import com.fasterxml.jackson.databind.ObjectMapper;
67 import com.woorea.openstack.heat.model.CreateStackParam;
68 import com.woorea.openstack.heat.model.Stack;
69
70 @Component
71 public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin{
72
73     public static final String OOF_DIRECTIVES = "oof_directives";
74     public static final String SDNC_DIRECTIVES = "sdnc_directives";
75     public static final String GENERIC_VNF_ID = "generic_vnf_id";
76     public static final String VF_MODULE_ID = "vf_module_id";
77     public static final String TEMPLATE_TYPE = "template_type";
78     public static final List<String> MULTICLOUD_INPUTS =
79             Arrays.asList(OOF_DIRECTIVES, SDNC_DIRECTIVES, GENERIC_VNF_ID, VF_MODULE_ID, TEMPLATE_TYPE);
80
81     private static final String ONAP_IP = "ONAP_IP";
82
83     private static final String DEFAULT_MSB_IP = "127.0.0.1";
84
85     private static final Integer DEFAULT_MSB_PORT = 80;
86
87     private static final Logger logger = LoggerFactory.getLogger(MsoMulticloudUtils.class);
88
89     private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
90
91     /******************************************************************************
92      *
93      * Methods (and associated utilities) to implement the VduPlugin interface
94      *
95      *******************************************************************************/
96
97     /**
98      * Create a new Stack in the specified cloud location and tenant. The Heat template
99      * and parameter map are passed in as arguments, along with the cloud access credentials.
100      * It is expected that parameters have been validated and contain at minimum the required
101      * parameters for the given template with no extra (undefined) parameters..
102      *
103      * The Stack name supplied by the caller must be unique in the scope of this tenant.
104      * However, it should also be globally unique, as it will be the identifier for the
105      * resource going forward in Inventory. This latter is managed by the higher levels
106      * invoking this function.
107      *
108      * The caller may choose to let this function poll Openstack for completion of the
109      * stack creation, or may handle polling itself via separate calls to query the status.
110      * In either case, a StackInfo object will be returned containing the current status.
111      * When polling is enabled, a status of CREATED is expected. When not polling, a
112      * status of BUILDING is expected.
113      *
114      * An error will be thrown if the requested Stack already exists in the specified
115      * Tenant and Cloud.
116      *
117      * For 1510 - add "environment", "files" (nested templates), and "heatFiles" (get_files) as
118      * parameters for createStack. If environment is non-null, it will be added to the stack.
119      * The nested templates and get_file entries both end up being added to the "files" on the
120      * stack. We must combine them before we add them to the stack if they're both non-null.
121      *
122      * @param cloudSiteId The cloud (may be a region) in which to create the stack.
123      * @param tenantId The Openstack ID of the tenant in which to create the Stack
124      * @param stackName The name of the stack to create
125      * @param heatTemplate The Heat template
126      * @param stackInputs A map of key/value inputs
127      * @param pollForCompletion Indicator that polling should be handled in Java vs. in the client
128      * @param environment An optional yaml-format string to specify environmental parameters
129      * @param files a Map<String, Object> that lists the child template IDs (file is the string, object is an int of
130      *        Template id)
131      * @param heatFiles a Map<String, Object> that lists the get_file entries (fileName, fileBody)
132      * @param backout Donot delete stack on create Failure - defaulted to True
133      * @return A StackInfo object
134      * @throws MsoOpenstackException Thrown if the Openstack API call returns an exception.
135      */
136
137     @SuppressWarnings("unchecked")
138     @Override
139     public StackInfo createStack (String cloudSiteId,
140                                   String tenantId,
141                                   String stackName,
142                                   String heatTemplate,
143                                   Map <String, ?> stackInputs,
144                                   boolean pollForCompletion,
145                                   int timeoutMinutes,
146                                   String environment,
147                                   Map <String, Object> files,
148                                   Map <String, Object> heatFiles,
149                                   boolean backout) throws MsoException {
150
151         logger.trace("Started MsoMulticloudUtils.createStack");
152
153         // Get the directives, if present.
154         String oofDirectives = "";
155         String sdncDirectives = "";
156         String genericVnfId = "";
157         String vfModuleId = "";
158         String templateType = "";
159
160         for (String key: MULTICLOUD_INPUTS) {
161             if (!stackInputs.isEmpty() && stackInputs.containsKey(key)) {
162                 if ( key == OOF_DIRECTIVES) {oofDirectives = (String) stackInputs.get(key);}
163                 if ( key == SDNC_DIRECTIVES) {sdncDirectives = (String) stackInputs.get(key);}
164                 if ( key == GENERIC_VNF_ID) {genericVnfId = (String) stackInputs.get(key);}
165                 if ( key == VF_MODULE_ID) {vfModuleId = (String) stackInputs.get(key);}
166                 if ( key == TEMPLATE_TYPE) {templateType = (String) stackInputs.get(key);}
167                          if (logger.isDebugEnabled()) {
168                     logger.debug(String.format("Found %s: %s", key, stackInputs.get(key)));
169                 }
170                 stackInputs.remove(key);
171             }
172         }
173
174         // create the multicloud payload
175         CreateStackParam stack = createStackParam(stackName, heatTemplate, stackInputs, timeoutMinutes, environment, files, heatFiles);
176
177         MulticloudRequest multicloudRequest= new MulticloudRequest();
178         HttpEntity<MulticloudRequest> request = null;
179
180         try {
181             multicloudRequest.setGenericVnfId(genericVnfId);
182             multicloudRequest.setVfModuleId(vfModuleId);
183             multicloudRequest.setOofDirectives(oofDirectives);
184             multicloudRequest.setSdncDirectives(sdncDirectives);
185             multicloudRequest.setTemplateType(templateType);
186             if (logger.isDebugEnabled()) {
187                 logger.debug(String.format("Stack Template Data is: %s", stack.toString().substring(16)));
188             }
189             multicloudRequest.setTemplateData(JSON_MAPPER.writeValueAsString(stack));
190             if (logger.isDebugEnabled()) {
191                 logger.debug(String.format("Multicloud Request is: %s", multicloudRequest.toString()));
192             }
193
194             CloudSite cloudSite = cloudConfig.getCloudSite(cloudSiteId).orElseThrow(() ->
195                     new MsoCloudSiteNotFound(cloudSiteId));
196             CloudIdentity cloudIdentity = cloudSite.getIdentityService();
197             HttpHeaders headers = new HttpHeaders();
198             headers.set ("X-Auth-User", cloudIdentity.getMsoId ());
199             headers.set ("X-Auth-Key", CryptoUtils.decryptCloudConfigPassword(cloudIdentity.getMsoPass ()));
200             headers.set(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON.toString());
201             headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON.toString());
202
203             if (logger.isDebugEnabled()) {
204                 logger.debug(String.format("Multicloud Request Headers: %s", headers.toString()));
205             }
206             request = new HttpEntity<>(multicloudRequest, headers);
207         } catch (Exception e) {
208             logger.debug("ERROR making multicloud JSON body ", e);
209         }
210         String multicloudEndpoint = getMulticloudEndpoint(cloudSiteId, null);
211         if (logger.isDebugEnabled()) {
212             logger.debug(String.format("Multicloud Endpoint is: %s", multicloudEndpoint));
213         }
214         RestClient multicloudClient = getMulticloudClient(multicloudEndpoint);
215
216         Response response = multicloudClient.post(request);
217
218         StackInfo responseStackInfo = new StackInfo();
219         responseStackInfo.setName(stackName);
220         responseStackInfo.setStatus(mapResponseToHeatStatus(response));
221
222         MulticloudCreateResponse multicloudResponseBody = null;
223         if (response.getStatus() == Response.Status.CREATED.getStatusCode() && response.hasEntity()) {
224             multicloudResponseBody = getCreateBody((java.io.InputStream)response.getEntity());
225             responseStackInfo.setCanonicalName(multicloudResponseBody.getWorkloadId());
226             if (logger.isDebugEnabled()) {
227                 logger.debug("Multicloud Create Response Body: " + multicloudResponseBody);
228             }
229         }
230
231         return responseStackInfo;
232     }
233
234     @Override
235     public Map<String, Object> queryStackForOutputs(String cloudSiteId,
236                                                            String tenantId, String stackName) throws MsoException {
237         logger.debug("MsoHeatUtils.queryStackForOutputs)");
238         StackInfo heatStack = this.queryStack(cloudSiteId, tenantId, stackName);
239         if (heatStack == null || heatStack.getStatus() == HeatStatus.NOTFOUND) {
240             return null;
241         }
242         return heatStack.getOutputs();
243     }
244
245     /**
246      * Query for a single stack (by Name) in a tenant. This call will always return a
247      * StackInfo object. If the stack does not exist, an "empty" StackInfo will be
248      * returned - containing only the stack name and a status of NOTFOUND.
249      *
250      * @param tenantId The Openstack ID of the tenant in which to query
251      * @param cloudSiteId The cloud identifier (may be a region) in which to query
252      * @param stackName The name of the stack to query (may be simple or canonical)
253      * @return A StackInfo object
254      * @throws MsoOpenstackException Thrown if the Openstack API call returns an exception.
255      */
256     @Override
257     public StackInfo queryStack (String cloudSiteId, String tenantId, String stackName) throws MsoException {
258         if (logger.isDebugEnabled()) {
259             logger.debug (String.format("Query multicloud HEAT stack: %s in tenant %s", stackName, tenantId));
260         }
261
262         StackInfo returnInfo = new StackInfo();
263         returnInfo.setName(stackName);
264
265         String multicloudEndpoint = getMulticloudEndpoint(cloudSiteId, stackName);
266         RestClient multicloudClient = getMulticloudClient(multicloudEndpoint);
267
268         if (multicloudClient != null) {
269             Response response = multicloudClient.get();
270             if (logger.isDebugEnabled()) {
271                 logger.debug (String.format("Mulicloud GET Response: %s", response.toString()));
272             }
273
274             returnInfo.setStatus(mapResponseToHeatStatus(response));
275
276             MulticloudQueryResponse multicloudQueryBody = null;
277             if (response.getStatus() == Response.Status.OK.getStatusCode() && response.hasEntity()) {
278                 multicloudQueryBody = getQueryBody((java.io.InputStream)response.getEntity());
279                 returnInfo.setCanonicalName(multicloudQueryBody.getWorkloadId());
280                 if (logger.isDebugEnabled()) {
281                     logger.debug("Multicloud Create Response Body: " + multicloudQueryBody.toString());
282                 }
283             }
284         }
285
286         return returnInfo;
287
288     }
289
290     public StackInfo deleteStack (String cloudSiteId, String tenantId, String stackName) throws MsoException {
291         if (logger.isDebugEnabled()) {
292             logger.debug (String.format("Delete multicloud HEAT stack: %s in tenant %s", stackName, tenantId));
293         }
294         StackInfo returnInfo = new StackInfo();
295         returnInfo.setName(stackName);
296         Response response = null;
297
298         String multicloudEndpoint = getMulticloudEndpoint(cloudSiteId, stackName);
299         RestClient multicloudClient = getMulticloudClient(multicloudEndpoint);
300
301         if (multicloudClient != null) {
302             response = multicloudClient.delete();
303             if (logger.isDebugEnabled()) {
304                 logger.debug(String.format("Multicloud Delete response is: %s", response.getEntity().toString()));
305             }
306         }
307         returnInfo.setStatus(mapResponseToHeatStatus(response));
308         return returnInfo;
309     }
310
311     // ---------------------------------------------------------------
312     // PRIVATE FUNCTIONS FOR USE WITHIN THIS CLASS
313     private HeatStatus mapResponseToHeatStatus(Response response) {
314         if (response.getStatusInfo().getStatusCode() == Response.Status.OK.getStatusCode()) {
315             return HeatStatus.CREATED;
316         } else if (response.getStatusInfo().getStatusCode() == Response.Status.CREATED.getStatusCode()) {
317             return HeatStatus.CREATED;
318         } else if (response.getStatusInfo().getStatusCode() == Response.Status.NO_CONTENT.getStatusCode()) {
319             return HeatStatus.CREATED;
320         } else if (response.getStatusInfo().getStatusCode() == Response.Status.BAD_REQUEST.getStatusCode()) {
321             return HeatStatus.FAILED;
322         } else if (response.getStatusInfo().getStatusCode() == Response.Status.UNAUTHORIZED.getStatusCode()) {
323             return HeatStatus.FAILED;
324         } else if (response.getStatusInfo().getStatusCode() == Response.Status.NOT_FOUND.getStatusCode()) {
325             return HeatStatus.NOTFOUND;
326         } else if (response.getStatusInfo().getStatusCode() == Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()) {
327             return HeatStatus.FAILED;
328         } else {
329             return HeatStatus.UNKNOWN;
330         }
331     }
332
333     private MulticloudCreateResponse getCreateBody(java.io.InputStream in) {
334         Scanner scanner = new Scanner(in);
335         scanner.useDelimiter("\\Z");
336         String body = "";
337         if (scanner.hasNext()) {
338             body = scanner.next();
339         }
340         scanner.close();
341
342         try {
343             return new ObjectMapper().readerFor(MulticloudCreateResponse.class).readValue(body);
344         } catch (Exception e) {
345             logger.debug("Exception retrieving multicloud vfModule POST response body " + e);
346         }
347         return null;
348     }
349
350     private MulticloudQueryResponse getQueryBody(java.io.InputStream in) {
351         Scanner scanner = new Scanner(in);
352         scanner.useDelimiter("\\Z");
353         String body = "";
354         if (scanner.hasNext()) {
355             body = scanner.next();
356         }
357         scanner.close();
358
359         try {
360             return new ObjectMapper().readerFor(MulticloudQueryResponse.class).readValue(body);
361         } catch (Exception e) {
362             logger.debug("Exception retrieving multicloud workload query response body " + e);
363         }
364         return null;
365     }
366
367     private String getMulticloudEndpoint(String cloudSiteId, String workloadId) throws MsoCloudSiteNotFound {
368
369         CloudSite cloudSite = cloudConfig.getCloudSite(cloudSiteId).orElseThrow(() -> new MsoCloudSiteNotFound(cloudSiteId));
370         String endpoint = cloudSite.getIdentityService().getIdentityUrl();
371
372         if (workloadId != null) {
373             if (logger.isDebugEnabled()) {
374                 logger.debug(String.format("Multicloud Endpoint is: %s/%s", endpoint, workloadId));
375             }
376             return String.format("%s/%s", endpoint, workloadId);
377         } else {
378             if (logger.isDebugEnabled()) {
379                 logger.debug(String.format("Multicloud Endpoint is: %s", endpoint));
380             }
381             return endpoint;
382         }
383     }
384
385     private RestClient getMulticloudClient(String endpoint) {
386         RestClient client = null;
387         try {
388             client= new HttpClient(UriBuilder.fromUri(endpoint).build().toURL(),
389                     MediaType.APPLICATION_JSON.toString(), TargetEntity.MULTICLOUD);
390         } catch (MalformedURLException e) {
391             logger.debug(String.format("Encountered malformed URL error getting multicloud rest client %s", e.getMessage()));
392         } catch (IllegalArgumentException e) {
393             logger.debug(String.format("Encountered illegal argument getting multicloud rest client %s",e.getMessage()));
394         } catch (UriBuilderException e) {
395             logger.debug(String.format("Encountered URI builder error getting multicloud rest client %s", e.getMessage()));
396         }
397         return client;
398     }
399
400     /**
401      * VduPlugin interface for instantiate function.
402      *
403      * Translate the VduPlugin parameters to the corresponding 'createStack' parameters,
404      * and then invoke the existing function.
405      */
406     @Override
407     public VduInstance instantiateVdu (
408             CloudInfo cloudInfo,
409             String instanceName,
410             Map<String,Object> inputs,
411             VduModelInfo vduModel,
412             boolean rollbackOnFailure)
413         throws VduException
414     {
415         String cloudSiteId = cloudInfo.getCloudSiteId();
416         String tenantId = cloudInfo.getTenantId();
417
418         // Translate the VDU ModelInformation structure to that which is needed for
419         // creating the Heat stack.  Loop through the artifacts, looking specifically
420         // for MAIN_TEMPLATE and ENVIRONMENT.  Any other artifact will
421         // be attached as a FILE.
422         String heatTemplate = null;
423         Map<String,Object> nestedTemplates = new HashMap<>();
424         Map<String,Object> files = new HashMap<>();
425         String heatEnvironment = null;
426
427         for (VduArtifact vduArtifact: vduModel.getArtifacts()) {
428             if (vduArtifact.getType() == ArtifactType.MAIN_TEMPLATE) {
429                 heatTemplate = new String(vduArtifact.getContent());
430             }
431             else if (vduArtifact.getType() == ArtifactType.NESTED_TEMPLATE) {
432                 nestedTemplates.put(vduArtifact.getName(), new String(vduArtifact.getContent()));
433             }
434             else if (vduArtifact.getType() == ArtifactType.ENVIRONMENT) {
435                 heatEnvironment = new String(vduArtifact.getContent());
436             }
437         }
438
439         try {
440             StackInfo stackInfo = createStack (cloudSiteId,
441                     tenantId,
442                     instanceName,
443                     heatTemplate,
444                     inputs,
445                     true,    // poll for completion
446                     vduModel.getTimeoutMinutes(),
447                     heatEnvironment,
448                     nestedTemplates,
449                     files,
450                     rollbackOnFailure);
451             // Populate a vduInstance from the StackInfo
452             return stackInfoToVduInstance(stackInfo);
453         }
454         catch (Exception e) {
455             throw new VduException ("MsoMulticloudUtils (instantiateVDU): createStack Exception", e);
456         }
457     }
458
459
460     /**
461      * VduPlugin interface for query function.
462      */
463     @Override
464     public VduInstance queryVdu (CloudInfo cloudInfo, String instanceId)
465         throws VduException
466     {
467         String cloudSiteId = cloudInfo.getCloudSiteId();
468         String tenantId = cloudInfo.getTenantId();
469
470         try {
471             // Query the Cloudify Deployment object and  populate a VduInstance
472             StackInfo stackInfo = queryStack (cloudSiteId, tenantId, instanceId);
473
474             return stackInfoToVduInstance(stackInfo);
475         }
476         catch (Exception e) {
477             throw new VduException ("MsoMulticloudUtils (queryVdu): queryStack Exception ", e);
478         }
479     }
480
481
482     /**
483      * VduPlugin interface for delete function.
484      */
485     @Override
486     public VduInstance deleteVdu (CloudInfo cloudInfo, String instanceId, int timeoutMinutes)
487         throws VduException
488     {
489         String cloudSiteId = cloudInfo.getCloudSiteId();
490         String tenantId = cloudInfo.getTenantId();
491
492         try {
493             // Delete the Multicloud stack
494             StackInfo stackInfo = deleteStack (tenantId, cloudSiteId, instanceId);
495
496             // Populate a VduInstance based on the deleted Cloudify Deployment object
497             VduInstance vduInstance = stackInfoToVduInstance(stackInfo);
498
499             // Override return state to DELETED (MulticloudUtils sets to NOTFOUND)
500             vduInstance.getStatus().setState(VduStateType.DELETED);
501
502             return vduInstance;
503         }
504         catch (Exception e) {
505             throw new VduException ("Delete VDU Exception", e);
506         }
507     }
508
509
510     /**
511      * VduPlugin interface for update function.
512      *
513      * Update is currently not supported in the MsoMulticloudUtils implementation of VduPlugin.
514      * Just return a VduException.
515      *
516      */
517     @Override
518     public VduInstance updateVdu (
519             CloudInfo cloudInfo,
520             String instanceId,
521             Map<String,Object> inputs,
522             VduModelInfo vduModel,
523             boolean rollbackOnFailure)
524         throws VduException
525     {
526         throw new VduException ("MsoMulticloudUtils: updateVdu interface not supported");
527     }
528
529
530     /*
531      * Convert the local DeploymentInfo object (Cloudify-specific) to a generic VduInstance object
532      */
533     protected VduInstance stackInfoToVduInstance (StackInfo stackInfo)
534     {
535         VduInstance vduInstance = new VduInstance();
536
537         if (logger.isDebugEnabled()) {
538             logger.debug(String.format("StackInfo to convert: %s", stackInfo.getParameters().toString()));
539         }
540         // The full canonical name as the instance UUID
541         vduInstance.setVduInstanceId(stackInfo.getCanonicalName());
542         vduInstance.setVduInstanceName(stackInfo.getName());
543
544         // Copy inputs and outputs
545         vduInstance.setInputs(stackInfo.getParameters());
546         vduInstance.setOutputs(stackInfo.getOutputs());
547
548         // Translate the status elements
549         vduInstance.setStatus(stackStatusToVduStatus (stackInfo));
550
551         return vduInstance;
552     }
553
554     private VduStatus stackStatusToVduStatus (StackInfo stackInfo)
555     {
556         VduStatus vduStatus = new VduStatus();
557
558         // Map the status fields to more generic VduStatus.
559         // There are lots of HeatStatus values, so this is a bit long...
560         HeatStatus heatStatus = stackInfo.getStatus();
561         String statusMessage = stackInfo.getStatusMessage();
562         logger.debug("HeatStatus = " + heatStatus + " msg = " + statusMessage);
563
564         if (logger.isDebugEnabled()) {
565             logger.debug(String.format("Stack Status: %s", heatStatus.toString()));
566             logger.debug(String.format("Stack Status Message: %s", statusMessage));
567         }
568
569         if (heatStatus == HeatStatus.INIT  ||  heatStatus == HeatStatus.BUILDING) {
570             vduStatus.setState(VduStateType.INSTANTIATING);
571             vduStatus.setLastAction((new PluginAction ("create", "in_progress", statusMessage)));
572         }
573         else if (heatStatus == HeatStatus.NOTFOUND) {
574             vduStatus.setState(VduStateType.NOTFOUND);
575         }
576         else if (heatStatus == HeatStatus.CREATED) {
577             vduStatus.setState(VduStateType.INSTANTIATED);
578             vduStatus.setLastAction((new PluginAction ("create", "complete", statusMessage)));
579         }
580         else if (heatStatus == HeatStatus.UPDATED) {
581             vduStatus.setState(VduStateType.INSTANTIATED);
582             vduStatus.setLastAction((new PluginAction ("update", "complete", statusMessage)));
583         }
584         else if (heatStatus == HeatStatus.UPDATING) {
585             vduStatus.setState(VduStateType.UPDATING);
586             vduStatus.setLastAction((new PluginAction ("update", "in_progress", statusMessage)));
587         }
588         else if (heatStatus == HeatStatus.DELETING) {
589             vduStatus.setState(VduStateType.DELETING);
590             vduStatus.setLastAction((new PluginAction ("delete", "in_progress", statusMessage)));
591         }
592         else if (heatStatus == HeatStatus.FAILED) {
593             vduStatus.setState(VduStateType.FAILED);
594             vduStatus.setErrorMessage(stackInfo.getStatusMessage());
595         } else {
596             vduStatus.setState(VduStateType.UNKNOWN);
597         }
598
599         return vduStatus;
600     }
601 }