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