cleaned up clds service code
[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  * Modifications copyright (c) 2018 Nokia\r
21  * ===================================================================\r
22  * \r
23  */\r
24 \r
25 package org.onap.clamp.clds.sdc.controller;\r
26 \r
27 import com.att.eelf.configuration.EELFLogger;\r
28 import com.att.eelf.configuration.EELFManager;\r
29 \r
30 import java.util.Date;\r
31 import java.util.Map.Entry;\r
32 import java.util.concurrent.ThreadLocalRandom;\r
33 \r
34 import org.onap.clamp.clds.config.ClampProperties;\r
35 import org.onap.clamp.clds.config.sdc.SdcSingleControllerConfiguration;\r
36 import org.onap.clamp.clds.exception.sdc.controller.CsarHandlerException;\r
37 import org.onap.clamp.clds.exception.sdc.controller.SdcArtifactInstallerException;\r
38 import org.onap.clamp.clds.exception.sdc.controller.SdcControllerException;\r
39 import org.onap.clamp.clds.exception.sdc.controller.SdcDownloadException;\r
40 import org.onap.clamp.clds.exception.sdc.controller.SdcParametersException;\r
41 import org.onap.clamp.clds.sdc.controller.installer.BlueprintArtifact;\r
42 import org.onap.clamp.clds.sdc.controller.installer.CsarHandler;\r
43 import org.onap.clamp.clds.sdc.controller.installer.CsarInstaller;\r
44 import org.onap.clamp.clds.util.LoggingUtils;\r
45 import org.onap.sdc.api.IDistributionClient;\r
46 import org.onap.sdc.api.consumer.IDistributionStatusMessage;\r
47 import org.onap.sdc.api.consumer.INotificationCallback;\r
48 import org.onap.sdc.api.notification.IArtifactInfo;\r
49 import org.onap.sdc.api.notification.INotificationData;\r
50 import org.onap.sdc.api.results.IDistributionClientDownloadResult;\r
51 import org.onap.sdc.api.results.IDistributionClientResult;\r
52 import org.onap.sdc.impl.DistributionClientFactory;\r
53 import org.onap.sdc.tosca.parser.exceptions.SdcToscaParserException;\r
54 import org.onap.sdc.utils.DistributionActionResultEnum;\r
55 import org.onap.sdc.utils.DistributionStatusEnum;\r
56 \r
57 /**\r
58  * This class handles one sdc controller defined in the config.\r
59  */\r
60 public class SdcSingleController {\r
61 \r
62     private static final EELFLogger logger = EELFManager.getInstance().getLogger(SdcSingleController.class);\r
63     private boolean isSdcClientAutoManaged = false;\r
64     private CsarInstaller csarInstaller;\r
65     private ClampProperties refProp;\r
66     public static final String CONFIG_SDC_FOLDER = "sdc.csarFolder";\r
67     private int nbOfNotificationsOngoing = 0;\r
68     private SdcSingleControllerStatus controllerStatus = SdcSingleControllerStatus.STOPPED;\r
69     private SdcSingleControllerConfiguration sdcConfig;\r
70     private IDistributionClient distributionClient;\r
71 \r
72     /**\r
73      * Inner class for Notification callback\r
74      */\r
75     private final class SdcNotificationCallBack implements INotificationCallback {\r
76 \r
77         private SdcSingleController sdcController;\r
78 \r
79         SdcNotificationCallBack(SdcSingleController controller) {\r
80             sdcController = controller;\r
81         }\r
82 \r
83         /**\r
84          * This method can be called multiple times at the same moment. The\r
85          * controller must be thread safe !\r
86          */\r
87         @Override\r
88         public void activateCallback(INotificationData iNotif) {\r
89             Date startTime = new Date();\r
90             logger.info("Receive a callback notification in SDC, nb of resources: " + iNotif.getResources().size());\r
91             sdcController.treatNotification(iNotif);\r
92             LoggingUtils.setTimeContext(startTime, new Date());\r
93             LoggingUtils.setResponseContext("0", "SDC Notification received and processed successfully",\r
94                     this.getClass().getName());\r
95         }\r
96     }\r
97 \r
98     public int getNbOfNotificationsOngoing() {\r
99         return nbOfNotificationsOngoing;\r
100     }\r
101 \r
102     private void changeControllerStatusIdle() {\r
103         if (this.nbOfNotificationsOngoing > 1) {\r
104             --this.nbOfNotificationsOngoing;\r
105         } else {\r
106             this.nbOfNotificationsOngoing = 0;\r
107             this.controllerStatus = SdcSingleControllerStatus.IDLE;\r
108         }\r
109     }\r
110 \r
111     protected final synchronized void changeControllerStatus(SdcSingleControllerStatus newControllerStatus) {\r
112         switch (newControllerStatus) {\r
113             case BUSY:\r
114                 ++this.nbOfNotificationsOngoing;\r
115                 this.controllerStatus = newControllerStatus;\r
116                 break;\r
117             case IDLE:\r
118                 this.changeControllerStatusIdle();\r
119                 break;\r
120             default:\r
121                 this.controllerStatus = newControllerStatus;\r
122                 break;\r
123         }\r
124     }\r
125 \r
126     public final synchronized SdcSingleControllerStatus getControllerStatus() {\r
127         return this.controllerStatus;\r
128     }\r
129 \r
130     public SdcSingleController(ClampProperties clampProp, CsarInstaller csarInstaller,\r
131             SdcSingleControllerConfiguration sdcSingleConfig, boolean isClientAutoManaged) {\r
132         this.isSdcClientAutoManaged = isClientAutoManaged;\r
133         this.sdcConfig = sdcSingleConfig;\r
134         this.refProp = clampProp;\r
135         this.csarInstaller = csarInstaller;\r
136     }\r
137 \r
138     /**\r
139      * This method initializes the SDC Controller and the SDC Client.\r
140      *\r
141      * @throws SdcControllerException\r
142      *             It throws an exception if the SDC Client cannot be\r
143      *             instantiated or if an init attempt is done when already\r
144      *             initialized\r
145      * @throws SdcParametersException\r
146      *             If there is an issue with the parameters provided\r
147      */\r
148     public void initSdc() throws SdcControllerException {\r
149         logger.info("Attempt to initialize the SDC Controller: " + sdcConfig.getSdcControllerName());\r
150         if (this.getControllerStatus() != SdcSingleControllerStatus.STOPPED) {\r
151             throw new SdcControllerException("The controller is already initialized, call the closeSDC method first");\r
152         }\r
153         if (distributionClient == null) {\r
154             distributionClient = DistributionClientFactory.createDistributionClient();\r
155         }\r
156         IDistributionClientResult result = distributionClient.init(sdcConfig, new SdcNotificationCallBack(this));\r
157         if (!result.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) {\r
158             logger.error("SDC distribution client init failed with reason:" + result.getDistributionMessageResult());\r
159             this.changeControllerStatus(SdcSingleControllerStatus.STOPPED);\r
160             throw new SdcControllerException("Initialization of the SDC Controller failed with reason: "\r
161                     + result.getDistributionMessageResult());\r
162         }\r
163         logger.info("SDC Controller successfully initialized: " + sdcConfig.getSdcControllerName());\r
164         logger.info("Attempt to start the SDC Controller: " + sdcConfig.getSdcControllerName());\r
165         result = this.distributionClient.start();\r
166         if (!result.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) {\r
167             logger.error("SDC distribution client start failed with reason:" + result.getDistributionMessageResult());\r
168             this.changeControllerStatus(SdcSingleControllerStatus.STOPPED);\r
169             throw new SdcControllerException(\r
170                     "Startup of the SDC Controller failed with reason: " + result.getDistributionMessageResult());\r
171         }\r
172         logger.info("SDC Controller successfully started: " + sdcConfig.getSdcControllerName());\r
173         this.changeControllerStatus(SdcSingleControllerStatus.IDLE);\r
174     }\r
175 \r
176     /**\r
177      * This method closes the SDC Controller and the SDC Client.\r
178      *\r
179      * @throws SdcControllerException\r
180      *             It throws an exception if the SDC Client cannot be closed\r
181      *             because it's currently BUSY in processing notifications.\r
182      */\r
183     public void closeSdc() throws SdcControllerException {\r
184         if (this.getControllerStatus() == SdcSingleControllerStatus.BUSY) {\r
185             throw new SdcControllerException("Cannot close the SDC controller as it's currently in BUSY state");\r
186         }\r
187         if (this.distributionClient != null) {\r
188             this.distributionClient.stop();\r
189             // If auto managed we can set it to Null, SdcController controls it.\r
190             // In the other case the client of this class has specified it, so\r
191             // we can't reset it\r
192             if (isSdcClientAutoManaged) {\r
193                 // Next init will initialize it with a new SDC Client\r
194                 this.distributionClient = null;\r
195             }\r
196         }\r
197         this.changeControllerStatus(SdcSingleControllerStatus.STOPPED);\r
198     }\r
199 \r
200     private void sendAllNotificationForCsarHandler(INotificationData iNotif, CsarHandler csar,\r
201             NotificationType notificationType, DistributionStatusEnum distributionStatus, String errorMessage) {\r
202         if (csar != null) {\r
203             // Notify for the CSAR\r
204             this.sendSdcNotification(notificationType, csar.getArtifactElement().getArtifactURL(),\r
205                     sdcConfig.getConsumerID(), iNotif.getDistributionID(), distributionStatus, errorMessage,\r
206                     System.currentTimeMillis());\r
207             // Notify for all VF resources found\r
208             for (Entry<String, BlueprintArtifact> blueprint : csar.getMapOfBlueprints().entrySet()) {\r
209                 // Normally always 1 artifact in resource for Clamp as we\r
210                 // specified\r
211                 // only VF_METADATA type\r
212                 this.sendSdcNotification(notificationType,\r
213                         blueprint.getValue().getResourceAttached().getArtifacts().get(0).getArtifactURL(),\r
214                         sdcConfig.getConsumerID(), iNotif.getDistributionID(), distributionStatus, errorMessage,\r
215                         System.currentTimeMillis());\r
216             }\r
217         } else {\r
218             this.sendSdcNotification(notificationType, null, sdcConfig.getConsumerID(), iNotif.getDistributionID(),\r
219                     distributionStatus, errorMessage, System.currentTimeMillis());\r
220         }\r
221     }\r
222 \r
223     /**\r
224      * This method processes the notification received from Sdc.\r
225      * \r
226      * @param iNotif\r
227      *            The INotificationData\r
228      */\r
229     public void treatNotification(INotificationData iNotif) {\r
230         CsarHandler csar = null;\r
231         try {\r
232             // wait for a random time, so that 2 running Clamp will not treat\r
233             // the same Notification at the same time\r
234             Thread.sleep(ThreadLocalRandom.current().nextInt(1, 10) * 1000L);\r
235             logger.info("Notification received for service UUID:" + iNotif.getServiceUUID());\r
236             this.changeControllerStatus(SdcSingleControllerStatus.BUSY);\r
237             csar = new CsarHandler(iNotif, this.sdcConfig.getSdcControllerName(),\r
238                     refProp.getStringValue(CONFIG_SDC_FOLDER));\r
239             csar.save(downloadTheArtifact(csar.getArtifactElement()));\r
240             if (csarInstaller.isCsarAlreadyDeployed(csar)) {\r
241                 sendAllNotificationForCsarHandler(iNotif, csar, NotificationType.DOWNLOAD,\r
242                         DistributionStatusEnum.ALREADY_DOWNLOADED, null);\r
243                 sendAllNotificationForCsarHandler(iNotif, csar, NotificationType.DEPLOY,\r
244                         DistributionStatusEnum.ALREADY_DEPLOYED, null);\r
245             } else {\r
246                 sendAllNotificationForCsarHandler(iNotif, csar, NotificationType.DOWNLOAD,\r
247                         DistributionStatusEnum.DOWNLOAD_OK, null);\r
248                 csarInstaller.installTheCsar(csar);\r
249                 sendAllNotificationForCsarHandler(iNotif, csar, NotificationType.DEPLOY,\r
250                         DistributionStatusEnum.DEPLOY_OK, null);\r
251             }\r
252         } catch (SdcArtifactInstallerException | SdcToscaParserException e) {\r
253             logger.error("SdcArtifactInstallerException exception caught during the notification processing", e);\r
254             sendAllNotificationForCsarHandler(iNotif, csar, NotificationType.DEPLOY,\r
255                     DistributionStatusEnum.DEPLOY_ERROR, e.getMessage());\r
256         } catch (SdcDownloadException | CsarHandlerException e) {\r
257             logger.error("SdcDownloadException exception caught during the notification processing", e);\r
258             sendAllNotificationForCsarHandler(iNotif, csar, NotificationType.DOWNLOAD,\r
259                     DistributionStatusEnum.DOWNLOAD_ERROR, e.getMessage());\r
260         } catch (InterruptedException e) {\r
261             logger.error("Interrupt exception caught during the notification processing", e);\r
262             sendAllNotificationForCsarHandler(iNotif, csar, NotificationType.DEPLOY,\r
263                     DistributionStatusEnum.DEPLOY_ERROR, e.getMessage());\r
264             Thread.currentThread().interrupt();\r
265         } catch (RuntimeException e) {\r
266             logger.error("Unexpected exception caught during the notification processing", e);\r
267             sendAllNotificationForCsarHandler(iNotif, csar, NotificationType.DEPLOY,\r
268                     DistributionStatusEnum.DEPLOY_ERROR, e.getMessage());\r
269         } finally {\r
270             this.changeControllerStatus(SdcSingleControllerStatus.IDLE);\r
271         }\r
272     }\r
273 \r
274     private enum NotificationType {\r
275         DOWNLOAD, DEPLOY\r
276     }\r
277 \r
278     private IDistributionClientDownloadResult downloadTheArtifact(IArtifactInfo artifact) throws SdcDownloadException {\r
279         logger.info("Trying to download the artifact : " + artifact.getArtifactURL() + " UUID: "\r
280                 + artifact.getArtifactUUID());\r
281         IDistributionClientDownloadResult downloadResult;\r
282         try {\r
283             downloadResult = distributionClient.download(artifact);\r
284             if (null == downloadResult) {\r
285                 logger.info("downloadResult is Null for: " + artifact.getArtifactUUID());\r
286                 return null;\r
287             }\r
288         } catch (RuntimeException e) {\r
289             throw new SdcDownloadException("Exception caught when downloading the artifact", e);\r
290         }\r
291         if (DistributionActionResultEnum.SUCCESS.equals(downloadResult.getDistributionActionResult())) {\r
292             logger.info("Successfully downloaded the artifact " + artifact.getArtifactURL() + " UUID "\r
293                     + artifact.getArtifactUUID() + "Size of payload " + downloadResult.getArtifactPayload().length);\r
294         } else {\r
295             throw new SdcDownloadException("Artifact " + artifact.getArtifactName()\r
296                     + " could not be downloaded from SDC URL " + artifact.getArtifactURL() + " UUID "\r
297                     + artifact.getArtifactUUID() + ")" + System.lineSeparator() + "Error message is "\r
298                     + downloadResult.getDistributionMessageResult() + System.lineSeparator());\r
299         }\r
300         return downloadResult;\r
301     }\r
302 \r
303     private void sendSdcNotification(NotificationType notificationType, String artifactURL, String consumerID,\r
304             String distributionID, DistributionStatusEnum status, String errorReason, long timestamp) {\r
305         String event = "Sending " + notificationType.name() + "(" + status.name() + ")"\r
306                 + " notification to SDC for artifact:" + artifactURL;\r
307         if (errorReason != null) {\r
308             event = event + "(" + errorReason + ")";\r
309         }\r
310         logger.info(event);\r
311         String action = "";\r
312         try {\r
313             IDistributionStatusMessage message = new DistributionStatusMessage(artifactURL, consumerID, distributionID,\r
314                     status, timestamp);\r
315             switch (notificationType) {\r
316                 case DOWNLOAD:\r
317                     this.sendDownloadStatus(message, errorReason);\r
318                     action = "sendDownloadStatus";\r
319                     break;\r
320                 case DEPLOY:\r
321                     this.sendDeploymentStatus(message, errorReason);\r
322                     action = "sendDeploymentdStatus";\r
323                     break;\r
324                 default:\r
325                     break;\r
326             }\r
327         } catch (RuntimeException e) {\r
328             logger.warn("Unable to send the SDC Notification (" + action + ") due to an exception", e);\r
329         }\r
330         logger.info("SDC Notification sent successfully(" + action + ")");\r
331     }\r
332 \r
333     private void sendDownloadStatus(IDistributionStatusMessage message, String errorReason) {\r
334         if (errorReason != null) {\r
335             this.distributionClient.sendDownloadStatus(message, errorReason);\r
336         } else {\r
337             this.distributionClient.sendDownloadStatus(message);\r
338         }\r
339     }\r
340 \r
341     private void sendDeploymentStatus(IDistributionStatusMessage message, String errorReason) {\r
342         if (errorReason != null) {\r
343             this.distributionClient.sendDeploymentStatus(message, errorReason);\r
344         } else {\r
345             this.distributionClient.sendDeploymentStatus(message);\r
346         }\r
347     }\r
348 }\r