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