14b0f1ec90397d724381c05c3fc895095bdc1b30
[policy/distribution.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2018 Ericsson. All rights reserved.
4  * ================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * SPDX-License-Identifier: Apache-2.0
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.distribution.reception.handling.sdc;
22
23 import java.io.File;
24 import java.io.FileOutputStream;
25 import java.io.IOException;
26 import java.nio.file.Files;
27 import java.nio.file.Path;
28
29 import org.onap.policy.common.logging.flexlogger.FlexLogger;
30 import org.onap.policy.common.logging.flexlogger.Logger;
31 import org.onap.policy.common.parameters.ParameterService;
32 import org.onap.policy.distribution.model.Csar;
33 import org.onap.policy.distribution.reception.decoding.PluginInitializationException;
34 import org.onap.policy.distribution.reception.decoding.PluginTerminationException;
35 import org.onap.policy.distribution.reception.decoding.PolicyDecodingException;
36 import org.onap.policy.distribution.reception.handling.AbstractReceptionHandler;
37 import org.onap.policy.distribution.reception.handling.sdc.exceptions.ArtifactDownloadException;
38 import org.onap.sdc.api.IDistributionClient;
39 import org.onap.sdc.api.consumer.IComponentDoneStatusMessage;
40 import org.onap.sdc.api.consumer.IDistributionStatusMessage;
41 import org.onap.sdc.api.consumer.INotificationCallback;
42 import org.onap.sdc.api.notification.IArtifactInfo;
43 import org.onap.sdc.api.notification.INotificationData;
44 import org.onap.sdc.api.results.IDistributionClientDownloadResult;
45 import org.onap.sdc.api.results.IDistributionClientResult;
46 import org.onap.sdc.impl.DistributionClientFactory;
47 import org.onap.sdc.utils.DistributionActionResultEnum;
48 import org.onap.sdc.utils.DistributionStatusEnum;
49
50 /**
51  * Handles reception of inputs from ONAP Service Design and Creation (SDC) from which policies may be decoded.
52  */
53 public class SdcReceptionHandler extends AbstractReceptionHandler implements INotificationCallback {
54
55     private static final Logger LOGGER = FlexLogger.getLogger(SdcReceptionHandler.class);
56
57     private SdcReceptionHandlerStatus sdcReceptionHandlerStatus = SdcReceptionHandlerStatus.STOPPED;
58     private SdcReceptionHandlerConfigurationParameterGroup handlerParameters;
59     private IDistributionClient distributionClient;
60     private SdcConfiguration sdcConfig;
61     private volatile int nbOfNotificationsOngoing = 0;
62
63     private enum DistributionStatusType {
64         DOWNLOAD, DEPLOY
65     }
66
67     @Override
68     protected void initializeReception(final String parameterGroupName) throws PluginInitializationException {
69         handlerParameters = ParameterService.get(parameterGroupName);
70         initializeSdcClient();
71         startSdcClient();
72     }
73
74     @Override
75     public void destroy() throws PluginTerminationException {
76         LOGGER.debug("Going to stop the SDC Client...");
77         if (distributionClient != null) {
78             final IDistributionClientResult clientResult = distributionClient.stop();
79             if (!clientResult.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) {
80                 final String message =
81                         "SDC client stop failed with reason:" + clientResult.getDistributionMessageResult();
82                 LOGGER.error(message);
83                 throw new PluginTerminationException(message);
84             }
85         }
86         changeSdcReceptionHandlerStatus(SdcReceptionHandlerStatus.STOPPED);
87         LOGGER.debug("SDC Client is stopped successfully");
88     }
89
90     @Override
91     public void activateCallback(final INotificationData notificationData) {
92         LOGGER.debug("Receieved the notification from SDC with ID: " + notificationData.getDistributionID());
93         changeSdcReceptionHandlerStatus(SdcReceptionHandlerStatus.BUSY);
94         processCsarServiceArtifacts(notificationData);
95         changeSdcReceptionHandlerStatus(SdcReceptionHandlerStatus.IDLE);
96         LOGGER.debug("Processed the notification from SDC with ID: " + notificationData.getDistributionID());
97     }
98
99     /**
100      * Method to change the status of this reception handler instance.
101      *
102      * @param newStatus the new status
103      */
104     private final synchronized void changeSdcReceptionHandlerStatus(final SdcReceptionHandlerStatus newStatus) {
105         switch (newStatus) {
106             case INIT:
107             case STOPPED:
108                 sdcReceptionHandlerStatus = newStatus;
109                 break;
110             case IDLE:
111                 handleIdleStatusChange(newStatus);
112                 break;
113             case BUSY:
114                 ++nbOfNotificationsOngoing;
115                 sdcReceptionHandlerStatus = newStatus;
116                 break;
117         }
118     }
119
120     /**
121      * Creates an instance of {@link IDistributionClient} from {@link DistributionClientFactory}.
122      *
123      * @return the {@link IDistributionClient} instance
124      */
125     protected IDistributionClient createSdcDistributionClient() {
126         return DistributionClientFactory.createDistributionClient();
127     }
128
129     /**
130      * Method to initialize the SDC client.
131      *
132      * @throws PluginInitializationException if the initialization of SDC Client fails
133      */
134     private void initializeSdcClient() throws PluginInitializationException {
135
136         LOGGER.debug("Initializing the SDC Client...");
137         if (sdcReceptionHandlerStatus != SdcReceptionHandlerStatus.STOPPED) {
138             final String message = "The SDC Client is already initialized";
139             LOGGER.error(message);
140             throw new PluginInitializationException(message);
141         }
142         sdcConfig = new SdcConfiguration(handlerParameters);
143         distributionClient = createSdcDistributionClient();
144         final IDistributionClientResult clientResult = distributionClient.init(sdcConfig, this);
145         if (!clientResult.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) {
146             changeSdcReceptionHandlerStatus(SdcReceptionHandlerStatus.STOPPED);
147             final String message =
148                     "SDC client initialization failed with reason:" + clientResult.getDistributionMessageResult();
149             LOGGER.error(message);
150             throw new PluginInitializationException(message);
151         }
152         LOGGER.debug("SDC Client is initialized successfully");
153         this.changeSdcReceptionHandlerStatus(SdcReceptionHandlerStatus.INIT);
154     }
155
156     /**
157      * Method to start the SDC client.
158      *
159      * @param configParameter the configuration parameters
160      * @throws PluginInitializationException if the start of SDC Client fails
161      */
162     private void startSdcClient() throws PluginInitializationException {
163
164         LOGGER.debug("Going to start the SDC Client...");
165         final IDistributionClientResult clientResult = distributionClient.start();
166         if (!clientResult.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) {
167             changeSdcReceptionHandlerStatus(SdcReceptionHandlerStatus.STOPPED);
168             final String message = "SDC client start failed with reason:" + clientResult.getDistributionMessageResult();
169             LOGGER.error(message);
170             throw new PluginInitializationException(message);
171         }
172         LOGGER.debug("SDC Client is started successfully");
173         this.changeSdcReceptionHandlerStatus(SdcReceptionHandlerStatus.IDLE);
174     }
175
176     /**
177      * Method to process csar service artifacts from incoming SDC notification.
178      *
179      * @param notificationData the notification from SDC
180      */
181     public void processCsarServiceArtifacts(final INotificationData notificationData) {
182         boolean artifactsProcessedSuccessfully = true;
183
184         for (final IArtifactInfo artifact : notificationData.getServiceArtifacts()) {
185             try {
186                 final IDistributionClientDownloadResult resultArtifact =
187                         downloadTheArtifact(artifact, notificationData);
188                 final Path filePath = writeArtifactToFile(artifact, resultArtifact);
189                 final Csar csarObject = new Csar(filePath.toString());
190                 inputReceived(csarObject);
191                 sendDistributionStatus(DistributionStatusType.DEPLOY, artifact.getArtifactURL(),
192                         notificationData.getDistributionID(), DistributionStatusEnum.DEPLOY_OK, null);
193                 deleteArtifactFile(filePath);
194             } catch (final ArtifactDownloadException | PolicyDecodingException exp) {
195                 LOGGER.error("Failed to process csar service artifacts ", exp);
196                 artifactsProcessedSuccessfully = false;
197                 sendDistributionStatus(DistributionStatusType.DEPLOY, artifact.getArtifactURL(),
198                         notificationData.getDistributionID(), DistributionStatusEnum.DEPLOY_ERROR,
199                         "Failed to deploy the artifact due to: " + exp.getMessage());
200             }
201         }
202         if (artifactsProcessedSuccessfully) {
203             sendComponentDoneStatus(notificationData.getDistributionID(), DistributionStatusEnum.COMPONENT_DONE_OK,
204                     null);
205         } else {
206             sendComponentDoneStatus(notificationData.getDistributionID(), DistributionStatusEnum.COMPONENT_DONE_ERROR,
207                     "Failed to process the artifact");
208         }
209     }
210
211     /**
212      * Method to download the distribution artifact.
213      *
214      * @param artifact the artifact
215      * @return the download result
216      * @throws ArtifactDownloadException if download fails
217      */
218     private IDistributionClientDownloadResult downloadTheArtifact(final IArtifactInfo artifact,
219             final INotificationData notificationData) throws ArtifactDownloadException {
220
221         final IDistributionClientDownloadResult downloadResult = distributionClient.download(artifact);
222         if (!downloadResult.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) {
223             final String message = "Failed to download artifact with name: " + artifact.getArtifactName() + " due to: "
224                     + downloadResult.getDistributionMessageResult();
225             LOGGER.error(message);
226             sendDistributionStatus(DistributionStatusType.DOWNLOAD, artifact.getArtifactURL(),
227                     notificationData.getDistributionID(), DistributionStatusEnum.DOWNLOAD_ERROR, message);
228             throw new ArtifactDownloadException(message);
229         }
230         sendDistributionStatus(DistributionStatusType.DOWNLOAD, artifact.getArtifactURL(),
231                 notificationData.getDistributionID(), DistributionStatusEnum.DOWNLOAD_OK, null);
232         return downloadResult;
233     }
234
235     /**
236      * Method to write the downloaded distribution artifact to local file system.
237      *
238      * @param artifact the notification artifact
239      * @param resultArtifact the download result artifact
240      * @return the local path of written file
241      * @throws ArtifactDownloadException if error occurs while writing the artifact
242      */
243     private Path writeArtifactToFile(final IArtifactInfo artifact,
244             final IDistributionClientDownloadResult resultArtifact) throws ArtifactDownloadException {
245         try {
246             final byte[] payloadBytes = resultArtifact.getArtifactPayload();
247             final File tempArtifactFile = File.createTempFile(artifact.getArtifactName(), null);
248             try (FileOutputStream fileOutputStream = new FileOutputStream(tempArtifactFile)) {
249                 fileOutputStream.write(payloadBytes, 0, payloadBytes.length);
250                 return tempArtifactFile.toPath();
251             }
252         } catch (final Exception exp) {
253             final String message = "Failed to write artifact to local repository";
254             LOGGER.error(message, exp);
255             throw new ArtifactDownloadException(message, exp);
256         }
257     }
258
259     /**
260      * Method to delete the downloaded notification artifact from local file system.
261      *
262      * @param filePath the path of file
263      */
264     private void deleteArtifactFile(final Path filePath) {
265         try {
266             Files.deleteIfExists(filePath);
267         } catch (final IOException exp) {
268             LOGGER.error("Failed to delete the downloaded artifact file", exp);
269         }
270     }
271
272     /**
273      * Sends the distribution status to SDC using the input values.
274      *
275      * @param statusType the status type
276      * @param artifactUrl the artifact url
277      * @param distributionId the distribution id
278      * @param status the status
279      * @param errorReason the error reason
280      */
281     private void sendDistributionStatus(final DistributionStatusType statusType, final String artifactUrl,
282             final String distributionId, final DistributionStatusEnum status, final String errorReason) {
283
284         IDistributionClientResult clientResult;
285         final DistributionStatusMessageBuilder messageBuilder = new DistributionStatusMessageBuilder()
286                 .setArtifactUrl(artifactUrl).setConsumerId(sdcConfig.getConsumerID()).setDistributionId(distributionId)
287                 .setDistributionStatus(status).setTimestamp(System.currentTimeMillis());
288         final IDistributionStatusMessage message = new DistributionStatusMessage(messageBuilder);
289         if (DistributionStatusType.DOWNLOAD.equals(statusType)) {
290             if (errorReason != null) {
291                 clientResult = distributionClient.sendDownloadStatus(message, errorReason);
292             } else {
293                 clientResult = distributionClient.sendDownloadStatus(message);
294             }
295         } else {
296             if (errorReason != null) {
297                 clientResult = distributionClient.sendDeploymentStatus(message, errorReason);
298             } else {
299                 clientResult = distributionClient.sendDeploymentStatus(message);
300             }
301         }
302         final StringBuilder loggerMessage = new StringBuilder();
303         loggerMessage.append("distribution status to SDC with values - ").append("DistributionId")
304                 .append(distributionId).append(" Artifact: ").append(artifactUrl).append(" StatusType: ")
305                 .append(statusType.name()).append(" Status: ").append(status.name());
306         if (errorReason != null) {
307             loggerMessage.append(" ErrorReason: ").append(errorReason);
308         }
309         if (!clientResult.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) {
310             loggerMessage.insert(0, "Failed sending ");
311             LOGGER.debug(loggerMessage);
312         } else {
313             loggerMessage.insert(0, "Successfully Sent ");
314             LOGGER.debug(loggerMessage);
315         }
316     }
317
318     /**
319      * Sends the component done status to SDC using the input values.
320      *
321      * @param distributionId the distribution Id
322      * @param status the distribution status
323      * @param errorReason the error reason
324      */
325     private void sendComponentDoneStatus(final String distributionId, final DistributionStatusEnum status,
326             final String errorReason) {
327         IDistributionClientResult clientResult;
328         final ComponentDoneStatusMessageBuilder messageBuilder = new ComponentDoneStatusMessageBuilder()
329                 .setConsumerId(sdcConfig.getConsumerID()).setDistributionId(distributionId)
330                 .setDistributionStatus(status).setTimestamp(System.currentTimeMillis());
331         final IComponentDoneStatusMessage message = new ComponentDoneStatusMessage(messageBuilder);
332         if (errorReason == null) {
333             clientResult = distributionClient.sendComponentDoneStatus(message);
334         } else {
335             clientResult = distributionClient.sendComponentDoneStatus(message, errorReason);
336         }
337
338         final StringBuilder loggerMessage = new StringBuilder();
339         loggerMessage.append("component done status to SDC with values - ").append("DistributionId")
340                 .append(distributionId).append(" Status: ").append(status.name());
341         if (errorReason != null) {
342             loggerMessage.append(" ErrorReason: ").append(errorReason);
343         }
344         if (!clientResult.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) {
345             loggerMessage.insert(0, "Failed sending ");
346             LOGGER.debug(loggerMessage);
347         } else {
348             loggerMessage.insert(0, "Successfully Sent ");
349             LOGGER.debug(loggerMessage);
350         }
351     }
352
353     /**
354      * Handle the status change of {@link SdcReceptionHandler} to Idle.
355      *
356      * @param newStatus the new status
357      */
358     private void handleIdleStatusChange(final SdcReceptionHandlerStatus newStatus) {
359         if (nbOfNotificationsOngoing > 1) {
360             --nbOfNotificationsOngoing;
361         } else {
362             nbOfNotificationsOngoing = 0;
363             sdcReceptionHandlerStatus = newStatus;
364         }
365     }
366 }