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