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