92326b19070a362f074e2bb12b3cab71ff7c4dca
[so.git] / asdc-controller / src / main / java / org / onap / so / asdc / client / ASDCController.java
1 /*-
2 d * ============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.client.exceptions.ASDCControllerException;
51 import org.onap.so.asdc.client.exceptions.ASDCDownloadException;
52 import org.onap.so.asdc.client.exceptions.ASDCParametersException;
53 import org.onap.so.asdc.client.exceptions.ArtifactInstallerException;
54 import org.onap.so.asdc.installer.IVfResourceInstaller;
55 import org.onap.so.asdc.installer.PnfResourceStructure;
56 import org.onap.so.asdc.installer.ResourceStructure;
57 import org.onap.so.asdc.installer.ResourceType;
58 import org.onap.so.asdc.installer.ToscaResourceStructure;
59 import org.onap.so.asdc.installer.VfResourceStructure;
60 import org.onap.so.asdc.installer.bpmn.BpmnInstaller;
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 BpmnInstaller bpmnInstaller;
93
94     @Autowired
95     private WatchdogDistributionStatusRepository wdsRepo;
96
97     @Autowired
98     private ASDCConfiguration asdcConfig;
99
100     @Autowired
101     private ASDCStatusCallBack asdcStatusCallBack;
102
103     @Autowired
104     private ASDCNotificationCallBack asdcNotificationCallBack;
105
106     private IDistributionClient distributionClient;
107
108     private static final String UUID_PARAM = "(UUID:";
109
110     @Autowired
111     private WatchdogDistribution wd;
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     private boolean checkResourceAlreadyDeployed(VfResourceStructure resource) throws ArtifactInstallerException {
254
255         if (toscaInstaller.isResourceAlreadyDeployed(resource)) {
256             logger.info("{} {} {} {}", MessageEnum.ASDC_ARTIFACT_ALREADY_EXIST.toString(),
257                     resource.getResourceInstance().getResourceInstanceName(),
258                     resource.getResourceInstance().getResourceUUID(), resource.getResourceInstance().getResourceName());
259
260             this.sendDeployNotificationsForResource(resource, DistributionStatusEnum.ALREADY_DOWNLOADED, null);
261             this.sendDeployNotificationsForResource(resource, DistributionStatusEnum.ALREADY_DEPLOYED, null);
262
263             return true;
264         } else {
265             return false;
266         }
267     }
268
269
270     protected IDistributionClientDownloadResult downloadTheArtifact(IArtifactInfo artifact, String distributionId)
271             throws ASDCDownloadException {
272
273         logger.info("Trying to download the artifact UUID: {} from URL: {}", artifact.getArtifactUUID(),
274                 artifact.getArtifactURL());
275         IDistributionClientDownloadResult downloadResult;
276
277         try {
278             downloadResult = distributionClient.download(artifact);
279             if (null == downloadResult) {
280                 logger.info("{} {}", MessageEnum.ASDC_ARTIFACT_NULL.toString(), artifact.getArtifactUUID());
281                 return downloadResult;
282             }
283         } catch (RuntimeException e) {
284             logger.debug("Not able to download the artifact due to an exception: " + artifact.getArtifactURL());
285             this.sendASDCNotification(NotificationType.DOWNLOAD, artifact.getArtifactURL(), asdcConfig.getConsumerID(),
286                     distributionId, DistributionStatusEnum.DOWNLOAD_ERROR, e.getMessage(), System.currentTimeMillis());
287
288             throw new ASDCDownloadException("Exception caught when downloading the artifact", e);
289         }
290
291         if (DistributionActionResultEnum.SUCCESS.equals(downloadResult.getDistributionActionResult())) {
292             logger.info("{} {} {} {}", MessageEnum.ASDC_ARTIFACT_DOWNLOAD_SUC.toString(), artifact.getArtifactURL(),
293                     artifact.getArtifactUUID(), String.valueOf(downloadResult.getArtifactPayload().length));
294
295         } else {
296             logger.error("{} {} {} {} {} {} {}", MessageEnum.ASDC_ARTIFACT_DOWNLOAD_FAIL.toString(),
297                     artifact.getArtifactName(), artifact.getArtifactURL(), artifact.getArtifactUUID(),
298                     downloadResult.getDistributionMessageResult(), ErrorCode.DataError.getValue(),
299                     "ASDC artifact download fail");
300
301             this.sendASDCNotification(NotificationType.DOWNLOAD, artifact.getArtifactURL(), asdcConfig.getConsumerID(),
302                     distributionId, DistributionStatusEnum.DOWNLOAD_ERROR,
303                     downloadResult.getDistributionMessageResult(), System.currentTimeMillis());
304
305             throw new ASDCDownloadException("Artifact " + artifact.getArtifactName()
306                     + " could not be downloaded from ASDC URL " + artifact.getArtifactURL() + UUID_PARAM
307                     + artifact.getArtifactUUID() + ")" + System.lineSeparator() + "Error message is "
308                     + downloadResult.getDistributionMessageResult() + System.lineSeparator());
309
310         }
311
312         this.sendASDCNotification(NotificationType.DOWNLOAD, artifact.getArtifactURL(), asdcConfig.getConsumerID(),
313                 distributionId, DistributionStatusEnum.DOWNLOAD_OK, null, System.currentTimeMillis());
314         return downloadResult;
315
316     }
317
318     private void writeArtifactToFile(IArtifactInfo artifact, IDistributionClientDownloadResult resultArtifact) {
319
320         String filePath =
321                 Paths.get(getMsoConfigPath(), "ASDC", artifact.getArtifactVersion(), artifact.getArtifactName())
322                         .normalize().toString();
323
324         logger.info("Trying to write artifact UUID: {}, URL: {} to file: {}", artifact.getArtifactUUID(),
325                 artifact.getArtifactURL(), filePath);
326
327         // make parent directory
328         File file = new File(filePath);
329         File fileParent = file.getParentFile();
330         if (!fileParent.exists()) {
331             fileParent.mkdirs();
332         }
333
334         byte[] payloadBytes = resultArtifact.getArtifactPayload();
335
336         try (FileOutputStream outFile = new FileOutputStream(filePath)) {
337             logger.info("{} {} {} {}", MessageEnum.ASDC_RECEIVE_SERVICE_NOTIF.toString(), "***WRITE FILE ARTIFACT NAME",
338                     "ASDC", artifact.getArtifactName());
339             outFile.write(payloadBytes, 0, payloadBytes.length);
340         } catch (Exception e) {
341             logger.debug("Exception :", e);
342             logger.error("{} {} {} {} {} {} {}", MessageEnum.ASDC_ARTIFACT_DOWNLOAD_FAIL.toString(),
343                     artifact.getArtifactName(), artifact.getArtifactURL(), artifact.getArtifactUUID(),
344                     resultArtifact.getDistributionMessageResult(), ErrorCode.DataError.getValue(),
345                     "ASDC write to file failed");
346         }
347
348     }
349
350
351     protected void sendDeployNotificationsForResource(ResourceStructure resourceStructure,
352             DistributionStatusEnum distribStatus, String errorReason) {
353
354         for (IArtifactInfo artifactInfo : resourceStructure.getResourceInstance().getArtifacts()) {
355
356             if ((DistributionStatusEnum.DEPLOY_OK.equals(distribStatus)
357                     && !artifactInfo.getArtifactType().equalsIgnoreCase("OTHER")
358                     && !resourceStructure.isAlreadyDeployed())
359                     // This could be NULL if the artifact is a VF module artifact, this won't be present in the MAP
360                     && resourceStructure.getArtifactsMapByUUID().get(artifactInfo.getArtifactUUID()) != null
361                     && resourceStructure.getArtifactsMapByUUID().get(artifactInfo.getArtifactUUID())
362                             .getDeployedInDb() == 0) {
363                 this.sendASDCNotification(NotificationType.DEPLOY, artifactInfo.getArtifactURL(),
364                         asdcConfig.getConsumerID(), resourceStructure.getNotification().getDistributionID(),
365                         DistributionStatusEnum.DEPLOY_ERROR,
366                         "The artifact has not been used by the modules defined in the resource",
367                         System.currentTimeMillis());
368             } else {
369                 this.sendASDCNotification(NotificationType.DEPLOY, artifactInfo.getArtifactURL(),
370                         asdcConfig.getConsumerID(), resourceStructure.getNotification().getDistributionID(),
371                         distribStatus, errorReason, System.currentTimeMillis());
372             }
373         }
374     }
375
376     protected void sendCsarDeployNotification(INotificationData iNotif, ResourceStructure resourceStructure,
377             ToscaResourceStructure toscaResourceStructure, boolean deploySuccessful, String errorReason) {
378
379         IArtifactInfo csarArtifact = toscaResourceStructure.getToscaArtifact();
380
381         if (deploySuccessful) {
382
383             this.sendASDCNotification(NotificationType.DEPLOY, csarArtifact.getArtifactURL(),
384                     asdcConfig.getConsumerID(), resourceStructure.getNotification().getDistributionID(),
385                     DistributionStatusEnum.DEPLOY_OK, errorReason, System.currentTimeMillis());
386
387         } else {
388
389             this.sendASDCNotification(NotificationType.DEPLOY, csarArtifact.getArtifactURL(),
390                     asdcConfig.getConsumerID(), resourceStructure.getNotification().getDistributionID(),
391                     DistributionStatusEnum.DEPLOY_ERROR, errorReason, System.currentTimeMillis());
392
393         }
394     }
395
396     protected void deployResourceStructure(ResourceStructure resourceStructure,
397             ToscaResourceStructure toscaResourceStructure) throws ArtifactInstallerException {
398
399         logger.info("{} {} {} {}", MessageEnum.ASDC_START_DEPLOY_ARTIFACT.toString(),
400                 resourceStructure.getResourceInstance().getResourceInstanceName(),
401                 resourceStructure.getResourceInstance().getResourceUUID(), "ASDC");
402         try {
403             resourceStructure.prepareInstall();
404             toscaInstaller.installTheResource(toscaResourceStructure, resourceStructure);
405
406         } catch (ArtifactInstallerException e) {
407             logger.info("{} {} {} {} {} {}", MessageEnum.ASDC_ARTIFACT_DOWNLOAD_FAIL.toString(),
408                     resourceStructure.getResourceInstance().getResourceName(),
409                     resourceStructure.getResourceInstance().getResourceUUID(),
410                     String.valueOf(resourceStructure.getNumberOfResources()), "ASDC", "deployResourceStructure");
411             sendDeployNotificationsForResource(resourceStructure, DistributionStatusEnum.DEPLOY_ERROR, e.getMessage());
412             throw e;
413         }
414
415         if (resourceStructure.isDeployedSuccessfully() || toscaResourceStructure.isDeployedSuccessfully()) {
416             logger.info("{} {} {} {} {} {}", MessageEnum.ASDC_ARTIFACT_DEPLOY_SUC.toString(),
417                     resourceStructure.getResourceInstance().getResourceName(),
418                     resourceStructure.getResourceInstance().getResourceUUID(),
419                     String.valueOf(resourceStructure.getNumberOfResources()), "ASDC", "deployResourceStructure");
420             sendDeployNotificationsForResource(resourceStructure, DistributionStatusEnum.DEPLOY_OK, null);
421         }
422
423     }
424
425
426     private enum NotificationType {
427         DOWNLOAD, DEPLOY
428     }
429
430     protected void sendASDCNotification(NotificationType notificationType, String artifactURL, String consumerID,
431             String distributionID, DistributionStatusEnum status, String errorReason, long timestamp) {
432
433         String event = "Sending " + notificationType.name() + "(" + status.name() + ")"
434                 + " notification to ASDC for artifact:" + artifactURL;
435
436         if (errorReason != null) {
437             event = event + "(" + errorReason + ")";
438         }
439         logger.info("{} {} {} {} {} {}", MessageEnum.ASDC_SEND_NOTIF_ASDC.toString(), notificationType.name(),
440                 status.name(), artifactURL, "ASDC", "sendASDCNotification");
441         logger.debug(event);
442
443         String action = "";
444         try {
445             IDistributionStatusMessage message =
446                     new DistributionStatusMessage(artifactURL, consumerID, distributionID, status, timestamp);
447
448             switch (notificationType) {
449                 case DOWNLOAD:
450                     if (errorReason != null) {
451                         this.distributionClient.sendDownloadStatus(message, errorReason);
452                     } else {
453                         this.distributionClient.sendDownloadStatus(message);
454                     }
455                     action = "sendDownloadStatus";
456                     break;
457                 case DEPLOY:
458                     if (errorReason != null) {
459                         this.distributionClient.sendDeploymentStatus(message, errorReason);
460                     } else {
461                         this.distributionClient.sendDeploymentStatus(message);
462                     }
463                     action = "sendDeploymentdStatus";
464                     break;
465                 default:
466                     break;
467             }
468         } catch (RuntimeException e) {
469             logger.warn("{} {} {} {} {}", MessageEnum.ASDC_SEND_NOTIF_ASDC_EXEC.toString(), "ASDC",
470                     "sendASDCNotification", ErrorCode.SchemaError.getValue(), "RuntimeException - sendASDCNotification",
471                     e);
472         }
473     }
474
475     protected void sendFinalDistributionStatus(String distributionID, DistributionStatusEnum status,
476             String errorReason) {
477
478         logger.debug("Enter sendFinalDistributionStatus with DistributionID " + distributionID + " and Status of "
479                 + status.name() + " and ErrorReason " + errorReason);
480
481         long subStarttime = System.currentTimeMillis();
482         try {
483
484             IFinalDistrStatusMessage finalDistribution = new FinalDistributionStatusMessage(distributionID, status,
485                     subStarttime, asdcConfig.getConsumerID());
486
487             if (errorReason == null) {
488                 this.distributionClient.sendFinalDistrStatus(finalDistribution);
489             } else {
490                 this.distributionClient.sendFinalDistrStatus(finalDistribution, errorReason);
491             }
492
493
494         } catch (RuntimeException e) {
495             logger.debug("Exception caught in sendFinalDistributionStatus {}", e.getMessage());
496             logger.warn("{} {} {} {} {}", MessageEnum.ASDC_SEND_NOTIF_ASDC_EXEC.toString(), "ASDC",
497                     "sendASDCNotification", ErrorCode.SchemaError.getValue(), "RuntimeException - sendASDCNotification",
498                     e);
499         }
500     }
501
502     private Optional<String> getNotificationJson(INotificationData iNotif) {
503         ObjectMapper mapper = new ObjectMapper();
504         mapper.setSerializationInclusion(Include.NON_NULL);
505         mapper.setSerializationInclusion(Include.NON_EMPTY);
506         mapper.setSerializationInclusion(Include.NON_ABSENT);
507         mapper.enable(MapperFeature.USE_ANNOTATIONS);
508         mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
509         Optional<String> returnValue = Optional.empty();
510         try {
511             returnValue = Optional.of(mapper.writeValueAsString(iNotif));
512         } catch (JsonProcessingException e) {
513             logger.error("Error converting incoming ASDC notification to JSON", e);
514         }
515         return returnValue;
516     }
517
518     public void treatNotification(INotificationData iNotif) {
519
520         int noOfArtifacts = 0;
521
522         for (IResourceInstance resource : iNotif.getResources()) {
523             noOfArtifacts += resource.getArtifacts().size();
524         }
525         logger.info("{} {} {} {}", MessageEnum.ASDC_RECEIVE_CALLBACK_NOTIF.toString(), String.valueOf(noOfArtifacts),
526                 iNotif.getServiceUUID(), "ASDC");
527         try {
528             logger.debug(ASDCNotificationLogging.dumpASDCNotification(iNotif));
529             logger.info("{} {} {} {}", MessageEnum.ASDC_RECEIVE_SERVICE_NOTIF.toString(), iNotif.getServiceUUID(),
530                     "ASDC", "treatNotification");
531
532             this.changeControllerStatus(ASDCControllerStatus.BUSY);
533             Optional<String> notificationMessage = getNotificationJson(iNotif);
534             toscaInstaller.processWatchdog(iNotif.getDistributionID(), iNotif.getServiceUUID(), notificationMessage,
535                     asdcConfig.getConsumerID());
536
537             // Process only the Resource artifacts in MSO
538             this.processResourceNotification(iNotif);
539
540             // ********************************************************************************************************
541             // Start Watchdog loop and wait for all components to complete before reporting final status back.
542             // **If timer expires first then we will report a Distribution Error back to ASDC
543             // ********************************************************************************************************
544             long initialStartTime = System.currentTimeMillis();
545             boolean componentsComplete = false;
546             String distributionStatus = null;
547             String watchdogError = null;
548             String overallStatus = null;
549             int watchDogTimeout = asdcConfig.getWatchDogTimeout() * 1000;
550             boolean isDeploySuccess = false;
551
552             while (!componentsComplete && (System.currentTimeMillis() - initialStartTime) < watchDogTimeout) {
553
554                 try {
555                     distributionStatus = wd.getOverallDistributionStatus(iNotif.getDistributionID());
556                     Thread.sleep(watchDogTimeout / 10);
557                 } catch (Exception e) {
558                     logger.debug("Exception in Watchdog Loop {}", e.getMessage());
559                     Thread.sleep(watchDogTimeout / 10);
560                 }
561
562                 if (distributionStatus != null
563                         && !distributionStatus.equalsIgnoreCase(DistributionStatus.INCOMPLETE.name())) {
564
565                     if (distributionStatus.equalsIgnoreCase(DistributionStatus.SUCCESS.name())) {
566                         isDeploySuccess = true;
567                         overallStatus = DistributionStatusEnum.DISTRIBUTION_COMPLETE_OK.name();
568                     } else {
569                         overallStatus = DistributionStatusEnum.DISTRIBUTION_COMPLETE_ERROR.name();
570                     }
571                     componentsComplete = true;
572                 }
573             }
574
575             if (!componentsComplete) {
576                 logger.debug("Timeout of {} seconds was reached before all components reported status",
577                         watchDogTimeout);
578                 watchdogError = "Timeout occurred while waiting for all components to report status";
579                 overallStatus = DistributionStatusEnum.DISTRIBUTION_COMPLETE_ERROR.name();
580             }
581
582             if (distributionStatus == null) {
583                 overallStatus = DistributionStatusEnum.DISTRIBUTION_COMPLETE_ERROR.name();
584                 logger.debug("DistributionStatus is null for DistributionId: {}", iNotif.getDistributionID());
585             }
586
587             try {
588                 wd.executePatchAAI(iNotif.getDistributionID(), iNotif.getServiceInvariantUUID(), overallStatus);
589                 logger.debug("A&AI Updated succefully with Distribution Status!");
590             } catch (Exception e) {
591                 logger.debug("Exception in Watchdog executePatchAAI(): {}", e.getMessage());
592                 watchdogError = "Error calling A&AI " + e.getMessage();
593                 if (e.getCause() != null) {
594                     logger.debug("Exception caused by: {}", e.getCause().getMessage());
595                 }
596             }
597
598             if (isDeploySuccess && watchdogError == null) {
599                 sendFinalDistributionStatus(iNotif.getDistributionID(), DistributionStatusEnum.DISTRIBUTION_COMPLETE_OK,
600                         null);
601                 WatchdogDistributionStatus wds = new WatchdogDistributionStatus(iNotif.getDistributionID());
602                 wds.setDistributionIdStatus(DistributionStatusEnum.DISTRIBUTION_COMPLETE_OK.toString());
603                 wdsRepo.save(wds);
604             } else {
605                 sendFinalDistributionStatus(iNotif.getDistributionID(),
606                         DistributionStatusEnum.DISTRIBUTION_COMPLETE_ERROR, watchdogError);
607                 WatchdogDistributionStatus wds = new WatchdogDistributionStatus(iNotif.getDistributionID());
608                 wds.setDistributionIdStatus(DistributionStatusEnum.DISTRIBUTION_COMPLETE_ERROR.toString());
609                 wdsRepo.save(wds);
610             }
611
612
613         } catch (ObjectOptimisticLockingFailureException e) {
614
615             logger.debug(
616                     "OptimisticLockingFailure for DistributionId: {} Another process "
617                             + "has already altered this distribution, so not going to process it on this site.",
618                     iNotif.getDistributionID());
619             logger.error("{} {} {} {} {} {}", MessageEnum.ASDC_GENERAL_EXCEPTION_ARG.toString(),
620                     "Database concurrency exception: ", "ASDC", "treatNotification",
621                     ErrorCode.BusinessProcesssError.getValue(), "RuntimeException in treatNotification", e);
622
623         } catch (Exception e) {
624             logger.error("", MessageEnum.ASDC_GENERAL_EXCEPTION_ARG.toString(),
625                     "Unexpected exception caught during the notification processing", "ASDC", "treatNotification",
626                     ErrorCode.SchemaError.getValue(), "RuntimeException in treatNotification", e);
627
628             try {
629                 wd.executePatchAAI(iNotif.getDistributionID(), iNotif.getServiceInvariantUUID(),
630                         DistributionStatusEnum.DISTRIBUTION_COMPLETE_ERROR.name());
631                 logger.debug("A&AI Updated succefully with Distribution Status of {}",
632                         DistributionStatusEnum.DISTRIBUTION_COMPLETE_ERROR.name());
633             } catch (Exception aaiException) {
634                 logger.debug("Exception in executePatchAAI(): {}", aaiException);
635                 if (aaiException.getCause() != null) {
636                     logger.debug("Exception caused by: {}", aaiException.getCause().getMessage());
637                 }
638             }
639
640             sendFinalDistributionStatus(iNotif.getDistributionID(), DistributionStatusEnum.DISTRIBUTION_COMPLETE_ERROR,
641                     e.getMessage());
642
643             WatchdogDistributionStatus wds = new WatchdogDistributionStatus(iNotif.getDistributionID());
644             wds.setDistributionIdStatus(DistributionStatusEnum.DISTRIBUTION_COMPLETE_ERROR.toString());
645             wdsRepo.save(wds);
646
647         } finally {
648             this.changeControllerStatus(ASDCControllerStatus.IDLE);
649         }
650     }
651
652     protected void processResourceNotification(INotificationData iNotif) {
653         // For each artifact, create a structure describing the VFModule in a ordered flat level
654         ResourceStructure resourceStructure = null;
655         String msoConfigPath = getMsoConfigPath();
656         ToscaResourceStructure toscaResourceStructure = new ToscaResourceStructure(msoConfigPath);
657         boolean deploySuccessful = true;
658         String errorMessage = null;
659
660         try {
661             this.processCsarServiceArtifacts(iNotif, toscaResourceStructure);
662             IArtifactInfo iArtifact = toscaResourceStructure.getToscaArtifact();
663             String filePath =
664                     msoConfigPath + "/ASDC/" + iArtifact.getArtifactVersion() + "/" + iArtifact.getArtifactName();
665             File csarFile = new File(filePath);
666             String csarFilePath = csarFile.getAbsolutePath();
667             if (bpmnInstaller.containsWorkflows(csarFilePath)) {
668                 bpmnInstaller.installBpmn(csarFilePath);
669             }
670
671             for (IResourceInstance resource : iNotif.getResources()) {
672
673                 String resourceType = resource.getResourceType();
674                 String category = resource.getCategory();
675
676                 logger.info("Processing Resource Type: {}, Model UUID: {}", resourceType, resource.getResourceUUID());
677
678                 if ("VF".equals(resourceType) && !"Allotted Resource".equalsIgnoreCase(category)) {
679                     resourceStructure = new VfResourceStructure(iNotif, resource);
680                 } else if ("PNF".equals(resourceType)) {
681                     resourceStructure = new PnfResourceStructure(iNotif, resource);
682                 } else {
683                     // There are cases where the Service has no VF resources, those are handled here
684                     logger.info("No resources found for Service: {}", iNotif.getServiceUUID());
685                     resourceStructure = new VfResourceStructure(iNotif, new ResourceInstance());
686                     resourceStructure.setResourceType(ResourceType.OTHER);
687                 }
688
689                 for (IArtifactInfo artifact : resource.getArtifacts()) {
690                     IDistributionClientDownloadResult resultArtifact =
691                             this.downloadTheArtifact(artifact, iNotif.getDistributionID());
692                     if (resultArtifact != null) {
693                         resourceStructure.addArtifactToStructure(distributionClient, artifact, resultArtifact);
694                     }
695                 }
696
697                 // Deploy VF resource and artifacts
698                 logger.debug("Preparing to deploy Service: {}", iNotif.getServiceUUID());
699                 try {
700                     this.deployResourceStructure(resourceStructure, toscaResourceStructure);
701                 } catch (ArtifactInstallerException e) {
702                     deploySuccessful = false;
703                     errorMessage = e.getMessage();
704                     logger.error("Exception occurred", e);
705                 }
706
707                 this.sendCsarDeployNotification(iNotif, resourceStructure, toscaResourceStructure, deploySuccessful,
708                         errorMessage);
709             }
710
711
712         } catch (ASDCDownloadException | UnsupportedEncodingException e) {
713             logger.error("{} {} {} {} {} {}", MessageEnum.ASDC_GENERAL_EXCEPTION_ARG.toString(),
714                     "Exception caught during Installation of artifact", "ASDC", "processResourceNotification",
715                     ErrorCode.BusinessProcesssError.getValue(), "Exception in processResourceNotification", e);
716         }
717     }
718
719     private String getMsoConfigPath() {
720         String msoConfigPath = System.getProperty("mso.config.path");
721         if (msoConfigPath == null) {
722             logger.info("Unable to find the system property mso.config.path, use the default configuration");
723             msoConfigPath = asdcConfig.getPropertyOrNull("mso.config.defaultpath");
724         }
725         if (msoConfigPath == null) {
726             logger.info("Unable to find the property: {} from configuration.", "mso.config.defaultpath");
727             msoConfigPath = "";
728         }
729         logger.info("MSO config path is: {}", msoConfigPath);
730         return msoConfigPath;
731     }
732
733     protected void processCsarServiceArtifacts(INotificationData iNotif,
734             ToscaResourceStructure toscaResourceStructure) {
735
736         List<IArtifactInfo> serviceArtifacts = iNotif.getServiceArtifacts();
737
738         for (IArtifactInfo artifact : serviceArtifacts) {
739
740             if (artifact.getArtifactType().equals(ASDCConfiguration.TOSCA_CSAR)) {
741
742                 try {
743
744                     toscaResourceStructure.setToscaArtifact(artifact);
745
746                     IDistributionClientDownloadResult resultArtifact =
747                             this.downloadTheArtifact(artifact, iNotif.getDistributionID());
748
749                     writeArtifactToFile(artifact, resultArtifact);
750
751                     toscaResourceStructure.updateResourceStructure(artifact);
752
753                     toscaResourceStructure.setServiceVersion(iNotif.getServiceVersion());
754
755                     logger.debug(ASDCNotificationLogging.dumpCSARNotification(iNotif, toscaResourceStructure));
756
757
758                 } catch (Exception e) {
759                     logger.error("{} {} {} {} {} {}", MessageEnum.ASDC_GENERAL_EXCEPTION_ARG.toString(),
760                             "Exception caught during processCsarServiceArtifacts", "ASDC",
761                             "processCsarServiceArtifacts", ErrorCode.BusinessProcesssError.getValue(),
762                             "Exception in processCsarServiceArtifacts", e);
763                 }
764             } else if (artifact.getArtifactType().equals(ASDCConfiguration.WORKFLOWS)) {
765
766                 try {
767
768                     IDistributionClientDownloadResult resultArtifact =
769                             this.downloadTheArtifact(artifact, iNotif.getDistributionID());
770
771                     writeArtifactToFile(artifact, resultArtifact);
772
773                     toscaResourceStructure.setToscaArtifact(artifact);
774
775                     logger.debug(ASDCNotificationLogging.dumpASDCNotification(iNotif));
776
777
778                 } catch (Exception e) {
779                     logger.info("Whats the error {}", e.getMessage());
780                     logger.error("{} {} {} {} {} {}", MessageEnum.ASDC_GENERAL_EXCEPTION_ARG.toString(),
781                             "Exception caught during processCsarServiceArtifacts", "ASDC",
782                             "processCsarServiceArtifacts", ErrorCode.BusinessProcesssError.getValue(),
783                             "Exception in processCsarServiceArtifacts", e);
784                 }
785             }
786
787
788         }
789     }
790
791     private static final String UNKNOWN = "Unknown";
792
793     /**
794      * @return the address of the ASDC we are connected to.
795      */
796     public String getAddress() {
797         if (asdcConfig != null) {
798             return asdcConfig.getAsdcAddress();
799         }
800         return UNKNOWN;
801     }
802
803     /**
804      * @return the environment name of the ASDC we are connected to.
805      */
806     public String getEnvironment() {
807         if (asdcConfig != null) {
808             return asdcConfig.getEnvironmentName();
809         }
810         return UNKNOWN;
811     }
812 }