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