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