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