Use distribution json for workflow install
[so.git] / asdc-controller / src / main / java / org / onap / so / asdc / client / ASDCController.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * Copyright (C) 2017 Huawei Technologies Co., Ltd. All rights reserved.
7  * ================================================================================
8  * Modifications Copyright (c) 2019 Samsung
9  * ================================================================================
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  * ============LICENSE_END=========================================================
22  */
23
24 package org.onap.so.asdc.client;
25
26
27 import com.fasterxml.jackson.annotation.JsonInclude.Include;
28 import com.fasterxml.jackson.core.JsonProcessingException;
29 import com.fasterxml.jackson.databind.DeserializationFeature;
30 import com.fasterxml.jackson.databind.MapperFeature;
31 import com.fasterxml.jackson.databind.ObjectMapper;
32 import java.io.File;
33 import java.io.FileOutputStream;
34 import java.io.IOException;
35 import java.io.UnsupportedEncodingException;
36 import java.nio.file.Paths;
37 import java.util.List;
38 import java.util.Optional;
39 import org.onap.sdc.api.IDistributionClient;
40 import org.onap.sdc.api.consumer.IDistributionStatusMessage;
41 import org.onap.sdc.api.consumer.IFinalDistrStatusMessage;
42 import org.onap.sdc.api.notification.IArtifactInfo;
43 import org.onap.sdc.api.notification.INotificationData;
44 import org.onap.sdc.api.notification.IResourceInstance;
45 import org.onap.sdc.api.results.IDistributionClientDownloadResult;
46 import org.onap.sdc.api.results.IDistributionClientResult;
47 import org.onap.sdc.impl.DistributionClientFactory;
48 import org.onap.sdc.utils.DistributionActionResultEnum;
49 import org.onap.sdc.utils.DistributionStatusEnum;
50 import org.onap.so.asdc.activity.DeployActivitySpecs;
51 import org.onap.so.asdc.client.exceptions.ASDCControllerException;
52 import org.onap.so.asdc.client.exceptions.ASDCDownloadException;
53 import org.onap.so.asdc.client.exceptions.ASDCParametersException;
54 import org.onap.so.asdc.client.exceptions.ArtifactInstallerException;
55 import org.onap.so.asdc.installer.IVfResourceInstaller;
56 import org.onap.so.asdc.installer.PnfResourceStructure;
57 import org.onap.so.asdc.installer.ResourceStructure;
58 import org.onap.so.asdc.installer.ResourceType;
59 import org.onap.so.asdc.installer.ToscaResourceStructure;
60 import org.onap.so.asdc.installer.VfResourceStructure;
61 import org.onap.so.asdc.installer.heat.ToscaResourceInstaller;
62 import org.onap.so.asdc.tenantIsolation.DistributionStatus;
63 import org.onap.so.asdc.tenantIsolation.WatchdogDistribution;
64 import org.onap.so.asdc.util.ASDCNotificationLogging;
65 import org.onap.so.db.request.beans.WatchdogDistributionStatus;
66 import org.onap.so.db.request.data.repository.WatchdogDistributionStatusRepository;
67 import org.onap.so.logger.ErrorCode;
68 import org.onap.so.logger.MessageEnum;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
71 import org.springframework.beans.factory.annotation.Autowired;
72 import org.springframework.orm.ObjectOptimisticLockingFailureException;
73 import org.springframework.stereotype.Component;
74
75 @Component
76 public class ASDCController {
77
78     protected static final Logger logger = LoggerFactory.getLogger(ASDCController.class);
79
80     protected boolean isAsdcClientAutoManaged = false;
81
82     protected String controllerName;
83
84     private ASDCControllerStatus controllerStatus = ASDCControllerStatus.STOPPED;
85
86     protected int nbOfNotificationsOngoing = 0;
87
88     @Autowired
89     private ToscaResourceInstaller toscaInstaller;
90
91     @Autowired
92     private WatchdogDistributionStatusRepository wdsRepo;
93
94     @Autowired
95     private ASDCConfiguration asdcConfig;
96
97     @Autowired
98     private ASDCStatusCallBack asdcStatusCallBack;
99
100     @Autowired
101     private ASDCNotificationCallBack asdcNotificationCallBack;
102
103     private IDistributionClient distributionClient;
104
105     private static final String UUID_PARAM = "(UUID:";
106
107     @Autowired
108     private WatchdogDistribution wd;
109
110     @Autowired
111     DeployActivitySpecs deployActivitySpecs;
112
113     public int getNbOfNotificationsOngoing() {
114         return nbOfNotificationsOngoing;
115     }
116
117     public IDistributionClient getDistributionClient() {
118         return distributionClient;
119     }
120
121     public void setDistributionClient(IDistributionClient distributionClient) {
122         this.distributionClient = distributionClient;
123     }
124
125     protected void changeControllerStatus(ASDCControllerStatus newControllerStatus) {
126         switch (newControllerStatus) {
127
128             case BUSY:
129                 ++this.nbOfNotificationsOngoing;
130                 this.controllerStatus = newControllerStatus;
131                 break;
132
133             case IDLE:
134                 if (this.nbOfNotificationsOngoing > 1) {
135                     --this.nbOfNotificationsOngoing;
136                 } else {
137                     this.nbOfNotificationsOngoing = 0;
138                     this.controllerStatus = newControllerStatus;
139                 }
140
141                 break;
142             default:
143                 this.controllerStatus = newControllerStatus;
144                 break;
145
146         }
147     }
148
149     public ASDCControllerStatus getControllerStatus() {
150         return this.controllerStatus;
151     }
152
153     public ASDCController() {
154         this("");
155     }
156
157     public ASDCController(String controllerConfigName) {
158         isAsdcClientAutoManaged = true;
159         this.controllerName = controllerConfigName;
160     }
161
162     public ASDCController(String controllerConfigName, IDistributionClient asdcClient,
163             IVfResourceInstaller resourceinstaller) {
164         distributionClient = asdcClient;
165     }
166
167     public ASDCController(String controllerConfigName, IDistributionClient asdcClient) {
168         distributionClient = asdcClient;
169         this.controllerName = controllerConfigName;
170     }
171
172     public String getControllerName() {
173         return controllerName;
174     }
175
176     public void setControllerName(String controllerName) {
177         this.controllerName = controllerName;
178     }
179
180     /**
181      * This method initializes the ASDC Controller and the ASDC Client.
182      *
183      * @throws ASDCControllerException It throws an exception if the ASDC Client cannot be instantiated or if an init
184      *         attempt is done when already initialized
185      * @throws ASDCParametersException If there is an issue with the parameters provided
186      * @throws IOException In case of issues when trying to load the key file
187      */
188     public void initASDC() throws ASDCControllerException {
189         String event = "Initialize the ASDC Controller";
190         logger.debug(event);
191         if (this.getControllerStatus() != ASDCControllerStatus.STOPPED) {
192             String endEvent = "The controller is already initialized, call the closeASDC method first";
193             throw new ASDCControllerException(endEvent);
194         }
195
196         if (asdcConfig != null) {
197             asdcConfig.setAsdcControllerName(controllerName);
198         }
199
200         if (this.distributionClient == null) {
201             distributionClient = DistributionClientFactory.createDistributionClient();
202         }
203
204         IDistributionClientResult result =
205                 this.distributionClient.init(asdcConfig, asdcNotificationCallBack, asdcStatusCallBack);
206         if (!result.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) {
207             String endEvent =
208                     "ASDC distribution client init failed with reason:" + result.getDistributionMessageResult();
209             logger.debug(endEvent);
210             this.changeControllerStatus(ASDCControllerStatus.STOPPED);
211             throw new ASDCControllerException("Initialization of the ASDC Controller failed with reason: "
212                     + result.getDistributionMessageResult());
213         }
214
215         result = this.distributionClient.start();
216         if (!result.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) {
217             String endEvent =
218                     "ASDC distribution client start failed with reason:" + result.getDistributionMessageResult();
219             logger.debug(endEvent);
220             this.changeControllerStatus(ASDCControllerStatus.STOPPED);
221             throw new ASDCControllerException(
222                     "Startup of the ASDC Controller failed with reason: " + result.getDistributionMessageResult());
223         }
224
225         this.changeControllerStatus(ASDCControllerStatus.IDLE);
226         logger.info("{} {} {}", MessageEnum.ASDC_INIT_ASDC_CLIENT_SUC.toString(), "ASDC", "changeControllerStatus");
227     }
228
229     /**
230      * This method closes the ASDC Controller and the ASDC Client.
231      *
232      * @throws ASDCControllerException It throws an exception if the ASDC Client cannot be closed because it's currently
233      *         BUSY in processing notifications.
234      */
235     public void closeASDC() throws ASDCControllerException {
236
237         if (this.getControllerStatus() == ASDCControllerStatus.BUSY) {
238             throw new ASDCControllerException("Cannot close the ASDC controller as it's currently in BUSY state");
239         }
240         if (this.distributionClient != null) {
241             this.distributionClient.stop();
242             // If auto managed we can set it to Null, ASDCController controls it.
243             // In the other case the client of this class has specified it, so we can't reset it
244             if (isAsdcClientAutoManaged) {
245                 // Next init will initialize it with a new ASDC Client
246                 this.distributionClient = null;
247             }
248
249         }
250         this.changeControllerStatus(ASDCControllerStatus.STOPPED);
251     }
252
253     protected boolean checkResourceAlreadyDeployed(ResourceStructure resource, boolean serviceDeployed)
254             throws ArtifactInstallerException {
255
256
257         if (toscaInstaller.isResourceAlreadyDeployed(resource, serviceDeployed)) {
258             logger.info("{} {} {} {}", MessageEnum.ASDC_ARTIFACT_ALREADY_EXIST.toString(),
259                     resource.getResourceInstance().getResourceInstanceName(),
260                     resource.getResourceInstance().getResourceUUID(), resource.getResourceInstance().getResourceName());
261
262             this.sendDeployNotificationsForResource(resource, DistributionStatusEnum.ALREADY_DOWNLOADED, null);
263             this.sendDeployNotificationsForResource(resource, DistributionStatusEnum.ALREADY_DEPLOYED, null);
264
265             return true;
266         } else {
267             return false;
268         }
269     }
270
271
272     protected IDistributionClientDownloadResult downloadTheArtifact(IArtifactInfo artifact, String distributionId)
273             throws ASDCDownloadException {
274
275         logger.info("Trying to download the artifact UUID: {} from URL: {}", artifact.getArtifactUUID(),
276                 artifact.getArtifactURL());
277         IDistributionClientDownloadResult downloadResult;
278
279         try {
280             downloadResult = distributionClient.download(artifact);
281             if (null == downloadResult) {
282                 logger.info("{} {}", MessageEnum.ASDC_ARTIFACT_NULL.toString(), artifact.getArtifactUUID());
283                 return downloadResult;
284             }
285         } catch (RuntimeException e) {
286             logger.debug("Not able to download the artifact due to an exception: " + artifact.getArtifactURL());
287             this.sendASDCNotification(NotificationType.DOWNLOAD, artifact.getArtifactURL(), asdcConfig.getConsumerID(),
288                     distributionId, DistributionStatusEnum.DOWNLOAD_ERROR, e.getMessage(), System.currentTimeMillis());
289
290             throw new ASDCDownloadException("Exception caught when downloading the artifact", e);
291         }
292
293         if (DistributionActionResultEnum.SUCCESS.equals(downloadResult.getDistributionActionResult())) {
294             logger.info("{} {} {} {}", MessageEnum.ASDC_ARTIFACT_DOWNLOAD_SUC.toString(), artifact.getArtifactURL(),
295                     artifact.getArtifactUUID(), String.valueOf(downloadResult.getArtifactPayload().length));
296
297         } else {
298             logger.error("{} {} {} {} {} {} {}", MessageEnum.ASDC_ARTIFACT_DOWNLOAD_FAIL.toString(),
299                     artifact.getArtifactName(), artifact.getArtifactURL(), artifact.getArtifactUUID(),
300                     downloadResult.getDistributionMessageResult(), ErrorCode.DataError.getValue(),
301                     "ASDC artifact download fail");
302
303             this.sendASDCNotification(NotificationType.DOWNLOAD, artifact.getArtifactURL(), asdcConfig.getConsumerID(),
304                     distributionId, DistributionStatusEnum.DOWNLOAD_ERROR,
305                     downloadResult.getDistributionMessageResult(), System.currentTimeMillis());
306
307             throw new ASDCDownloadException("Artifact " + artifact.getArtifactName()
308                     + " could not be downloaded from ASDC URL " + artifact.getArtifactURL() + UUID_PARAM
309                     + artifact.getArtifactUUID() + ")" + System.lineSeparator() + "Error message is "
310                     + downloadResult.getDistributionMessageResult() + System.lineSeparator());
311
312         }
313
314         this.sendASDCNotification(NotificationType.DOWNLOAD, artifact.getArtifactURL(), asdcConfig.getConsumerID(),
315                 distributionId, DistributionStatusEnum.DOWNLOAD_OK, null, System.currentTimeMillis());
316         return downloadResult;
317
318     }
319
320     private void writeArtifactToFile(IArtifactInfo artifact, IDistributionClientDownloadResult resultArtifact) {
321
322         String filePath =
323                 Paths.get(getMsoConfigPath(), "ASDC", artifact.getArtifactVersion(), artifact.getArtifactName())
324                         .normalize().toString();
325
326         logger.info("Trying to write artifact UUID: {}, URL: {} to file: {}", artifact.getArtifactUUID(),
327                 artifact.getArtifactURL(), filePath);
328
329         // make parent directory
330         File file = new File(filePath);
331         File fileParent = file.getParentFile();
332         if (!fileParent.exists()) {
333             fileParent.mkdirs();
334         }
335
336         byte[] payloadBytes = resultArtifact.getArtifactPayload();
337
338         try (FileOutputStream outFile = new FileOutputStream(filePath)) {
339             logger.info("{} {} {} {}", MessageEnum.ASDC_RECEIVE_SERVICE_NOTIF.toString(), "***WRITE FILE ARTIFACT NAME",
340                     "ASDC", artifact.getArtifactName());
341             outFile.write(payloadBytes, 0, payloadBytes.length);
342         } catch (Exception e) {
343             logger.debug("Exception :", e);
344             logger.error("{} {} {} {} {} {} {}", MessageEnum.ASDC_ARTIFACT_DOWNLOAD_FAIL.toString(),
345                     artifact.getArtifactName(), artifact.getArtifactURL(), artifact.getArtifactUUID(),
346                     resultArtifact.getDistributionMessageResult(), ErrorCode.DataError.getValue(),
347                     "ASDC write to file failed");
348         }
349
350     }
351
352
353     protected void sendDeployNotificationsForResource(ResourceStructure resourceStructure,
354             DistributionStatusEnum distribStatus, String errorReason) {
355
356         for (IArtifactInfo artifactInfo : resourceStructure.getResourceInstance().getArtifacts()) {
357
358             if ((DistributionStatusEnum.DEPLOY_OK.equals(distribStatus)
359                     && !artifactInfo.getArtifactType().equalsIgnoreCase("OTHER")
360                     && !resourceStructure.isAlreadyDeployed())
361                     // This could be NULL if the artifact is a VF module artifact, this won't be present in the MAP
362                     && resourceStructure.getArtifactsMapByUUID().get(artifactInfo.getArtifactUUID()) != null
363                     && resourceStructure.getArtifactsMapByUUID().get(artifactInfo.getArtifactUUID())
364                             .getDeployedInDb() == 0) {
365                 this.sendASDCNotification(NotificationType.DEPLOY, artifactInfo.getArtifactURL(),
366                         asdcConfig.getConsumerID(), resourceStructure.getNotification().getDistributionID(),
367                         DistributionStatusEnum.DEPLOY_ERROR,
368                         "The artifact has not been used by the modules defined in the resource",
369                         System.currentTimeMillis());
370             } else {
371                 this.sendASDCNotification(NotificationType.DEPLOY, artifactInfo.getArtifactURL(),
372                         asdcConfig.getConsumerID(), resourceStructure.getNotification().getDistributionID(),
373                         distribStatus, errorReason, System.currentTimeMillis());
374             }
375         }
376     }
377
378     protected void sendCsarDeployNotification(INotificationData iNotif, ResourceStructure resourceStructure,
379             ToscaResourceStructure toscaResourceStructure, boolean deploySuccessful, String errorReason) {
380
381         IArtifactInfo csarArtifact = toscaResourceStructure.getToscaArtifact();
382
383         if (deploySuccessful) {
384
385             this.sendASDCNotification(NotificationType.DEPLOY, csarArtifact.getArtifactURL(),
386                     asdcConfig.getConsumerID(), resourceStructure.getNotification().getDistributionID(),
387                     DistributionStatusEnum.DEPLOY_OK, errorReason, System.currentTimeMillis());
388
389         } else {
390
391             this.sendASDCNotification(NotificationType.DEPLOY, csarArtifact.getArtifactURL(),
392                     asdcConfig.getConsumerID(), resourceStructure.getNotification().getDistributionID(),
393                     DistributionStatusEnum.DEPLOY_ERROR, errorReason, System.currentTimeMillis());
394
395         }
396     }
397
398     protected void deployResourceStructure(ResourceStructure resourceStructure,
399             ToscaResourceStructure toscaResourceStructure) throws ArtifactInstallerException {
400
401         logger.info("{} {} {} {}", MessageEnum.ASDC_START_DEPLOY_ARTIFACT.toString(),
402                 resourceStructure.getResourceInstance().getResourceInstanceName(),
403                 resourceStructure.getResourceInstance().getResourceUUID(), "ASDC");
404         try {
405             resourceStructure.prepareInstall();
406             toscaInstaller.installTheResource(toscaResourceStructure, resourceStructure);
407
408         } catch (ArtifactInstallerException e) {
409             logger.info("{} {} {} {} {} {}", MessageEnum.ASDC_ARTIFACT_DOWNLOAD_FAIL.toString(),
410                     resourceStructure.getResourceInstance().getResourceName(),
411                     resourceStructure.getResourceInstance().getResourceUUID(),
412                     String.valueOf(resourceStructure.getNumberOfResources()), "ASDC", "deployResourceStructure");
413             sendDeployNotificationsForResource(resourceStructure, DistributionStatusEnum.DEPLOY_ERROR, e.getMessage());
414             throw e;
415         }
416
417         if (resourceStructure.isDeployedSuccessfully() || toscaResourceStructure.isDeployedSuccessfully()) {
418             logger.info("{} {} {} {} {} {}", MessageEnum.ASDC_ARTIFACT_DEPLOY_SUC.toString(),
419                     resourceStructure.getResourceInstance().getResourceName(),
420                     resourceStructure.getResourceInstance().getResourceUUID(),
421                     String.valueOf(resourceStructure.getNumberOfResources()), "ASDC", "deployResourceStructure");
422             sendDeployNotificationsForResource(resourceStructure, DistributionStatusEnum.DEPLOY_OK, null);
423         }
424
425     }
426
427
428     private enum NotificationType {
429         DOWNLOAD, DEPLOY
430     }
431
432     protected void sendASDCNotification(NotificationType notificationType, String artifactURL, String consumerID,
433             String distributionID, DistributionStatusEnum status, String errorReason, long timestamp) {
434
435         String event = "Sending " + notificationType.name() + "(" + status.name() + ")"
436                 + " notification to ASDC for artifact:" + artifactURL;
437
438         if (errorReason != null) {
439             event = event + "(" + errorReason + ")";
440         }
441         logger.info("{} {} {} {} {} {}", MessageEnum.ASDC_SEND_NOTIF_ASDC.toString(), notificationType.name(),
442                 status.name(), artifactURL, "ASDC", "sendASDCNotification");
443         logger.debug(event);
444
445         String action = "";
446         try {
447             IDistributionStatusMessage message =
448                     new DistributionStatusMessage(artifactURL, consumerID, distributionID, status, timestamp);
449
450             switch (notificationType) {
451                 case DOWNLOAD:
452                     if (errorReason != null) {
453                         this.distributionClient.sendDownloadStatus(message, errorReason);
454                     } else {
455                         this.distributionClient.sendDownloadStatus(message);
456                     }
457                     action = "sendDownloadStatus";
458                     break;
459                 case DEPLOY:
460                     if (errorReason != null) {
461                         this.distributionClient.sendDeploymentStatus(message, errorReason);
462                     } else {
463                         this.distributionClient.sendDeploymentStatus(message);
464                     }
465                     action = "sendDeploymentdStatus";
466                     break;
467                 default:
468                     break;
469             }
470         } catch (RuntimeException e) {
471             logger.warn("{} {} {} {} {}", MessageEnum.ASDC_SEND_NOTIF_ASDC_EXEC.toString(), "ASDC",
472                     "sendASDCNotification", ErrorCode.SchemaError.getValue(), "RuntimeException - sendASDCNotification",
473                     e);
474         }
475     }
476
477     protected void sendFinalDistributionStatus(String distributionID, DistributionStatusEnum status,
478             String errorReason) {
479
480         logger.debug("Enter sendFinalDistributionStatus with DistributionID " + distributionID + " and Status of "
481                 + status.name() + " and ErrorReason " + errorReason);
482
483         long subStarttime = System.currentTimeMillis();
484         try {
485
486             IFinalDistrStatusMessage finalDistribution = new FinalDistributionStatusMessage(distributionID, status,
487                     subStarttime, asdcConfig.getConsumerID());
488
489             if (errorReason == null) {
490                 this.distributionClient.sendFinalDistrStatus(finalDistribution);
491             } else {
492                 this.distributionClient.sendFinalDistrStatus(finalDistribution, errorReason);
493             }
494
495
496         } catch (RuntimeException e) {
497             logger.debug("Exception caught in sendFinalDistributionStatus {}", e.getMessage());
498             logger.warn("{} {} {} {} {}", MessageEnum.ASDC_SEND_NOTIF_ASDC_EXEC.toString(), "ASDC",
499                     "sendASDCNotification", ErrorCode.SchemaError.getValue(), "RuntimeException - sendASDCNotification",
500                     e);
501         }
502     }
503
504     private Optional<String> getNotificationJson(INotificationData iNotif) {
505         ObjectMapper mapper = new ObjectMapper();
506         mapper.setSerializationInclusion(Include.NON_NULL);
507         mapper.setSerializationInclusion(Include.NON_EMPTY);
508         mapper.setSerializationInclusion(Include.NON_ABSENT);
509         mapper.enable(MapperFeature.USE_ANNOTATIONS);
510         mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
511         Optional<String> returnValue = Optional.empty();
512         try {
513             returnValue = Optional.of(mapper.writeValueAsString(iNotif));
514         } catch (JsonProcessingException e) {
515             logger.error("Error converting incoming ASDC notification to JSON", e);
516         }
517         return returnValue;
518     }
519
520     public void treatNotification(INotificationData iNotif) {
521
522         int noOfArtifacts = 0;
523
524         for (IResourceInstance resource : iNotif.getResources()) {
525             noOfArtifacts += resource.getArtifacts().size();
526         }
527         logger.info("{} {} {} {}", MessageEnum.ASDC_RECEIVE_CALLBACK_NOTIF.toString(), String.valueOf(noOfArtifacts),
528                 iNotif.getServiceUUID(), "ASDC");
529         try {
530             logger.debug(ASDCNotificationLogging.dumpASDCNotification(iNotif));
531             logger.info("{} {} {} {}", MessageEnum.ASDC_RECEIVE_SERVICE_NOTIF.toString(), iNotif.getServiceUUID(),
532                     "ASDC", "treatNotification");
533
534             this.changeControllerStatus(ASDCControllerStatus.BUSY);
535             Optional<String> notificationMessage = getNotificationJson(iNotif);
536             toscaInstaller.processWatchdog(iNotif.getDistributionID(), iNotif.getServiceUUID(), notificationMessage,
537                     asdcConfig.getConsumerID());
538
539             // Process only the Resource artifacts in MSO
540             this.processResourceNotification(iNotif);
541
542             // ********************************************************************************************************
543             // Start Watchdog loop and wait for all components to complete before reporting final status back.
544             // **If timer expires first then we will report a Distribution Error back to ASDC
545             // ********************************************************************************************************
546             long initialStartTime = System.currentTimeMillis();
547             boolean componentsComplete = false;
548             String distributionStatus = null;
549             String watchdogError = null;
550             String overallStatus = null;
551             int watchDogTimeout = asdcConfig.getWatchDogTimeout() * 1000;
552             boolean isDeploySuccess = false;
553
554             while (!componentsComplete && (System.currentTimeMillis() - initialStartTime) < watchDogTimeout) {
555
556                 try {
557                     distributionStatus = wd.getOverallDistributionStatus(iNotif.getDistributionID());
558                     Thread.sleep(watchDogTimeout / 10);
559                 } catch (Exception e) {
560                     logger.debug("Exception in Watchdog Loop {}", e.getMessage());
561                     Thread.sleep(watchDogTimeout / 10);
562                 }
563
564                 if (distributionStatus != null
565                         && !distributionStatus.equalsIgnoreCase(DistributionStatus.INCOMPLETE.name())) {
566
567                     if (distributionStatus.equalsIgnoreCase(DistributionStatus.SUCCESS.name())) {
568                         isDeploySuccess = true;
569                         overallStatus = DistributionStatusEnum.DISTRIBUTION_COMPLETE_OK.name();
570                     } else {
571                         overallStatus = DistributionStatusEnum.DISTRIBUTION_COMPLETE_ERROR.name();
572                     }
573                     componentsComplete = true;
574                 }
575             }
576
577             if (!componentsComplete) {
578                 logger.debug("Timeout of {} seconds was reached before all components reported status",
579                         watchDogTimeout);
580                 watchdogError = "Timeout occurred while waiting for all components to report status";
581                 overallStatus = DistributionStatusEnum.DISTRIBUTION_COMPLETE_ERROR.name();
582             }
583
584             if (distributionStatus == null) {
585                 overallStatus = DistributionStatusEnum.DISTRIBUTION_COMPLETE_ERROR.name();
586                 logger.debug("DistributionStatus is null for DistributionId: {}", iNotif.getDistributionID());
587             }
588
589             try {
590                 wd.executePatchAAI(iNotif.getDistributionID(), iNotif.getServiceInvariantUUID(), overallStatus);
591                 logger.debug("A&AI Updated succefully with Distribution Status!");
592             } catch (Exception e) {
593                 logger.debug("Exception in Watchdog executePatchAAI(): {}", e.getMessage());
594                 watchdogError = "Error calling A&AI " + e.getMessage();
595                 if (e.getCause() != null) {
596                     logger.debug("Exception caused by: {}", e.getCause().getMessage());
597                 }
598             }
599
600             if (isDeploySuccess && watchdogError == null) {
601                 sendFinalDistributionStatus(iNotif.getDistributionID(), DistributionStatusEnum.DISTRIBUTION_COMPLETE_OK,
602                         null);
603                 WatchdogDistributionStatus wds = new WatchdogDistributionStatus(iNotif.getDistributionID());
604                 wds.setDistributionIdStatus(DistributionStatusEnum.DISTRIBUTION_COMPLETE_OK.toString());
605                 wdsRepo.save(wds);
606             } else {
607                 sendFinalDistributionStatus(iNotif.getDistributionID(),
608                         DistributionStatusEnum.DISTRIBUTION_COMPLETE_ERROR, watchdogError);
609                 WatchdogDistributionStatus wds = new WatchdogDistributionStatus(iNotif.getDistributionID());
610                 wds.setDistributionIdStatus(DistributionStatusEnum.DISTRIBUTION_COMPLETE_ERROR.toString());
611                 wdsRepo.save(wds);
612             }
613
614
615         } catch (ObjectOptimisticLockingFailureException e) {
616
617             logger.debug(
618                     "OptimisticLockingFailure for DistributionId: {} Another process "
619                             + "has already altered this distribution, so not going to process it on this site.",
620                     iNotif.getDistributionID());
621             logger.error("{} {} {} {} {} {}", MessageEnum.ASDC_GENERAL_EXCEPTION_ARG.toString(),
622                     "Database concurrency exception: ", "ASDC", "treatNotification",
623                     ErrorCode.BusinessProcesssError.getValue(), "RuntimeException in treatNotification", e);
624
625         } catch (Exception e) {
626             logger.error("", MessageEnum.ASDC_GENERAL_EXCEPTION_ARG.toString(),
627                     "Unexpected exception caught during the notification processing", "ASDC", "treatNotification",
628                     ErrorCode.SchemaError.getValue(), "RuntimeException in treatNotification", e);
629
630             try {
631                 wd.executePatchAAI(iNotif.getDistributionID(), iNotif.getServiceInvariantUUID(),
632                         DistributionStatusEnum.DISTRIBUTION_COMPLETE_ERROR.name());
633                 logger.debug("A&AI Updated succefully with Distribution Status of {}",
634                         DistributionStatusEnum.DISTRIBUTION_COMPLETE_ERROR.name());
635             } catch (Exception aaiException) {
636                 logger.debug("Exception in executePatchAAI(): {}", aaiException);
637                 if (aaiException.getCause() != null) {
638                     logger.debug("Exception caused by: {}", aaiException.getCause().getMessage());
639                 }
640             }
641
642             sendFinalDistributionStatus(iNotif.getDistributionID(), DistributionStatusEnum.DISTRIBUTION_COMPLETE_ERROR,
643                     e.getMessage());
644
645             WatchdogDistributionStatus wds = new WatchdogDistributionStatus(iNotif.getDistributionID());
646             wds.setDistributionIdStatus(DistributionStatusEnum.DISTRIBUTION_COMPLETE_ERROR.toString());
647             wdsRepo.save(wds);
648
649         } finally {
650             this.changeControllerStatus(ASDCControllerStatus.IDLE);
651         }
652     }
653
654     protected void processResourceNotification(INotificationData iNotif) {
655         // For each artifact, create a structure describing the VFModule in a ordered flat level
656         ResourceStructure resourceStructure = null;
657         String msoConfigPath = getMsoConfigPath();
658         boolean hasVFResource = false;
659         ToscaResourceStructure toscaResourceStructure = new ToscaResourceStructure(msoConfigPath);
660         boolean deploySuccessful = true;
661         String errorMessage = null;
662         boolean serviceDeployed = false;
663
664         try {
665             this.processCsarServiceArtifacts(iNotif, toscaResourceStructure);
666             IArtifactInfo iArtifact = toscaResourceStructure.getToscaArtifact();
667             String filePath =
668                     msoConfigPath + "/ASDC/" + iArtifact.getArtifactVersion() + "/" + iArtifact.getArtifactName();
669             File csarFile = new File(filePath);
670             String csarFilePath = csarFile.getAbsolutePath();
671
672             for (IResourceInstance resource : iNotif.getResources()) {
673
674                 String resourceType = resource.getResourceType();
675                 String category = resource.getCategory();
676
677                 logger.info("Processing Resource Type: {}, Model UUID: {}", resourceType, resource.getResourceUUID());
678
679                 if ("VF".equals(resourceType)) {
680                     resourceStructure = new VfResourceStructure(iNotif, resource);
681                 } else if ("PNF".equals(resourceType)) {
682                     resourceStructure = new PnfResourceStructure(iNotif, resource);
683                 } else {
684                     // There are cases where the Service has no VF resources, those are handled here
685                     logger.info("No resources found for Service: {}", iNotif.getServiceUUID());
686                     resourceStructure = new VfResourceStructure(iNotif, new ResourceInstance());
687                     resourceStructure.setResourceType(ResourceType.OTHER);
688                 }
689
690                 try {
691
692                     if (!this.checkResourceAlreadyDeployed(resourceStructure, serviceDeployed)) {
693
694                         logger.debug("Processing Resource Type: " + resourceType + " and Model UUID: "
695                                 + resourceStructure.getResourceInstance().getResourceUUID());
696
697                         if ("VF".equals(resourceType)) {
698                             hasVFResource = true;
699                             for (IArtifactInfo artifact : resource.getArtifacts()) {
700                                 IDistributionClientDownloadResult resultArtifact =
701                                         this.downloadTheArtifact(artifact, iNotif.getDistributionID());
702                                 if (resultArtifact != null) {
703
704                                     if (ASDCConfiguration.VF_MODULES_METADATA.equals(artifact.getArtifactType())) {
705                                         logger.debug("VF_MODULE_ARTIFACT: "
706                                                 + new String(resultArtifact.getArtifactPayload(), "UTF-8"));
707                                         logger.debug(ASDCNotificationLogging
708                                                 .dumpVfModuleMetaDataList(((VfResourceStructure) resourceStructure)
709                                                         .decodeVfModuleArtifact(resultArtifact.getArtifactPayload())));
710                                     }
711                                     if (!ASDCConfiguration.WORKFLOW.equals(artifact.getArtifactType())) {
712                                         resourceStructure.addArtifactToStructure(distributionClient, artifact,
713                                                 resultArtifact);
714                                     } else {
715                                         writeArtifactToFile(artifact, resultArtifact);
716                                         logger.debug(
717                                                 "Adding workflow artifact to structure: " + artifact.getArtifactName());
718                                         resourceStructure.addWorkflowArtifactToStructure(artifact, resultArtifact);
719                                     }
720                                 }
721                             }
722
723                             // Deploy VF resource and artifacts
724                             logger.debug("Preparing to deploy Service: {}", iNotif.getServiceUUID());
725
726
727                             this.deployResourceStructure(resourceStructure, toscaResourceStructure);
728                             serviceDeployed = true;
729                         }
730                     }
731
732                 } catch (ArtifactInstallerException e) {
733                     deploySuccessful = false;
734                     errorMessage = e.getMessage();
735                     logger.error("Exception occurred", e);
736                 }
737
738                 if (!hasVFResource) {
739
740                     logger.debug("No resources found for Service: " + iNotif.getServiceUUID());
741
742                     logger.debug("Preparing to deploy Service: {}", iNotif.getServiceUUID());
743                     try {
744                         this.deployResourceStructure(resourceStructure, toscaResourceStructure);
745                     } catch (ArtifactInstallerException e) {
746                         deploySuccessful = false;
747                         errorMessage = e.getMessage();
748                         logger.error("Exception occurred", e);
749                     }
750                 }
751                 this.sendCsarDeployNotification(iNotif, resourceStructure, toscaResourceStructure, deploySuccessful,
752                         errorMessage);
753             }
754
755
756         } catch (ASDCDownloadException | UnsupportedEncodingException e) {
757             logger.error("{} {} {} {} {} {}", MessageEnum.ASDC_GENERAL_EXCEPTION_ARG.toString(),
758                     "Exception caught during Installation of artifact", "ASDC", "processResourceNotification",
759                     ErrorCode.BusinessProcesssError.getValue(), "Exception in processResourceNotification", e);
760         }
761     }
762
763     private String getMsoConfigPath() {
764         String msoConfigPath = System.getProperty("mso.config.path");
765         if (msoConfigPath == null) {
766             logger.info("Unable to find the system property mso.config.path, use the default configuration");
767             msoConfigPath = asdcConfig.getPropertyOrNull("mso.config.defaultpath");
768         }
769         if (msoConfigPath == null) {
770             logger.info("Unable to find the property: {} from configuration.", "mso.config.defaultpath");
771             msoConfigPath = "";
772         }
773         logger.info("MSO config path is: {}", msoConfigPath);
774         return msoConfigPath;
775     }
776
777     protected void processCsarServiceArtifacts(INotificationData iNotif,
778             ToscaResourceStructure toscaResourceStructure) {
779
780         List<IArtifactInfo> serviceArtifacts = iNotif.getServiceArtifacts();
781
782         for (IArtifactInfo artifact : serviceArtifacts) {
783
784             if (artifact.getArtifactType().equals(ASDCConfiguration.TOSCA_CSAR)) {
785
786                 try {
787
788                     toscaResourceStructure.setToscaArtifact(artifact);
789
790                     IDistributionClientDownloadResult resultArtifact =
791                             this.downloadTheArtifact(artifact, iNotif.getDistributionID());
792
793                     writeArtifactToFile(artifact, resultArtifact);
794
795                     toscaResourceStructure.updateResourceStructure(artifact);
796
797                     toscaResourceStructure.setServiceVersion(iNotif.getServiceVersion());
798
799                     logger.debug(ASDCNotificationLogging.dumpCSARNotification(iNotif, toscaResourceStructure));
800
801
802                 } catch (Exception e) {
803                     logger.error("{} {} {} {} {} {}", MessageEnum.ASDC_GENERAL_EXCEPTION_ARG.toString(),
804                             "Exception caught during processCsarServiceArtifacts", "ASDC",
805                             "processCsarServiceArtifacts", ErrorCode.BusinessProcesssError.getValue(),
806                             "Exception in processCsarServiceArtifacts", e);
807                 }
808             } else if (artifact.getArtifactType().equals(ASDCConfiguration.WORKFLOW)) {
809
810                 try {
811
812                     IDistributionClientDownloadResult resultArtifact =
813                             this.downloadTheArtifact(artifact, iNotif.getDistributionID());
814
815                     writeArtifactToFile(artifact, resultArtifact);
816
817                     toscaResourceStructure.setToscaArtifact(artifact);
818
819                     logger.debug(ASDCNotificationLogging.dumpASDCNotification(iNotif));
820
821
822                 } catch (Exception e) {
823                     logger.info("Whats the error {}", e.getMessage());
824                     logger.error("{} {} {} {} {} {}", MessageEnum.ASDC_GENERAL_EXCEPTION_ARG.toString(),
825                             "Exception caught during processCsarServiceArtifacts", "ASDC",
826                             "processCsarServiceArtifacts", ErrorCode.BusinessProcesssError.getValue(),
827                             "Exception in processCsarServiceArtifacts", e);
828                 }
829             }
830
831
832         }
833     }
834
835     private static final String UNKNOWN = "Unknown";
836
837     /**
838      * @return the address of the ASDC we are connected to.
839      */
840     public String getAddress() {
841         if (asdcConfig != null) {
842             return asdcConfig.getAsdcAddress();
843         }
844         return UNKNOWN;
845     }
846
847     /**
848      * @return the environment name of the ASDC we are connected to.
849      */
850     public String getEnvironment() {
851         if (asdcConfig != null) {
852             return asdcConfig.getEnvironmentName();
853         }
854         return UNKNOWN;
855     }
856 }