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