Add properties to model
[clamp.git] / src / main / java / org / onap / clamp / clds / sdc / controller / SdcSingleController.java
1 /*-\r
2  * ============LICENSE_START=======================================================\r
3  * ONAP CLAMP\r
4  * ================================================================================\r
5  * Copyright (C) 2018 AT&T Intellectual Property. All rights\r
6  *                             reserved.\r
7  * ================================================================================\r
8  * Licensed under the Apache License, Version 2.0 (the "License");\r
9  * you may not use this file except in compliance with the License.\r
10  * You may obtain a copy of the License at\r
11  *\r
12  * http://www.apache.org/licenses/LICENSE-2.0\r
13  *\r
14  * Unless required by applicable law or agreed to in writing, software\r
15  * distributed under the License is distributed on an "AS IS" BASIS,\r
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
17  * See the License for the specific language governing permissions and\r
18  * limitations under the License.\r
19  * ============LICENSE_END============================================\r
20  * ===================================================================\r
21  * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
22  */\r
23 \r
24 package org.onap.clamp.clds.sdc.controller;\r
25 \r
26 import com.att.eelf.configuration.EELFLogger;\r
27 import com.att.eelf.configuration.EELFManager;\r
28 \r
29 import java.util.Date;\r
30 \r
31 import org.onap.clamp.clds.config.ClampProperties;\r
32 import org.onap.clamp.clds.config.sdc.SdcSingleControllerConfiguration;\r
33 import org.onap.clamp.clds.exception.sdc.controller.CsarHandlerException;\r
34 import org.onap.clamp.clds.exception.sdc.controller.SdcArtifactInstallerException;\r
35 import org.onap.clamp.clds.exception.sdc.controller.SdcControllerException;\r
36 import org.onap.clamp.clds.exception.sdc.controller.SdcDownloadException;\r
37 import org.onap.clamp.clds.exception.sdc.controller.SdcParametersException;\r
38 import org.onap.clamp.clds.sdc.controller.installer.CsarHandler;\r
39 import org.onap.clamp.clds.sdc.controller.installer.CsarInstaller;\r
40 import org.onap.clamp.clds.util.LoggingUtils;\r
41 import org.openecomp.sdc.api.IDistributionClient;\r
42 import org.openecomp.sdc.api.consumer.IDistributionStatusMessage;\r
43 import org.openecomp.sdc.api.consumer.INotificationCallback;\r
44 import org.openecomp.sdc.api.notification.IArtifactInfo;\r
45 import org.openecomp.sdc.api.notification.INotificationData;\r
46 import org.openecomp.sdc.api.results.IDistributionClientDownloadResult;\r
47 import org.openecomp.sdc.api.results.IDistributionClientResult;\r
48 import org.openecomp.sdc.impl.DistributionClientFactory;\r
49 import org.openecomp.sdc.tosca.parser.exceptions.SdcToscaParserException;\r
50 import org.openecomp.sdc.utils.DistributionActionResultEnum;\r
51 import org.openecomp.sdc.utils.DistributionStatusEnum;\r
52 import org.springframework.beans.factory.annotation.Autowired;\r
53 \r
54 /**\r
55  * This class handles one sdc controller defined in the config. It's\r
56  * instantiated by Spring config.\r
57  */\r
58 public class SdcSingleController {\r
59 \r
60     private static final EELFLogger logger = EELFManager.getInstance().getLogger(SdcSingleController.class);\r
61     protected boolean isAsdcClientAutoManaged = false;\r
62     @Autowired\r
63     protected CsarInstaller resourceInstaller;\r
64     @Autowired\r
65     protected ClampProperties refProp;\r
66     public static final String CONFIG_SDC_FOLDER = "sdc.csarFolder";\r
67 \r
68     /**\r
69      * Inner class for Notification callback\r
70      */\r
71     private final class ASDCNotificationCallBack implements INotificationCallback {\r
72 \r
73         private SdcSingleController asdcController;\r
74 \r
75         ASDCNotificationCallBack(SdcSingleController controller) {\r
76             asdcController = controller;\r
77         }\r
78 \r
79         /**\r
80          * This method can be called multiple times at the same moment. The\r
81          * controller must be thread safe !\r
82          */\r
83         @Override\r
84         public void activateCallback(INotificationData iNotif) {\r
85             Date startTime = new Date();\r
86             String event = "Receive a callback notification in ASDC, nb of resources: " + iNotif.getResources().size();\r
87             logger.debug(event);\r
88             asdcController.treatNotification(iNotif);\r
89             LoggingUtils.setTimeContext(startTime, new Date());\r
90             LoggingUtils.setResponseContext("0", "SDC Notification received and processed successfully",\r
91                     this.getClass().getName());\r
92         }\r
93     }\r
94 \r
95     // ***** Controller STATUS code\r
96     protected int nbOfNotificationsOngoing = 0;\r
97 \r
98     public int getNbOfNotificationsOngoing() {\r
99         return nbOfNotificationsOngoing;\r
100     }\r
101 \r
102     private SdcSingleControllerStatus controllerStatus = SdcSingleControllerStatus.STOPPED;\r
103 \r
104     protected final synchronized void changeControllerStatus(SdcSingleControllerStatus newControllerStatus) {\r
105         switch (newControllerStatus) {\r
106             case BUSY:\r
107                 ++this.nbOfNotificationsOngoing;\r
108                 this.controllerStatus = newControllerStatus;\r
109                 break;\r
110             case IDLE:\r
111                 if (this.nbOfNotificationsOngoing > 1) {\r
112                     --this.nbOfNotificationsOngoing;\r
113                 } else {\r
114                     this.nbOfNotificationsOngoing = 0;\r
115                     this.controllerStatus = newControllerStatus;\r
116                 }\r
117                 break;\r
118             default:\r
119                 this.controllerStatus = newControllerStatus;\r
120                 break;\r
121         }\r
122     }\r
123 \r
124     public final synchronized SdcSingleControllerStatus getControllerStatus() {\r
125         return this.controllerStatus;\r
126     }\r
127 \r
128     // ***** END of Controller STATUS code\r
129     protected SdcSingleControllerConfiguration sdcConfig;\r
130     private IDistributionClient distributionClient;\r
131 \r
132     public SdcSingleController(SdcSingleControllerConfiguration sdcSingleConfig, boolean isClientAutoManaged) {\r
133         this.isAsdcClientAutoManaged = isClientAutoManaged;\r
134         sdcConfig = sdcSingleConfig;\r
135     }\r
136 \r
137     /**\r
138      * This method initializes the SDC Controller and the SDC Client.\r
139      *\r
140      * @throws SdcControllerException\r
141      *             It throws an exception if the SDC Client cannot be\r
142      *             instantiated or if an init attempt is done when already\r
143      *             initialized\r
144      * @throws SdcParametersException\r
145      *             If there is an issue with the parameters provided\r
146      */\r
147     public void initSdc() throws SdcControllerException {\r
148         logger.debug("Attempt to initialize the SDC Controller");\r
149         if (this.getControllerStatus() != SdcSingleControllerStatus.STOPPED) {\r
150             throw new SdcControllerException("The controller is already initialized, call the closeSDC method first");\r
151         }\r
152         if (this.distributionClient == null) {\r
153             distributionClient = DistributionClientFactory.createDistributionClient();\r
154         }\r
155         IDistributionClientResult result = this.distributionClient.init(sdcConfig, new ASDCNotificationCallBack(this));\r
156         if (!result.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) {\r
157             logger.error("ASDC distribution client init failed with reason:" + result.getDistributionMessageResult());\r
158             this.changeControllerStatus(SdcSingleControllerStatus.STOPPED);\r
159             throw new SdcControllerException("Initialization of the SDC Controller failed with reason: "\r
160                     + result.getDistributionMessageResult());\r
161         }\r
162         result = this.distributionClient.start();\r
163         if (!result.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) {\r
164             logger.debug("SDC distribution client start failed with reason:" + result.getDistributionMessageResult());\r
165             this.changeControllerStatus(SdcSingleControllerStatus.STOPPED);\r
166             throw new SdcControllerException(\r
167                     "Startup of the SDC Controller failed with reason: " + result.getDistributionMessageResult());\r
168         }\r
169         this.changeControllerStatus(SdcSingleControllerStatus.IDLE);\r
170     }\r
171 \r
172     /**\r
173      * This method closes the SDC Controller and the SDC Client.\r
174      *\r
175      * @throws SdcControllerException\r
176      *             It throws an exception if the SDC Client cannot be closed\r
177      *             because it's currently BUSY in processing notifications.\r
178      */\r
179     public void closeSdc() throws SdcControllerException {\r
180         if (this.getControllerStatus() == SdcSingleControllerStatus.BUSY) {\r
181             throw new SdcControllerException("Cannot close the ASDC controller as it's currently in BUSY state");\r
182         }\r
183         if (this.distributionClient != null) {\r
184             this.distributionClient.stop();\r
185             // If auto managed we can set it to Null, SdcController controls it.\r
186             // In the other case the client of this class has specified it, so\r
187             // we can't reset it\r
188             if (isAsdcClientAutoManaged) {\r
189                 // Next init will initialize it with a new Sdc Client\r
190                 this.distributionClient = null;\r
191             }\r
192         }\r
193         this.changeControllerStatus(SdcSingleControllerStatus.STOPPED);\r
194     }\r
195 \r
196     /**\r
197      * This method processes the notification received from Sdc.\r
198      * \r
199      * @param iNotif\r
200      *            The INotificationData\r
201      */\r
202     public void treatNotification(INotificationData iNotif) {\r
203         CsarHandler csar = null;\r
204         try {\r
205             logger.info("Notification received for service UUID:" + iNotif.getServiceUUID());\r
206             this.changeControllerStatus(SdcSingleControllerStatus.BUSY);\r
207             csar = new CsarHandler(iNotif, this.sdcConfig.getSdcControllerName(),\r
208                     refProp.getStringValue(CONFIG_SDC_FOLDER));\r
209             if (resourceInstaller.isCsarAlreadyDeployed(csar)) {\r
210                 csar.save(downloadTheArtifact(csar.getArtifactElement()));\r
211                 this.sendASDCNotification(NotificationType.DOWNLOAD, csar.getArtifactElement().getArtifactURL(),\r
212                         sdcConfig.getConsumerID(), iNotif.getDistributionID(), DistributionStatusEnum.DOWNLOAD_OK, null,\r
213                         System.currentTimeMillis());\r
214                 resourceInstaller.installTheCsar(csar);\r
215                 this.sendASDCNotification(NotificationType.DEPLOY, csar.getArtifactElement().getArtifactURL(),\r
216                         sdcConfig.getConsumerID(), iNotif.getDistributionID(), DistributionStatusEnum.DEPLOY_OK, null,\r
217                         System.currentTimeMillis());\r
218             } else {\r
219                 this.sendASDCNotification(NotificationType.DOWNLOAD, csar.getArtifactElement().getArtifactURL(),\r
220                         sdcConfig.getConsumerID(), iNotif.getDistributionID(),\r
221                         DistributionStatusEnum.ALREADY_DOWNLOADED, null, System.currentTimeMillis());\r
222                 this.sendASDCNotification(NotificationType.DOWNLOAD, csar.getArtifactElement().getArtifactURL(),\r
223                         sdcConfig.getConsumerID(), iNotif.getDistributionID(), DistributionStatusEnum.ALREADY_DEPLOYED,\r
224                         null, System.currentTimeMillis());\r
225             }\r
226         } catch (SdcArtifactInstallerException e) {\r
227             logger.error("SdcArtifactInstallerException exception caught during the notification processing", e);\r
228             this.sendASDCNotification(NotificationType.DEPLOY, csar.getArtifactElement().getArtifactURL(),\r
229                     sdcConfig.getConsumerID(), iNotif.getDistributionID(), DistributionStatusEnum.DEPLOY_ERROR,\r
230                     e.getMessage(), System.currentTimeMillis());\r
231         } catch (SdcDownloadException e) {\r
232             logger.error("SdcDownloadException exception caught during the notification processing", e);\r
233             this.sendASDCNotification(NotificationType.DOWNLOAD, csar.getArtifactElement().getArtifactURL(),\r
234                     sdcConfig.getConsumerID(), iNotif.getDistributionID(), DistributionStatusEnum.DOWNLOAD_ERROR,\r
235                     e.getMessage(), System.currentTimeMillis());\r
236         } catch (CsarHandlerException e) {\r
237             logger.error("CsarHandlerException exception caught during the notification processing", e);\r
238             this.sendASDCNotification(NotificationType.DOWNLOAD, csar.getArtifactElement().getArtifactURL(),\r
239                     sdcConfig.getConsumerID(), iNotif.getDistributionID(), DistributionStatusEnum.DOWNLOAD_ERROR,\r
240                     e.getMessage(), System.currentTimeMillis());\r
241         } catch (SdcToscaParserException e) {\r
242             this.sendASDCNotification(NotificationType.DEPLOY, csar.getArtifactElement().getArtifactURL(),\r
243                     sdcConfig.getConsumerID(), iNotif.getDistributionID(), DistributionStatusEnum.DEPLOY_ERROR,\r
244                     e.getMessage(), System.currentTimeMillis());\r
245         } catch (RuntimeException e) {\r
246             logger.error("Unexpected exception caught during the notification processing", e);\r
247         } finally {\r
248             this.changeControllerStatus(SdcSingleControllerStatus.IDLE);\r
249         }\r
250     }\r
251 \r
252     private enum NotificationType {\r
253         DOWNLOAD, DEPLOY\r
254     }\r
255 \r
256     private IDistributionClientDownloadResult downloadTheArtifact(IArtifactInfo artifact) throws SdcDownloadException {\r
257         logger.debug("Trying to download the artifact : " + artifact.getArtifactURL() + " UUID: "\r
258                 + artifact.getArtifactUUID());\r
259         IDistributionClientDownloadResult downloadResult;\r
260         try {\r
261             downloadResult = distributionClient.download(artifact);\r
262             if (null == downloadResult) {\r
263                 logger.info("downloadResult is Null for: " + artifact.getArtifactUUID());\r
264                 return null;\r
265             }\r
266         } catch (RuntimeException e) {\r
267             throw new SdcDownloadException("Exception caught when downloading the artifact", e);\r
268         }\r
269         if (DistributionActionResultEnum.SUCCESS.equals(downloadResult.getDistributionActionResult())) {\r
270             logger.info("Successfully downloaded the artifact " + artifact.getArtifactURL() + " UUID "\r
271                     + artifact.getArtifactUUID() + "Size of payload " + downloadResult.getArtifactPayload().length);\r
272         } else {\r
273             throw new SdcDownloadException("Artifact " + artifact.getArtifactName()\r
274                     + " could not be downloaded from ASDC URL " + artifact.getArtifactURL() + " UUID "\r
275                     + artifact.getArtifactUUID() + ")" + System.lineSeparator() + "Error message is "\r
276                     + downloadResult.getDistributionMessageResult() + System.lineSeparator());\r
277         }\r
278         return downloadResult;\r
279     }\r
280 \r
281     private void sendASDCNotification(NotificationType notificationType, String artifactURL, String consumerID,\r
282             String distributionID, DistributionStatusEnum status, String errorReason, long timestamp) {\r
283         String event = "Sending " + notificationType.name() + "(" + status.name() + ")"\r
284                 + " notification to ASDC for artifact:" + artifactURL;\r
285         if (errorReason != null) {\r
286             event = event + "(" + errorReason + ")";\r
287         }\r
288         logger.info(event);\r
289         String action = "";\r
290         try {\r
291             IDistributionStatusMessage message = new DistributionStatusMessage(artifactURL, consumerID, distributionID,\r
292                     status, timestamp);\r
293             switch (notificationType) {\r
294                 case DOWNLOAD:\r
295                     if (errorReason != null) {\r
296                         this.distributionClient.sendDownloadStatus(message, errorReason);\r
297                     } else {\r
298                         this.distributionClient.sendDownloadStatus(message);\r
299                     }\r
300                     action = "sendDownloadStatus";\r
301                     break;\r
302                 case DEPLOY:\r
303                     if (errorReason != null) {\r
304                         this.distributionClient.sendDeploymentStatus(message, errorReason);\r
305                     } else {\r
306                         this.distributionClient.sendDeploymentStatus(message);\r
307                     }\r
308                     action = "sendDeploymentdStatus";\r
309                     break;\r
310                 default:\r
311                     break;\r
312             }\r
313         } catch (RuntimeException e) {\r
314             logger.warn("Unable to send the Sdc Notification (" + action + ") due to an exception", e);\r
315         }\r
316         logger.info("Sdc Notification sent successfully(" + action + ")");\r
317     }\r
318 }\r